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(
150 table_index_reg: &Reg,
151 table_size: u32,
152 table_byte_offset: u32,
153 ) -> Vec<u8> {
154 let idx = reg_to_bits(table_index_reg);
155 let mut bytes = Vec::with_capacity(32);
156 let size_lo = table_size & 0xFFFF;
158 let movw: u32 = 0xE300_0000 | ((size_lo >> 12) << 16) | (12 << 12) | (size_lo & 0xFFF);
159 bytes.extend_from_slice(&movw.to_le_bytes());
160 let size_hi = table_size >> 16;
162 if size_hi != 0 {
163 let movt: u32 = 0xE340_0000 | ((size_hi >> 12) << 16) | (12 << 12) | (size_hi & 0xFFF);
164 bytes.extend_from_slice(&movt.to_le_bytes());
165 }
166 let cmp: u32 = 0xE150_000C | (idx << 16);
168 bytes.extend_from_slice(&cmp.to_le_bytes());
169 bytes.extend_from_slice(&0x3A00_0000u32.to_le_bytes());
172 bytes.extend_from_slice(&0xE7F0_00F0u32.to_le_bytes());
175 let mov: u32 = 0xE1A0C000 | (2 << 7) | idx;
178 bytes.extend_from_slice(&mov.to_le_bytes());
179 if table_byte_offset == 0 {
180 let ldr: u32 = 0xE79BC00C;
183 bytes.extend_from_slice(&ldr.to_le_bytes());
184 } else {
185 assert!(
188 table_byte_offset <= 4095,
189 "call_indirect table base offset {table_byte_offset} exceeds \
190 LDR imm12 — the selector must have declined this (#650)"
191 );
192 bytes.extend_from_slice(&0xE08BC00Cu32.to_le_bytes());
194 let ldr: u32 = 0xE59CC000 | (table_byte_offset & 0xFFF);
196 bytes.extend_from_slice(&ldr.to_le_bytes());
197 }
198 let blx: u32 = 0xE12FFF3C;
200 bytes.extend_from_slice(&blx.to_le_bytes());
201 bytes
202 }
203
204 fn encode_arm_expanded(&self, op: &ArmOp) -> Result<Option<Vec<u8>>> {
213 use synth_synthesis::Condition;
214
215 fn cond_bits(cond: &Condition) -> u32 {
217 match cond {
218 Condition::EQ => 0x0,
219 Condition::NE => 0x1,
220 Condition::HS => 0x2, Condition::LO => 0x3, Condition::HI => 0x8, Condition::LS => 0x9, Condition::GE => 0xA,
225 Condition::LT => 0xB,
226 Condition::GT => 0xC,
227 Condition::LE => 0xD,
228 }
229 }
230 fn w(b: &mut Vec<u8>, word: u32) {
231 b.extend_from_slice(&word.to_le_bytes());
232 }
233 fn mov_cond_imm(b: &mut Vec<u8>, cond: u32, rd: u32, imm: u32) {
235 w(b, (cond << 28) | 0x03A0_0000 | (rd << 12) | imm);
236 }
237 fn set_cond(b: &mut Vec<u8>, cond: &Condition, rd: u32) {
239 mov_cond_imm(b, cond_bits(cond), rd, 1);
240 mov_cond_imm(b, cond_bits(&cond.invert()), rd, 0);
241 }
242 fn cmp_reg(b: &mut Vec<u8>, rn: u32, rm: u32) {
244 w(b, 0xE150_0000 | (rn << 16) | rm);
245 }
246 fn sbcs(b: &mut Vec<u8>, rd: u32, rn: u32, rm: u32) {
248 w(b, 0xE0D0_0000 | (rn << 16) | (rd << 12) | rm);
249 }
250 fn movw(b: &mut Vec<u8>, rd: u32, v: u32) {
252 w(
253 b,
254 0xE300_0000 | (((v >> 12) & 0xF) << 16) | (rd << 12) | (v & 0xFFF),
255 );
256 }
257 fn movt(b: &mut Vec<u8>, rd: u32, v: u32) {
259 w(
260 b,
261 0xE340_0000 | (((v >> 12) & 0xF) << 16) | (rd << 12) | (v & 0xFFF),
262 );
263 }
264 fn shift_reg(b: &mut Vec<u8>, ty: u32, rd: u32, rn: u32, rs: u32) {
269 w(b, 0xE1A0_0010 | (rd << 12) | (rs << 8) | (ty << 5) | rn);
270 }
271 const LSL: u32 = 0;
272 const LSR: u32 = 1;
273 const ASR: u32 = 2;
274 fn shift_imm(b: &mut Vec<u8>, ty: u32, rd: u32, rn: u32, imm: u32) {
276 w(
277 b,
278 0xE1A0_0000 | (rd << 12) | ((imm & 0x1F) << 7) | (ty << 5) | rn,
279 );
280 }
281 fn dp_reg(b: &mut Vec<u8>, base: u32, rd: u32, rn: u32, rm: u32) {
284 w(b, base | (rn << 16) | (rd << 12) | rm);
285 }
286 fn orr_lsr31(b: &mut Vec<u8>, rd: u32, rm: u32) {
289 w(
290 b,
291 0xE180_0000 | (rd << 16) | (rd << 12) | (31 << 7) | (1 << 5) | rm,
292 );
293 }
294 fn negate64(b: &mut Vec<u8>, lo: u32, hi: u32) {
296 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)); }
301 fn skip_negate_if_positive(b: &mut Vec<u8>, x: u32) {
304 w(b, 0xE110_0000 | (x << 16) | x); w(b, 0x5A00_0003); }
307 fn div_loop(b: &mut Vec<u8>, counter: u32) {
311 w(b, 0xE3A0_0040 | (counter << 12)); let loop_start = b.len();
313 shift_imm(b, LSL, 5, 5, 1);
315 orr_lsr31(b, 5, 4);
316 shift_imm(b, LSL, 4, 4, 1);
317 shift_imm(b, LSL, 7, 7, 1);
319 orr_lsr31(b, 7, 6);
320 shift_imm(b, LSL, 6, 6, 1);
321 orr_lsr31(b, 6, 1);
322 shift_imm(b, LSL, 1, 1, 1);
324 orr_lsr31(b, 1, 0);
325 shift_imm(b, LSL, 0, 0, 1);
326 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);
338 w(b, 0x1A00_0000 | (((diff / 4) as u32) & 0x00FF_FFFF)); }
340 fn popcnt_word(b: &mut Vec<u8>, x: u32, c: u32) {
344 shift_imm(b, LSR, 12, x, 1);
346 movw(b, c, 0x5555);
347 movt(b, c, 0x5555);
348 dp_reg(b, 0xE000_0000, 12, 12, c); dp_reg(b, 0xE040_0000, x, x, 12); movw(b, c, 0x3333);
352 movt(b, c, 0x3333);
353 dp_reg(b, 0xE000_0000, 12, x, c); shift_imm(b, LSR, x, x, 2);
355 dp_reg(b, 0xE000_0000, x, x, c); dp_reg(b, 0xE080_0000, x, x, 12); shift_imm(b, LSR, 12, x, 4);
359 dp_reg(b, 0xE080_0000, x, x, 12); movw(b, c, 0x0F0F);
361 movt(b, c, 0x0F0F);
362 dp_reg(b, 0xE000_0000, x, x, c); movw(b, c, 0x0101);
365 movt(b, c, 0x0101);
366 w(b, 0xE000_0090 | (x << 16) | (c << 8) | x); shift_imm(b, LSR, x, x, 24);
368 }
369
370 let mut b: Vec<u8> = Vec::new();
371 match op {
372 ArmOp::SetCond { rd, cond } => {
375 set_cond(&mut b, cond, reg_to_bits(rd));
376 }
377
378 ArmOp::SelectMove { rd, rm, cond } => {
380 w(
381 &mut b,
382 (cond_bits(cond) << 28)
383 | 0x01A0_0000
384 | (reg_to_bits(rd) << 12)
385 | reg_to_bits(rm),
386 );
387 }
388
389 ArmOp::I64SetCond {
394 rd,
395 rn_lo,
396 rn_hi,
397 rm_lo,
398 rm_hi,
399 cond,
400 } => {
401 let rd_b = reg_to_bits(rd);
402 let (n_lo, n_hi, m_lo, m_hi) = (
403 reg_to_bits(rn_lo),
404 reg_to_bits(rn_hi),
405 reg_to_bits(rm_lo),
406 reg_to_bits(rm_hi),
407 );
408 match cond {
409 Condition::EQ | Condition::NE => {
410 cmp_reg(&mut b, n_lo, m_lo);
411 w(&mut b, 0x0150_0000 | (n_hi << 16) | m_hi);
413 set_cond(&mut b, cond, rd_b);
414 }
415 Condition::LT => {
418 cmp_reg(&mut b, n_lo, m_lo);
419 sbcs(&mut b, rd_b, n_hi, m_hi);
420 set_cond(&mut b, &Condition::LT, rd_b);
421 }
422 Condition::GE => {
423 cmp_reg(&mut b, n_lo, m_lo);
424 sbcs(&mut b, rd_b, n_hi, m_hi);
425 set_cond(&mut b, &Condition::GE, rd_b);
426 }
427 Condition::GT => {
428 cmp_reg(&mut b, m_lo, n_lo);
429 sbcs(&mut b, rd_b, m_hi, n_hi);
430 set_cond(&mut b, &Condition::LT, rd_b);
431 }
432 Condition::LE => {
433 cmp_reg(&mut b, m_lo, n_lo);
434 sbcs(&mut b, rd_b, m_hi, n_hi);
435 set_cond(&mut b, &Condition::GE, rd_b);
436 }
437 Condition::LO => {
438 cmp_reg(&mut b, n_lo, m_lo);
439 sbcs(&mut b, rd_b, n_hi, m_hi);
440 set_cond(&mut b, &Condition::LO, rd_b);
441 }
442 Condition::HS => {
443 cmp_reg(&mut b, n_lo, m_lo);
444 sbcs(&mut b, rd_b, n_hi, m_hi);
445 set_cond(&mut b, &Condition::HS, rd_b);
446 }
447 Condition::HI => {
448 cmp_reg(&mut b, m_lo, n_lo);
449 sbcs(&mut b, rd_b, m_hi, n_hi);
450 set_cond(&mut b, &Condition::LO, rd_b);
451 }
452 Condition::LS => {
453 cmp_reg(&mut b, m_lo, n_lo);
454 sbcs(&mut b, rd_b, m_hi, n_hi);
455 set_cond(&mut b, &Condition::HS, rd_b);
456 }
457 }
458 }
459
460 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
462 let rd_b = reg_to_bits(rd);
463 w(
464 &mut b,
465 0xE190_0000 | (reg_to_bits(rn_lo) << 16) | (rd_b << 12) | reg_to_bits(rn_hi),
466 );
467 set_cond(&mut b, &Condition::EQ, rd_b);
468 }
469
470 ArmOp::I64Eqz { rd, rnlo, rnhi } => {
473 return self
474 .encode_arm(&ArmOp::I64SetCondZ {
475 rd: *rd,
476 rn_lo: *rnlo,
477 rn_hi: *rnhi,
478 })
479 .map(Some);
480 }
481 ArmOp::I64Eq {
482 rd,
483 rnlo,
484 rnhi,
485 rmlo,
486 rmhi,
487 }
488 | ArmOp::I64Ne {
489 rd,
490 rnlo,
491 rnhi,
492 rmlo,
493 rmhi,
494 }
495 | ArmOp::I64LtS {
496 rd,
497 rnlo,
498 rnhi,
499 rmlo,
500 rmhi,
501 }
502 | ArmOp::I64LtU {
503 rd,
504 rnlo,
505 rnhi,
506 rmlo,
507 rmhi,
508 }
509 | ArmOp::I64LeS {
510 rd,
511 rnlo,
512 rnhi,
513 rmlo,
514 rmhi,
515 }
516 | ArmOp::I64LeU {
517 rd,
518 rnlo,
519 rnhi,
520 rmlo,
521 rmhi,
522 }
523 | ArmOp::I64GtS {
524 rd,
525 rnlo,
526 rnhi,
527 rmlo,
528 rmhi,
529 }
530 | ArmOp::I64GtU {
531 rd,
532 rnlo,
533 rnhi,
534 rmlo,
535 rmhi,
536 }
537 | ArmOp::I64GeS {
538 rd,
539 rnlo,
540 rnhi,
541 rmlo,
542 rmhi,
543 }
544 | ArmOp::I64GeU {
545 rd,
546 rnlo,
547 rnhi,
548 rmlo,
549 rmhi,
550 } => {
551 let cond = match op {
552 ArmOp::I64Eq { .. } => Condition::EQ,
553 ArmOp::I64Ne { .. } => Condition::NE,
554 ArmOp::I64LtS { .. } => Condition::LT,
555 ArmOp::I64LtU { .. } => Condition::LO,
556 ArmOp::I64LeS { .. } => Condition::LE,
557 ArmOp::I64LeU { .. } => Condition::LS,
558 ArmOp::I64GtS { .. } => Condition::GT,
559 ArmOp::I64GtU { .. } => Condition::HI,
560 ArmOp::I64GeS { .. } => Condition::GE,
561 _ => Condition::HS,
562 };
563 return self
564 .encode_arm(&ArmOp::I64SetCond {
565 rd: *rd,
566 rn_lo: *rnlo,
567 rn_hi: *rnhi,
568 rm_lo: *rmlo,
569 rm_hi: *rmhi,
570 cond,
571 })
572 .map(Some);
573 }
574
575 ArmOp::I64Mul {
578 rd_lo,
579 rd_hi,
580 rn_lo,
581 rn_hi,
582 rm_lo,
583 rm_hi,
584 } => {
585 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
586 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
587 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
588 w(&mut b, 0xE000_0090 | (12 << 16) | (mh << 8) | nl);
590 w(
592 &mut b,
593 0xE020_0090 | (12 << 16) | (12 << 12) | (ml << 8) | nh,
594 );
595 w(
597 &mut b,
598 0xE080_0090 | (dh << 16) | (dl << 12) | (ml << 8) | nl,
599 );
600 w(&mut b, 0xE080_0000 | (dh << 16) | (dh << 12) | 12);
602 }
603
604 ArmOp::I64Shl {
609 rd_lo,
610 rd_hi,
611 rn_lo,
612 rn_hi,
613 rm_lo,
614 rm_hi,
615 } => {
616 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
617 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
618 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
619 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)); }
631 ArmOp::I64ShrU {
632 rd_lo,
633 rd_hi,
634 rn_lo,
635 rn_hi,
636 rm_lo,
637 rm_hi,
638 } => {
639 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
640 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
641 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
642 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)); }
654 ArmOp::I64ShrS {
655 rd_lo,
656 rd_hi,
657 rn_lo,
658 rn_hi,
659 rm_lo,
660 rm_hi,
661 } => {
662 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
663 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
664 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
665 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); }
677
678 ArmOp::I64Rotl {
682 rdlo,
683 rdhi,
684 rnlo,
685 rnhi,
686 shift,
687 } => {
688 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, shift]);
689 for word in [
690 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, ] {
712 w(&mut b, word);
713 }
714 emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
715 }
716 ArmOp::I64Rotr {
717 rdlo,
718 rdhi,
719 rnlo,
720 rnhi,
721 shift,
722 } => {
723 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, shift]);
724 for word in [
725 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, ] {
747 w(&mut b, word);
748 }
749 emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
750 }
751
752 ArmOp::I64Clz { rd, rnlo, rnhi } => {
756 let (rd_b, lo, hi) = (reg_to_bits(rd), reg_to_bits(rnlo), reg_to_bits(rnhi));
757 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)); }
763
764 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
768 let (rd_b, lo, hi) = (reg_to_bits(rd), reg_to_bits(rnlo), reg_to_bits(rnhi));
769 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)); }
776
777 ArmOp::I64Const { rdlo, rdhi, value } => {
780 let lo32 = *value as u32;
781 let hi32 = (*value >> 32) as u32;
782 movw(&mut b, reg_to_bits(rdlo), lo32 & 0xFFFF);
783 if lo32 > 0xFFFF {
784 movt(&mut b, reg_to_bits(rdlo), lo32 >> 16);
785 }
786 movw(&mut b, reg_to_bits(rdhi), hi32 & 0xFFFF);
787 if hi32 > 0xFFFF {
788 movt(&mut b, reg_to_bits(rdhi), hi32 >> 16);
789 }
790 }
791
792 ArmOp::I64Ldr { rdlo, rdhi, addr } | ArmOp::I64Str { rdlo, rdhi, addr } => {
796 let base = if let Some(rm) = addr.offset_reg {
797 w(
799 &mut b,
800 0xE080_0000
801 | (reg_to_bits(&addr.base) << 16)
802 | (12 << 12)
803 | reg_to_bits(&rm),
804 );
805 12
806 } else {
807 reg_to_bits(&addr.base)
808 };
809 if addr.offset < 0 || addr.offset > 0xFFB {
810 return Err(synth_core::Error::synthesis(format!(
811 "i64 load/store offset {} out of the A32 imm12 range (0..=4091) — materialize the offset into a register",
812 addr.offset
813 )));
814 }
815 let off = addr.offset as u32;
816 let opc: u32 = if matches!(op, ArmOp::I64Ldr { .. }) {
817 0xE590_0000 } else {
819 0xE580_0000 };
821 w(&mut b, opc | (base << 16) | (reg_to_bits(rdlo) << 12) | off);
822 w(
823 &mut b,
824 opc | (base << 16) | (reg_to_bits(rdhi) << 12) | (off + 4),
825 );
826 }
827
828 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
830 if rdlo != rn {
831 w(
832 &mut b,
833 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rn),
834 );
835 }
836 w(
837 &mut b,
838 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
839 );
840 }
841
842 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
844 if rdlo != rn {
845 w(
846 &mut b,
847 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rn),
848 );
849 }
850 w(&mut b, 0xE3A0_0000 | (reg_to_bits(rdhi) << 12));
851 }
852
853 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
855 w(
856 &mut b,
857 0xE6AF_0070 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
858 );
859 w(
860 &mut b,
861 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
862 );
863 }
864 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
865 w(
866 &mut b,
867 0xE6BF_0070 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
868 );
869 w(
870 &mut b,
871 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
872 );
873 }
874 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
875 if rdlo != rnlo {
876 w(
877 &mut b,
878 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
879 );
880 }
881 w(
882 &mut b,
883 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rnlo),
884 );
885 }
886
887 ArmOp::I32WrapI64 { rd, rnlo } => {
890 w(
891 &mut b,
892 0xE1A0_0000 | (reg_to_bits(rd) << 12) | reg_to_bits(rnlo),
893 );
894 }
895
896 ArmOp::I64Add {
900 rdlo,
901 rdhi,
902 rnlo,
903 rnhi,
904 rmlo,
905 rmhi,
906 } => {
907 dp_reg(
908 &mut b,
909 0xE090_0000, reg_to_bits(rdlo),
911 reg_to_bits(rnlo),
912 reg_to_bits(rmlo),
913 );
914 dp_reg(
915 &mut b,
916 0xE0A0_0000, reg_to_bits(rdhi),
918 reg_to_bits(rnhi),
919 reg_to_bits(rmhi),
920 );
921 }
922 ArmOp::I64Sub {
923 rdlo,
924 rdhi,
925 rnlo,
926 rnhi,
927 rmlo,
928 rmhi,
929 } => {
930 dp_reg(
931 &mut b,
932 0xE050_0000, reg_to_bits(rdlo),
934 reg_to_bits(rnlo),
935 reg_to_bits(rmlo),
936 );
937 dp_reg(
938 &mut b,
939 0xE0C0_0000, reg_to_bits(rdhi),
941 reg_to_bits(rnhi),
942 reg_to_bits(rmhi),
943 );
944 }
945
946 ArmOp::I64And {
948 rdlo,
949 rdhi,
950 rnlo,
951 rnhi,
952 rmlo,
953 rmhi,
954 }
955 | ArmOp::I64Or {
956 rdlo,
957 rdhi,
958 rnlo,
959 rnhi,
960 rmlo,
961 rmhi,
962 }
963 | ArmOp::I64Xor {
964 rdlo,
965 rdhi,
966 rnlo,
967 rnhi,
968 rmlo,
969 rmhi,
970 } => {
971 let base = match op {
972 ArmOp::I64And { .. } => 0xE000_0000, ArmOp::I64Or { .. } => 0xE180_0000, _ => 0xE020_0000, };
976 dp_reg(
977 &mut b,
978 base,
979 reg_to_bits(rdlo),
980 reg_to_bits(rnlo),
981 reg_to_bits(rmlo),
982 );
983 dp_reg(
984 &mut b,
985 base,
986 reg_to_bits(rdhi),
987 reg_to_bits(rnhi),
988 reg_to_bits(rmhi),
989 );
990 }
991
992 ArmOp::I64DivU {
996 rdlo,
997 rdhi,
998 rnlo,
999 rnhi,
1000 rmlo,
1001 rmhi,
1002 elide_zero_guard,
1003 } => {
1004 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1005 if !elide_zero_guard {
1008 emit_a32_i64_divisor_zero_trap(&mut b);
1009 }
1010 w(&mut b, 0xE92D_00F0); for r in 4..8u32 {
1012 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1014 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)?;
1019 }
1020
1021 ArmOp::I64DivS {
1024 rdlo,
1025 rdhi,
1026 rnlo,
1027 rnhi,
1028 rmlo,
1029 rmhi,
1030 elide_zero_guard,
1031 elide_overflow_guard,
1032 } => {
1033 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1034 if !elide_zero_guard {
1040 emit_a32_i64_divisor_zero_trap(&mut b);
1041 }
1042 if !elide_overflow_guard {
1043 emit_a32_i64_divs_overflow_trap(&mut b);
1046 }
1047 w(&mut b, 0xE92D_0FF0); w(&mut b, 0xE021_9003); skip_negate_if_positive(&mut b, 1);
1050 negate64(&mut b, 0, 1);
1051 skip_negate_if_positive(&mut b, 3);
1052 negate64(&mut b, 2, 3);
1053 for r in 4..8u32 {
1054 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1056 div_loop(&mut b, 8); w(&mut b, 0xE1A0_0004); w(&mut b, 0xE1A0_1005); skip_negate_if_positive(&mut b, 9);
1060 negate64(&mut b, 0, 1);
1061 w(&mut b, 0xE8BD_0FF0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
1063 }
1064
1065 ArmOp::I64RemU {
1067 rdlo,
1068 rdhi,
1069 rnlo,
1070 rnhi,
1071 rmlo,
1072 rmhi,
1073 elide_zero_guard,
1074 } => {
1075 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1076 if !elide_zero_guard {
1077 emit_a32_i64_divisor_zero_trap(&mut b);
1078 }
1079 w(&mut b, 0xE92D_01F0); for r in 4..8u32 {
1081 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1083 div_loop(&mut b, 8);
1084 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)?;
1088 }
1089
1090 ArmOp::I64RemS {
1092 rdlo,
1093 rdhi,
1094 rnlo,
1095 rnhi,
1096 rmlo,
1097 rmhi,
1098 elide_zero_guard,
1099 } => {
1100 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1101 if !elide_zero_guard {
1102 emit_a32_i64_divisor_zero_trap(&mut b);
1103 }
1104 w(&mut b, 0xE92D_0FF0); w(&mut b, 0xE1A0_9001); skip_negate_if_positive(&mut b, 1);
1107 negate64(&mut b, 0, 1);
1108 skip_negate_if_positive(&mut b, 3);
1109 negate64(&mut b, 2, 3);
1110 for r in 4..8u32 {
1111 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1113 div_loop(&mut b, 8);
1114 w(&mut b, 0xE1A0_0006); w(&mut b, 0xE1A0_1007); skip_negate_if_positive(&mut b, 9);
1117 negate64(&mut b, 0, 1);
1118 w(&mut b, 0xE8BD_0FF0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
1120 }
1121
1122 ArmOp::Popcnt { rd, rm } => {
1126 let rd_b = reg_to_bits(rd);
1127 if rd != rm {
1128 w(&mut b, 0xE1A0_0000 | (rd_b << 12) | reg_to_bits(rm)); }
1130 movw(&mut b, 12, 0x5555);
1132 movt(&mut b, 12, 0x5555);
1133 shift_imm(&mut b, LSR, 11, rd_b, 1);
1134 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);
1138 movt(&mut b, 12, 0x3333);
1139 dp_reg(&mut b, 0xE000_0000, 11, rd_b, 12); shift_imm(&mut b, LSR, rd_b, rd_b, 2);
1141 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);
1145 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11); movw(&mut b, 12, 0x0F0F);
1147 movt(&mut b, 12, 0x0F0F);
1148 dp_reg(&mut b, 0xE000_0000, rd_b, rd_b, 12); shift_imm(&mut b, LSR, 11, rd_b, 8);
1151 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11);
1152 shift_imm(&mut b, LSR, 11, rd_b, 16);
1153 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11);
1154 w(&mut b, 0xE200_003F | (rd_b << 16) | (rd_b << 12)); }
1156
1157 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
1161 let hi = reg_to_bits(rnhi);
1162 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);
1170 popcnt_word(&mut b, 5, 3);
1171 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)); }
1180
1181 _ => return Ok(None),
1182 }
1183 Ok(Some(b))
1184 }
1185
1186 fn encode_arm(&self, op: &ArmOp) -> Result<Vec<u8>> {
1187 if let Some(bytes) = self.encode_arm_expanded(op)? {
1194 return Ok(bytes);
1195 }
1196 if let Some(bytes) = self.encode_arm_reg_offset_mem(op)? {
1203 return Ok(bytes);
1204 }
1205 if let ArmOp::CallIndirect {
1211 table_index_reg,
1212 table_size,
1213 table_byte_offset,
1214 ..
1215 } = op
1216 {
1217 return Ok(Self::encode_arm_call_indirect(
1218 table_index_reg,
1219 *table_size,
1220 *table_byte_offset,
1221 ));
1222 }
1223 let instr: u32 = match op {
1224 ArmOp::Add { rd, rn, op2 } => {
1226 let rd_bits = reg_to_bits(rd);
1227 let rn_bits = reg_to_bits(rn);
1228 let (op2_bits, i_flag) = encode_operand2(op2)?;
1229
1230 0xE0800000 | (i_flag << 25)
1233 | (rn_bits << 16)
1234 | (rd_bits << 12)
1235 | op2_bits
1236 }
1237
1238 ArmOp::Sub { rd, rn, op2 } => {
1239 let rd_bits = reg_to_bits(rd);
1240 let rn_bits = reg_to_bits(rn);
1241 let (op2_bits, i_flag) = encode_operand2(op2)?;
1242
1243 0xE0400000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1245 }
1246
1247 ArmOp::Adds { rd, rn, op2 } => {
1249 let rd_bits = reg_to_bits(rd);
1250 let rn_bits = reg_to_bits(rn);
1251 let (op2_bits, i_flag) = encode_operand2(op2)?;
1252
1253 0xE0900000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1255 }
1256
1257 ArmOp::Adc { rd, rn, op2 } => {
1258 let rd_bits = reg_to_bits(rd);
1259 let rn_bits = reg_to_bits(rn);
1260 let (op2_bits, i_flag) = encode_operand2(op2)?;
1261
1262 0xE0A00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1264 }
1265
1266 ArmOp::Subs { rd, rn, op2 } => {
1267 let rd_bits = reg_to_bits(rd);
1268 let rn_bits = reg_to_bits(rn);
1269 let (op2_bits, i_flag) = encode_operand2(op2)?;
1270
1271 0xE0500000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1273 }
1274
1275 ArmOp::Sbc { rd, rn, op2 } => {
1276 let rd_bits = reg_to_bits(rd);
1277 let rn_bits = reg_to_bits(rn);
1278 let (op2_bits, i_flag) = encode_operand2(op2)?;
1279
1280 0xE0C00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1282 }
1283
1284 ArmOp::Mul { rd, rn, rm } => {
1285 let rd_bits = reg_to_bits(rd);
1286 let rn_bits = reg_to_bits(rn);
1287 let rm_bits = reg_to_bits(rm);
1288
1289 0xE0000090 | (rd_bits << 16) | (rn_bits << 8) | rm_bits
1291 }
1292
1293 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
1294 let rdlo_bits = reg_to_bits(rdlo);
1295 let rdhi_bits = reg_to_bits(rdhi);
1296 let rn_bits = reg_to_bits(rn);
1297 let rm_bits = reg_to_bits(rm);
1298
1299 0xE0800090 | (rdhi_bits << 16) | (rdlo_bits << 12) | (rm_bits << 8) | rn_bits
1301 }
1302
1303 ArmOp::Sdiv { rd, rn, rm } => {
1304 let rd_bits = reg_to_bits(rd);
1305 let rn_bits = reg_to_bits(rn);
1306 let rm_bits = reg_to_bits(rm);
1307
1308 0xE710F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
1311 }
1312
1313 ArmOp::Udiv { rd, rn, rm } => {
1314 let rd_bits = reg_to_bits(rd);
1315 let rn_bits = reg_to_bits(rn);
1316 let rm_bits = reg_to_bits(rm);
1317
1318 0xE730F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
1321 }
1322
1323 ArmOp::Mls { rd, rn, rm, ra } => {
1324 let rd_bits = reg_to_bits(rd);
1325 let rn_bits = reg_to_bits(rn);
1326 let rm_bits = reg_to_bits(rm);
1327 let ra_bits = reg_to_bits(ra);
1328
1329 0xE0600090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
1332 }
1333
1334 ArmOp::Mla { rd, rn, rm, ra } => {
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 let ra_bits = reg_to_bits(ra);
1339
1340 0xE0200090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
1343 }
1344
1345 ArmOp::And { rd, rn, op2 } => {
1346 let rd_bits = reg_to_bits(rd);
1347 let rn_bits = reg_to_bits(rn);
1348 let (op2_bits, i_flag) = encode_operand2(op2)?;
1349
1350 0xE0000000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1352 }
1353
1354 ArmOp::Orr { rd, rn, op2 } => {
1355 let rd_bits = reg_to_bits(rd);
1356 let rn_bits = reg_to_bits(rn);
1357 let (op2_bits, i_flag) = encode_operand2(op2)?;
1358
1359 0xE1800000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1361 }
1362
1363 ArmOp::Eor { rd, rn, op2 } => {
1364 let rd_bits = reg_to_bits(rd);
1365 let rn_bits = reg_to_bits(rn);
1366 let (op2_bits, i_flag) = encode_operand2(op2)?;
1367
1368 0xE0200000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1370 }
1371
1372 ArmOp::Lsl { rd, rn, shift } => {
1374 let rd_bits = reg_to_bits(rd);
1375 let rn_bits = reg_to_bits(rn);
1376 let shift_bits = *shift & 0x1F;
1377
1378 0xE1A00000 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1380 }
1381
1382 ArmOp::Lsr { rd, rn, shift } => {
1383 let rd_bits = reg_to_bits(rd);
1384 let rn_bits = reg_to_bits(rn);
1385 let shift_bits = *shift & 0x1F;
1386
1387 0xE1A00020 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1389 }
1390
1391 ArmOp::Asr { rd, rn, shift } => {
1392 let rd_bits = reg_to_bits(rd);
1393 let rn_bits = reg_to_bits(rn);
1394 let shift_bits = *shift & 0x1F;
1395
1396 0xE1A00040 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1398 }
1399
1400 ArmOp::Ror { rd, rn, shift } => {
1401 let rd_bits = reg_to_bits(rd);
1402 let rn_bits = reg_to_bits(rn);
1403 let shift_bits = *shift & 0x1F;
1404
1405 0xE1A00060 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1407 }
1408
1409 ArmOp::LslReg { rd, rn, rm } => {
1412 let rd_bits = reg_to_bits(rd);
1413 let rn_bits = reg_to_bits(rn);
1414 let rm_bits = reg_to_bits(rm);
1415 0xE1A00010 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1416 }
1417 ArmOp::LsrReg { rd, rn, rm } => {
1418 let rd_bits = reg_to_bits(rd);
1419 let rn_bits = reg_to_bits(rn);
1420 let rm_bits = reg_to_bits(rm);
1421 0xE1A00030 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1422 }
1423 ArmOp::AsrReg { rd, rn, rm } => {
1424 let rd_bits = reg_to_bits(rd);
1425 let rn_bits = reg_to_bits(rn);
1426 let rm_bits = reg_to_bits(rm);
1427 0xE1A00050 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1428 }
1429 ArmOp::RorReg { rd, rn, rm } => {
1430 let rd_bits = reg_to_bits(rd);
1431 let rn_bits = reg_to_bits(rn);
1432 let rm_bits = reg_to_bits(rm);
1433 0xE1A00070 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1434 }
1435
1436 ArmOp::Rsb { rd, rn, imm } => {
1438 let rd_bits = reg_to_bits(rd);
1439 let rn_bits = reg_to_bits(rn);
1440 0xE2600000 | (rn_bits << 16) | (rd_bits << 12) | (*imm & 0xFF)
1443 }
1444
1445 ArmOp::Clz { rd, rm } => {
1447 let rd_bits = reg_to_bits(rd);
1448 let rm_bits = reg_to_bits(rm);
1449
1450 0xE16F0F10 | (rd_bits << 12) | rm_bits
1453 }
1454
1455 ArmOp::Rbit { rd, rm } => {
1456 let rd_bits = reg_to_bits(rd);
1457 let rm_bits = reg_to_bits(rm);
1458
1459 0xE6FF0F30 | (rd_bits << 12) | rm_bits
1462 }
1463
1464 ArmOp::Sxtb { rd, rm } => {
1465 let rd_bits = reg_to_bits(rd);
1466 let rm_bits = reg_to_bits(rm);
1467
1468 0xE6AF0070 | (rd_bits << 12) | rm_bits
1471 }
1472
1473 ArmOp::Sxth { rd, rm } => {
1474 let rd_bits = reg_to_bits(rd);
1475 let rm_bits = reg_to_bits(rm);
1476
1477 0xE6BF0070 | (rd_bits << 12) | rm_bits
1480 }
1481
1482 ArmOp::Uxtb { rd, rm } => {
1483 let rd_bits = reg_to_bits(rd);
1484 let rm_bits = reg_to_bits(rm);
1485 0xE6EF0070 | (rd_bits << 12) | rm_bits
1487 }
1488
1489 ArmOp::Uxth { rd, rm } => {
1490 let rd_bits = reg_to_bits(rd);
1491 let rm_bits = reg_to_bits(rm);
1492 0xE6FF0070 | (rd_bits << 12) | rm_bits
1494 }
1495
1496 ArmOp::Mov { rd, op2 } => {
1498 let rd_bits = reg_to_bits(rd);
1499 let (op2_bits, i_flag) = encode_operand2(op2)?;
1500
1501 0xE1A00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
1503 }
1504
1505 ArmOp::Mvn { rd, op2 } => {
1506 let rd_bits = reg_to_bits(rd);
1507 let (op2_bits, i_flag) = encode_operand2(op2)?;
1508
1509 0xE1E00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
1511 }
1512
1513 ArmOp::Movw { rd, imm16 } => {
1516 let rd_bits = reg_to_bits(rd);
1517 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
1518 let imm12 = (*imm16 as u32) & 0xFFF;
1519 0xE3000000 | (imm4 << 16) | (rd_bits << 12) | imm12
1520 }
1521
1522 ArmOp::Movt { rd, imm16 } => {
1525 let rd_bits = reg_to_bits(rd);
1526 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
1527 let imm12 = (*imm16 as u32) & 0xFFF;
1528 0xE3400000 | (imm4 << 16) | (rd_bits << 12) | imm12
1529 }
1530
1531 ArmOp::MovwSym { rd, addend, .. } => {
1534 let rd_bits = reg_to_bits(rd);
1535 let v = (*addend as u32) & 0xffff;
1536 0xE3000000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
1537 }
1538 ArmOp::MovtSym { rd, addend, .. } => {
1539 let rd_bits = reg_to_bits(rd);
1540 let v = ((*addend as u32) >> 16) & 0xffff;
1541 0xE3400000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
1542 }
1543
1544 ArmOp::LdrSym { .. } => {
1548 return Err(synth_core::Error::synthesis(
1549 "LdrSym (literal-pool address load) is Thumb-2-only",
1550 ));
1551 }
1552
1553 ArmOp::Cmp { rn, op2 } => {
1555 let rn_bits = reg_to_bits(rn);
1556 let (op2_bits, i_flag) = encode_operand2(op2)?;
1557
1558 0xE1500000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
1560 }
1561
1562 ArmOp::Cmn { rn, op2 } => {
1564 let rn_bits = reg_to_bits(rn);
1565 let (op2_bits, i_flag) = encode_operand2(op2)?;
1566
1567 0xE1700000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
1569 }
1570
1571 ArmOp::Ldr { rd, addr } => {
1573 let rd_bits = reg_to_bits(rd);
1574 let (base_bits, offset_bits) = encode_mem_addr(addr);
1575
1576 0xE5900000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1579 }
1580
1581 ArmOp::Str { rd, addr } => {
1582 let rd_bits = reg_to_bits(rd);
1583 let (base_bits, offset_bits) = encode_mem_addr(addr);
1584
1585 0xE5800000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1587 }
1588
1589 ArmOp::Ldrb { rd, addr } => {
1591 let rd_bits = reg_to_bits(rd);
1592 let (base_bits, offset_bits) = encode_mem_addr(addr);
1593 0xE5D00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1595 }
1596
1597 ArmOp::Ldrsb { rd, addr } => {
1598 let rd_bits = reg_to_bits(rd);
1599 let (base_bits, offset_bits) = encode_mem_addr(addr);
1600 let offset_val = offset_bits & 0xFF;
1603 let imm4h = (offset_val >> 4) & 0xF;
1604 let imm4l = offset_val & 0xF;
1605 0xE1D000D0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1606 }
1607
1608 ArmOp::Ldrh { rd, addr } => {
1609 let rd_bits = reg_to_bits(rd);
1610 let (base_bits, offset_bits) = encode_mem_addr(addr);
1611 let offset_val = offset_bits & 0xFF;
1613 let imm4h = (offset_val >> 4) & 0xF;
1614 let imm4l = offset_val & 0xF;
1615 0xE1D000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1616 }
1617
1618 ArmOp::Ldrsh { 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;
1623 let imm4h = (offset_val >> 4) & 0xF;
1624 let imm4l = offset_val & 0xF;
1625 0xE1D000F0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1626 }
1627
1628 ArmOp::Strb { rd, addr } => {
1630 let rd_bits = reg_to_bits(rd);
1631 let (base_bits, offset_bits) = encode_mem_addr(addr);
1632 0xE5C00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1634 }
1635
1636 ArmOp::Strh { rd, addr } => {
1637 let rd_bits = reg_to_bits(rd);
1638 let (base_bits, offset_bits) = encode_mem_addr(addr);
1639 let offset_val = offset_bits & 0xFF;
1641 let imm4h = (offset_val >> 4) & 0xF;
1642 let imm4l = offset_val & 0xF;
1643 0xE1C000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1644 }
1645
1646 ArmOp::MemorySize { rd } => {
1648 let rd_bits = reg_to_bits(rd);
1649 0xE1A00820 | (rd_bits << 12) | 0x0A }
1654
1655 ArmOp::MemoryGrow { rd, .. } => {
1656 let rd_bits = reg_to_bits(rd);
1657 0xE3E00000 | (rd_bits << 12) }
1660
1661 ArmOp::Label { .. } => {
1663 return Ok(Vec::new());
1664 }
1665
1666 ArmOp::B { label: _ } => {
1668 0xEA000000
1671 }
1672
1673 ArmOp::Bcc { cond, label: _ } => {
1675 use synth_synthesis::Condition;
1676 let cond_bits: u32 = match cond {
1677 Condition::EQ => 0x0,
1678 Condition::NE => 0x1,
1679 Condition::HS => 0x2,
1680 Condition::LO => 0x3,
1681 Condition::HI => 0x8,
1682 Condition::LS => 0x9,
1683 Condition::GE => 0xA,
1684 Condition::LT => 0xB,
1685 Condition::GT => 0xC,
1686 Condition::LE => 0xD,
1687 };
1688 (cond_bits << 28) | 0x0A000000
1690 }
1691
1692 ArmOp::Bhs { label: _ } => {
1694 0x2A000000 }
1697
1698 ArmOp::Blo { label: _ } => {
1700 0x3A000000 }
1703
1704 ArmOp::BOffset { offset } => {
1708 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
1718 0xEA000000 | offset_bits
1719 }
1720
1721 ArmOp::BCondOffset { cond, offset } => {
1723 use synth_synthesis::Condition;
1724 let cond_bits: u32 = match cond {
1725 Condition::EQ => 0x0,
1726 Condition::NE => 0x1,
1727 Condition::HS => 0x2,
1728 Condition::LO => 0x3,
1729 Condition::HI => 0x8,
1730 Condition::LS => 0x9,
1731 Condition::GE => 0xA,
1732 Condition::LT => 0xB,
1733 Condition::GT => 0xC,
1734 Condition::LE => 0xD,
1735 };
1736 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
1740 (cond_bits << 28) | 0x0A000000 | offset_bits
1741 }
1742
1743 ArmOp::Bl { label: _ } => {
1744 0xEB000000
1746 }
1747
1748 ArmOp::Bx { rm } => {
1749 let rm_bits = reg_to_bits(rm);
1750
1751 0xE12FFF10 | rm_bits
1753 }
1754
1755 ArmOp::Blx { rm } => {
1756 let rm_bits = reg_to_bits(rm);
1757
1758 0xE12FFF30 | rm_bits
1760 }
1761
1762 ArmOp::Push { regs } => {
1763 let mut reg_list: u32 = 0;
1765 for r in regs {
1766 reg_list |= 1 << reg_to_bits(r);
1767 }
1768 0xE92D0000 | reg_list
1769 }
1770
1771 ArmOp::Pop { regs } => {
1772 let mut reg_list: u32 = 0;
1774 for r in regs {
1775 reg_list |= 1 << reg_to_bits(r);
1776 }
1777 0xE8BD0000 | reg_list
1778 }
1779
1780 ArmOp::Nop => {
1781 0xE1A00000
1783 }
1784
1785 ArmOp::Udf { imm } => {
1786 let imm8 = *imm as u32;
1789 0xE7F000F0 | ((imm8 & 0xF0) << 4) | (imm8 & 0x0F)
1790 }
1791
1792 ArmOp::Popcnt { .. } | ArmOp::SetCond { .. } | ArmOp::SelectMove { .. } => {
1796 unreachable!("handled by encode_arm_expanded (#615)")
1797 }
1798
1799 ArmOp::Select { .. }
1807 | ArmOp::LocalGet { .. }
1808 | ArmOp::LocalSet { .. }
1809 | ArmOp::LocalTee { .. }
1810 | ArmOp::GlobalGet { .. }
1811 | ArmOp::GlobalSet { .. }
1812 | ArmOp::BrTable { .. }
1813 | ArmOp::Call { .. } => {
1814 return Err(synth_core::Error::synthesis(format!(
1815 "verification-only pseudo-op {op:?} reached the A32 encoder — \
1816 codegen lowers it before encoding; refusing to emit a silent NOP (#615)"
1817 )));
1818 }
1819
1820 ArmOp::CallIndirect { .. } => {
1824 unreachable!("CallIndirect handled by encode_arm_call_indirect (#594)")
1825 }
1826
1827 ArmOp::I64Add { .. }
1832 | ArmOp::I64Sub { .. }
1833 | ArmOp::I64DivS { .. }
1834 | ArmOp::I64DivU { .. }
1835 | ArmOp::I64RemS { .. }
1836 | ArmOp::I64RemU { .. }
1837 | ArmOp::I64Clz { .. }
1838 | ArmOp::I64Ctz { .. }
1839 | ArmOp::I64Popcnt { .. }
1840 | ArmOp::I64And { .. }
1841 | ArmOp::I64Or { .. }
1842 | ArmOp::I64Xor { .. }
1843 | ArmOp::I64Eqz { .. }
1844 | ArmOp::I64Eq { .. }
1845 | ArmOp::I64Ne { .. }
1846 | ArmOp::I64LtS { .. }
1847 | ArmOp::I64LtU { .. }
1848 | ArmOp::I64LeS { .. }
1849 | ArmOp::I64LeU { .. }
1850 | ArmOp::I64GtS { .. }
1851 | ArmOp::I64GtU { .. }
1852 | ArmOp::I64GeS { .. }
1853 | ArmOp::I64GeU { .. }
1854 | ArmOp::I64Const { .. }
1855 | ArmOp::I64Ldr { .. }
1856 | ArmOp::I64Str { .. }
1857 | ArmOp::I64ExtendI32S { .. }
1858 | ArmOp::I64ExtendI32U { .. }
1859 | ArmOp::I64Extend8S { .. }
1860 | ArmOp::I64Extend16S { .. }
1861 | ArmOp::I64Extend32S { .. }
1862 | ArmOp::I32WrapI64 { .. } => {
1863 unreachable!("handled by encode_arm_expanded (#615)")
1864 }
1865
1866 ArmOp::F32Add { sd, sn, sm } => encode_vfp_3reg(0xEE300A00, sd, sn, sm)?,
1868 ArmOp::F32Sub { sd, sn, sm } => encode_vfp_3reg(0xEE300A40, sd, sn, sm)?,
1869 ArmOp::F32Mul { sd, sn, sm } => encode_vfp_3reg(0xEE200A00, sd, sn, sm)?,
1870 ArmOp::F32Div { sd, sn, sm } => encode_vfp_3reg(0xEE800A00, sd, sn, sm)?,
1871 ArmOp::F32Abs { sd, sm } => encode_vfp_2reg(0xEEB00AC0, sd, sm)?,
1872 ArmOp::F32Neg { sd, sm } => encode_vfp_2reg(0xEEB10A40, sd, sm)?,
1873 ArmOp::F32Sqrt { sd, sm } => encode_vfp_2reg(0xEEB10AC0, sd, sm)?,
1874
1875 ArmOp::F32Ceil { sd, sm } => {
1878 return self.encode_arm_f32_rounding(sd, sm, 0b01); }
1880 ArmOp::F32Floor { sd, sm } => {
1881 return self.encode_arm_f32_rounding(sd, sm, 0b10); }
1883 ArmOp::F32Trunc { sd, sm } => {
1884 return self.encode_arm_f32_rounding(sd, sm, 0b11); }
1886 ArmOp::F32Nearest { sd, sm } => {
1887 return self.encode_arm_f32_rounding(sd, sm, 0b00); }
1889 ArmOp::F32Min { sd, sn, sm } => {
1890 return self.encode_arm_f32_minmax(sd, sn, sm, true);
1891 }
1892 ArmOp::F32Max { sd, sn, sm } => {
1893 return self.encode_arm_f32_minmax(sd, sn, sm, false);
1894 }
1895 ArmOp::F32Copysign { sd, sn, sm } => {
1896 return self.encode_arm_f32_copysign(sd, sn, sm);
1897 }
1898
1899 ArmOp::F32Eq { rd, sn, sm } => {
1901 return self.encode_arm_f32_compare(rd, sn, sm, 0x0); }
1903 ArmOp::F32Ne { rd, sn, sm } => {
1904 return self.encode_arm_f32_compare(rd, sn, sm, 0x1); }
1906 ArmOp::F32Lt { rd, sn, sm } => {
1907 return self.encode_arm_f32_compare(rd, sn, sm, 0x4); }
1909 ArmOp::F32Le { rd, sn, sm } => {
1910 return self.encode_arm_f32_compare(rd, sn, sm, 0x9); }
1912 ArmOp::F32Gt { rd, sn, sm } => {
1913 return self.encode_arm_f32_compare(rd, sn, sm, 0xC); }
1915 ArmOp::F32Ge { rd, sn, sm } => {
1916 return self.encode_arm_f32_compare(rd, sn, sm, 0xA); }
1918
1919 ArmOp::F32Const { sd, value } => {
1921 return self.encode_arm_f32_const(sd, *value);
1922 }
1923
1924 ArmOp::F32Load { sd, addr } => encode_vfp_ldst(0xED900A00, sd, addr)?,
1925 ArmOp::F32Store { sd, addr } => encode_vfp_ldst(0xED800A00, sd, addr)?,
1926
1927 ArmOp::F32ConvertI32S { sd, rm } => {
1929 return self.encode_arm_f32_convert_i32(sd, rm, true);
1930 }
1931 ArmOp::F32ConvertI32U { sd, rm } => {
1932 return self.encode_arm_f32_convert_i32(sd, rm, false);
1933 }
1934 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
1935 return Err(synth_core::Error::synthesis(
1936 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
1937 ));
1938 }
1939 ArmOp::F32ReinterpretI32 { sd, rm } => encode_vmov_core_sreg(true, sd, rm)?,
1940 ArmOp::I32ReinterpretF32 { rd, sm } => encode_vmov_core_sreg(false, sm, rd)?,
1941 ArmOp::I32TruncF32S { rd, sm } => {
1942 return self.encode_arm_i32_trunc_f32(rd, sm, true);
1943 }
1944 ArmOp::I32TruncF32U { rd, sm } => {
1945 return self.encode_arm_i32_trunc_f32(rd, sm, false);
1946 }
1947
1948 ArmOp::F64Add { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B00, dd, dn, dm)?,
1951 ArmOp::F64Sub { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B40, dd, dn, dm)?,
1952 ArmOp::F64Mul { dd, dn, dm } => encode_vfp_3reg_f64(0xEE200B00, dd, dn, dm)?,
1953 ArmOp::F64Div { dd, dn, dm } => encode_vfp_3reg_f64(0xEE800B00, dd, dn, dm)?,
1954 ArmOp::F64Abs { dd, dm } => encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?,
1955 ArmOp::F64Neg { dd, dm } => encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?,
1956 ArmOp::F64Sqrt { dd, dm } => encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?,
1957
1958 ArmOp::F64Ceil { dd, dm } => {
1961 return self.encode_arm_f64_rounding(dd, dm, 0b01);
1962 }
1963 ArmOp::F64Floor { dd, dm } => {
1964 return self.encode_arm_f64_rounding(dd, dm, 0b10);
1965 }
1966 ArmOp::F64Trunc { dd, dm } => {
1967 return self.encode_arm_f64_rounding(dd, dm, 0b11);
1968 }
1969 ArmOp::F64Nearest { dd, dm } => {
1970 return self.encode_arm_f64_rounding(dd, dm, 0b00);
1971 }
1972 ArmOp::F64Min { dd, dn, dm } => {
1973 return self.encode_arm_f64_minmax(dd, dn, dm, true);
1974 }
1975 ArmOp::F64Max { dd, dn, dm } => {
1976 return self.encode_arm_f64_minmax(dd, dn, dm, false);
1977 }
1978 ArmOp::F64Copysign { dd, dn, dm } => {
1979 return self.encode_arm_f64_copysign(dd, dn, dm);
1980 }
1981
1982 ArmOp::F64Eq { rd, dn, dm } => {
1984 return self.encode_arm_f64_compare(rd, dn, dm, 0x0);
1985 }
1986 ArmOp::F64Ne { rd, dn, dm } => {
1987 return self.encode_arm_f64_compare(rd, dn, dm, 0x1);
1988 }
1989 ArmOp::F64Lt { rd, dn, dm } => {
1990 return self.encode_arm_f64_compare(rd, dn, dm, 0x4);
1991 }
1992 ArmOp::F64Le { rd, dn, dm } => {
1993 return self.encode_arm_f64_compare(rd, dn, dm, 0x9);
1994 }
1995 ArmOp::F64Gt { rd, dn, dm } => {
1996 return self.encode_arm_f64_compare(rd, dn, dm, 0xC);
1997 }
1998 ArmOp::F64Ge { rd, dn, dm } => {
1999 return self.encode_arm_f64_compare(rd, dn, dm, 0xA);
2000 }
2001
2002 ArmOp::F64Const { dd, value } => {
2003 return self.encode_arm_f64_const(dd, *value);
2004 }
2005
2006 ArmOp::F64Load { dd, addr } => encode_vfp_ldst_f64(0xED900B00, dd, addr)?,
2007 ArmOp::F64Store { dd, addr } => encode_vfp_ldst_f64(0xED800B00, dd, addr)?,
2008
2009 ArmOp::F64ConvertI32S { dd, rm } => {
2010 return self.encode_arm_f64_convert_i32(dd, rm, true);
2011 }
2012 ArmOp::F64ConvertI32U { dd, rm } => {
2013 return self.encode_arm_f64_convert_i32(dd, rm, false);
2014 }
2015 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
2016 return Err(synth_core::Error::synthesis(
2017 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
2018 ));
2019 }
2020 ArmOp::F64PromoteF32 { dd, sm } => {
2021 return self.encode_arm_f64_promote_f32(dd, sm);
2022 }
2023 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => {
2024 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?
2025 }
2026 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => {
2027 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?
2028 }
2029 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
2030 return Err(synth_core::Error::synthesis(
2031 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
2032 ));
2033 }
2034 ArmOp::I32TruncF64S { rd, dm } => {
2035 return self.encode_arm_i32_trunc_f64(rd, dm, true);
2036 }
2037 ArmOp::I32TruncF64U { rd, dm } => {
2038 return self.encode_arm_i32_trunc_f64(rd, dm, false);
2039 }
2040 ArmOp::I64SetCond { .. }
2043 | ArmOp::I64SetCondZ { .. }
2044 | ArmOp::I64Mul { .. }
2045 | ArmOp::I64Shl { .. }
2046 | ArmOp::I64ShrS { .. }
2047 | ArmOp::I64ShrU { .. }
2048 | ArmOp::I64Rotl { .. }
2049 | ArmOp::I64Rotr { .. } => {
2050 unreachable!("handled by encode_arm_expanded (#615)")
2051 }
2052
2053 ArmOp::MveLoad { .. }
2055 | ArmOp::MveStore { .. }
2056 | ArmOp::MveConst { .. }
2057 | ArmOp::MveAnd { .. }
2058 | ArmOp::MveOrr { .. }
2059 | ArmOp::MveEor { .. }
2060 | ArmOp::MveMvn { .. }
2061 | ArmOp::MveBic { .. }
2062 | ArmOp::MveAddI { .. }
2063 | ArmOp::MveSubI { .. }
2064 | ArmOp::MveMulI { .. }
2065 | ArmOp::MveNegI { .. }
2066 | ArmOp::MveCmpEqI { .. }
2067 | ArmOp::MveCmpNeI { .. }
2068 | ArmOp::MveCmpLtS { .. }
2069 | ArmOp::MveCmpLtU { .. }
2070 | ArmOp::MveCmpGtS { .. }
2071 | ArmOp::MveCmpGtU { .. }
2072 | ArmOp::MveCmpLeS { .. }
2073 | ArmOp::MveCmpLeU { .. }
2074 | ArmOp::MveCmpGeS { .. }
2075 | ArmOp::MveCmpGeU { .. }
2076 | ArmOp::MveDup { .. }
2077 | ArmOp::MveExtractLane { .. }
2078 | ArmOp::MveInsertLane { .. }
2079 | ArmOp::MveAddF32 { .. }
2080 | ArmOp::MveSubF32 { .. }
2081 | ArmOp::MveMulF32 { .. }
2082 | ArmOp::MveNegF32 { .. }
2083 | ArmOp::MveAbsF32 { .. }
2084 | ArmOp::MveCmpEqF32 { .. }
2085 | ArmOp::MveCmpNeF32 { .. }
2086 | ArmOp::MveCmpLtF32 { .. }
2087 | ArmOp::MveCmpLeF32 { .. }
2088 | ArmOp::MveCmpGtF32 { .. }
2089 | ArmOp::MveCmpGeF32 { .. }
2090 | ArmOp::MveDupF32 { .. }
2091 | ArmOp::MveExtractLaneF32 { .. }
2092 | ArmOp::MveReplaceLaneF32 { .. }
2093 | ArmOp::MveDivF32 { .. }
2094 | ArmOp::MveSqrtF32 { .. } => {
2095 return Err(synth_core::Error::synthesis(format!(
2101 "MVE op {op:?} has no A32 (ARM-mode) encoding — MVE is Thumb-2 only (#615)"
2102 )));
2103 }
2104 };
2105
2106 Ok(instr.to_le_bytes().to_vec())
2108 }
2109
2110 fn encode_arm_f32_compare(
2114 &self,
2115 rd: &Reg,
2116 sn: &VfpReg,
2117 sm: &VfpReg,
2118 cond_code: u32,
2119 ) -> Result<Vec<u8>> {
2120 let mut bytes = Vec::new();
2121
2122 let sn_num = vfp_sreg_to_num(sn)?;
2124 let sm_num = vfp_sreg_to_num(sm)?;
2125 let (vd, d) = encode_sreg(sn_num);
2126 let (vm, m) = encode_sreg(sm_num);
2127 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2128 bytes.extend_from_slice(&vcmp.to_le_bytes());
2129
2130 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2132
2133 let rd_bits = reg_to_bits(rd);
2135 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2136 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2137
2138 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2140 bytes.extend_from_slice(&mov_one.to_le_bytes());
2141
2142 Ok(bytes)
2143 }
2144
2145 fn encode_arm_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
2147 let mut bytes = Vec::new();
2148 let bits = value.to_bits();
2149
2150 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
2155 let movw = 0xE3000000 | (rt << 12) | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2156 bytes.extend_from_slice(&movw.to_le_bytes());
2157
2158 let hi16 = (bits >> 16) & 0xFFFF;
2160 let movt = 0xE3400000 | (rt << 12) | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2161 bytes.extend_from_slice(&movt.to_le_bytes());
2162
2163 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
2165 bytes.extend_from_slice(&vmov.to_le_bytes());
2166
2167 Ok(bytes)
2168 }
2169
2170 fn encode_arm_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2172 let mut bytes = Vec::new();
2173
2174 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
2176 bytes.extend_from_slice(&vmov.to_le_bytes());
2177
2178 let sd_num = vfp_sreg_to_num(sd)?;
2181 let (vd, d) = encode_sreg(sd_num);
2182 let (vm, m) = encode_sreg(sd_num); let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
2184 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2185 bytes.extend_from_slice(&vcvt.to_le_bytes());
2186
2187 Ok(bytes)
2188 }
2189
2190 fn encode_arm_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2202 let mut bytes = Vec::new();
2203 let sm_num = vfp_sreg_to_num(sm)?;
2204 let sd_num = vfp_sreg_to_num(sd)?;
2205 let (vd_s, d_s) = encode_sreg(sd_num);
2206 let (vm_s, m_s) = encode_sreg(sm_num);
2207
2208 if mode == 0b11 {
2209 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2212 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2213 } else {
2214 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
2219 bytes.extend_from_slice(&vmrs.to_le_bytes());
2220
2221 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2224 bytes.extend_from_slice(&bic.to_le_bytes());
2225
2226 if mode != 0 {
2228 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2230 bytes.extend_from_slice(&orr.to_le_bytes());
2231 }
2232
2233 let vmsr = 0xEEE10A10 | (rt << 12);
2235 bytes.extend_from_slice(&vmsr.to_le_bytes());
2236
2237 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2239 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2240
2241 bytes.extend_from_slice(&vmrs.to_le_bytes());
2243 bytes.extend_from_slice(&bic.to_le_bytes());
2244 bytes.extend_from_slice(&vmsr.to_le_bytes());
2245 }
2246
2247 let (vd2, d2) = encode_sreg(sd_num);
2249 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
2250 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2251
2252 Ok(bytes)
2253 }
2254
2255 fn encode_arm_f32_minmax(
2257 &self,
2258 sd: &VfpReg,
2259 sn: &VfpReg,
2260 sm: &VfpReg,
2261 is_min: bool,
2262 ) -> Result<Vec<u8>> {
2263 let mut bytes = Vec::new();
2264 let sn_num = vfp_sreg_to_num(sn)?;
2265 let sm_num = vfp_sreg_to_num(sm)?;
2266 let sd_num = vfp_sreg_to_num(sd)?;
2267
2268 let (vd, d) = encode_sreg(sd_num);
2270 let (vn, n) = encode_sreg(sn_num);
2271 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2272 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2273
2274 let (vm, m) = encode_sreg(sm_num);
2276 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2277 bytes.extend_from_slice(&vcmp.to_le_bytes());
2278
2279 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2281
2282 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2285
2286 let vmov_cond = (cond << 28) | 0x0EB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2288 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2289
2290 Ok(bytes)
2291 }
2292
2293 fn encode_arm_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2295 let mut bytes = Vec::new();
2296
2297 let vmov_sm = encode_vmov_core_sreg(false, sm, &Reg::R12)?;
2299 bytes.extend_from_slice(&vmov_sm.to_le_bytes());
2300
2301 let vmov_sn = encode_vmov_core_sreg(false, sn, &Reg::R0)?;
2303 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2304
2305 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2309 bytes.extend_from_slice(&and_sign.to_le_bytes());
2310
2311 let bic_sign = 0xE3C00000u32 | (1 << 8) | 0x02;
2314 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2315
2316 let orr = 0xE1800000u32 | 12;
2319 bytes.extend_from_slice(&orr.to_le_bytes());
2320
2321 let vmov_result = encode_vmov_core_sreg(true, sd, &Reg::R0)?;
2323 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2324
2325 Ok(bytes)
2326 }
2327
2328 fn encode_arm_f64_compare(
2330 &self,
2331 rd: &Reg,
2332 dn: &VfpReg,
2333 dm: &VfpReg,
2334 cond_code: u32,
2335 ) -> Result<Vec<u8>> {
2336 let mut bytes = Vec::new();
2337
2338 let dn_num = vfp_dreg_to_num(dn)?;
2340 let dm_num = vfp_dreg_to_num(dm)?;
2341 let (vd, d) = encode_dreg(dn_num);
2342 let (vm, m) = encode_dreg(dm_num);
2343 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2344 bytes.extend_from_slice(&vcmp.to_le_bytes());
2345
2346 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2348
2349 let rd_bits = reg_to_bits(rd);
2351 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2352 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2353
2354 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2356 bytes.extend_from_slice(&mov_one.to_le_bytes());
2357
2358 Ok(bytes)
2359 }
2360
2361 fn encode_arm_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
2363 let mut bytes = Vec::new();
2364 let bits = value.to_bits();
2365 let lo32 = bits as u32;
2366 let hi32 = (bits >> 32) as u32;
2367
2368 let lo16 = lo32 & 0xFFFF;
2370 let movw_r0 = 0xE3000000 | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2371 bytes.extend_from_slice(&movw_r0.to_le_bytes());
2372 let hi16 = (lo32 >> 16) & 0xFFFF;
2373 let movt_r0 = 0xE3400000 | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2374 bytes.extend_from_slice(&movt_r0.to_le_bytes());
2375
2376 let lo16 = hi32 & 0xFFFF;
2378 let movw_r12 = 0xE3000000 | ((lo16 >> 12) << 16) | (12 << 12) | (lo16 & 0xFFF);
2379 bytes.extend_from_slice(&movw_r12.to_le_bytes());
2380 let hi16 = (hi32 >> 16) & 0xFFFF;
2381 let movt_r12 = 0xE3400000 | ((hi16 >> 12) << 16) | (12 << 12) | (hi16 & 0xFFF);
2382 bytes.extend_from_slice(&movt_r12.to_le_bytes());
2383
2384 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
2386 bytes.extend_from_slice(&vmov.to_le_bytes());
2387
2388 Ok(bytes)
2389 }
2390
2391 fn encode_arm_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2393 let mut bytes = Vec::new();
2394
2395 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
2397 bytes.extend_from_slice(&vmov.to_le_bytes());
2398
2399 let dd_num = vfp_dreg_to_num(dd)?;
2402 let (vd, d) = encode_dreg(dd_num);
2403 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
2404 let vcvt = base | (d << 22) | (vd << 12);
2406 bytes.extend_from_slice(&vcvt.to_le_bytes());
2407
2408 Ok(bytes)
2409 }
2410
2411 fn encode_arm_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2413 let dd_num = vfp_dreg_to_num(dd)?;
2414 let sm_num = vfp_sreg_to_num(sm)?;
2415 let (vd, d) = encode_dreg(dd_num);
2416 let (vm, m) = encode_sreg(sm_num);
2417
2418 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
2420 Ok(vcvt.to_le_bytes().to_vec())
2421 }
2422
2423 fn encode_arm_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2425 let mut bytes = Vec::new();
2426 let dm_num = vfp_dreg_to_num(dm)?;
2427 let (vm, m) = encode_dreg(dm_num);
2428
2429 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
2432 let vcvt = base | (m << 5) | vm;
2433 bytes.extend_from_slice(&vcvt.to_le_bytes());
2434
2435 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
2437 bytes.extend_from_slice(&vmov.to_le_bytes());
2438
2439 Ok(bytes)
2440 }
2441
2442 fn encode_arm_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2450 let mut bytes = Vec::new();
2451 let dm_num = vfp_dreg_to_num(dm)?;
2452 let dd_num = vfp_dreg_to_num(dd)?;
2453 let (vm, m) = encode_dreg(dm_num);
2454 let (vd, d) = encode_dreg(dd_num);
2455
2456 if mode == 0b11 {
2457 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
2459 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2460 } else {
2461 let rt: u32 = 12;
2463
2464 let vmrs = 0xEEF10A10 | (rt << 12);
2466 bytes.extend_from_slice(&vmrs.to_le_bytes());
2467
2468 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2470 bytes.extend_from_slice(&bic.to_le_bytes());
2471
2472 if mode != 0 {
2474 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2475 bytes.extend_from_slice(&orr.to_le_bytes());
2476 }
2477
2478 let vmsr = 0xEEE10A10 | (rt << 12);
2480 bytes.extend_from_slice(&vmsr.to_le_bytes());
2481
2482 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
2484 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2485
2486 bytes.extend_from_slice(&vmrs.to_le_bytes());
2488 bytes.extend_from_slice(&bic.to_le_bytes());
2489 bytes.extend_from_slice(&vmsr.to_le_bytes());
2490 }
2491
2492 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
2494 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2495
2496 Ok(bytes)
2497 }
2498
2499 fn encode_arm_f64_minmax(
2501 &self,
2502 dd: &VfpReg,
2503 dn: &VfpReg,
2504 dm: &VfpReg,
2505 is_min: bool,
2506 ) -> Result<Vec<u8>> {
2507 let mut bytes = Vec::new();
2508 let dn_num = vfp_dreg_to_num(dn)?;
2509 let dm_num = vfp_dreg_to_num(dm)?;
2510 let dd_num = vfp_dreg_to_num(dd)?;
2511
2512 let (vd, d) = encode_dreg(dd_num);
2514 let (vn, n) = encode_dreg(dn_num);
2515 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2516 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2517
2518 let (vm, m) = encode_dreg(dm_num);
2520 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2521 bytes.extend_from_slice(&vcmp.to_le_bytes());
2522
2523 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2525
2526 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2527 let vmov_cond = (cond << 28) | 0x0EB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2528 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2529
2530 Ok(bytes)
2531 }
2532
2533 fn encode_arm_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
2535 let mut bytes = Vec::new();
2536
2537 let vmov_dm = encode_vmov_core_dreg(false, dm, &Reg::R0, &Reg::R12)?;
2539 bytes.extend_from_slice(&vmov_dm.to_le_bytes());
2540
2541 let vmov_dn = encode_vmov_core_dreg(false, dn, &Reg::R1, &Reg::R2)?;
2544 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2545
2546 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2548 bytes.extend_from_slice(&and_sign.to_le_bytes());
2549
2550 let bic_sign = 0xE3C00000u32 | (2 << 16) | (2 << 12) | (1 << 8) | 0x02;
2552 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2553
2554 let orr = 0xE1800000u32 | (2 << 16) | (2 << 12) | 12;
2556 bytes.extend_from_slice(&orr.to_le_bytes());
2557
2558 let vmov_result = encode_vmov_core_dreg(true, dd, &Reg::R1, &Reg::R2)?;
2560 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2561
2562 Ok(bytes)
2563 }
2564
2565 fn encode_arm_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2567 let mut bytes = Vec::new();
2568
2569 let sm_num = vfp_sreg_to_num(sm)?;
2572 let (vd, d) = encode_sreg(sm_num);
2573 let (vm, m) = encode_sreg(sm_num);
2574 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
2575 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2576 bytes.extend_from_slice(&vcvt.to_le_bytes());
2577
2578 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
2580 bytes.extend_from_slice(&vmov.to_le_bytes());
2581
2582 Ok(bytes)
2583 }
2584
2585 fn encode_thumb(&self, op: &ArmOp) -> Result<Vec<u8>> {
2587 match op {
2590 ArmOp::Add { rd, rn, op2 } => {
2592 let rd_bits = reg_to_bits(rd) as u16;
2593 let rn_bits = reg_to_bits(rn) as u16;
2594
2595 if let Operand2::Reg(rm) = op2 {
2596 let rm_bits = reg_to_bits(rm) as u16;
2597 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2605 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2607 Ok(instr.to_le_bytes().to_vec())
2608 } else {
2609 self.encode_thumb32_add_reg_raw(
2611 rd_bits as u32,
2612 rn_bits as u32,
2613 rm_bits as u32,
2614 )
2615 }
2616 } else if let Operand2::Imm(imm) = op2 {
2617 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2618 let instr: u16 = 0x1C00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2620 Ok(instr.to_le_bytes().to_vec())
2621 } else {
2622 self.encode_thumb32_add(rd, rn, *imm as u32)
2624 }
2625 } else {
2626 self.encode_thumb32_add(rd, rn, 0)
2628 }
2629 }
2630
2631 ArmOp::Sub { rd, rn, op2 } => {
2632 let rd_bits = reg_to_bits(rd) as u16;
2633 let rn_bits = reg_to_bits(rn) as u16;
2634
2635 if let Operand2::Reg(rm) = op2 {
2636 let rm_bits = reg_to_bits(rm) as u16;
2637 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2639 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2641 Ok(instr.to_le_bytes().to_vec())
2642 } else {
2643 self.encode_thumb32_sub_reg_raw(
2645 rd_bits as u32,
2646 rn_bits as u32,
2647 rm_bits as u32,
2648 )
2649 }
2650 } else if let Operand2::Imm(imm) = op2 {
2651 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2652 let instr: u16 = 0x1E00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2654 Ok(instr.to_le_bytes().to_vec())
2655 } else {
2656 self.encode_thumb32_sub(rd, rn, *imm as u32)
2657 }
2658 } else {
2659 self.encode_thumb32_sub(rd, rn, 0)
2660 }
2661 }
2662
2663 ArmOp::Mov { rd, op2 } => {
2664 let rd_bits = reg_to_bits(rd) as u16;
2665
2666 if let Operand2::Imm(imm) = op2 {
2667 let uimm = *imm as u32;
2680 if uimm <= 255 && rd_bits < 8 {
2681 let imm_bits = (*imm as u16) & 0xFF;
2683 let instr: u16 = 0x2000 | (rd_bits << 8) | imm_bits;
2684 Ok(instr.to_le_bytes().to_vec())
2685 } else if uimm <= 0xFFFF {
2686 self.encode_thumb32_movw(rd, uimm)
2688 } else {
2689 let mut bytes = self.encode_thumb32_movw(rd, uimm & 0xFFFF)?;
2691 bytes.extend(self.encode_thumb32_movt_raw(reg_to_bits(rd), uimm >> 16)?);
2692 Ok(bytes)
2693 }
2694 } else if let Operand2::Reg(rm) = op2 {
2695 let rm_bits = reg_to_bits(rm) as u16;
2696 let d_bit = (rd_bits >> 3) & 1;
2699 let instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
2700 Ok(instr.to_le_bytes().to_vec())
2701 } else {
2702 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2704 }
2705 }
2706
2707 ArmOp::Push { regs } => {
2708 let mut reg_list: u16 = 0;
2712 let mut need_32bit = false;
2713 for r in regs {
2714 let bit = reg_to_bits(r);
2715 if bit >= 8 && *r != Reg::LR {
2716 need_32bit = true;
2717 }
2718 reg_list |= 1 << bit;
2719 }
2720 if !need_32bit {
2721 let m_bit = if reg_list & (1 << 14) != 0 {
2723 1u16
2724 } else {
2725 0u16
2726 };
2727 let low_regs = reg_list & 0xFF;
2728 let instr: u16 = 0xB400 | (m_bit << 8) | low_regs;
2729 Ok(instr.to_le_bytes().to_vec())
2730 } else {
2731 let hw1: u16 = 0xE92D;
2733 let hw2: u16 = reg_list;
2734 let mut bytes = hw1.to_le_bytes().to_vec();
2735 bytes.extend_from_slice(&hw2.to_le_bytes());
2736 Ok(bytes)
2737 }
2738 }
2739
2740 ArmOp::Pop { regs } => {
2741 let mut reg_list: u16 = 0;
2745 let mut need_32bit = false;
2746 for r in regs {
2747 let bit = reg_to_bits(r);
2748 if bit >= 8 && *r != Reg::PC {
2749 need_32bit = true;
2750 }
2751 reg_list |= 1 << bit;
2752 }
2753 if !need_32bit {
2754 let p_bit = if reg_list & (1 << 15) != 0 {
2756 1u16
2757 } else {
2758 0u16
2759 };
2760 let low_regs = reg_list & 0xFF;
2761 let instr: u16 = 0xBC00 | (p_bit << 8) | low_regs;
2762 Ok(instr.to_le_bytes().to_vec())
2763 } else {
2764 let hw1: u16 = 0xE8BD;
2766 let hw2: u16 = reg_list;
2767 let mut bytes = hw1.to_le_bytes().to_vec();
2768 bytes.extend_from_slice(&hw2.to_le_bytes());
2769 Ok(bytes)
2770 }
2771 }
2772
2773 ArmOp::Nop => {
2774 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2776 }
2777
2778 ArmOp::Udf { imm } => {
2779 let instr: u16 = 0xDE00 | (*imm as u16);
2782 let bytes = instr.to_le_bytes().to_vec();
2783 encoding_contracts::verify_thumb16(&bytes);
2784 Ok(bytes)
2785 }
2786
2787 ArmOp::Adds { rd, rn, op2 } => {
2790 let rd_bits = reg_to_bits(rd) as u16;
2791 let rn_bits = reg_to_bits(rn) as u16;
2792
2793 if let Operand2::Reg(rm) = op2 {
2794 let rm_bits = reg_to_bits(rm) as u16;
2795 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2800 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2802 Ok(instr.to_le_bytes().to_vec())
2803 } else {
2804 self.encode_thumb32_adds_reg_raw(
2805 rd_bits as u32,
2806 rn_bits as u32,
2807 rm_bits as u32,
2808 )
2809 }
2810 } else {
2811 self.encode_thumb32_adds(rd, rn, 0)
2813 }
2814 }
2815
2816 ArmOp::Adc { rd, rn, op2 } => {
2819 let rd_bits = reg_to_bits(rd);
2820 let rn_bits = reg_to_bits(rn);
2821
2822 if let Operand2::Reg(rm) = op2 {
2823 let rm_bits = reg_to_bits(rm);
2824 let hw1: u16 = (0xEB40 | rn_bits) as u16;
2826 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2827
2828 let mut bytes = hw1.to_le_bytes().to_vec();
2829 bytes.extend_from_slice(&hw2.to_le_bytes());
2830 Ok(bytes)
2831 } else {
2832 let hw1: u16 = (0xF140 | rn_bits) as u16;
2834 let hw2: u16 = (rd_bits << 8) as u16;
2835 let mut bytes = hw1.to_le_bytes().to_vec();
2836 bytes.extend_from_slice(&hw2.to_le_bytes());
2837 Ok(bytes)
2838 }
2839 }
2840
2841 ArmOp::Subs { rd, rn, op2 } => {
2843 let rd_bits = reg_to_bits(rd) as u16;
2844 let rn_bits = reg_to_bits(rn) as u16;
2845
2846 if let Operand2::Reg(rm) = op2 {
2847 let rm_bits = reg_to_bits(rm) as u16;
2848 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2852 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2854 Ok(instr.to_le_bytes().to_vec())
2855 } else {
2856 self.encode_thumb32_subs_reg_raw(
2857 rd_bits as u32,
2858 rn_bits as u32,
2859 rm_bits as u32,
2860 )
2861 }
2862 } else {
2863 self.encode_thumb32_subs(rd, rn, 0)
2865 }
2866 }
2867
2868 ArmOp::Sbc { rd, rn, op2 } => {
2871 let rd_bits = reg_to_bits(rd);
2872 let rn_bits = reg_to_bits(rn);
2873
2874 if let Operand2::Reg(rm) = op2 {
2875 let rm_bits = reg_to_bits(rm);
2876 let hw1: u16 = (0xEB60 | rn_bits) as u16;
2878 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2879
2880 let mut bytes = hw1.to_le_bytes().to_vec();
2881 bytes.extend_from_slice(&hw2.to_le_bytes());
2882 Ok(bytes)
2883 } else {
2884 let hw1: u16 = (0xF160 | rn_bits) as u16;
2886 let hw2: u16 = (rd_bits << 8) as u16;
2887 let mut bytes = hw1.to_le_bytes().to_vec();
2888 bytes.extend_from_slice(&hw2.to_le_bytes());
2889 Ok(bytes)
2890 }
2891 }
2892
2893 ArmOp::Sdiv { rd, rn, rm } => {
2897 let rd_bits = reg_to_bits(rd);
2898 let rn_bits = reg_to_bits(rn);
2899 let rm_bits = reg_to_bits(rm);
2900 reg_bits_checked(rd_bits)?;
2901 reg_bits_checked(rn_bits)?;
2902 reg_bits_checked(rm_bits)?;
2903
2904 let hw1: u16 = (0xFB90 | rn_bits) as u16;
2908 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2909
2910 let mut bytes = hw1.to_le_bytes().to_vec();
2912 bytes.extend_from_slice(&hw2.to_le_bytes());
2913 encoding_contracts::verify_thumb32(&bytes);
2914 Ok(bytes)
2915 }
2916
2917 ArmOp::Udiv { rd, rn, rm } => {
2919 let rd_bits = reg_to_bits(rd);
2920 let rn_bits = reg_to_bits(rn);
2921 let rm_bits = reg_to_bits(rm);
2922 reg_bits_checked(rd_bits)?;
2923 reg_bits_checked(rn_bits)?;
2924 reg_bits_checked(rm_bits)?;
2925
2926 let hw1: u16 = (0xFBB0 | rn_bits) as u16;
2928 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2929
2930 let mut bytes = hw1.to_le_bytes().to_vec();
2931 bytes.extend_from_slice(&hw2.to_le_bytes());
2932 encoding_contracts::verify_thumb32(&bytes);
2933 Ok(bytes)
2934 }
2935
2936 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
2937 let rdlo_bits = reg_to_bits(rdlo);
2938 let rdhi_bits = reg_to_bits(rdhi);
2939 let rn_bits = reg_to_bits(rn);
2940 let rm_bits = reg_to_bits(rm);
2941 reg_bits_checked(rdlo_bits)?;
2942 reg_bits_checked(rdhi_bits)?;
2943 reg_bits_checked(rn_bits)?;
2944 reg_bits_checked(rm_bits)?;
2945
2946 let hw1: u16 = (0xFBA0 | rn_bits) as u16;
2948 let hw2: u16 = ((rdlo_bits << 12) | (rdhi_bits << 8) | rm_bits) as u16;
2949
2950 let mut bytes = hw1.to_le_bytes().to_vec();
2951 bytes.extend_from_slice(&hw2.to_le_bytes());
2952 encoding_contracts::verify_thumb32(&bytes);
2953 Ok(bytes)
2954 }
2955
2956 ArmOp::Mul { rd, rn, rm } => {
2958 let rd_bits = reg_to_bits(rd);
2959 let rn_bits = reg_to_bits(rn);
2960 let rm_bits = reg_to_bits(rm);
2961
2962 let hw1: u16 = (0xFB00 | rn_bits) as u16;
2965 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
2966
2967 let mut bytes = hw1.to_le_bytes().to_vec();
2968 bytes.extend_from_slice(&hw2.to_le_bytes());
2969 Ok(bytes)
2970 }
2971
2972 ArmOp::Mls { rd, rn, rm, ra } => {
2974 let rd_bits = reg_to_bits(rd);
2975 let rn_bits = reg_to_bits(rn);
2976 let rm_bits = reg_to_bits(rm);
2977 let ra_bits = reg_to_bits(ra);
2978
2979 let hw1: u16 = (0xFB00 | rn_bits) as u16;
2982 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | 0x10 | rm_bits) as u16;
2983
2984 let mut bytes = hw1.to_le_bytes().to_vec();
2985 bytes.extend_from_slice(&hw2.to_le_bytes());
2986 Ok(bytes)
2987 }
2988
2989 ArmOp::Mla { rd, rn, rm, ra } => {
2990 let rd_bits = reg_to_bits(rd);
2991 let rn_bits = reg_to_bits(rn);
2992 let rm_bits = reg_to_bits(rm);
2993 let ra_bits = reg_to_bits(ra);
2994
2995 let hw1: u16 = (0xFB00 | rn_bits) as u16;
2998 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | rm_bits) as u16;
2999
3000 let mut bytes = hw1.to_le_bytes().to_vec();
3001 bytes.extend_from_slice(&hw2.to_le_bytes());
3002 Ok(bytes)
3003 }
3004
3005 ArmOp::And { rd, rn, op2 } => {
3007 if let Operand2::Reg(rm) = op2 {
3008 let rd_bits = reg_to_bits(rd);
3009 let rn_bits = reg_to_bits(rn);
3010 let rm_bits = reg_to_bits(rm);
3011
3012 let hw1: u16 = (0xEA00 | rn_bits) as u16;
3014 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3015
3016 let mut bytes = hw1.to_le_bytes().to_vec();
3017 bytes.extend_from_slice(&hw2.to_le_bytes());
3018 Ok(bytes)
3019 } else if let Operand2::Imm(imm) = op2 {
3020 let rd_bits = reg_to_bits(rd);
3021 let rn_bits = reg_to_bits(rn);
3022
3023 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
3030 synth_core::Error::synthesis(
3031 "AND immediate is not a valid ThumbExpandImm — materialize into a register",
3032 )
3033 })?;
3034 let i_bit = (field >> 11) & 1;
3035 let imm3 = (field >> 8) & 0x7;
3036 let imm8 = field & 0xFF;
3037
3038 let hw1: u16 = (0xF000 | (i_bit << 10) | rn_bits) as u16;
3039 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
3040
3041 let mut bytes = hw1.to_le_bytes().to_vec();
3042 bytes.extend_from_slice(&hw2.to_le_bytes());
3043 Ok(bytes)
3044 } else {
3045 let instr: u16 = 0xBF00;
3047 Ok(instr.to_le_bytes().to_vec())
3048 }
3049 }
3050
3051 ArmOp::Orr { rd, rn, op2 } => {
3053 if let Operand2::Reg(rm) = op2 {
3054 let rd_bits = reg_to_bits(rd);
3055 let rn_bits = reg_to_bits(rn);
3056 let rm_bits = reg_to_bits(rm);
3057
3058 let hw1: u16 = (0xEA40 | rn_bits) as u16;
3060 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3061
3062 let mut bytes = hw1.to_le_bytes().to_vec();
3063 bytes.extend_from_slice(&hw2.to_le_bytes());
3064 Ok(bytes)
3065 } else if let Operand2::Imm(imm) = op2 {
3066 let imm_val = *imm as u32;
3071 if imm_val > 0xFF {
3072 return Err(synth_core::Error::synthesis(
3073 "ORR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
3074 ));
3075 }
3076 let rd_bits = reg_to_bits(rd);
3077 let rn_bits = reg_to_bits(rn);
3078 let hw1: u16 = (0xF040 | rn_bits) as u16;
3079 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
3080 let mut bytes = hw1.to_le_bytes().to_vec();
3081 bytes.extend_from_slice(&hw2.to_le_bytes());
3082 Ok(bytes)
3083 } else {
3084 let instr: u16 = 0xBF00;
3085 Ok(instr.to_le_bytes().to_vec())
3086 }
3087 }
3088
3089 ArmOp::Eor { rd, rn, op2 } => {
3091 if let Operand2::Reg(rm) = op2 {
3092 let rd_bits = reg_to_bits(rd);
3093 let rn_bits = reg_to_bits(rn);
3094 let rm_bits = reg_to_bits(rm);
3095
3096 let hw1: u16 = (0xEA80 | rn_bits) as u16;
3098 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3099
3100 let mut bytes = hw1.to_le_bytes().to_vec();
3101 bytes.extend_from_slice(&hw2.to_le_bytes());
3102 Ok(bytes)
3103 } else if let Operand2::Imm(imm) = op2 {
3104 let imm_val = *imm as u32;
3108 if imm_val > 0xFF {
3109 return Err(synth_core::Error::synthesis(
3110 "EOR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
3111 ));
3112 }
3113 let rd_bits = reg_to_bits(rd);
3114 let rn_bits = reg_to_bits(rn);
3115 let hw1: u16 = (0xF080 | rn_bits) as u16;
3116 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
3117 let mut bytes = hw1.to_le_bytes().to_vec();
3118 bytes.extend_from_slice(&hw2.to_le_bytes());
3119 Ok(bytes)
3120 } else {
3121 let instr: u16 = 0xBF00;
3122 Ok(instr.to_le_bytes().to_vec())
3123 }
3124 }
3125
3126 ArmOp::Lsl { rd, rn, shift } => {
3128 let rd_bits = reg_to_bits(rd) as u16;
3129 let rn_bits = reg_to_bits(rn) as u16;
3130 let shift_bits = (*shift as u16) & 0x1F;
3131
3132 if rd_bits < 8 && rn_bits < 8 {
3133 let instr: u16 = (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3135 Ok(instr.to_le_bytes().to_vec())
3136 } else {
3137 self.encode_thumb32_shift(rd, rn, *shift, 0b00) }
3140 }
3141
3142 ArmOp::Lsr { rd, rn, shift } => {
3143 let rd_bits = reg_to_bits(rd) as u16;
3144 let rn_bits = reg_to_bits(rn) as u16;
3145 let shift_bits = (*shift as u16) & 0x1F;
3146
3147 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3148 let instr: u16 = 0x0800 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3150 Ok(instr.to_le_bytes().to_vec())
3151 } else {
3152 self.encode_thumb32_shift(rd, rn, *shift, 0b01) }
3154 }
3155
3156 ArmOp::Asr { rd, rn, shift } => {
3157 let rd_bits = reg_to_bits(rd) as u16;
3158 let rn_bits = reg_to_bits(rn) as u16;
3159 let shift_bits = (*shift as u16) & 0x1F;
3160
3161 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3162 let instr: u16 = 0x1000 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3164 Ok(instr.to_le_bytes().to_vec())
3165 } else {
3166 self.encode_thumb32_shift(rd, rn, *shift, 0b10) }
3168 }
3169
3170 ArmOp::Ror { rd, rn, shift } => {
3171 self.encode_thumb32_shift(rd, rn, *shift, 0b11) }
3174
3175 ArmOp::LslReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b00),
3179 ArmOp::LsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b01),
3180 ArmOp::AsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b10),
3181 ArmOp::RorReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b11),
3182
3183 ArmOp::Rsb { rd, rn, imm } => {
3186 let rd_bits = reg_to_bits(rd);
3187 let rn_bits = reg_to_bits(rn);
3188 let imm_val = *imm;
3189
3190 let i_bit = (imm_val >> 11) & 1;
3191 let imm3 = (imm_val >> 8) & 0x7;
3192 let imm8 = imm_val & 0xFF;
3193
3194 let hw1: u16 = (0xF1C0 | (i_bit << 10) | rn_bits) as u16;
3196 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
3198
3199 let mut bytes = hw1.to_le_bytes().to_vec();
3200 bytes.extend_from_slice(&hw2.to_le_bytes());
3201 Ok(bytes)
3202 }
3203
3204 ArmOp::Clz { rd, rm } => {
3206 let rd_bits = reg_to_bits(rd);
3207 let rm_bits = reg_to_bits(rm);
3208
3209 let hw1: u16 = (0xFAB0 | rm_bits) as u16;
3212 let hw2: u16 = (0xF080 | (rd_bits << 8) | rm_bits) as u16;
3213
3214 let mut bytes = hw1.to_le_bytes().to_vec();
3215 bytes.extend_from_slice(&hw2.to_le_bytes());
3216 Ok(bytes)
3217 }
3218
3219 ArmOp::Rbit { rd, rm } => {
3221 let rd_bits = reg_to_bits(rd);
3222 let rm_bits = reg_to_bits(rm);
3223
3224 let hw1: u16 = (0xFA90 | rm_bits) as u16;
3227 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rm_bits) as u16;
3228
3229 let mut bytes = hw1.to_le_bytes().to_vec();
3230 bytes.extend_from_slice(&hw2.to_le_bytes());
3231 Ok(bytes)
3232 }
3233
3234 ArmOp::Sxtb { rd, rm } => {
3236 let rd_bits = reg_to_bits(rd) as u16;
3237 let rm_bits = reg_to_bits(rm) as u16;
3238
3239 if rd_bits < 8 && rm_bits < 8 {
3240 let instr: u16 = 0xB240 | (rm_bits << 3) | rd_bits;
3242 Ok(instr.to_le_bytes().to_vec())
3243 } else {
3244 let rd_bits32 = rd_bits as u32;
3247 let rm_bits32 = rm_bits as u32;
3248 let hw1: u16 = 0xFA4F;
3249 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
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
3256 ArmOp::Sxth { rd, rm } => {
3258 let rd_bits = reg_to_bits(rd) as u16;
3259 let rm_bits = reg_to_bits(rm) as u16;
3260
3261 if rd_bits < 8 && rm_bits < 8 {
3262 let instr: u16 = 0xB200 | (rm_bits << 3) | rd_bits;
3264 Ok(instr.to_le_bytes().to_vec())
3265 } else {
3266 let rd_bits32 = rd_bits as u32;
3269 let rm_bits32 = rm_bits as u32;
3270 let hw1: u16 = 0xFA0F;
3271 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3272 let mut bytes = hw1.to_le_bytes().to_vec();
3273 bytes.extend_from_slice(&hw2.to_le_bytes());
3274 Ok(bytes)
3275 }
3276 }
3277
3278 ArmOp::Uxtb { rd, rm } => {
3280 let rd_bits = reg_to_bits(rd) as u16;
3281 let rm_bits = reg_to_bits(rm) as u16;
3282 if rd_bits < 8 && rm_bits < 8 {
3283 let instr: u16 = 0xB2C0 | (rm_bits << 3) | rd_bits;
3285 Ok(instr.to_le_bytes().to_vec())
3286 } else {
3287 let hw1: u16 = 0xFA5F;
3289 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3290 let mut bytes = hw1.to_le_bytes().to_vec();
3291 bytes.extend_from_slice(&hw2.to_le_bytes());
3292 Ok(bytes)
3293 }
3294 }
3295
3296 ArmOp::Uxth { rd, rm } => {
3298 let rd_bits = reg_to_bits(rd) as u16;
3299 let rm_bits = reg_to_bits(rm) as u16;
3300 if rd_bits < 8 && rm_bits < 8 {
3301 let instr: u16 = 0xB280 | (rm_bits << 3) | rd_bits;
3303 Ok(instr.to_le_bytes().to_vec())
3304 } else {
3305 let hw1: u16 = 0xFA1F;
3307 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3308 let mut bytes = hw1.to_le_bytes().to_vec();
3309 bytes.extend_from_slice(&hw2.to_le_bytes());
3310 Ok(bytes)
3311 }
3312 }
3313
3314 ArmOp::Cmp { rn, op2 } => {
3316 let rn_bits = reg_to_bits(rn) as u16;
3317
3318 if let Operand2::Imm(imm) = op2 {
3319 if *imm >= 0 && *imm <= 255 && rn_bits < 8 {
3322 let instr: u16 = 0x2800 | (rn_bits << 8) | (*imm as u16 & 0xFF);
3324 Ok(instr.to_le_bytes().to_vec())
3325 } else {
3326 self.encode_thumb32_cmp_imm(rn, *imm as u32)
3327 }
3328 } else if let Operand2::Reg(rm) = op2 {
3329 let rm_bits = reg_to_bits(rm) as u16;
3330 if rn_bits < 8 && rm_bits < 8 {
3331 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
3333 Ok(instr.to_le_bytes().to_vec())
3334 } else {
3335 let n_bit = (rn_bits >> 3) & 1;
3337 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
3338 Ok(instr.to_le_bytes().to_vec())
3339 }
3340 } else {
3341 let instr: u16 = 0xBF00;
3342 Ok(instr.to_le_bytes().to_vec())
3343 }
3344 }
3345
3346 ArmOp::Cmn { rn, op2 } => {
3349 let rn_bits = reg_to_bits(rn) as u16;
3350
3351 if let Operand2::Imm(imm) = op2 {
3352 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
3358 synth_core::Error::synthesis(
3359 "CMN immediate is not a valid ThumbExpandImm — materialize into a register",
3360 )
3361 })?;
3362 let i_bit = (field >> 11) & 1;
3363 let imm3 = (field >> 8) & 0x7;
3364 let imm8 = field & 0xFF;
3365 let hw1: u16 = (0xF110 | (i_bit << 10) as u16) | rn_bits;
3366 let hw2: u16 = (imm3 << 12) as u16 | 0x0F00 | imm8 as u16;
3367 let mut bytes = hw1.to_le_bytes().to_vec();
3368 bytes.extend_from_slice(&hw2.to_le_bytes());
3369 Ok(bytes)
3370 } else if let Operand2::Reg(rm) = op2 {
3371 let rm_bits = reg_to_bits(rm) as u16;
3372 if rn_bits < 8 && rm_bits < 8 {
3378 let instr: u16 = 0x42C0 | (rm_bits << 3) | rn_bits;
3380 Ok(instr.to_le_bytes().to_vec())
3381 } else {
3382 let hw1: u16 = 0xEB10 | rn_bits;
3383 let hw2: u16 = 0x0F00 | rm_bits;
3384 let mut bytes = hw1.to_le_bytes().to_vec();
3385 bytes.extend_from_slice(&hw2.to_le_bytes());
3386 Ok(bytes)
3387 }
3388 } else {
3389 Ok(vec![0xBF, 0x00])
3390 }
3391 }
3392
3393 ArmOp::Ldr { rd, addr } => {
3395 let rd_bits = reg_to_bits(rd);
3396 let base_bits = reg_to_bits(&addr.base);
3397
3398 if let Some(offset_reg) = &addr.offset_reg {
3400 let rm_bits = reg_to_bits(offset_reg);
3401
3402 if addr.offset != 0 {
3404 let scratch = Reg::R12;
3407 let mut bytes =
3408 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3409 bytes.extend(self.encode_thumb32_ldr_reg(rd, &addr.base, &scratch)?);
3410 return Ok(bytes);
3411 }
3412
3413 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3416 let instr: u16 = 0x5800
3418 | ((rm_bits as u16) << 6)
3419 | ((base_bits as u16) << 3)
3420 | (rd_bits as u16);
3421 return Ok(instr.to_le_bytes().to_vec());
3422 }
3423
3424 return self.encode_thumb32_ldr_reg(rd, &addr.base, offset_reg);
3426 }
3427
3428 let offset = addr.offset as u32;
3430
3431 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3432 let imm5 = (offset >> 2) as u16;
3434 let instr: u16 =
3435 0x6800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3436 Ok(instr.to_le_bytes().to_vec())
3437 } else {
3438 self.encode_thumb32_ldr(rd, &addr.base, offset)
3439 }
3440 }
3441
3442 ArmOp::Str { rd, addr } => {
3444 let rd_bits = reg_to_bits(rd);
3445 let base_bits = reg_to_bits(&addr.base);
3446
3447 if let Some(offset_reg) = &addr.offset_reg {
3449 let rm_bits = reg_to_bits(offset_reg);
3450
3451 if addr.offset != 0 {
3453 let scratch = Reg::R12;
3456 let mut bytes =
3457 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3458 bytes.extend(self.encode_thumb32_str_reg(rd, &addr.base, &scratch)?);
3459 return Ok(bytes);
3460 }
3461
3462 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3465 let instr: u16 = 0x5000
3467 | ((rm_bits as u16) << 6)
3468 | ((base_bits as u16) << 3)
3469 | (rd_bits as u16);
3470 return Ok(instr.to_le_bytes().to_vec());
3471 }
3472
3473 return self.encode_thumb32_str_reg(rd, &addr.base, offset_reg);
3475 }
3476
3477 let offset = addr.offset as u32;
3479
3480 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3481 let imm5 = (offset >> 2) as u16;
3483 let instr: u16 =
3484 0x6000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3485 Ok(instr.to_le_bytes().to_vec())
3486 } else {
3487 self.encode_thumb32_str(rd, &addr.base, offset)
3488 }
3489 }
3490
3491 ArmOp::Ldrb { rd, addr } => {
3493 let rd_bits = reg_to_bits(rd);
3494 let base_bits = reg_to_bits(&addr.base);
3495
3496 if let Some(offset_reg) = &addr.offset_reg {
3497 if addr.offset != 0 {
3498 let scratch = Reg::R12;
3499 let mut bytes =
3500 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3501 bytes.extend(self.encode_thumb32_ldrb_reg(rd, &addr.base, &scratch)?);
3502 return Ok(bytes);
3503 }
3504 return self.encode_thumb32_ldrb_reg(rd, &addr.base, offset_reg);
3505 }
3506
3507 let offset = addr.offset as u32;
3508 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3509 let instr: u16 = 0x7800
3511 | ((offset as u16) << 6)
3512 | ((base_bits as u16) << 3)
3513 | (rd_bits as u16);
3514 Ok(instr.to_le_bytes().to_vec())
3515 } else {
3516 self.encode_thumb32_ldrb_imm(rd, &addr.base, offset)
3517 }
3518 }
3519
3520 ArmOp::Ldrsb { rd, addr } => {
3522 let rd_bits = reg_to_bits(rd);
3523 let base_bits = reg_to_bits(&addr.base);
3524
3525 if let Some(offset_reg) = &addr.offset_reg {
3526 if addr.offset != 0 {
3527 let scratch = Reg::R12;
3528 let mut bytes =
3529 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3530 bytes.extend(self.encode_thumb32_ldrsb_reg(rd, &addr.base, &scratch)?);
3531 return Ok(bytes);
3532 }
3533 return self.encode_thumb32_ldrsb_reg(rd, &addr.base, offset_reg);
3534 }
3535
3536 let offset = addr.offset as u32;
3537 if rd_bits < 8 && base_bits < 8 && offset == 0 {
3540 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3542 } else {
3543 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3544 }
3545 }
3546
3547 ArmOp::Ldrh { rd, addr } => {
3549 let rd_bits = reg_to_bits(rd);
3550 let base_bits = reg_to_bits(&addr.base);
3551
3552 if let Some(offset_reg) = &addr.offset_reg {
3553 if addr.offset != 0 {
3554 let scratch = Reg::R12;
3555 let mut bytes =
3556 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3557 bytes.extend(self.encode_thumb32_ldrh_reg(rd, &addr.base, &scratch)?);
3558 return Ok(bytes);
3559 }
3560 return self.encode_thumb32_ldrh_reg(rd, &addr.base, offset_reg);
3561 }
3562
3563 let offset = addr.offset as u32;
3564 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3565 let imm5 = (offset >> 1) as u16;
3567 let instr: u16 =
3568 0x8800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3569 Ok(instr.to_le_bytes().to_vec())
3570 } else {
3571 self.encode_thumb32_ldrh_imm(rd, &addr.base, offset)
3572 }
3573 }
3574
3575 ArmOp::Ldrsh { rd, addr } => {
3577 if let Some(offset_reg) = &addr.offset_reg {
3578 if addr.offset != 0 {
3579 let scratch = Reg::R12;
3580 let mut bytes =
3581 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3582 bytes.extend(self.encode_thumb32_ldrsh_reg(rd, &addr.base, &scratch)?);
3583 return Ok(bytes);
3584 }
3585 return self.encode_thumb32_ldrsh_reg(rd, &addr.base, offset_reg);
3586 }
3587
3588 let offset = addr.offset as u32;
3589 self.encode_thumb32_ldrsh_imm(rd, &addr.base, offset)
3590 }
3591
3592 ArmOp::Strb { rd, addr } => {
3594 let rd_bits = reg_to_bits(rd);
3595 let base_bits = reg_to_bits(&addr.base);
3596
3597 if let Some(offset_reg) = &addr.offset_reg {
3598 if addr.offset != 0 {
3599 let scratch = Reg::R12;
3600 let mut bytes =
3601 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3602 bytes.extend(self.encode_thumb32_strb_reg(rd, &addr.base, &scratch)?);
3603 return Ok(bytes);
3604 }
3605 return self.encode_thumb32_strb_reg(rd, &addr.base, offset_reg);
3606 }
3607
3608 let offset = addr.offset as u32;
3609 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3610 let instr: u16 = 0x7000
3612 | ((offset as u16) << 6)
3613 | ((base_bits as u16) << 3)
3614 | (rd_bits as u16);
3615 Ok(instr.to_le_bytes().to_vec())
3616 } else {
3617 self.encode_thumb32_strb_imm(rd, &addr.base, offset)
3618 }
3619 }
3620
3621 ArmOp::Strh { rd, addr } => {
3623 let rd_bits = reg_to_bits(rd);
3624 let base_bits = reg_to_bits(&addr.base);
3625
3626 if let Some(offset_reg) = &addr.offset_reg {
3627 if addr.offset != 0 {
3628 let scratch = Reg::R12;
3629 let mut bytes =
3630 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3631 bytes.extend(self.encode_thumb32_strh_reg(rd, &addr.base, &scratch)?);
3632 return Ok(bytes);
3633 }
3634 return self.encode_thumb32_strh_reg(rd, &addr.base, offset_reg);
3635 }
3636
3637 let offset = addr.offset as u32;
3638 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3639 let imm5 = (offset >> 1) as u16;
3641 let instr: u16 =
3642 0x8000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3643 Ok(instr.to_le_bytes().to_vec())
3644 } else {
3645 self.encode_thumb32_strh_imm(rd, &addr.base, offset)
3646 }
3647 }
3648
3649 ArmOp::MemorySize { rd } => {
3651 let rd_bits = reg_to_bits(rd);
3654 let r10_bits = reg_to_bits(&Reg::R10);
3655 if rd_bits < 8 && r10_bits < 8 {
3656 let instr: u16 =
3657 0x0800 | (16u16 << 6) | ((r10_bits as u16) << 3) | (rd_bits as u16);
3658 Ok(instr.to_le_bytes().to_vec())
3659 } else {
3660 let imm5: u32 = 16;
3662 let imm3 = (imm5 >> 2) & 0x7;
3663 let imm2 = imm5 & 0x3;
3664 let hw1: u16 = 0xEA4F;
3665 let hw2: u16 =
3666 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | 0x10 | r10_bits) as u16;
3667 let mut bytes = hw1.to_le_bytes().to_vec();
3668 bytes.extend_from_slice(&hw2.to_le_bytes());
3669 Ok(bytes)
3670 }
3671 }
3672
3673 ArmOp::MemoryGrow { rd, .. } => {
3675 let rd_bits = reg_to_bits(rd);
3679 let hw1: u16 = 0xF06F; let hw2: u16 = (rd_bits << 8) as u16; let mut bytes = hw1.to_le_bytes().to_vec();
3682 bytes.extend_from_slice(&hw2.to_le_bytes());
3683 Ok(bytes)
3684 }
3685
3686 ArmOp::Bx { rm } => {
3688 let rm_bits = reg_to_bits(rm) as u16;
3689 let instr: u16 = 0x4700 | (rm_bits << 3);
3691 Ok(instr.to_le_bytes().to_vec())
3692 }
3693
3694 ArmOp::Blx { rm } => {
3697 let rm_bits = reg_to_bits(rm) as u16;
3698 let instr: u16 = 0x4780 | (rm_bits << 3);
3699 Ok(instr.to_le_bytes().to_vec())
3700 }
3701
3702 ArmOp::CallIndirect {
3710 rd: _,
3711 type_idx: _,
3712 table_index_reg,
3713 table_size,
3714 table_byte_offset,
3715 } => {
3716 let idx_reg = reg_to_bits(table_index_reg);
3717 let mut bytes = Vec::new();
3718
3719 let size_lo = *table_size & 0xFFFF;
3738 let hw1: u16 =
3739 (0xF240 | (((size_lo >> 11) & 1) << 10) | ((size_lo >> 12) & 0xF)) as u16;
3740 let hw2: u16 =
3741 ((((size_lo >> 8) & 0x7) << 12) | (12 << 8) | (size_lo & 0xFF)) as u16;
3742 bytes.extend_from_slice(&hw1.to_le_bytes());
3743 bytes.extend_from_slice(&hw2.to_le_bytes());
3744 let size_hi = *table_size >> 16;
3748 if size_hi != 0 {
3749 let hw1: u16 =
3750 (0xF2C0 | (((size_hi >> 11) & 1) << 10) | ((size_hi >> 12) & 0xF)) as u16;
3751 let hw2: u16 =
3752 ((((size_hi >> 8) & 0x7) << 12) | (12 << 8) | (size_hi & 0xFF)) as u16;
3753 bytes.extend_from_slice(&hw1.to_le_bytes());
3754 bytes.extend_from_slice(&hw2.to_le_bytes());
3755 }
3756 let cmp: u16 = (0x4500 | ((idx_reg & 8) << 4) | (12 << 3) | (idx_reg & 7)) as u16;
3759 bytes.extend_from_slice(&cmp.to_le_bytes());
3760 bytes.extend_from_slice(&0xD300u16.to_le_bytes());
3763 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
3766
3767 let hw1: u16 = 0xEA4F_u16; let hw2: u16 = ((0x0C00 | (0b10 << 6)) | idx_reg) as u16;
3776 bytes.extend_from_slice(&hw1.to_le_bytes());
3777 bytes.extend_from_slice(&hw2.to_le_bytes());
3778
3779 if *table_byte_offset == 0 {
3780 let ldr_hw1: u16 = 0xF85B; let ldr_hw2: u16 = 0xC00C; bytes.extend_from_slice(&ldr_hw1.to_le_bytes());
3789 bytes.extend_from_slice(&ldr_hw2.to_le_bytes());
3790 } else {
3791 assert!(
3796 *table_byte_offset <= 4095,
3797 "call_indirect table base offset {table_byte_offset} exceeds \
3798 LDR imm12 — the selector must have declined this (#650)"
3799 );
3800 bytes.extend_from_slice(&0xEB0Bu16.to_le_bytes());
3803 bytes.extend_from_slice(&0x0C0Cu16.to_le_bytes());
3804 bytes.extend_from_slice(&0xF8DCu16.to_le_bytes());
3807 bytes.extend_from_slice(
3808 &((0xC000u16) | (*table_byte_offset as u16 & 0x0FFF)).to_le_bytes(),
3809 );
3810 }
3811
3812 let blx: u16 = 0x47E0; bytes.extend_from_slice(&blx.to_le_bytes());
3816
3817 Ok(bytes)
3818 }
3819
3820 ArmOp::Label { .. } => Ok(Vec::new()),
3822
3823 ArmOp::Bcc { cond, label: _ } => {
3825 use synth_synthesis::Condition;
3826 let cond_bits: u16 = match cond {
3827 Condition::EQ => 0x0,
3828 Condition::NE => 0x1,
3829 Condition::HS => 0x2,
3830 Condition::LO => 0x3,
3831 Condition::HI => 0x8,
3832 Condition::LS => 0x9,
3833 Condition::GE => 0xA,
3834 Condition::LT => 0xB,
3835 Condition::GT => 0xC,
3836 Condition::LE => 0xD,
3837 };
3838 let instr: u16 = 0xD000 | (cond_bits << 8);
3840 Ok(instr.to_le_bytes().to_vec())
3841 }
3842
3843 ArmOp::B { label: _ } => {
3845 let instr: u16 = 0xE000; Ok(instr.to_le_bytes().to_vec())
3849 }
3850
3851 ArmOp::Bhs { label: _ } => {
3854 let instr: u16 = 0xD200; Ok(instr.to_le_bytes().to_vec())
3858 }
3859
3860 ArmOp::Blo { label: _ } => {
3863 let instr: u16 = 0xD300; Ok(instr.to_le_bytes().to_vec())
3867 }
3868
3869 ArmOp::BOffset { offset } => {
3872 let halfword_offset = *offset;
3875
3876 if (-1024..=1022).contains(&halfword_offset) {
3879 let imm11 = (halfword_offset as u16) & 0x7FF;
3881 let instr: u16 = 0xE000 | imm11;
3882 Ok(instr.to_le_bytes().to_vec())
3883 } else {
3884 let signed_offset = halfword_offset << 1; let s = if signed_offset < 0 { 1u32 } else { 0u32 };
3900 let uoffset = signed_offset as u32;
3901 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;
3909 let hw2: u16 = (0x9000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
3910
3911 let mut bytes = hw1.to_le_bytes().to_vec();
3912 bytes.extend_from_slice(&hw2.to_le_bytes());
3913 Ok(bytes)
3914 }
3915 }
3916
3917 ArmOp::BCondOffset { cond, offset } => {
3919 use synth_synthesis::Condition;
3920 let cond_bits: u16 = match cond {
3921 Condition::EQ => 0x0,
3922 Condition::NE => 0x1,
3923 Condition::HS => 0x2,
3924 Condition::LO => 0x3,
3925 Condition::HI => 0x8,
3926 Condition::LS => 0x9,
3927 Condition::GE => 0xA,
3928 Condition::LT => 0xB,
3929 Condition::GT => 0xC,
3930 Condition::LE => 0xD,
3931 };
3932
3933 let halfword_offset = *offset;
3936
3937 if (-128..=127).contains(&halfword_offset) {
3940 let imm8 = (halfword_offset as u16) & 0xFF;
3941 let instr: u16 = 0xD000 | (cond_bits << 8) | imm8;
3942 Ok(instr.to_le_bytes().to_vec())
3943 } else {
3944 let offset = halfword_offset >> 1;
3948 let s = if offset < 0 { 1u32 } else { 0u32 };
3949 let imm6 = ((offset >> 11) as u32) & 0x3F;
3950 let imm11 = (offset as u32) & 0x7FF;
3951 let j1 = if s == 1 { 1 } else { 0 };
3952 let j2 = if s == 1 { 1 } else { 0 };
3953
3954 let hw1: u16 = (0xF000 | (s << 10) | ((cond_bits as u32) << 6) | imm6) as u16;
3955 let hw2: u16 = (0x8000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
3956
3957 let mut bytes = hw1.to_le_bytes().to_vec();
3958 bytes.extend_from_slice(&hw2.to_le_bytes());
3959 Ok(bytes)
3960 }
3961 }
3962
3963 ArmOp::Bl { label: _ } => {
3964 let hw1: u16 = 0xF7FF;
3979 let hw2: u16 = 0xFFFE;
3980 let mut bytes = hw1.to_le_bytes().to_vec();
3981 bytes.extend_from_slice(&hw2.to_le_bytes());
3982 Ok(bytes)
3983 }
3984
3985 ArmOp::Mvn { rd, op2 } => {
3987 if let Operand2::Reg(rm) = op2 {
3988 let rd_bits = reg_to_bits(rd) as u16;
3989 let rm_bits = reg_to_bits(rm) as u16;
3990
3991 if rd_bits < 8 && rm_bits < 8 {
3992 let instr: u16 = 0x43C0 | (rm_bits << 3) | rd_bits;
3994 Ok(instr.to_le_bytes().to_vec())
3995 } else {
3996 let hw1: u16 = 0xEA6F_u16;
3998 let hw2: u16 = ((reg_to_bits(rd) << 8) | reg_to_bits(rm)) as u16;
3999 let mut bytes = hw1.to_le_bytes().to_vec();
4000 bytes.extend_from_slice(&hw2.to_le_bytes());
4001 Ok(bytes)
4002 }
4003 } else {
4004 let instr: u16 = 0xBF00;
4005 Ok(instr.to_le_bytes().to_vec())
4006 }
4007 }
4008
4009 ArmOp::Movw { rd, imm16 } => {
4011 self.encode_thumb32_movw_raw(reg_to_bits(rd), *imm16 as u32)
4012 }
4013
4014 ArmOp::Movt { rd, imm16 } => {
4016 self.encode_thumb32_movt_raw(reg_to_bits(rd), *imm16 as u32)
4017 }
4018
4019 ArmOp::MovwSym { rd, addend, .. } => {
4024 self.encode_thumb32_movw_raw(reg_to_bits(rd), (*addend as u32) & 0xffff)
4025 }
4026 ArmOp::MovtSym { rd, addend, .. } => {
4027 self.encode_thumb32_movt_raw(reg_to_bits(rd), ((*addend as u32) >> 16) & 0xffff)
4028 }
4029
4030 ArmOp::LdrSym { rd, .. } => {
4038 let rt = reg_to_bits(rd) as u16;
4039 let hw1: u16 = 0xF8DF; let hw2: u16 = rt << 12; let mut bytes = Vec::with_capacity(4);
4042 bytes.extend_from_slice(&hw1.to_le_bytes());
4043 bytes.extend_from_slice(&hw2.to_le_bytes());
4044 Ok(bytes)
4045 }
4046
4047 ArmOp::SetCond { rd, cond } => {
4053 let rd_bits = reg_to_bits(rd) as u16;
4054
4055 use synth_synthesis::Condition;
4057 let cond_bits: u16 = match cond {
4058 Condition::EQ => 0x0,
4059 Condition::NE => 0x1,
4060 Condition::LT => 0xB,
4061 Condition::LE => 0xD,
4062 Condition::GT => 0xC,
4063 Condition::GE => 0xA,
4064 Condition::LO => 0x3, Condition::LS => 0x9, Condition::HI => 0x8, Condition::HS => 0x2, };
4069
4070 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
4075 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
4076
4077 let mut bytes = ite_instr.to_le_bytes().to_vec();
4088 let push_mov = |bytes: &mut Vec<u8>, imm: u16| {
4089 if rd_bits <= 7 {
4090 let m: u16 = 0x2000 | (rd_bits << 8) | imm; bytes.extend_from_slice(&m.to_le_bytes());
4092 } else {
4093 let hw1: u16 = 0xF04F;
4095 let hw2: u16 = (rd_bits << 8) | imm;
4096 bytes.extend_from_slice(&hw1.to_le_bytes());
4097 bytes.extend_from_slice(&hw2.to_le_bytes());
4098 }
4099 };
4100 push_mov(&mut bytes, 1); push_mov(&mut bytes, 0); Ok(bytes)
4103 }
4104
4105 ArmOp::I64SetCond {
4110 rd,
4111 rn_lo,
4112 rn_hi,
4113 rm_lo,
4114 rm_hi,
4115 cond,
4116 } => {
4117 use synth_synthesis::Condition;
4118 let rd_bits = reg_to_bits(rd) as u16;
4119 let mut bytes = Vec::new();
4120
4121 let encode_cmp_reg = |rn: &synth_synthesis::Reg,
4123 rm: &synth_synthesis::Reg|
4124 -> Vec<u8> {
4125 let rn_bits = reg_to_bits(rn) as u16;
4126 let rm_bits = reg_to_bits(rm) as u16;
4127 if rn_bits < 8 && rm_bits < 8 {
4128 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
4129 instr.to_le_bytes().to_vec()
4130 } else {
4131 let n_bit = (rn_bits >> 3) & 1;
4132 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
4133 instr.to_le_bytes().to_vec()
4134 }
4135 };
4136
4137 let encode_ite = |cond_bits: u16| -> Vec<u8> {
4139 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
4140 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
4141 ite_instr.to_le_bytes().to_vec()
4142 };
4143
4144 let encode_setcond = |cond_bits: u16, rd_bits: u16| -> Vec<u8> {
4146 let mut b = encode_ite(cond_bits);
4147 if rd_bits < 8 {
4148 let mov_one: u16 = 0x2001 | (rd_bits << 8);
4149 let mov_zero: u16 = 0x2000 | (rd_bits << 8);
4150 b.extend_from_slice(&mov_one.to_le_bytes());
4151 b.extend_from_slice(&mov_zero.to_le_bytes());
4152 } else {
4153 for imm in [1u16, 0u16] {
4161 let hw1: u16 = 0xF04F;
4162 let hw2: u16 = (rd_bits << 8) | imm;
4163 b.extend_from_slice(&hw1.to_le_bytes());
4164 b.extend_from_slice(&hw2.to_le_bytes());
4165 }
4166 }
4167 b
4168 };
4169
4170 match cond {
4171 Condition::EQ | Condition::NE => {
4172 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4174
4175 let it_eq: u16 = 0xBF08; bytes.extend_from_slice(&it_eq.to_le_bytes());
4178
4179 bytes.extend_from_slice(&encode_cmp_reg(rn_hi, rm_hi));
4181
4182 let cond_bits: u16 = match cond {
4184 Condition::EQ => 0x0,
4185 Condition::NE => 0x1,
4186 _ => unreachable!(),
4187 };
4188 bytes.extend_from_slice(&encode_setcond(cond_bits, rd_bits));
4189 }
4190
4191 Condition::LT => {
4192 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4194
4195 let rn_hi_bits = reg_to_bits(rn_hi);
4198 let rm_hi_bits = reg_to_bits(rm_hi);
4199 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4200 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4201 bytes.extend_from_slice(&hw1.to_le_bytes());
4202 bytes.extend_from_slice(&hw2.to_le_bytes());
4203
4204 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4207
4208 Condition::GT => {
4209 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4212
4213 let rm_hi_bits = reg_to_bits(rm_hi);
4215 let rn_hi_bits = reg_to_bits(rn_hi);
4216 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4217 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4218 bytes.extend_from_slice(&hw1.to_le_bytes());
4219 bytes.extend_from_slice(&hw2.to_le_bytes());
4220
4221 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4224
4225 Condition::LE => {
4226 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4230
4231 let rm_hi_bits = reg_to_bits(rm_hi);
4233 let rn_hi_bits = reg_to_bits(rn_hi);
4234 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4235 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4236 bytes.extend_from_slice(&hw1.to_le_bytes());
4237 bytes.extend_from_slice(&hw2.to_le_bytes());
4238
4239 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4242
4243 Condition::GE => {
4244 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4247
4248 let rn_hi_bits = reg_to_bits(rn_hi);
4250 let rm_hi_bits = reg_to_bits(rm_hi);
4251 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4252 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4253 bytes.extend_from_slice(&hw1.to_le_bytes());
4254 bytes.extend_from_slice(&hw2.to_le_bytes());
4255
4256 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4259
4260 Condition::LO => {
4262 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4264 let rn_hi_bits = reg_to_bits(rn_hi);
4265 let rm_hi_bits = reg_to_bits(rm_hi);
4266 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4267 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4268 bytes.extend_from_slice(&hw1.to_le_bytes());
4269 bytes.extend_from_slice(&hw2.to_le_bytes());
4270 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4272
4273 Condition::HI => {
4274 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4276 let rm_hi_bits = reg_to_bits(rm_hi);
4277 let rn_hi_bits = reg_to_bits(rn_hi);
4278 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4279 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4280 bytes.extend_from_slice(&hw1.to_le_bytes());
4281 bytes.extend_from_slice(&hw2.to_le_bytes());
4282 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4284
4285 Condition::LS => {
4286 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4288 let rm_hi_bits = reg_to_bits(rm_hi);
4289 let rn_hi_bits = reg_to_bits(rn_hi);
4290 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4291 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4292 bytes.extend_from_slice(&hw1.to_le_bytes());
4293 bytes.extend_from_slice(&hw2.to_le_bytes());
4294 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
4296
4297 Condition::HS => {
4298 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4300 let rn_hi_bits = reg_to_bits(rn_hi);
4301 let rm_hi_bits = reg_to_bits(rm_hi);
4302 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4303 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4304 bytes.extend_from_slice(&hw1.to_le_bytes());
4305 bytes.extend_from_slice(&hw2.to_le_bytes());
4306 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
4308 }
4309
4310 Ok(bytes)
4311 }
4312
4313 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
4316 let rd_bits = reg_to_bits(rd);
4317 let rn_lo_bits = reg_to_bits(rn_lo);
4318 let rn_hi_bits = reg_to_bits(rn_hi);
4319 let mut bytes = Vec::new();
4320
4321 let hw1: u16 = (0xEA40 | rn_lo_bits) as u16;
4323 let hw2: u16 = ((rd_bits << 8) | rn_hi_bits) as u16;
4324 bytes.extend_from_slice(&hw1.to_le_bytes());
4325 bytes.extend_from_slice(&hw2.to_le_bytes());
4326
4327 if rd_bits < 8 {
4332 let cmp_instr: u16 = 0x2800 | ((rd_bits as u16) << 8);
4333 bytes.extend_from_slice(&cmp_instr.to_le_bytes());
4334 } else {
4335 let hw1: u16 = 0xF1B0 | (rd_bits as u16);
4336 let hw2: u16 = 0x0F00;
4337 bytes.extend_from_slice(&hw1.to_le_bytes());
4338 bytes.extend_from_slice(&hw2.to_le_bytes());
4339 }
4340
4341 let mask = 0xC_u16; let ite_instr: u16 = 0xBF00 | mask;
4345 bytes.extend_from_slice(&ite_instr.to_le_bytes());
4346 if rd_bits < 8 {
4347 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
4348 let mov_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
4349 bytes.extend_from_slice(&mov_one.to_le_bytes());
4350 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4351 } else {
4352 for imm in [1u16, 0u16] {
4353 let hw1: u16 = 0xF04F;
4354 let hw2: u16 = ((rd_bits as u16) << 8) | imm;
4355 bytes.extend_from_slice(&hw1.to_le_bytes());
4356 bytes.extend_from_slice(&hw2.to_le_bytes());
4357 }
4358 }
4359
4360 Ok(bytes)
4361 }
4362
4363 ArmOp::I64Mul {
4367 rd_lo,
4368 rd_hi,
4369 rn_lo,
4370 rn_hi,
4371 rm_lo,
4372 rm_hi,
4373 } => {
4374 let rd_lo_bits = reg_to_bits(rd_lo);
4375 let rd_hi_bits = reg_to_bits(rd_hi);
4376 let rn_lo_bits = reg_to_bits(rn_lo);
4377 let rn_hi_bits = reg_to_bits(rn_hi);
4378 let rm_lo_bits = reg_to_bits(rm_lo);
4379 let rm_hi_bits = reg_to_bits(rm_hi);
4380 let r12: u32 = 12; let mut bytes = Vec::new();
4382
4383 let hw1: u16 = (0xFB00 | rn_lo_bits) as u16;
4386 let hw2: u16 = (0xF000 | (r12 << 8) | rm_hi_bits) as u16;
4387 bytes.extend_from_slice(&hw1.to_le_bytes());
4388 bytes.extend_from_slice(&hw2.to_le_bytes());
4389
4390 let hw1: u16 = (0xFB00 | rn_hi_bits) as u16;
4393 let hw2: u16 = ((r12 << 12) | (r12 << 8) | rm_lo_bits) as u16;
4394 bytes.extend_from_slice(&hw1.to_le_bytes());
4395 bytes.extend_from_slice(&hw2.to_le_bytes());
4396
4397 let hw1: u16 = (0xFBA0 | rn_lo_bits) as u16;
4400 let hw2: u16 = ((rd_lo_bits << 12) | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4401 bytes.extend_from_slice(&hw1.to_le_bytes());
4402 bytes.extend_from_slice(&hw2.to_le_bytes());
4403
4404 let d_bit = (rd_hi_bits >> 3) & 1;
4407 let add_instr: u16 =
4408 (0x4400 | (d_bit << 7) | (r12 << 3) | (rd_hi_bits & 0x7)) as u16;
4409 bytes.extend_from_slice(&add_instr.to_le_bytes());
4410
4411 Ok(bytes)
4412 }
4413
4414 ArmOp::I64Shl {
4417 rd_lo,
4418 rd_hi,
4419 rn_lo,
4420 rn_hi,
4421 rm_lo,
4422 rm_hi,
4423 } => {
4424 let rd_lo_bits = reg_to_bits(rd_lo);
4425 let rd_hi_bits = reg_to_bits(rd_hi);
4426 let rn_lo_bits = reg_to_bits(rn_lo);
4427 let rn_hi_bits = reg_to_bits(rn_hi);
4428 let rm_lo_bits = reg_to_bits(rm_lo);
4429 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4431
4432 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4434 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4435 bytes.extend_from_slice(&hw1.to_le_bytes());
4436 bytes.extend_from_slice(&hw2.to_le_bytes());
4437
4438 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4440 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4441 bytes.extend_from_slice(&hw1.to_le_bytes());
4442 bytes.extend_from_slice(&hw2.to_le_bytes());
4443
4444 let bpl: u16 = 0xD50A;
4446 bytes.extend_from_slice(&bpl.to_le_bytes());
4447
4448 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4451 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4452 bytes.extend_from_slice(&hw1.to_le_bytes());
4453 bytes.extend_from_slice(&hw2.to_le_bytes());
4454
4455 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4457 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4458 bytes.extend_from_slice(&hw1.to_le_bytes());
4459 bytes.extend_from_slice(&hw2.to_le_bytes());
4460
4461 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4463 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4464 bytes.extend_from_slice(&hw1.to_le_bytes());
4465 bytes.extend_from_slice(&hw2.to_le_bytes());
4466
4467 let hw1: u16 = (0xEA40 | rd_hi_bits) as u16;
4469 let hw2: u16 = ((rd_hi_bits << 8) | rm_hi_bits) as u16;
4470 bytes.extend_from_slice(&hw1.to_le_bytes());
4471 bytes.extend_from_slice(&hw2.to_le_bytes());
4472
4473 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4475 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4476 bytes.extend_from_slice(&hw1.to_le_bytes());
4477 bytes.extend_from_slice(&hw2.to_le_bytes());
4478
4479 let b_done: u16 = 0xE002;
4481 bytes.extend_from_slice(&b_done.to_le_bytes());
4482
4483 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4486 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_hi_bits) as u16;
4487 bytes.extend_from_slice(&hw1.to_le_bytes());
4488 bytes.extend_from_slice(&hw2.to_le_bytes());
4489
4490 let mov_zero: u16 = 0x2000 | ((rd_lo_bits as u16) << 8);
4492 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4493
4494 Ok(bytes) }
4496
4497 ArmOp::I64ShrU {
4499 rd_lo,
4500 rd_hi,
4501 rn_lo,
4502 rn_hi,
4503 rm_lo,
4504 rm_hi,
4505 } => {
4506 let rd_lo_bits = reg_to_bits(rd_lo);
4507 let rd_hi_bits = reg_to_bits(rd_hi);
4508 let rn_lo_bits = reg_to_bits(rn_lo);
4509 let rn_hi_bits = reg_to_bits(rn_hi);
4510 let rm_lo_bits = reg_to_bits(rm_lo);
4511 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4513
4514 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4516 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4517 bytes.extend_from_slice(&hw1.to_le_bytes());
4518 bytes.extend_from_slice(&hw2.to_le_bytes());
4519
4520 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4522 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4523 bytes.extend_from_slice(&hw1.to_le_bytes());
4524 bytes.extend_from_slice(&hw2.to_le_bytes());
4525
4526 let bpl: u16 = 0xD50A;
4528 bytes.extend_from_slice(&bpl.to_le_bytes());
4529
4530 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4533 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4534 bytes.extend_from_slice(&hw1.to_le_bytes());
4535 bytes.extend_from_slice(&hw2.to_le_bytes());
4536
4537 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4539 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4540 bytes.extend_from_slice(&hw1.to_le_bytes());
4541 bytes.extend_from_slice(&hw2.to_le_bytes());
4542
4543 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4545 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4546 bytes.extend_from_slice(&hw1.to_le_bytes());
4547 bytes.extend_from_slice(&hw2.to_le_bytes());
4548
4549 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4551 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4552 bytes.extend_from_slice(&hw1.to_le_bytes());
4553 bytes.extend_from_slice(&hw2.to_le_bytes());
4554
4555 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4557 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4558 bytes.extend_from_slice(&hw1.to_le_bytes());
4559 bytes.extend_from_slice(&hw2.to_le_bytes());
4560
4561 let b_done: u16 = 0xE002;
4563 bytes.extend_from_slice(&b_done.to_le_bytes());
4564
4565 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4568 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4569 bytes.extend_from_slice(&hw1.to_le_bytes());
4570 bytes.extend_from_slice(&hw2.to_le_bytes());
4571
4572 let mov_zero: u16 = 0x2000 | ((rd_hi_bits as u16) << 8);
4574 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4575
4576 Ok(bytes) }
4578
4579 ArmOp::I64ShrS {
4581 rd_lo,
4582 rd_hi,
4583 rn_lo,
4584 rn_hi,
4585 rm_lo,
4586 rm_hi,
4587 } => {
4588 let rd_lo_bits = reg_to_bits(rd_lo);
4589 let rd_hi_bits = reg_to_bits(rd_hi);
4590 let rn_lo_bits = reg_to_bits(rn_lo);
4591 let rn_hi_bits = reg_to_bits(rn_hi);
4592 let rm_lo_bits = reg_to_bits(rm_lo);
4593 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4595
4596 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4598 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4599 bytes.extend_from_slice(&hw1.to_le_bytes());
4600 bytes.extend_from_slice(&hw2.to_le_bytes());
4601
4602 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4604 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4605 bytes.extend_from_slice(&hw1.to_le_bytes());
4606 bytes.extend_from_slice(&hw2.to_le_bytes());
4607
4608 let bpl: u16 = 0xD50A;
4610 bytes.extend_from_slice(&bpl.to_le_bytes());
4611
4612 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4615 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4616 bytes.extend_from_slice(&hw1.to_le_bytes());
4617 bytes.extend_from_slice(&hw2.to_le_bytes());
4618
4619 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4621 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4622 bytes.extend_from_slice(&hw1.to_le_bytes());
4623 bytes.extend_from_slice(&hw2.to_le_bytes());
4624
4625 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4627 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4628 bytes.extend_from_slice(&hw1.to_le_bytes());
4629 bytes.extend_from_slice(&hw2.to_le_bytes());
4630
4631 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4633 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4634 bytes.extend_from_slice(&hw1.to_le_bytes());
4635 bytes.extend_from_slice(&hw2.to_le_bytes());
4636
4637 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4639 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4640 bytes.extend_from_slice(&hw1.to_le_bytes());
4641 bytes.extend_from_slice(&hw2.to_le_bytes());
4642
4643 let b_done: u16 = 0xE003;
4645 bytes.extend_from_slice(&b_done.to_le_bytes());
4646
4647 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4650 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4651 bytes.extend_from_slice(&hw1.to_le_bytes());
4652 bytes.extend_from_slice(&hw2.to_le_bytes());
4653
4654 let hw1: u16 = 0xEA4F;
4658 let hw2: u16 = (0x7000 | (rd_hi_bits << 8) | 0x00E0 | rn_hi_bits) as u16;
4659 bytes.extend_from_slice(&hw1.to_le_bytes());
4660 bytes.extend_from_slice(&hw2.to_le_bytes());
4661
4662 Ok(bytes) }
4664
4665 ArmOp::I64Rotl {
4676 rdlo,
4677 rdhi,
4678 rnlo,
4679 rnhi,
4680 shift,
4681 } => {
4682 let mut bytes = Vec::new();
4683 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4684
4685 let core: [u16; 35] = [
4686 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, ];
4709 for hw in core {
4710 bytes.extend_from_slice(&hw.to_le_bytes());
4711 }
4712
4713 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4714 Ok(bytes) }
4716
4717 ArmOp::I64Rotr {
4724 rdlo,
4725 rdhi,
4726 rnlo,
4727 rnhi,
4728 shift,
4729 } => {
4730 let mut bytes = Vec::new();
4731 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4732
4733 let core: [u16; 35] = [
4734 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, ];
4757 for hw in core {
4758 bytes.extend_from_slice(&hw.to_le_bytes());
4759 }
4760
4761 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4762 Ok(bytes) }
4764
4765 ArmOp::I64Clz { rd, rnlo, rnhi } => {
4779 let rd_bits = reg_to_bits(rd);
4780 let rn_lo_bits = reg_to_bits(rnlo);
4781 let rn_hi_bits = reg_to_bits(rnhi);
4782 let mut bytes = Vec::new();
4783
4784 let hw1: u16 = (0xF1B0 | rn_hi_bits) as u16;
4786 let hw2: u16 = 0x0F00;
4787 bytes.extend_from_slice(&hw1.to_le_bytes());
4788 bytes.extend_from_slice(&hw2.to_le_bytes());
4789
4790 let beq: u16 = 0xD003;
4793 bytes.extend_from_slice(&beq.to_le_bytes());
4794
4795 let hw1: u16 = (0xFAB0 | rn_hi_bits) as u16;
4798 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_hi_bits) as u16;
4799 bytes.extend_from_slice(&hw1.to_le_bytes());
4800 bytes.extend_from_slice(&hw2.to_le_bytes());
4801
4802 let b_done: u16 = 0xE004;
4805 bytes.extend_from_slice(&b_done.to_le_bytes());
4806
4807 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
4809
4810 let hw1: u16 = (0xFAB0 | rn_lo_bits) as u16;
4814 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_lo_bits) as u16;
4815 bytes.extend_from_slice(&hw1.to_le_bytes());
4816 bytes.extend_from_slice(&hw2.to_le_bytes());
4817
4818 let hw1: u16 = (0xF100 | rd_bits) as u16;
4820 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
4821 bytes.extend_from_slice(&hw1.to_le_bytes());
4822 bytes.extend_from_slice(&hw2.to_le_bytes());
4823
4824 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4828 bytes.extend_from_slice(&mov0.to_le_bytes());
4829
4830 Ok(bytes)
4831 }
4832
4833 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
4849 let rd_bits = reg_to_bits(rd);
4850 let rn_lo_bits = reg_to_bits(rnlo);
4851 let rn_hi_bits = reg_to_bits(rnhi);
4852 let mut bytes = Vec::new();
4853
4854 let hw1: u16 = (0xF1B0 | rn_lo_bits) as u16;
4856 let hw2: u16 = 0x0F00;
4857 bytes.extend_from_slice(&hw1.to_le_bytes());
4858 bytes.extend_from_slice(&hw2.to_le_bytes());
4859
4860 let beq: u16 = 0xD005;
4863 bytes.extend_from_slice(&beq.to_le_bytes());
4864
4865 let hw1: u16 = (0xFA90 | rn_lo_bits) as u16;
4868 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_lo_bits) as u16;
4869 bytes.extend_from_slice(&hw1.to_le_bytes());
4870 bytes.extend_from_slice(&hw2.to_le_bytes());
4871
4872 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
4875 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
4876 bytes.extend_from_slice(&hw1.to_le_bytes());
4877 bytes.extend_from_slice(&hw2.to_le_bytes());
4878
4879 let b_done: u16 = 0xE006;
4882 bytes.extend_from_slice(&b_done.to_le_bytes());
4883
4884 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
4886
4887 let hw1: u16 = (0xFA90 | rn_hi_bits) as u16;
4891 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_hi_bits) as u16;
4892 bytes.extend_from_slice(&hw1.to_le_bytes());
4893 bytes.extend_from_slice(&hw2.to_le_bytes());
4894
4895 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
4898 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
4899 bytes.extend_from_slice(&hw1.to_le_bytes());
4900 bytes.extend_from_slice(&hw2.to_le_bytes());
4901
4902 let hw1: u16 = (0xF100 | rd_bits) as u16;
4904 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
4905 bytes.extend_from_slice(&hw1.to_le_bytes());
4906 bytes.extend_from_slice(&hw2.to_le_bytes());
4907
4908 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4911 bytes.extend_from_slice(&mov0.to_le_bytes());
4912
4913 Ok(bytes)
4914 }
4915
4916 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
4920 let rd_bits = reg_to_bits(rd);
4921 let rn_lo_bits = reg_to_bits(rnlo);
4922 let rn_hi_bits = reg_to_bits(rnhi);
4923 let r12: u32 = 12; let r3: u32 = 3; let mut bytes = Vec::new();
4926
4927 bytes.extend_from_slice(&0xB438u16.to_le_bytes());
4929
4930 let mov: u16 = (0x4600 | (1 << 7) | (rn_lo_bits << 3) | 4) as u16;
4943 bytes.extend_from_slice(&mov.to_le_bytes());
4944 let mov: u16 = (0x4600 | (rn_hi_bits << 3) | 5) as u16;
4946 bytes.extend_from_slice(&mov.to_le_bytes());
4947 bytes.extend_from_slice(&0x4664u16.to_le_bytes());
4949
4950 let hw1: u16 = 0xEA4F;
4954 let hw2: u16 = ((r12 << 8) | 0x50 | 4) as u16;
4955 bytes.extend_from_slice(&hw1.to_le_bytes());
4956 bytes.extend_from_slice(&hw2.to_le_bytes());
4957
4958 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
4961 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4962 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
4964 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4965
4966 let hw1: u16 = (0xEA00 | r12) as u16;
4968 let hw2: u16 = ((r12 << 8) | r3) as u16;
4969 bytes.extend_from_slice(&hw1.to_le_bytes());
4970 bytes.extend_from_slice(&hw2.to_le_bytes());
4971
4972 let hw1: u16 = (0xEBA0 | 4) as u16;
4974 let hw2: u16 = ((4 << 8) | r12) as u16;
4975 bytes.extend_from_slice(&hw1.to_le_bytes());
4976 bytes.extend_from_slice(&hw2.to_le_bytes());
4977
4978 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
4982 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4983 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
4985 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4986
4987 let hw1: u16 = (0xEA00 | 4) as u16;
4989 let hw2: u16 = ((r12 << 8) | r3) as u16;
4990 bytes.extend_from_slice(&hw1.to_le_bytes());
4991 bytes.extend_from_slice(&hw2.to_le_bytes());
4992
4993 let hw1: u16 = 0xEA4F;
4995 let hw2: u16 = ((4 << 8) | 0x90 | 4) as u16;
4996 bytes.extend_from_slice(&hw1.to_le_bytes());
4997 bytes.extend_from_slice(&hw2.to_le_bytes());
4998
4999 let hw1: u16 = (0xEA00 | 4) as u16;
5001 let hw2: u16 = ((4 << 8) | r3) as u16;
5002 bytes.extend_from_slice(&hw1.to_le_bytes());
5003 bytes.extend_from_slice(&hw2.to_le_bytes());
5004
5005 let hw1: u16 = (0xEB00 | 4) as u16;
5007 let hw2: u16 = ((4 << 8) | r12) as u16;
5008 bytes.extend_from_slice(&hw1.to_le_bytes());
5009 bytes.extend_from_slice(&hw2.to_le_bytes());
5010
5011 let hw1: u16 = 0xEA4F;
5016 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 4) as u16;
5017 bytes.extend_from_slice(&hw1.to_le_bytes());
5018 bytes.extend_from_slice(&hw2.to_le_bytes());
5019
5020 let hw1: u16 = (0xEB00 | 4) as u16;
5022 let hw2: u16 = ((4 << 8) | r12) as u16;
5023 bytes.extend_from_slice(&hw1.to_le_bytes());
5024 bytes.extend_from_slice(&hw2.to_le_bytes());
5025
5026 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
5031 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5032 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
5034 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5035
5036 let hw1: u16 = (0xEA00 | 4) as u16;
5038 let hw2: u16 = ((4 << 8) | r3) as u16;
5039 bytes.extend_from_slice(&hw1.to_le_bytes());
5040 bytes.extend_from_slice(&hw2.to_le_bytes());
5041
5042 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
5046 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5047 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
5049 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5050
5051 let hw1: u16 = (0xFB00 | 4) as u16;
5054 let hw2: u16 = (0xF000 | (4 << 8) | r3) as u16;
5055 bytes.extend_from_slice(&hw1.to_le_bytes());
5056 bytes.extend_from_slice(&hw2.to_le_bytes());
5057
5058 let hw1: u16 = 0xEA4F;
5061 let hw2: u16 = (0x6000 | (4 << 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 = 0xEA4F;
5068 let hw2: u16 = ((r12 << 8) | 0x50 | 5) as u16;
5069 bytes.extend_from_slice(&hw1.to_le_bytes());
5070 bytes.extend_from_slice(&hw2.to_le_bytes());
5071
5072 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
5074 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5075 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
5076 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5077
5078 let hw1: u16 = (0xEA00 | r12) as u16;
5079 let hw2: u16 = ((r12 << 8) | r3) as u16;
5080 bytes.extend_from_slice(&hw1.to_le_bytes());
5081 bytes.extend_from_slice(&hw2.to_le_bytes());
5082
5083 let hw1: u16 = (0xEBA0 | 5) as u16;
5084 let hw2: u16 = ((5 << 8) | r12) as u16;
5085 bytes.extend_from_slice(&hw1.to_le_bytes());
5086 bytes.extend_from_slice(&hw2.to_le_bytes());
5087
5088 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
5090 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5091 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
5092 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5093
5094 let hw1: u16 = (0xEA00 | 5) as u16;
5095 let hw2: u16 = ((r12 << 8) | r3) as u16;
5096 bytes.extend_from_slice(&hw1.to_le_bytes());
5097 bytes.extend_from_slice(&hw2.to_le_bytes());
5098
5099 let hw1: u16 = 0xEA4F;
5100 let hw2: u16 = ((5 << 8) | 0x90 | 5) as u16;
5101 bytes.extend_from_slice(&hw1.to_le_bytes());
5102 bytes.extend_from_slice(&hw2.to_le_bytes());
5103
5104 let hw1: u16 = (0xEA00 | 5) as u16;
5105 let hw2: u16 = ((5 << 8) | r3) as u16;
5106 bytes.extend_from_slice(&hw1.to_le_bytes());
5107 bytes.extend_from_slice(&hw2.to_le_bytes());
5108
5109 let hw1: u16 = (0xEB00 | 5) as u16;
5110 let hw2: u16 = ((5 << 8) | r12) as u16;
5111 bytes.extend_from_slice(&hw1.to_le_bytes());
5112 bytes.extend_from_slice(&hw2.to_le_bytes());
5113
5114 let hw1: u16 = 0xEA4F;
5117 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 5) as u16;
5118 bytes.extend_from_slice(&hw1.to_le_bytes());
5119 bytes.extend_from_slice(&hw2.to_le_bytes());
5120
5121 let hw1: u16 = (0xEB00 | 5) as u16;
5122 let hw2: u16 = ((5 << 8) | r12) as u16;
5123 bytes.extend_from_slice(&hw1.to_le_bytes());
5124 bytes.extend_from_slice(&hw2.to_le_bytes());
5125
5126 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
5128 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5129 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
5130 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5131
5132 let hw1: u16 = (0xEA00 | 5) as u16;
5133 let hw2: u16 = ((5 << 8) | r3) as u16;
5134 bytes.extend_from_slice(&hw1.to_le_bytes());
5135 bytes.extend_from_slice(&hw2.to_le_bytes());
5136
5137 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
5139 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5140 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
5141 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5142
5143 let hw1: u16 = (0xFB00 | 5) as u16;
5146 let hw2: u16 = (0xF000 | (5 << 8) | r3) as u16;
5147 bytes.extend_from_slice(&hw1.to_le_bytes());
5148 bytes.extend_from_slice(&hw2.to_le_bytes());
5149
5150 let hw1: u16 = 0xEA4F;
5153 let hw2: u16 = (0x6000 | (5 << 8) | 0x10 | 5) as u16;
5154 bytes.extend_from_slice(&hw1.to_le_bytes());
5155 bytes.extend_from_slice(&hw2.to_le_bytes());
5156
5157 bytes.extend_from_slice(&0xEB04u16.to_le_bytes());
5166 bytes.extend_from_slice(&0x0C05u16.to_le_bytes());
5167
5168 bytes.extend_from_slice(&0xBC38u16.to_le_bytes());
5170
5171 let mov: u16 =
5175 (0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7)) as u16;
5176 bytes.extend_from_slice(&mov.to_le_bytes());
5177
5178 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5182 bytes.extend_from_slice(&(((rn_hi_bits & 0xF) << 8) as u16).to_le_bytes());
5183
5184 Ok(bytes)
5185 }
5186
5187 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
5190 let rdlo_bits = reg_to_bits(rdlo);
5191 let rdhi_bits = reg_to_bits(rdhi);
5192 let rnlo_bits = reg_to_bits(rnlo);
5193 let mut bytes = Vec::new();
5194
5195 let hw1: u16 = 0xFA4F_u16;
5198 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5199 bytes.extend_from_slice(&hw1.to_le_bytes());
5200 bytes.extend_from_slice(&hw2.to_le_bytes());
5201
5202 let hw1: u16 = 0xEA4F;
5207 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5208 bytes.extend_from_slice(&hw1.to_le_bytes());
5209 bytes.extend_from_slice(&hw2.to_le_bytes());
5210
5211 Ok(bytes)
5212 }
5213
5214 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
5217 let rdlo_bits = reg_to_bits(rdlo);
5218 let rdhi_bits = reg_to_bits(rdhi);
5219 let rnlo_bits = reg_to_bits(rnlo);
5220 let mut bytes = Vec::new();
5221
5222 let hw1: u16 = 0xFA0F_u16;
5225 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5226 bytes.extend_from_slice(&hw1.to_le_bytes());
5227 bytes.extend_from_slice(&hw2.to_le_bytes());
5228
5229 let hw1: u16 = 0xEA4F;
5231 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5232 bytes.extend_from_slice(&hw1.to_le_bytes());
5233 bytes.extend_from_slice(&hw2.to_le_bytes());
5234
5235 Ok(bytes)
5236 }
5237
5238 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
5241 let rdlo_bits = reg_to_bits(rdlo);
5242 let rdhi_bits = reg_to_bits(rdhi);
5243 let rnlo_bits = reg_to_bits(rnlo);
5244 let mut bytes = Vec::new();
5245
5246 if rdlo_bits != rnlo_bits {
5248 let d_bit = ((rdlo_bits >> 3) & 1) as u16;
5250 let mov: u16 = 0x4600
5251 | (d_bit << 7)
5252 | ((rnlo_bits as u16) << 3)
5253 | ((rdlo_bits & 0x7) as u16);
5254 bytes.extend_from_slice(&mov.to_le_bytes());
5255 }
5256
5257 let hw1: u16 = 0xEA4F;
5259 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rnlo_bits) as u16;
5260 bytes.extend_from_slice(&hw1.to_le_bytes());
5261 bytes.extend_from_slice(&hw2.to_le_bytes());
5262
5263 Ok(bytes)
5264 }
5265
5266 ArmOp::SelectMove { rd, rm, cond } => {
5269 let rd_bits = reg_to_bits(rd) as u16;
5270 let rm_bits = reg_to_bits(rm) as u16;
5271
5272 use synth_synthesis::Condition;
5274 let cond_bits: u16 = match cond {
5275 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, };
5286
5287 let it_instr: u16 = 0xBF00 | (cond_bits << 4) | 0x8;
5290
5291 let d_bit = (rd_bits >> 3) & 1;
5294 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5295
5296 let mut bytes = it_instr.to_le_bytes().to_vec();
5298 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5299 Ok(bytes)
5300 }
5301
5302 ArmOp::Popcnt { rd, rm } => {
5313 let mut bytes = Vec::new();
5314
5315 if rd != rm {
5317 let rd_bits = reg_to_bits(rd) as u16;
5318 let rm_bits = reg_to_bits(rm) as u16;
5319 let d_bit = (rd_bits >> 3) & 1;
5321 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5322 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5323 }
5324
5325 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x5555)?);
5328 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x5555)?);
5329
5330 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 1)?);
5333
5334 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(11, 11, 12)?);
5336
5337 bytes.extend_from_slice(&self.encode_thumb32_sub_reg_raw(
5339 reg_to_bits(rd),
5340 reg_to_bits(rd),
5341 11,
5342 )?);
5343
5344 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x3333)?);
5347 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x3333)?);
5348
5349 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5351 11,
5352 reg_to_bits(rd),
5353 12,
5354 )?);
5355
5356 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(
5358 reg_to_bits(rd),
5359 reg_to_bits(rd),
5360 2,
5361 )?);
5362
5363 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5365 reg_to_bits(rd),
5366 reg_to_bits(rd),
5367 12,
5368 )?);
5369
5370 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5372 reg_to_bits(rd),
5373 reg_to_bits(rd),
5374 11,
5375 )?);
5376
5377 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 4)?);
5380
5381 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5383 reg_to_bits(rd),
5384 reg_to_bits(rd),
5385 11,
5386 )?);
5387
5388 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x0F0F)?);
5390 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x0F0F)?);
5391
5392 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5394 reg_to_bits(rd),
5395 reg_to_bits(rd),
5396 12,
5397 )?);
5398
5399 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 8)?);
5402
5403 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5405 reg_to_bits(rd),
5406 reg_to_bits(rd),
5407 11,
5408 )?);
5409
5410 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 16)?);
5413
5414 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5416 reg_to_bits(rd),
5417 reg_to_bits(rd),
5418 11,
5419 )?);
5420
5421 bytes.extend_from_slice(&self.encode_thumb32_and_imm_raw(
5424 reg_to_bits(rd),
5425 reg_to_bits(rd),
5426 0x3F,
5427 )?);
5428
5429 Ok(bytes)
5430 }
5431
5432 ArmOp::I64DivU {
5443 rdlo,
5444 rdhi,
5445 rnlo,
5446 rnhi,
5447 rmlo,
5448 rmhi,
5449 elide_zero_guard,
5450 } => {
5451 let mut bytes = Vec::new();
5452 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5453 if !elide_zero_guard {
5456 emit_i64_divisor_zero_trap(&mut bytes);
5457 }
5458
5459 bytes.extend_from_slice(&0xB4F0u16.to_le_bytes());
5463
5464 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());
5475 bytes.extend_from_slice(&0x0C40u16.to_le_bytes());
5476
5477 let loop_start = bytes.len();
5479
5480 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes());
5491 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());
5500 bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
5501 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes());
5505 bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5506
5507 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes());
5512 bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5513 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());
5544 bytes.extend_from_slice(&0x0703u16.to_le_bytes());
5545 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5548
5549 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
5553 bytes.extend_from_slice(&0x0C01u16.to_le_bytes());
5554
5555 let branch_offset_bytes = bytes.len() - loop_start + 4; let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5558 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5559 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5560
5561 bytes.extend_from_slice(&0x4620u16.to_le_bytes()); bytes.extend_from_slice(&0x4629u16.to_le_bytes()); bytes.extend_from_slice(&0xBCF0u16.to_le_bytes());
5569
5570 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5571 Ok(bytes)
5572 }
5573
5574 ArmOp::I64DivS {
5580 rdlo,
5581 rdhi,
5582 rnlo,
5583 rnhi,
5584 rmlo,
5585 rmhi,
5586 elide_zero_guard,
5587 elide_overflow_guard,
5588 } => {
5589 let mut bytes = Vec::new();
5590 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5591 if !elide_zero_guard {
5597 emit_i64_divisor_zero_trap(&mut bytes);
5598 }
5599 if !elide_overflow_guard {
5600 emit_i64_divs_overflow_trap(&mut bytes);
5603 }
5604
5605 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5607 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5608
5609 bytes.extend_from_slice(&0xEA81u16.to_le_bytes());
5612 bytes.extend_from_slice(&0x0903u16.to_le_bytes());
5613
5614 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());
5627
5628 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());
5638
5639 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5642 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5643 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5645 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5646 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5648 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5649
5650 let loop_start = bytes.len();
5651
5652 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5656 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());
5662 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5665
5666 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5670 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());
5683 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5685
5686 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5689
5690 let branch_offset_bytes = bytes.len() - loop_start + 4;
5691 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5692 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5693 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5694
5695 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());
5702 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());
5710
5711 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5713 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5714
5715 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5716 Ok(bytes)
5717 }
5718
5719 ArmOp::I64RemU {
5724 rdlo,
5725 rdhi,
5726 rnlo,
5727 rnhi,
5728 rmlo,
5729 rmhi,
5730 elide_zero_guard,
5731 } => {
5732 let mut bytes = Vec::new();
5733 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5734 if !elide_zero_guard {
5735 emit_i64_divisor_zero_trap(&mut bytes);
5736 }
5737
5738 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5740 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5741
5742 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5744 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5745 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5747 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5748 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5750 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5751
5752 let loop_start = bytes.len();
5753
5754 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5758 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());
5764 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5767
5768 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5772 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());
5785 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5787
5788 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5791
5792 let branch_offset_bytes = bytes.len() - loop_start + 4;
5793 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5794 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5795 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5796
5797 bytes.extend_from_slice(&0x4630u16.to_le_bytes()); bytes.extend_from_slice(&0x4639u16.to_le_bytes()); bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5803 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5804
5805 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5806 Ok(bytes)
5807 }
5808
5809 ArmOp::I64RemS {
5815 rdlo,
5816 rdhi,
5817 rnlo,
5818 rnhi,
5819 rmlo,
5820 rmhi,
5821 elide_zero_guard,
5822 } => {
5823 let mut bytes = Vec::new();
5824 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5825 if !elide_zero_guard {
5826 emit_i64_divisor_zero_trap(&mut bytes);
5827 }
5828
5829 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5831 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5832
5833 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());
5847
5848 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());
5858
5859 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5862 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5863 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5865 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5866 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5868 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5869
5870 let loop_start = bytes.len();
5871
5872 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5876 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());
5882 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5885
5886 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5890 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());
5903 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5905
5906 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5909
5910 let branch_offset_bytes = bytes.len() - loop_start + 4;
5911 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5912 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5913 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5914
5915 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());
5922 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());
5930
5931 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5933 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5934
5935 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5936 Ok(bytes)
5937 }
5938
5939 ArmOp::F32Add { sd, sn, sm } => {
5942 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A00, sd, sn, sm)?))
5943 }
5944 ArmOp::F32Sub { sd, sn, sm } => {
5945 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A40, sd, sn, sm)?))
5946 }
5947 ArmOp::F32Mul { sd, sn, sm } => {
5948 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE200A00, sd, sn, sm)?))
5949 }
5950 ArmOp::F32Div { sd, sn, sm } => {
5951 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE800A00, sd, sn, sm)?))
5952 }
5953 ArmOp::F32Abs { sd, sm } => {
5954 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB00AC0, sd, sm)?))
5955 }
5956 ArmOp::F32Neg { sd, sm } => {
5957 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10A40, sd, sm)?))
5958 }
5959 ArmOp::F32Sqrt { sd, sm } => {
5960 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10AC0, sd, sm)?))
5961 }
5962
5963 ArmOp::F32Ceil { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b01),
5966 ArmOp::F32Floor { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b10),
5967 ArmOp::F32Trunc { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b11),
5968 ArmOp::F32Nearest { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b00),
5969 ArmOp::F32Min { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, true),
5970 ArmOp::F32Max { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, false),
5971 ArmOp::F32Copysign { sd, sn, sm } => self.encode_thumb_f32_copysign(sd, sn, sm),
5972
5973 ArmOp::F32Eq { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x0),
5975 ArmOp::F32Ne { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x1),
5976 ArmOp::F32Lt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x4),
5977 ArmOp::F32Le { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x9),
5978 ArmOp::F32Gt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xC),
5979 ArmOp::F32Ge { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xA),
5980
5981 ArmOp::F32Const { sd, value } => self.encode_thumb_f32_const(sd, *value),
5982
5983 ArmOp::F32Load { sd, addr } => {
5984 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED900A00, sd, addr)?))
5985 }
5986 ArmOp::F32Store { sd, addr } => {
5987 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED800A00, sd, addr)?))
5988 }
5989
5990 ArmOp::F32ConvertI32S { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, true),
5991 ArmOp::F32ConvertI32U { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, false),
5992 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
5993 Err(synth_core::Error::synthesis(
5994 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
5995 ))
5996 }
5997 ArmOp::F32ReinterpretI32 { sd, rm } => {
5998 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(true, sd, rm)?))
5999 }
6000 ArmOp::I32ReinterpretF32 { rd, sm } => {
6001 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(false, sm, rd)?))
6002 }
6003 ArmOp::I32TruncF32S { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, true),
6004 ArmOp::I32TruncF32U { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, false),
6005
6006 ArmOp::F64Add { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6009 0xEE300B00, dd, dn, dm,
6010 )?)),
6011 ArmOp::F64Sub { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6012 0xEE300B40, dd, dn, dm,
6013 )?)),
6014 ArmOp::F64Mul { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6015 0xEE200B00, dd, dn, dm,
6016 )?)),
6017 ArmOp::F64Div { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6018 0xEE800B00, dd, dn, dm,
6019 )?)),
6020 ArmOp::F64Abs { dd, dm } => {
6021 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?))
6022 }
6023 ArmOp::F64Neg { dd, dm } => {
6024 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?))
6025 }
6026 ArmOp::F64Sqrt { dd, dm } => {
6027 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?))
6028 }
6029
6030 ArmOp::F64Ceil { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b01),
6033 ArmOp::F64Floor { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b10),
6034 ArmOp::F64Trunc { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b11),
6035 ArmOp::F64Nearest { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b00),
6036 ArmOp::F64Min { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, true),
6037 ArmOp::F64Max { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, false),
6038 ArmOp::F64Copysign { dd, dn, dm } => self.encode_thumb_f64_copysign(dd, dn, dm),
6039
6040 ArmOp::F64Eq { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x0),
6042 ArmOp::F64Ne { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x1),
6043 ArmOp::F64Lt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x4),
6044 ArmOp::F64Le { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x9),
6045 ArmOp::F64Gt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xC),
6046 ArmOp::F64Ge { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xA),
6047
6048 ArmOp::F64Const { dd, value } => self.encode_thumb_f64_const(dd, *value),
6049
6050 ArmOp::F64Load { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
6051 0xED900B00, dd, addr,
6052 )?)),
6053 ArmOp::F64Store { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
6054 0xED800B00, dd, addr,
6055 )?)),
6056
6057 ArmOp::F64ConvertI32S { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, true),
6058 ArmOp::F64ConvertI32U { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, false),
6059 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
6060 Err(synth_core::Error::synthesis(
6061 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
6062 ))
6063 }
6064 ArmOp::F64PromoteF32 { dd, sm } => self.encode_thumb_f64_promote_f32(dd, sm),
6065 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => Ok(vfp_to_thumb_bytes(
6066 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?,
6067 )),
6068 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => Ok(vfp_to_thumb_bytes(
6069 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?,
6070 )),
6071 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
6072 Err(synth_core::Error::synthesis(
6073 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
6074 ))
6075 }
6076 ArmOp::I32TruncF64S { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, true),
6077 ArmOp::I32TruncF64U { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, false),
6078
6079 ArmOp::I64Add {
6083 rdlo,
6084 rdhi,
6085 rnlo,
6086 rnhi,
6087 rmlo,
6088 rmhi,
6089 } => {
6090 let mut bytes = Vec::new();
6091 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adds {
6093 rd: *rdlo,
6094 rn: *rnlo,
6095 op2: Operand2::Reg(*rmlo),
6096 })?);
6097 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adc {
6099 rd: *rdhi,
6100 rn: *rnhi,
6101 op2: Operand2::Reg(*rmhi),
6102 })?);
6103 Ok(bytes)
6104 }
6105
6106 ArmOp::I64Sub {
6108 rdlo,
6109 rdhi,
6110 rnlo,
6111 rnhi,
6112 rmlo,
6113 rmhi,
6114 } => {
6115 let mut bytes = Vec::new();
6116 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Subs {
6118 rd: *rdlo,
6119 rn: *rnlo,
6120 op2: Operand2::Reg(*rmlo),
6121 })?);
6122 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Sbc {
6124 rd: *rdhi,
6125 rn: *rnhi,
6126 op2: Operand2::Reg(*rmhi),
6127 })?);
6128 Ok(bytes)
6129 }
6130
6131 ArmOp::I64And {
6133 rdlo,
6134 rdhi,
6135 rnlo,
6136 rnhi,
6137 rmlo,
6138 rmhi,
6139 } => {
6140 let mut bytes = Vec::new();
6141 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
6142 rd: *rdlo,
6143 rn: *rnlo,
6144 op2: Operand2::Reg(*rmlo),
6145 })?);
6146 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
6147 rd: *rdhi,
6148 rn: *rnhi,
6149 op2: Operand2::Reg(*rmhi),
6150 })?);
6151 Ok(bytes)
6152 }
6153
6154 ArmOp::I64Or {
6156 rdlo,
6157 rdhi,
6158 rnlo,
6159 rnhi,
6160 rmlo,
6161 rmhi,
6162 } => {
6163 let mut bytes = Vec::new();
6164 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
6165 rd: *rdlo,
6166 rn: *rnlo,
6167 op2: Operand2::Reg(*rmlo),
6168 })?);
6169 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
6170 rd: *rdhi,
6171 rn: *rnhi,
6172 op2: Operand2::Reg(*rmhi),
6173 })?);
6174 Ok(bytes)
6175 }
6176
6177 ArmOp::I64Xor {
6179 rdlo,
6180 rdhi,
6181 rnlo,
6182 rnhi,
6183 rmlo,
6184 rmhi,
6185 } => {
6186 let mut bytes = Vec::new();
6187 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6188 rd: *rdlo,
6189 rn: *rnlo,
6190 op2: Operand2::Reg(*rmlo),
6191 })?);
6192 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6193 rd: *rdhi,
6194 rn: *rnhi,
6195 op2: Operand2::Reg(*rmhi),
6196 })?);
6197 Ok(bytes)
6198 }
6199
6200 ArmOp::I64Eqz { rd, rnlo, rnhi } => self.encode_thumb(&ArmOp::I64SetCondZ {
6202 rd: *rd,
6203 rn_lo: *rnlo,
6204 rn_hi: *rnhi,
6205 }),
6206
6207 ArmOp::I64Eq {
6209 rd,
6210 rnlo,
6211 rnhi,
6212 rmlo,
6213 rmhi,
6214 } => self.encode_thumb(&ArmOp::I64SetCond {
6215 rd: *rd,
6216 rn_lo: *rnlo,
6217 rn_hi: *rnhi,
6218 rm_lo: *rmlo,
6219 rm_hi: *rmhi,
6220 cond: synth_synthesis::Condition::EQ,
6221 }),
6222
6223 ArmOp::I64Ne {
6224 rd,
6225 rnlo,
6226 rnhi,
6227 rmlo,
6228 rmhi,
6229 } => self.encode_thumb(&ArmOp::I64SetCond {
6230 rd: *rd,
6231 rn_lo: *rnlo,
6232 rn_hi: *rnhi,
6233 rm_lo: *rmlo,
6234 rm_hi: *rmhi,
6235 cond: synth_synthesis::Condition::NE,
6236 }),
6237
6238 ArmOp::I64LtS {
6239 rd,
6240 rnlo,
6241 rnhi,
6242 rmlo,
6243 rmhi,
6244 } => self.encode_thumb(&ArmOp::I64SetCond {
6245 rd: *rd,
6246 rn_lo: *rnlo,
6247 rn_hi: *rnhi,
6248 rm_lo: *rmlo,
6249 rm_hi: *rmhi,
6250 cond: synth_synthesis::Condition::LT,
6251 }),
6252
6253 ArmOp::I64LtU {
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::LO,
6266 }),
6267
6268 ArmOp::I64LeS {
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::LE,
6281 }),
6282
6283 ArmOp::I64LeU {
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::LS,
6296 }),
6297
6298 ArmOp::I64GtS {
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::GT,
6311 }),
6312
6313 ArmOp::I64GtU {
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::HI,
6326 }),
6327
6328 ArmOp::I64GeS {
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::GE,
6341 }),
6342
6343 ArmOp::I64GeU {
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::HS,
6356 }),
6357
6358 ArmOp::I64Const { rdlo, rdhi, value } => {
6360 let lo32 = *value as u32;
6361 let hi32 = (*value >> 32) as u32;
6362 let mut bytes = Vec::new();
6363 bytes.extend_from_slice(
6365 &self.encode_thumb32_movw_raw(reg_to_bits(rdlo), lo32 & 0xFFFF)?,
6366 );
6367 if lo32 > 0xFFFF {
6368 bytes.extend_from_slice(
6369 &self.encode_thumb32_movt_raw(reg_to_bits(rdlo), lo32 >> 16)?,
6370 );
6371 }
6372 bytes.extend_from_slice(
6374 &self.encode_thumb32_movw_raw(reg_to_bits(rdhi), hi32 & 0xFFFF)?,
6375 );
6376 if hi32 > 0xFFFF {
6377 bytes.extend_from_slice(
6378 &self.encode_thumb32_movt_raw(reg_to_bits(rdhi), hi32 >> 16)?,
6379 );
6380 }
6381 Ok(bytes)
6382 }
6383
6384 ArmOp::I64Ldr { rdlo, rdhi, addr } => {
6386 let mut bytes = Vec::new();
6387 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6398 bytes.extend_from_slice(&self.encode_thumb32_ldr(rdlo, &base, offset)?);
6399 bytes.extend_from_slice(&self.encode_thumb32_ldr(
6400 rdhi,
6401 &base,
6402 offset.wrapping_add(4),
6403 )?);
6404 Ok(bytes)
6405 }
6406
6407 ArmOp::I64Str { rdlo, rdhi, addr } => {
6409 let mut bytes = Vec::new();
6410 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6413 bytes.extend_from_slice(&self.encode_thumb32_str(rdlo, &base, offset)?);
6414 bytes.extend_from_slice(&self.encode_thumb32_str(
6415 rdhi,
6416 &base,
6417 offset.wrapping_add(4),
6418 )?);
6419 Ok(bytes)
6420 }
6421
6422 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
6424 let mut bytes = Vec::new();
6425 if rdlo != rn {
6426 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6428 rd: *rdlo,
6429 op2: Operand2::Reg(*rn),
6430 })?);
6431 }
6432 bytes.extend_from_slice(
6434 &self.encode_thumb32_shift(rdhi, rdlo, 31, 0b10)?, );
6436 Ok(bytes)
6437 }
6438
6439 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
6441 let mut bytes = Vec::new();
6442 if rdlo != rn {
6443 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6445 rd: *rdlo,
6446 op2: Operand2::Reg(*rn),
6447 })?);
6448 }
6449 let rdhi_bits = reg_to_bits(rdhi) as u16;
6451 let instr: u16 = 0x2000 | (rdhi_bits << 8);
6452 bytes.extend_from_slice(&instr.to_le_bytes());
6453 Ok(bytes)
6454 }
6455
6456 ArmOp::I32WrapI64 { rd, rnlo } => {
6458 if rd == rnlo {
6459 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6462 } else {
6463 self.encode_thumb(&ArmOp::Mov {
6465 rd: *rd,
6466 op2: Operand2::Reg(*rnlo),
6467 })
6468 }
6469 }
6470
6471 ArmOp::MveLoad { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vldrw(qd, addr))),
6473 ArmOp::MveStore { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vstrw(qd, addr))),
6474 ArmOp::MveConst { qd, bytes } => self.encode_thumb_mve_const(qd, bytes),
6475 ArmOp::MveAnd { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6476 0xEF000150, qd, qn, qm,
6477 ))),
6478 ArmOp::MveOrr { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6479 0xEF200150, qd, qn, qm,
6480 ))),
6481 ArmOp::MveEor { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6482 0xFF000150, qd, qn, qm,
6483 ))),
6484 ArmOp::MveMvn { qd, qm } => {
6485 let qd_enc = qreg_to_num(qd);
6487 let qm_enc = qreg_to_num(qm);
6488 let instr: u32 = 0xFFB005C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6489 Ok(vfp_to_thumb_bytes(instr))
6490 }
6491 ArmOp::MveBic { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6492 0xEF100150, qd, qn, qm,
6493 ))),
6494 ArmOp::MveAddI { qd, qn, qm, size } => {
6495 let sz = mve_size_bits(size);
6496 let base: u32 = 0xEF000840 | (sz << 20);
6497 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6498 }
6499 ArmOp::MveSubI { qd, qn, qm, size } => {
6500 let sz = mve_size_bits(size);
6501 let base: u32 = 0xFF000840 | (sz << 20);
6502 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6503 }
6504 ArmOp::MveMulI { qd, qn, qm, size } => {
6505 let sz = mve_size_bits(size);
6506 let base: u32 = 0xEF000950 | (sz << 20);
6507 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6508 }
6509 ArmOp::MveNegI { qd, qm, size } => {
6510 let sz = mve_size_bits(size);
6511 let qd_enc = qreg_to_num(qd);
6513 let qm_enc = qreg_to_num(qm);
6514 let base: u32 = 0xFFB103C0 | (sz << 18);
6515 let instr = base | ((qd_enc * 2) << 12) | (qm_enc * 2);
6516 Ok(vfp_to_thumb_bytes(instr))
6517 }
6518 ArmOp::MveDup { qd, rn, size } => {
6519 let sz = mve_size_bits(size);
6520 let qd_enc = qreg_to_num(qd);
6521 let rn_bits = reg_to_bits(rn);
6522 let be = match sz {
6525 0 => 0b00u32, 1 => 0b01, _ => 0b00, };
6529 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12) | (be << 5);
6530 Ok(vfp_to_thumb_bytes(instr))
6531 }
6532 ArmOp::MveExtractLane { rd, qn, lane, size } => {
6533 let qn_enc = qreg_to_num(qn);
6534 let rd_bits = reg_to_bits(rd);
6535 let d_reg = qn_enc * 2 + ((*lane as u32) >> 1);
6538 let lane_in_d = (*lane as u32) & 1;
6539 let _sz = mve_size_bits(size);
6540 let instr: u32 = 0xEE100B10 | (d_reg << 16) | (rd_bits << 12) | (lane_in_d << 21);
6542 Ok(vfp_to_thumb_bytes(instr))
6543 }
6544 ArmOp::MveInsertLane { qd, rn, lane, size } => {
6545 let qd_enc = qreg_to_num(qd);
6546 let rn_bits = reg_to_bits(rn);
6547 let d_reg = qd_enc * 2 + ((*lane as u32) >> 1);
6548 let lane_in_d = (*lane as u32) & 1;
6549 let _sz = mve_size_bits(size);
6550 let instr: u32 = 0xEE000B10 | (d_reg << 16) | (rn_bits << 12) | (lane_in_d << 21);
6552 Ok(vfp_to_thumb_bytes(instr))
6553 }
6554
6555 ArmOp::MveCmpEqI { qd, qn, qm, size }
6557 | ArmOp::MveCmpNeI { qd, qn, qm, size }
6558 | ArmOp::MveCmpLtS { qd, qn, qm, size }
6559 | ArmOp::MveCmpLtU { qd, qn, qm, size }
6560 | ArmOp::MveCmpGtS { qd, qn, qm, size }
6561 | ArmOp::MveCmpGtU { qd, qn, qm, size }
6562 | ArmOp::MveCmpLeS { qd, qn, qm, size }
6563 | ArmOp::MveCmpLeU { qd, qn, qm, size }
6564 | ArmOp::MveCmpGeS { qd, qn, qm, size }
6565 | ArmOp::MveCmpGeU { qd, qn, qm, size } => {
6566 let sz = mve_size_bits(size);
6569 let base: u32 = 0xEF000840 | (sz << 20);
6570 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6571 }
6572
6573 ArmOp::MveAddF32 { qd, qn, qm } => {
6575 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6577 }
6578 ArmOp::MveSubF32 { qd, qn, qm } => {
6579 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF200D40, qd, qn, qm)))
6581 }
6582 ArmOp::MveMulF32 { qd, qn, qm } => {
6583 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xFF000D50, qd, qn, qm)))
6585 }
6586 ArmOp::MveNegF32 { qd, qm } => {
6587 let qd_enc = qreg_to_num(qd);
6588 let qm_enc = qreg_to_num(qm);
6589 let instr: u32 = 0xFFB907C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6591 Ok(vfp_to_thumb_bytes(instr))
6592 }
6593 ArmOp::MveAbsF32 { qd, qm } => {
6594 let qd_enc = qreg_to_num(qd);
6595 let qm_enc = qreg_to_num(qm);
6596 let instr: u32 = 0xFFB90740 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6598 Ok(vfp_to_thumb_bytes(instr))
6599 }
6600 ArmOp::MveCmpEqF32 { qd, qn, qm }
6601 | ArmOp::MveCmpNeF32 { qd, qn, qm }
6602 | ArmOp::MveCmpLtF32 { qd, qn, qm }
6603 | ArmOp::MveCmpLeF32 { qd, qn, qm }
6604 | ArmOp::MveCmpGtF32 { qd, qn, qm }
6605 | ArmOp::MveCmpGeF32 { qd, qn, qm } => {
6606 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6608 }
6609 ArmOp::MveDupF32 { qd, rn } => {
6610 let qd_enc = qreg_to_num(qd);
6611 let rn_bits = reg_to_bits(rn);
6612 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12);
6614 Ok(vfp_to_thumb_bytes(instr))
6615 }
6616 ArmOp::MveExtractLaneF32 { rd, qn, lane } => {
6617 let qn_enc = qreg_to_num(qn);
6618 let rd_bits = reg_to_bits(rd);
6619 let s_num = qn_enc * 4 + (*lane as u32);
6621 let (vn, n) = encode_sreg(s_num);
6622 let instr: u32 = 0xEE100A10 | (vn << 16) | (rd_bits << 12) | (n << 7);
6623 Ok(vfp_to_thumb_bytes(instr))
6624 }
6625 ArmOp::MveReplaceLaneF32 { qd, rn, lane } => {
6626 let qd_enc = qreg_to_num(qd);
6627 let rn_bits = reg_to_bits(rn);
6628 let s_num = qd_enc * 4 + (*lane as u32);
6630 let (vn, n) = encode_sreg(s_num);
6631 let instr: u32 = 0xEE000A10 | (vn << 16) | (rn_bits << 12) | (n << 7);
6632 Ok(vfp_to_thumb_bytes(instr))
6633 }
6634 ArmOp::MveDivF32 { qd, qn, qm } => {
6635 self.encode_thumb_mve_lane_wise_f32_binop(qd, qn, qm, 0xEE800A00)
6637 }
6638 ArmOp::MveSqrtF32 { qd, qm } => {
6639 self.encode_thumb_mve_lane_wise_f32_sqrt(qd, qm)
6641 }
6642
6643 _ => {
6645 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6647 }
6648 }
6649 }
6650
6651 fn encode_thumb_f32_compare(
6655 &self,
6656 rd: &Reg,
6657 sn: &VfpReg,
6658 sm: &VfpReg,
6659 cond_code: u32,
6660 ) -> Result<Vec<u8>> {
6661 let mut bytes = Vec::new();
6662 let rd_bits = reg_to_bits(rd);
6663
6664 let sn_num = vfp_sreg_to_num(sn)?;
6666 let sm_num = vfp_sreg_to_num(sm)?;
6667 let (vd, d) = encode_sreg(sn_num);
6668 let (vm, m) = encode_sreg(sm_num);
6669 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6670 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6671
6672 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6674
6675 if rd_bits < 8 {
6677 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
6678 bytes.extend_from_slice(&movs_zero.to_le_bytes());
6679 } else {
6680 let hw1: u16 = 0xF04F;
6682 let hw2: u16 = (rd_bits as u16) << 8;
6683 bytes.extend_from_slice(&hw1.to_le_bytes());
6684 bytes.extend_from_slice(&hw2.to_le_bytes());
6685 }
6686
6687 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
6691 bytes.extend_from_slice(&it.to_le_bytes());
6692
6693 if rd_bits < 8 {
6695 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
6696 bytes.extend_from_slice(&mov_one.to_le_bytes());
6697 } else {
6698 let hw1: u16 = 0xF04F;
6700 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
6701 bytes.extend_from_slice(&hw1.to_le_bytes());
6702 bytes.extend_from_slice(&hw2.to_le_bytes());
6703 }
6704
6705 Ok(bytes)
6706 }
6707
6708 fn encode_thumb_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
6710 let mut bytes = Vec::new();
6711 let bits = value.to_bits();
6712 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
6717 let imm4 = (lo16 >> 12) & 0xF;
6718 let i_bit = (lo16 >> 11) & 1;
6719 let imm3 = (lo16 >> 8) & 0x7;
6720 let imm8 = lo16 & 0xFF;
6721 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
6722 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6723 bytes.extend_from_slice(&hw1.to_le_bytes());
6724 bytes.extend_from_slice(&hw2.to_le_bytes());
6725
6726 let hi16 = (bits >> 16) & 0xFFFF;
6728 let imm4 = (hi16 >> 12) & 0xF;
6729 let i_bit = (hi16 >> 11) & 1;
6730 let imm3 = (hi16 >> 8) & 0x7;
6731 let imm8 = hi16 & 0xFF;
6732 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
6733 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6734 bytes.extend_from_slice(&hw1.to_le_bytes());
6735 bytes.extend_from_slice(&hw2.to_le_bytes());
6736
6737 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
6739 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6740
6741 Ok(bytes)
6742 }
6743
6744 fn encode_thumb_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
6746 let mut bytes = Vec::new();
6747
6748 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
6750 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6751
6752 let sd_num = vfp_sreg_to_num(sd)?;
6754 let (vd, d) = encode_sreg(sd_num);
6755 let (vm, m) = encode_sreg(sd_num);
6756 let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
6757 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
6758 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6759
6760 Ok(bytes)
6761 }
6762
6763 fn encode_thumb_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
6771 let mut bytes = Vec::new();
6772 let sm_num = vfp_sreg_to_num(sm)?;
6773 let sd_num = vfp_sreg_to_num(sd)?;
6774 let (vd_s, d_s) = encode_sreg(sd_num);
6775 let (vm_s, m_s) = encode_sreg(sm_num);
6776
6777 if mode == 0b11 {
6778 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6780 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6781 } else {
6782 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
6787 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6788
6789 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF); let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
6795 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6796 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6797
6798 if mode != 0 {
6800 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF); let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
6802 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
6803 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
6804 }
6805
6806 let vmsr = 0xEEE10A10 | (rt << 12);
6808 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6809
6810 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6812 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6813
6814 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6816 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6817 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6818 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6819 }
6820
6821 let (vd2, d2) = encode_sreg(sd_num);
6823 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
6824 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
6825
6826 Ok(bytes)
6827 }
6828
6829 fn encode_thumb_f32_minmax(
6831 &self,
6832 sd: &VfpReg,
6833 sn: &VfpReg,
6834 sm: &VfpReg,
6835 is_min: bool,
6836 ) -> Result<Vec<u8>> {
6837 let mut bytes = Vec::new();
6838 let sn_num = vfp_sreg_to_num(sn)?;
6839 let sm_num = vfp_sreg_to_num(sm)?;
6840 let sd_num = vfp_sreg_to_num(sd)?;
6841
6842 let (vd, d) = encode_sreg(sd_num);
6844 let (vn, n) = encode_sreg(sn_num);
6845 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
6846 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sn));
6847
6848 let (vm, m) = encode_sreg(sm_num);
6850 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
6851 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6852
6853 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6855
6856 let cond: u16 = if is_min { 0xC } else { 0x4 };
6858 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
6859 bytes.extend_from_slice(&it.to_le_bytes());
6860
6861 let vmov_sm = 0xEEB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6863 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sm));
6864
6865 Ok(bytes)
6866 }
6867
6868 fn encode_thumb_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
6870 let mut bytes = Vec::new();
6871
6872 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
6874 false,
6875 sm,
6876 &Reg::R12,
6877 )?));
6878
6879 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
6881 false,
6882 sn,
6883 &Reg::R0,
6884 )?));
6885
6886 let hw1: u16 = 0xF000 | 12; let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
6898 bytes.extend_from_slice(&hw2.to_le_bytes());
6899
6900 let hw1: u16 = 0xF020; let hw2: u16 = (0x1 << 12) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
6904 bytes.extend_from_slice(&hw2.to_le_bytes());
6905
6906 let hw1: u16 = 0xEA40; let hw2: u16 = 12; bytes.extend_from_slice(&hw1.to_le_bytes());
6910 bytes.extend_from_slice(&hw2.to_le_bytes());
6911
6912 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
6914 true,
6915 sd,
6916 &Reg::R0,
6917 )?));
6918
6919 Ok(bytes)
6920 }
6921
6922 fn encode_thumb_f64_compare(
6924 &self,
6925 rd: &Reg,
6926 dn: &VfpReg,
6927 dm: &VfpReg,
6928 cond_code: u32,
6929 ) -> Result<Vec<u8>> {
6930 let mut bytes = Vec::new();
6931 let rd_bits = reg_to_bits(rd);
6932
6933 let dn_num = vfp_dreg_to_num(dn)?;
6935 let dm_num = vfp_dreg_to_num(dm)?;
6936 let (vd, d) = encode_dreg(dn_num);
6937 let (vm, m) = encode_dreg(dm_num);
6938 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6939 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6940
6941 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6943
6944 if rd_bits < 8 {
6946 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
6947 bytes.extend_from_slice(&movs_zero.to_le_bytes());
6948 } else {
6949 let hw1: u16 = 0xF04F;
6950 let hw2: u16 = (rd_bits as u16) << 8;
6951 bytes.extend_from_slice(&hw1.to_le_bytes());
6952 bytes.extend_from_slice(&hw2.to_le_bytes());
6953 }
6954
6955 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
6957 bytes.extend_from_slice(&it.to_le_bytes());
6958
6959 if rd_bits < 8 {
6961 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
6962 bytes.extend_from_slice(&mov_one.to_le_bytes());
6963 } else {
6964 let hw1: u16 = 0xF04F;
6965 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
6966 bytes.extend_from_slice(&hw1.to_le_bytes());
6967 bytes.extend_from_slice(&hw2.to_le_bytes());
6968 }
6969
6970 Ok(bytes)
6971 }
6972
6973 fn encode_thumb_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
6975 let mut bytes = Vec::new();
6976 let bits = value.to_bits();
6977 let lo32 = bits as u32;
6978 let hi32 = (bits >> 32) as u32;
6979
6980 let lo16 = lo32 & 0xFFFF;
6982 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(0, lo16)?);
6983
6984 let hi16 = (lo32 >> 16) & 0xFFFF;
6986 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(0, hi16)?);
6987
6988 let lo16 = hi32 & 0xFFFF;
6990 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
6991
6992 let hi16 = (hi32 >> 16) & 0xFFFF;
6994 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
6995
6996 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
6998 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6999
7000 Ok(bytes)
7001 }
7002
7003 fn encode_thumb_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
7005 let mut bytes = Vec::new();
7006
7007 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
7009 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7010
7011 let dd_num = vfp_dreg_to_num(dd)?;
7013 let (vd, d) = encode_dreg(dd_num);
7014 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
7015 let vcvt = base | (d << 22) | (vd << 12);
7016 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7017
7018 Ok(bytes)
7019 }
7020
7021 fn encode_thumb_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
7023 let dd_num = vfp_dreg_to_num(dd)?;
7024 let sm_num = vfp_sreg_to_num(sm)?;
7025 let (vd, d) = encode_dreg(dd_num);
7026 let (vm, m) = encode_sreg(sm_num);
7027
7028 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
7029 Ok(vfp_to_thumb_bytes(vcvt))
7030 }
7031
7032 fn encode_thumb_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7034 let mut bytes = Vec::new();
7035 let dm_num = vfp_dreg_to_num(dm)?;
7036 let (vm, m) = encode_dreg(dm_num);
7037
7038 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
7040 let vcvt = base | (m << 5) | vm;
7041 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7042
7043 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
7045 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7046
7047 Ok(bytes)
7048 }
7049
7050 fn encode_thumb_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
7054 let mut bytes = Vec::new();
7055 let dm_num = vfp_dreg_to_num(dm)?;
7056 let dd_num = vfp_dreg_to_num(dd)?;
7057 let (vm, m) = encode_dreg(dm_num);
7058 let (vd, d) = encode_dreg(dd_num);
7059
7060 if mode == 0b11 {
7061 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
7063 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
7064 } else {
7065 let rt: u32 = 12;
7066
7067 let vmrs = 0xEEF10A10 | (rt << 12);
7069 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
7070
7071 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF);
7073 let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
7074 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
7075 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
7076
7077 if mode != 0 {
7079 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF);
7080 let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
7081 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
7082 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
7083 }
7084
7085 let vmsr = 0xEEE10A10 | (rt << 12);
7087 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
7088
7089 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
7091 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
7092
7093 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
7095 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
7096 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
7097 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
7098 }
7099
7100 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
7102 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
7103
7104 Ok(bytes)
7105 }
7106
7107 fn encode_thumb_f64_minmax(
7109 &self,
7110 dd: &VfpReg,
7111 dn: &VfpReg,
7112 dm: &VfpReg,
7113 is_min: bool,
7114 ) -> Result<Vec<u8>> {
7115 let mut bytes = Vec::new();
7116 let dn_num = vfp_dreg_to_num(dn)?;
7117 let dm_num = vfp_dreg_to_num(dm)?;
7118 let dd_num = vfp_dreg_to_num(dd)?;
7119
7120 let (vd, d) = encode_dreg(dd_num);
7122 let (vn, n) = encode_dreg(dn_num);
7123 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
7124 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dn));
7125
7126 let (vm, m) = encode_dreg(dm_num);
7128 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
7129 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7130
7131 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7133
7134 let cond: u16 = if is_min { 0xC } else { 0x4 };
7136 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
7137 bytes.extend_from_slice(&it.to_le_bytes());
7138
7139 let vmov_dm = 0xEEB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7141 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dm));
7142
7143 Ok(bytes)
7144 }
7145
7146 fn encode_thumb_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
7148 let mut bytes = Vec::new();
7149
7150 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7152 false,
7153 dm,
7154 &Reg::R0,
7155 &Reg::R12,
7156 )?));
7157
7158 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7160 false,
7161 dn,
7162 &Reg::R1,
7163 &Reg::R2,
7164 )?));
7165
7166 let hw1: u16 = 0xF000 | 12;
7168 let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02;
7169 bytes.extend_from_slice(&hw1.to_le_bytes());
7170 bytes.extend_from_slice(&hw2.to_le_bytes());
7171
7172 let hw1: u16 = 0xF020 | 2;
7174 let hw2: u16 = (0x1 << 12) | (2 << 8) | 0x02;
7175 bytes.extend_from_slice(&hw1.to_le_bytes());
7176 bytes.extend_from_slice(&hw2.to_le_bytes());
7177
7178 let hw1: u16 = 0xEA40 | 2;
7180 let hw2: u16 = (2 << 8) | 12;
7181 bytes.extend_from_slice(&hw1.to_le_bytes());
7182 bytes.extend_from_slice(&hw2.to_le_bytes());
7183
7184 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7186 true,
7187 dd,
7188 &Reg::R1,
7189 &Reg::R2,
7190 )?));
7191
7192 Ok(bytes)
7193 }
7194
7195 fn encode_thumb_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7197 let mut bytes = Vec::new();
7198
7199 let sm_num = vfp_sreg_to_num(sm)?;
7200 let (vd, d) = encode_sreg(sm_num);
7201 let (vm, m) = encode_sreg(sm_num);
7202 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
7203 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
7204 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7205
7206 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
7208 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7209
7210 Ok(bytes)
7211 }
7212
7213 fn encode_thumb32_add(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7217 let rd_bits = reg_to_bits(rd);
7218 let rn_bits = reg_to_bits(rn);
7219
7220 let i_bit = (imm >> 11) & 1;
7222 let imm3 = (imm >> 8) & 0x7;
7223 let imm8 = imm & 0xFF;
7224
7225 let hw1_base = if imm <= 0xFF {
7226 0xF100
7230 } else if imm <= 0xFFF {
7231 0xF200
7235 } else {
7236 return Err(synth_core::Error::synthesis(
7237 "ADD immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7238 ));
7239 };
7240
7241 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7242 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7243
7244 let mut bytes = hw1.to_le_bytes().to_vec();
7245 bytes.extend_from_slice(&hw2.to_le_bytes());
7246 Ok(bytes)
7247 }
7248
7249 fn encode_thumb32_sub(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7251 let rd_bits = reg_to_bits(rd);
7252 let rn_bits = reg_to_bits(rn);
7253
7254 let i_bit = (imm >> 11) & 1;
7255 let imm3 = (imm >> 8) & 0x7;
7256 let imm8 = imm & 0xFF;
7257
7258 let hw1_base = if imm <= 0xFF {
7259 0xF1A0
7262 } else if imm <= 0xFFF {
7263 0xF2A0
7266 } else {
7267 return Err(synth_core::Error::synthesis(
7268 "SUB immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7269 ));
7270 };
7271
7272 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7273 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7274
7275 let mut bytes = hw1.to_le_bytes().to_vec();
7276 bytes.extend_from_slice(&hw2.to_le_bytes());
7277 Ok(bytes)
7278 }
7279
7280 fn encode_thumb32_adds(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7282 let rd_bits = reg_to_bits(rd);
7283 let rn_bits = reg_to_bits(rn);
7284
7285 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7288 synth_core::Error::synthesis(
7289 "ADDS immediate is not a valid ThumbExpandImm — materialize into a register",
7290 )
7291 })?;
7292 let i_bit = (field >> 11) & 1;
7293 let imm3 = (field >> 8) & 0x7;
7294 let imm8 = field & 0xFF;
7295
7296 let hw1: u16 = (0xF110 | (i_bit << 10) | rn_bits) as u16;
7299 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7300
7301 let mut bytes = hw1.to_le_bytes().to_vec();
7302 bytes.extend_from_slice(&hw2.to_le_bytes());
7303 Ok(bytes)
7304 }
7305
7306 fn encode_thumb32_subs(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7308 let rd_bits = reg_to_bits(rd);
7309 let rn_bits = reg_to_bits(rn);
7310
7311 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7314 synth_core::Error::synthesis(
7315 "SUBS immediate is not a valid ThumbExpandImm — materialize into a register",
7316 )
7317 })?;
7318 let i_bit = (field >> 11) & 1;
7319 let imm3 = (field >> 8) & 0x7;
7320 let imm8 = field & 0xFF;
7321
7322 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7325 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7326
7327 let mut bytes = hw1.to_le_bytes().to_vec();
7328 bytes.extend_from_slice(&hw2.to_le_bytes());
7329 Ok(bytes)
7330 }
7331
7332 fn encode_thumb32_movw(&self, rd: &Reg, imm: u32) -> Result<Vec<u8>> {
7341 let rd_bits = reg_to_bits(rd);
7342 reg_bits_checked(rd_bits)?;
7343 let imm16 = imm & 0xFFFF;
7344
7345 let imm4 = (imm16 >> 12) & 0xF;
7348 let i_bit = (imm16 >> 11) & 1;
7349 let imm3 = (imm16 >> 8) & 0x7;
7350 let imm8 = imm16 & 0xFF;
7351
7352 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7353 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7354
7355 let mut bytes = hw1.to_le_bytes().to_vec();
7356 bytes.extend_from_slice(&hw2.to_le_bytes());
7357 encoding_contracts::verify_thumb32(&bytes);
7358 Ok(bytes)
7359 }
7360
7361 fn encode_thumb32_shift(
7369 &self,
7370 rd: &Reg,
7371 rm: &Reg,
7372 shift: u32,
7373 shift_type: u8,
7374 ) -> Result<Vec<u8>> {
7375 let rd_bits = reg_to_bits(rd);
7376 let rm_bits = reg_to_bits(rm);
7377 reg_bits_checked(rd_bits)?;
7378 reg_bits_checked(rm_bits)?;
7379 let imm5 = shift & 0x1F;
7380 let imm2 = imm5 & 0x3;
7381 let imm3 = (imm5 >> 2) & 0x7;
7382
7383 let hw1: u16 = 0xEA4F;
7386 let hw2: u16 =
7387 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | ((shift_type as u32) << 4) | rm_bits)
7388 as u16;
7389
7390 let mut bytes = hw1.to_le_bytes().to_vec();
7391 bytes.extend_from_slice(&hw2.to_le_bytes());
7392 Ok(bytes)
7393 }
7394
7395 fn encode_thumb32_shift_reg(
7399 &self,
7400 rd: &Reg,
7401 rn: &Reg,
7402 rm: &Reg,
7403 shift_type: u8,
7404 ) -> Result<Vec<u8>> {
7405 let rd_bits = reg_to_bits(rd);
7406 let rn_bits = reg_to_bits(rn);
7407 let rm_bits = reg_to_bits(rm);
7408
7409 let hw1: u16 = (0xFA00 | ((shift_type as u32) << 5) | rn_bits) as u16;
7411 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
7413
7414 let mut bytes = hw1.to_le_bytes().to_vec();
7415 bytes.extend_from_slice(&hw2.to_le_bytes());
7416 Ok(bytes)
7417 }
7418
7419 fn encode_thumb32_cmp_imm(&self, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7421 let rn_bits = reg_to_bits(rn);
7422
7423 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7427 synth_core::Error::synthesis(
7428 "CMP immediate is not a valid ThumbExpandImm — materialize into a register",
7429 )
7430 })?;
7431 let i_bit = (field >> 11) & 1;
7432 let imm3 = (field >> 8) & 0x7;
7433 let imm8 = field & 0xFF;
7434
7435 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7437 let hw2: u16 = ((imm3 << 12) | 0x0F00 | imm8) as u16;
7438
7439 let mut bytes = hw1.to_le_bytes().to_vec();
7440 bytes.extend_from_slice(&hw2.to_le_bytes());
7441 Ok(bytes)
7442 }
7443
7444 fn i64_effective_base(&self, bytes: &mut Vec<u8>, addr: &MemAddr) -> Result<(Reg, u32)> {
7466 let offset = if addr.offset < 0 {
7467 0u32
7468 } else {
7469 addr.offset as u32
7470 };
7471 match addr.offset_reg {
7472 Some(idx) => {
7473 let ip = Reg::R12;
7474 if offset.wrapping_add(4) > 0xFFF {
7475 bytes.extend_from_slice(&self.encode_thumb32_add_imm(&ip, &idx, offset)?);
7479 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
7481 reg_to_bits(&ip),
7482 reg_to_bits(&ip),
7483 reg_to_bits(&addr.base),
7484 )?);
7485 Ok((ip, 0))
7486 } else {
7487 let hw1: u16 = 0xEB00 | reg_to_bits(&addr.base) as u16;
7489 let hw2: u16 = 0x0C00 | reg_to_bits(&idx) as u16;
7490 bytes.extend_from_slice(&hw1.to_le_bytes());
7491 bytes.extend_from_slice(&hw2.to_le_bytes());
7492 Ok((ip, offset))
7493 }
7494 }
7495 None => Ok((addr.base, offset)),
7496 }
7497 }
7498
7499 fn encode_thumb32_ldr(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7501 let rd_bits = reg_to_bits(rd);
7502 let base_bits = reg_to_bits(base);
7503
7504 check_ldst_imm12(offset)?;
7506 let hw1: u16 = (0xF8D0 | base_bits) as u16;
7507 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7508
7509 let mut bytes = hw1.to_le_bytes().to_vec();
7510 bytes.extend_from_slice(&hw2.to_le_bytes());
7511 Ok(bytes)
7512 }
7513
7514 fn encode_thumb32_str(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7516 let rd_bits = reg_to_bits(rd);
7517 let base_bits = reg_to_bits(base);
7518
7519 check_ldst_imm12(offset)?;
7521 let hw1: u16 = (0xF8C0 | base_bits) as u16;
7522 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7523
7524 let mut bytes = hw1.to_le_bytes().to_vec();
7525 bytes.extend_from_slice(&hw2.to_le_bytes());
7526 Ok(bytes)
7527 }
7528
7529 fn encode_thumb32_ldr_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7531 let rd_bits = reg_to_bits(rd);
7532 let base_bits = reg_to_bits(base);
7533 let rm_bits = reg_to_bits(offset_reg);
7534
7535 let hw1: u16 = (0xF850 | base_bits) as u16;
7539 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7540
7541 let mut bytes = hw1.to_le_bytes().to_vec();
7542 bytes.extend_from_slice(&hw2.to_le_bytes());
7543 Ok(bytes)
7544 }
7545
7546 fn encode_thumb32_str_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7548 let rd_bits = reg_to_bits(rd);
7549 let base_bits = reg_to_bits(base);
7550 let rm_bits = reg_to_bits(offset_reg);
7551
7552 let hw1: u16 = (0xF840 | base_bits) as u16;
7556 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7557
7558 let mut bytes = hw1.to_le_bytes().to_vec();
7559 bytes.extend_from_slice(&hw2.to_le_bytes());
7560 Ok(bytes)
7561 }
7562
7563 fn encode_thumb32_ldrb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7567 let rd_bits = reg_to_bits(rd);
7568 let base_bits = reg_to_bits(base);
7569 check_ldst_imm12(offset)?;
7571 let hw1: u16 = (0xF890 | base_bits) as u16;
7572 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7573 let mut bytes = hw1.to_le_bytes().to_vec();
7574 bytes.extend_from_slice(&hw2.to_le_bytes());
7575 Ok(bytes)
7576 }
7577
7578 fn encode_thumb32_ldrb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7580 let rd_bits = reg_to_bits(rd);
7581 let base_bits = reg_to_bits(base);
7582 let rm_bits = reg_to_bits(offset_reg);
7583 let hw1: u16 = (0xF810 | base_bits) as u16;
7585 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
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_ldrsb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7593 let rd_bits = reg_to_bits(rd);
7594 let base_bits = reg_to_bits(base);
7595 check_ldst_imm12(offset)?;
7597 let hw1: u16 = (0xF990 | base_bits) as u16;
7598 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7599 let mut bytes = hw1.to_le_bytes().to_vec();
7600 bytes.extend_from_slice(&hw2.to_le_bytes());
7601 Ok(bytes)
7602 }
7603
7604 fn encode_thumb32_ldrsb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7606 let rd_bits = reg_to_bits(rd);
7607 let base_bits = reg_to_bits(base);
7608 let rm_bits = reg_to_bits(offset_reg);
7609 let hw1: u16 = (0xF910 | base_bits) as u16;
7611 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7612 let mut bytes = hw1.to_le_bytes().to_vec();
7613 bytes.extend_from_slice(&hw2.to_le_bytes());
7614 Ok(bytes)
7615 }
7616
7617 fn encode_thumb32_ldrh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7619 let rd_bits = reg_to_bits(rd);
7620 let base_bits = reg_to_bits(base);
7621 check_ldst_imm12(offset)?;
7623 let hw1: u16 = (0xF8B0 | base_bits) as u16;
7624 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7625 let mut bytes = hw1.to_le_bytes().to_vec();
7626 bytes.extend_from_slice(&hw2.to_le_bytes());
7627 Ok(bytes)
7628 }
7629
7630 fn encode_thumb32_ldrh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7632 let rd_bits = reg_to_bits(rd);
7633 let base_bits = reg_to_bits(base);
7634 let rm_bits = reg_to_bits(offset_reg);
7635 let hw1: u16 = (0xF830 | base_bits) as u16;
7637 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7638 let mut bytes = hw1.to_le_bytes().to_vec();
7639 bytes.extend_from_slice(&hw2.to_le_bytes());
7640 Ok(bytes)
7641 }
7642
7643 fn encode_thumb32_ldrsh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7645 let rd_bits = reg_to_bits(rd);
7646 let base_bits = reg_to_bits(base);
7647 check_ldst_imm12(offset)?;
7649 let hw1: u16 = (0xF9B0 | base_bits) as u16;
7650 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7651 let mut bytes = hw1.to_le_bytes().to_vec();
7652 bytes.extend_from_slice(&hw2.to_le_bytes());
7653 Ok(bytes)
7654 }
7655
7656 fn encode_thumb32_ldrsh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7658 let rd_bits = reg_to_bits(rd);
7659 let base_bits = reg_to_bits(base);
7660 let rm_bits = reg_to_bits(offset_reg);
7661 let hw1: u16 = (0xF930 | base_bits) as u16;
7663 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7664 let mut bytes = hw1.to_le_bytes().to_vec();
7665 bytes.extend_from_slice(&hw2.to_le_bytes());
7666 Ok(bytes)
7667 }
7668
7669 fn encode_thumb32_strb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7671 let rd_bits = reg_to_bits(rd);
7672 let base_bits = reg_to_bits(base);
7673 check_ldst_imm12(offset)?;
7675 let hw1: u16 = (0xF880 | base_bits) as u16;
7676 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7677 let mut bytes = hw1.to_le_bytes().to_vec();
7678 bytes.extend_from_slice(&hw2.to_le_bytes());
7679 Ok(bytes)
7680 }
7681
7682 fn encode_thumb32_strb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7684 let rd_bits = reg_to_bits(rd);
7685 let base_bits = reg_to_bits(base);
7686 let rm_bits = reg_to_bits(offset_reg);
7687 let hw1: u16 = (0xF800 | base_bits) as u16;
7689 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7690 let mut bytes = hw1.to_le_bytes().to_vec();
7691 bytes.extend_from_slice(&hw2.to_le_bytes());
7692 Ok(bytes)
7693 }
7694
7695 fn encode_thumb32_strh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7697 let rd_bits = reg_to_bits(rd);
7698 let base_bits = reg_to_bits(base);
7699 check_ldst_imm12(offset)?;
7701 let hw1: u16 = (0xF8A0 | base_bits) as u16;
7702 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7703 let mut bytes = hw1.to_le_bytes().to_vec();
7704 bytes.extend_from_slice(&hw2.to_le_bytes());
7705 Ok(bytes)
7706 }
7707
7708 fn encode_thumb32_strh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7710 let rd_bits = reg_to_bits(rd);
7711 let base_bits = reg_to_bits(base);
7712 let rm_bits = reg_to_bits(offset_reg);
7713 let hw1: u16 = (0xF820 | base_bits) as u16;
7715 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7716 let mut bytes = hw1.to_le_bytes().to_vec();
7717 bytes.extend_from_slice(&hw2.to_le_bytes());
7718 Ok(bytes)
7719 }
7720
7721 fn encode_thumb32_add_imm(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7723 let rd_bits = reg_to_bits(rd);
7724 let rn_bits = reg_to_bits(rn);
7725
7726 if imm <= 0xFFF {
7732 let i_bit = (imm >> 11) & 1;
7733 let imm3 = (imm >> 8) & 0x7;
7734 let imm8 = imm & 0xFF;
7735
7736 let hw1: u16 = (0xF100 | (i_bit << 10) | rn_bits) as u16;
7737 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7738
7739 let mut bytes = hw1.to_le_bytes().to_vec();
7740 bytes.extend_from_slice(&hw2.to_le_bytes());
7741 Ok(bytes)
7742 } else {
7743 let scratch: u32 = if rd_bits == rn_bits {
7757 12 } else {
7759 rd_bits };
7761 if scratch == rn_bits {
7769 return Err(synth_core::Error::synthesis(format!(
7770 "ADD #imm: cannot lower #{imm:#x} for Rd==Rn==R12 — no free scratch \
7771 register (R12 is the reserved encoder scratch and aliases Rn here)"
7772 )));
7773 }
7774
7775 let lo16 = imm & 0xFFFF;
7776 let hi16 = (imm >> 16) & 0xFFFF;
7777
7778 let mut bytes = self.encode_thumb32_movw_raw(scratch, lo16)?;
7779 if hi16 != 0 {
7780 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(scratch, hi16)?);
7781 }
7782 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(rd_bits, rn_bits, scratch)?);
7783 Ok(bytes)
7784 }
7785 }
7786
7787 fn encode_thumb32_movw_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7797 reg_bits_checked(rd)?;
7798 encoding_contracts::verify_imm16(imm16);
7799 let imm16 = imm16 & 0xFFFF;
7802 let imm4 = (imm16 >> 12) & 0xF;
7803 let i_bit = (imm16 >> 11) & 1;
7804 let imm3 = (imm16 >> 8) & 0x7;
7805 let imm8 = imm16 & 0xFF;
7806
7807 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7808 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7809
7810 let mut bytes = hw1.to_le_bytes().to_vec();
7811 bytes.extend_from_slice(&hw2.to_le_bytes());
7812 encoding_contracts::verify_thumb32(&bytes);
7813 Ok(bytes)
7814 }
7815
7816 fn encode_thumb32_movt_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7824 reg_bits_checked(rd)?;
7825 encoding_contracts::verify_imm16(imm16);
7826 let imm16 = imm16 & 0xFFFF;
7829 let imm4 = (imm16 >> 12) & 0xF;
7830 let i_bit = (imm16 >> 11) & 1;
7831 let imm3 = (imm16 >> 8) & 0x7;
7832 let imm8 = imm16 & 0xFF;
7833
7834 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
7835 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7836
7837 let mut bytes = hw1.to_le_bytes().to_vec();
7838 bytes.extend_from_slice(&hw2.to_le_bytes());
7839 encoding_contracts::verify_thumb32(&bytes);
7840 Ok(bytes)
7841 }
7842
7843 fn encode_thumb32_lsr_raw(&self, rd: u32, rm: u32, shift: u32) -> Result<Vec<u8>> {
7845 let imm5 = shift & 0x1F;
7848 let imm2 = imm5 & 0x3;
7849 let imm3 = (imm5 >> 2) & 0x7;
7850
7851 let hw1: u16 = 0xEA4F;
7852 let hw2: u16 = ((imm3 << 12) | (rd << 8) | (imm2 << 6) | (0b01 << 4) | rm) as u16;
7853
7854 let mut bytes = hw1.to_le_bytes().to_vec();
7855 bytes.extend_from_slice(&hw2.to_le_bytes());
7856 Ok(bytes)
7857 }
7858
7859 fn encode_thumb32_and_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7861 let hw1: u16 = (0xEA00 | rn) as u16;
7864 let hw2: u16 = ((rd << 8) | rm) as u16;
7865
7866 let mut bytes = hw1.to_le_bytes().to_vec();
7867 bytes.extend_from_slice(&hw2.to_le_bytes());
7868 Ok(bytes)
7869 }
7870
7871 fn encode_thumb32_and_imm_raw(&self, rd: u32, rn: u32, imm: u32) -> Result<Vec<u8>> {
7873 let i_bit = (imm >> 11) & 1;
7877 let imm3 = (imm >> 8) & 0x7;
7878 let imm8 = imm & 0xFF;
7879
7880 let hw1: u16 = (0xF000 | (i_bit << 10) | rn) as u16;
7881 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7882
7883 let mut bytes = hw1.to_le_bytes().to_vec();
7884 bytes.extend_from_slice(&hw2.to_le_bytes());
7885 Ok(bytes)
7886 }
7887
7888 fn encode_thumb32_sub_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7890 let hw1: u16 = (0xEBA0 | rn) as u16;
7893 let hw2: u16 = ((rd << 8) | rm) as u16;
7894
7895 let mut bytes = hw1.to_le_bytes().to_vec();
7896 bytes.extend_from_slice(&hw2.to_le_bytes());
7897 Ok(bytes)
7898 }
7899
7900 fn encode_thumb32_add_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7902 let hw1: u16 = (0xEB00 | rn) as u16;
7905 let hw2: u16 = ((rd << 8) | rm) as u16;
7906
7907 let mut bytes = hw1.to_le_bytes().to_vec();
7908 bytes.extend_from_slice(&hw2.to_le_bytes());
7909 Ok(bytes)
7910 }
7911
7912 fn encode_thumb32_adds_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7916 let hw1: u16 = (0xEB10 | rn) as u16;
7918 let hw2: u16 = ((rd << 8) | rm) as u16;
7919 let mut bytes = hw1.to_le_bytes().to_vec();
7920 bytes.extend_from_slice(&hw2.to_le_bytes());
7921 Ok(bytes)
7922 }
7923
7924 fn encode_thumb32_subs_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7927 let hw1: u16 = (0xEBB0 | rn) as u16;
7929 let hw2: u16 = ((rd << 8) | rm) as u16;
7930 let mut bytes = hw1.to_le_bytes().to_vec();
7931 bytes.extend_from_slice(&hw2.to_le_bytes());
7932 Ok(bytes)
7933 }
7934
7935 pub fn encode_sequence(&self, ops: &[ArmOp]) -> Result<Vec<u8>> {
7937 let mut code = Vec::new();
7938
7939 for op in ops {
7940 let encoded = self.encode(op)?;
7941 code.extend_from_slice(&encoded);
7942 }
7943
7944 Ok(code)
7945 }
7946}
7947
7948fn try_thumb_expand_imm(value: u32) -> Option<u32> {
7956 if value <= 0xFF {
7958 return Some(value);
7959 }
7960 let b0 = value & 0xFF; let b1 = (value >> 8) & 0xFF; if value == (b0 << 16) | b0 {
7964 return Some(0x100 | b0);
7965 }
7966 if value == (b1 << 24) | (b1 << 8) {
7968 return Some(0x200 | b1);
7969 }
7970 if value == (b0 << 24) | (b0 << 16) | (b0 << 8) | b0 {
7972 return Some(0x300 | b0);
7973 }
7974 for rot in 8..=31u32 {
7978 let unrot = value.rotate_left(rot);
7979 if (0x80..=0xFF).contains(&unrot) {
7980 return Some((rot << 7) | (unrot & 0x7F));
7981 }
7982 }
7983 None
7984}
7985
7986fn check_ldst_imm12(offset: u32) -> Result<()> {
7992 if offset > 0xFFF {
7993 Err(synth_core::Error::synthesis(
7994 "load/store immediate offset > 0xFFF (4095) — materialize the offset into a register",
7995 ))
7996 } else {
7997 Ok(())
7998 }
7999}
8000
8001fn reg_to_bits(reg: &Reg) -> u32 {
8002 match reg {
8003 Reg::R0 => 0,
8004 Reg::R1 => 1,
8005 Reg::R2 => 2,
8006 Reg::R3 => 3,
8007 Reg::R4 => 4,
8008 Reg::R5 => 5,
8009 Reg::R6 => 6,
8010 Reg::R7 => 7,
8011 Reg::R8 => 8,
8012 Reg::R9 => 9,
8013 Reg::R10 => 10,
8014 Reg::R11 => 11,
8015 Reg::R12 => 12,
8016 Reg::SP => 13,
8017 Reg::LR => 14,
8018 Reg::PC => 15,
8019 }
8020}
8021
8022fn emit_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
8053 debug_assert!(srcs.len() <= 4);
8054 bytes.extend_from_slice(&0xB40Fu16.to_le_bytes());
8056 for src in srcs.iter().rev() {
8058 let rt = reg_to_bits(src) as u16;
8059 bytes.extend_from_slice(&0xF84Du16.to_le_bytes());
8060 bytes.extend_from_slice(&((rt << 12) | 0x0D04).to_le_bytes());
8061 }
8062 for i in 0..srcs.len() as u16 {
8064 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes());
8065 }
8066}
8067
8068fn emit_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8072 let lo = reg_to_bits(rdlo);
8073 let hi = reg_to_bits(rdhi);
8074 if lo == 1 && hi == 0 {
8075 return Err(synth_core::Error::synthesis(
8078 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8079 ));
8080 }
8081 let mov16 = |bytes: &mut Vec<u8>, rd: u32, rm: u32| {
8082 let d = ((rd >> 3) & 1) as u16;
8083 bytes.extend_from_slice(
8084 &(0x4600u16 | (d << 7) | ((rm as u16) << 3) | ((rd & 7) as u16)).to_le_bytes(),
8085 );
8086 };
8087 if hi == 0 {
8088 mov16(bytes, lo, 0);
8090 mov16(bytes, hi, 1);
8091 } else {
8092 mov16(bytes, hi, 1);
8094 mov16(bytes, lo, 0);
8095 }
8096 for i in 0..4u32 {
8097 if i == lo || i == hi {
8098 bytes.extend_from_slice(&0xB001u16.to_le_bytes()); } else {
8101 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes()); }
8103 }
8104 Ok(())
8105}
8106
8107fn emit_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8111 bytes.extend_from_slice(&0xEA52u16.to_le_bytes()); bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8113 bytes.extend_from_slice(&0xD100u16.to_le_bytes()); bytes.extend_from_slice(&0xDE00u16.to_le_bytes()); }
8116
8117fn emit_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8127 bytes.extend_from_slice(&0xEA02u16.to_le_bytes());
8129 bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8130 bytes.extend_from_slice(&0xF11Cu16.to_le_bytes());
8132 bytes.extend_from_slice(&0x0F01u16.to_le_bytes());
8133 bytes.extend_from_slice(&0xD105u16.to_le_bytes());
8135 bytes.extend_from_slice(&0x2800u16.to_le_bytes());
8137 bytes.extend_from_slice(&0xD103u16.to_le_bytes());
8139 bytes.extend_from_slice(&0xF1B1u16.to_le_bytes());
8141 bytes.extend_from_slice(&0x4F00u16.to_le_bytes());
8142 bytes.extend_from_slice(&0xD100u16.to_le_bytes());
8144 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
8146 }
8148
8149fn emit_a32_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
8163 debug_assert!(srcs.len() <= 4);
8164 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8165 w(bytes, 0xE92D_000F);
8167 for src in srcs.iter().rev() {
8169 w(bytes, 0xE52D_0004 | (reg_to_bits(src) << 12));
8170 }
8171 for i in 0..srcs.len() as u32 {
8173 w(bytes, 0xE49D_0004 | (i << 12));
8174 }
8175}
8176
8177fn emit_a32_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8181 let lo = reg_to_bits(rdlo);
8182 let hi = reg_to_bits(rdhi);
8183 if lo == 1 && hi == 0 {
8184 return Err(synth_core::Error::synthesis(
8187 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8188 ));
8189 }
8190 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8191 let mov = |bytes: &mut Vec<u8>, rd: u32, rm: u32| w(bytes, 0xE1A0_0000 | (rd << 12) | rm);
8192 if hi == 0 {
8193 mov(bytes, lo, 0);
8195 mov(bytes, hi, 1);
8196 } else {
8197 mov(bytes, hi, 1);
8199 mov(bytes, lo, 0);
8200 }
8201 for i in 0..4u32 {
8202 if i == lo || i == hi {
8203 w(bytes, 0xE28D_D004); } else {
8206 w(bytes, 0xE49D_0004 | (i << 12)); }
8208 }
8209 Ok(())
8210}
8211
8212fn emit_a32_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8216 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8217 w(bytes, 0xE192_C003); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8221
8222fn emit_a32_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8227 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8228 w(bytes, 0xE002_C003); w(bytes, 0xE37C_0001); w(bytes, 0x0350_0000); w(bytes, 0x0351_0102); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8235
8236fn reg_bits_checked(bits: u32) -> Result<()> {
8244 if bits > 14 {
8245 return Err(synth_core::Error::synthesis(format!(
8246 "register bits {bits} (PC/R15) is not a valid operand for this Thumb-2 encoding"
8247 )));
8248 }
8249 Ok(())
8250}
8251
8252fn try_encode_rotated_imm(val: u32) -> Option<(u32, u32)> {
8255 if val == 0 {
8256 return Some((0, 1));
8257 }
8258 for rot in 0..16u32 {
8259 let shift = rot * 2;
8260 let unrotated = val.rotate_left(shift);
8262 if unrotated <= 0xFF {
8263 return Some(((rot << 8) | unrotated, 1));
8265 }
8266 }
8267 None
8268}
8269
8270fn encode_operand2(op2: &Operand2) -> Result<(u32, u32)> {
8275 match op2 {
8276 Operand2::Imm(val) => {
8277 let uval = *val as u32;
8278 if let Some(encoded) = try_encode_rotated_imm(uval) {
8280 Ok(encoded)
8281 } else {
8282 Err(synth_core::Error::synthesis(format!(
8291 "encode_operand2: immediate {uval:#x} ({val}) is not an ARM32 \
8292 rotated immediate — the selector must materialize large \
8293 constants via MOVW/MOVT"
8294 )))
8295 }
8296 }
8297
8298 Operand2::Reg(reg) => {
8299 let reg_bits = reg_to_bits(reg);
8300 Ok((reg_bits, 0)) }
8302
8303 Operand2::RegShift {
8304 rm,
8305 shift: _,
8306 amount,
8307 } => {
8308 let rm_bits = reg_to_bits(rm);
8310 let shift_bits = (*amount & 0x1F) << 7;
8311 Ok((shift_bits | rm_bits, 0))
8312 }
8313 }
8314}
8315
8316fn encode_mem_addr(addr: &MemAddr) -> (u32, u32) {
8318 let base_bits = reg_to_bits(&addr.base);
8319 let offset_bits = (addr.offset as u32) & 0xFFF; (base_bits, offset_bits)
8321}
8322
8323fn vfp_sreg_to_num(reg: &VfpReg) -> Result<u32> {
8325 match reg {
8326 VfpReg::S0 => Ok(0),
8327 VfpReg::S1 => Ok(1),
8328 VfpReg::S2 => Ok(2),
8329 VfpReg::S3 => Ok(3),
8330 VfpReg::S4 => Ok(4),
8331 VfpReg::S5 => Ok(5),
8332 VfpReg::S6 => Ok(6),
8333 VfpReg::S7 => Ok(7),
8334 VfpReg::S8 => Ok(8),
8335 VfpReg::S9 => Ok(9),
8336 VfpReg::S10 => Ok(10),
8337 VfpReg::S11 => Ok(11),
8338 VfpReg::S12 => Ok(12),
8339 VfpReg::S13 => Ok(13),
8340 VfpReg::S14 => Ok(14),
8341 VfpReg::S15 => Ok(15),
8342 VfpReg::S16 => Ok(16),
8343 VfpReg::S17 => Ok(17),
8344 VfpReg::S18 => Ok(18),
8345 VfpReg::S19 => Ok(19),
8346 VfpReg::S20 => Ok(20),
8347 VfpReg::S21 => Ok(21),
8348 VfpReg::S22 => Ok(22),
8349 VfpReg::S23 => Ok(23),
8350 VfpReg::S24 => Ok(24),
8351 VfpReg::S25 => Ok(25),
8352 VfpReg::S26 => Ok(26),
8353 VfpReg::S27 => Ok(27),
8354 VfpReg::S28 => Ok(28),
8355 VfpReg::S29 => Ok(29),
8356 VfpReg::S30 => Ok(30),
8357 VfpReg::S31 => Ok(31),
8358 _ => Err(synth_core::Error::SynthesisError(
8360 "D-register not supported in single-precision VFP encoding".to_string(),
8361 )),
8362 }
8363}
8364
8365fn vfp_dreg_to_num(reg: &VfpReg) -> Result<u32> {
8367 match reg {
8368 VfpReg::D0 => Ok(0),
8369 VfpReg::D1 => Ok(1),
8370 VfpReg::D2 => Ok(2),
8371 VfpReg::D3 => Ok(3),
8372 VfpReg::D4 => Ok(4),
8373 VfpReg::D5 => Ok(5),
8374 VfpReg::D6 => Ok(6),
8375 VfpReg::D7 => Ok(7),
8376 VfpReg::D8 => Ok(8),
8377 VfpReg::D9 => Ok(9),
8378 VfpReg::D10 => Ok(10),
8379 VfpReg::D11 => Ok(11),
8380 VfpReg::D12 => Ok(12),
8381 VfpReg::D13 => Ok(13),
8382 VfpReg::D14 => Ok(14),
8383 VfpReg::D15 => Ok(15),
8384 _ => Err(synth_core::Error::SynthesisError(
8386 "S-register not supported in double-precision VFP encoding".to_string(),
8387 )),
8388 }
8389}
8390
8391fn encode_sreg(s: u32) -> (u32, u32) {
8395 (s >> 1, s & 1)
8396}
8397
8398fn encode_dreg(d: u32) -> (u32, u32) {
8402 (d & 0xF, (d >> 4) & 1)
8403}
8404
8405fn encode_vfp_3reg(base: u32, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<u32> {
8411 let sd_num = vfp_sreg_to_num(sd)?;
8412 let sn_num = vfp_sreg_to_num(sn)?;
8413 let sm_num = vfp_sreg_to_num(sm)?;
8414 let (vd, d) = encode_sreg(sd_num);
8415 let (vn, n) = encode_sreg(sn_num);
8416 let (vm, m) = encode_sreg(sm_num);
8417
8418 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8419}
8420
8421fn encode_vfp_2reg(base: u32, sd: &VfpReg, sm: &VfpReg) -> Result<u32> {
8424 let sd_num = vfp_sreg_to_num(sd)?;
8425 let sm_num = vfp_sreg_to_num(sm)?;
8426 let (vd, d) = encode_sreg(sd_num);
8427 let (vm, m) = encode_sreg(sm_num);
8428
8429 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8430}
8431
8432fn encode_vfp_ldst(base: u32, sd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8436 let sd_num = vfp_sreg_to_num(sd)?;
8437 let (vd, d) = encode_sreg(sd_num);
8438 let rn = reg_to_bits(&addr.base);
8439
8440 let offset = addr.offset;
8441 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8442 let abs_offset = offset.unsigned_abs();
8443 let imm8 = (abs_offset / 4) & 0xFF;
8444
8445 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8446}
8447
8448fn encode_vmov_core_sreg(to_sreg: bool, sreg: &VfpReg, core: &Reg) -> Result<u32> {
8452 let s_num = vfp_sreg_to_num(sreg)?;
8453 let (vn, n) = encode_sreg(s_num);
8454 let rt = reg_to_bits(core);
8455
8456 let base = if to_sreg { 0xEE000A10 } else { 0xEE100A10 };
8457 Ok(base | (vn << 16) | (rt << 12) | (n << 7))
8458}
8459
8460fn encode_vfp_3reg_f64(base: u32, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<u32> {
8464 let dd_num = vfp_dreg_to_num(dd)?;
8465 let dn_num = vfp_dreg_to_num(dn)?;
8466 let dm_num = vfp_dreg_to_num(dm)?;
8467 let (vd, d) = encode_dreg(dd_num);
8468 let (vn, n) = encode_dreg(dn_num);
8469 let (vm, m) = encode_dreg(dm_num);
8470
8471 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8472}
8473
8474fn encode_vfp_2reg_f64(base: u32, dd: &VfpReg, dm: &VfpReg) -> Result<u32> {
8476 let dd_num = vfp_dreg_to_num(dd)?;
8477 let dm_num = vfp_dreg_to_num(dm)?;
8478 let (vd, d) = encode_dreg(dd_num);
8479 let (vm, m) = encode_dreg(dm_num);
8480
8481 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8482}
8483
8484fn encode_vfp_ldst_f64(base: u32, dd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8487 let dd_num = vfp_dreg_to_num(dd)?;
8488 let (vd, d) = encode_dreg(dd_num);
8489 let rn = reg_to_bits(&addr.base);
8490
8491 let offset = addr.offset;
8492 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8493 let abs_offset = offset.unsigned_abs();
8494 let imm8 = (abs_offset / 4) & 0xFF;
8495
8496 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8497}
8498
8499fn encode_vmov_core_dreg(
8503 to_dreg: bool,
8504 dreg: &VfpReg,
8505 core_lo: &Reg,
8506 core_hi: &Reg,
8507) -> Result<u32> {
8508 let d_num = vfp_dreg_to_num(dreg)?;
8509 let (vm, m) = encode_dreg(d_num);
8510 let rt = reg_to_bits(core_lo);
8511 let rt2 = reg_to_bits(core_hi);
8512
8513 let base = if to_dreg { 0xEC400B10 } else { 0xEC500B10 };
8514 Ok(base | (rt2 << 16) | (rt << 12) | (m << 5) | vm)
8515}
8516
8517fn vfp_to_thumb_bytes(instr: u32) -> Vec<u8> {
8519 let hw1 = ((instr >> 16) & 0xFFFF) as u16;
8520 let hw2 = (instr & 0xFFFF) as u16;
8521 let mut bytes = hw1.to_le_bytes().to_vec();
8522 bytes.extend_from_slice(&hw2.to_le_bytes());
8523 bytes
8524}
8525
8526fn qreg_to_num(reg: &QReg) -> u32 {
8532 match reg {
8533 QReg::Q0 => 0,
8534 QReg::Q1 => 1,
8535 QReg::Q2 => 2,
8536 QReg::Q3 => 3,
8537 QReg::Q4 => 4,
8538 QReg::Q5 => 5,
8539 QReg::Q6 => 6,
8540 QReg::Q7 => 7,
8541 }
8542}
8543
8544fn mve_size_bits(size: &MveSize) -> u32 {
8546 match size {
8547 MveSize::S8 => 0b00,
8548 MveSize::S16 => 0b01,
8549 MveSize::S32 => 0b10,
8550 }
8551}
8552
8553fn encode_mve_3reg(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8557 let d = qreg_to_num(qd) * 2;
8558 let n = qreg_to_num(qn) * 2;
8559 let m = qreg_to_num(qm) * 2;
8560
8561 let vd = d & 0xF;
8566 let d_bit = (d >> 4) & 1;
8567 let vn = n & 0xF;
8568 let n_bit = (n >> 4) & 1;
8569 let vm = m & 0xF;
8570 let m_bit = (m >> 4) & 1;
8571
8572 base | (d_bit << 22) | (vn << 16) | (vd << 12) | (n_bit << 7) | (m_bit << 5) | vm
8573}
8574
8575fn encode_mve_3reg_bitwise(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8577 encode_mve_3reg(base, qd, qn, qm)
8578}
8579
8580fn encode_mve_vldrw(qd: &QReg, addr: &MemAddr) -> u32 {
8583 let qd_enc = qreg_to_num(qd) * 2;
8584 let rn = reg_to_bits(&addr.base);
8585 let offset = addr.offset;
8586 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8587 let abs_offset = offset.unsigned_abs();
8588 let imm7 = (abs_offset / 4) & 0x7F; 0xED100E80
8592 | (u_bit << 23)
8593 | ((qd_enc >> 4) << 22)
8594 | (rn << 16)
8595 | ((qd_enc & 0xF) << 12)
8596 | (imm7 & 0x7F)
8597}
8598
8599fn encode_mve_vstrw(qd: &QReg, addr: &MemAddr) -> u32 {
8601 let qd_enc = qreg_to_num(qd) * 2;
8602 let rn = reg_to_bits(&addr.base);
8603 let offset = addr.offset;
8604 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8605 let abs_offset = offset.unsigned_abs();
8606 let imm7 = (abs_offset / 4) & 0x7F;
8607
8608 0xED000E80
8609 | (u_bit << 23)
8610 | ((qd_enc >> 4) << 22)
8611 | (rn << 16)
8612 | ((qd_enc & 0xF) << 12)
8613 | (imm7 & 0x7F)
8614}
8615
8616impl ArmEncoder {
8617 fn encode_thumb_mve_const(&self, qd: &QReg, bytes: &[u8; 16]) -> Result<Vec<u8>> {
8619 let mut result = Vec::new();
8620 let qd_num = qreg_to_num(qd);
8621
8622 for i in 0..4 {
8624 let word = u32::from_le_bytes([
8625 bytes[i * 4],
8626 bytes[i * 4 + 1],
8627 bytes[i * 4 + 2],
8628 bytes[i * 4 + 3],
8629 ]);
8630 let lo16 = word & 0xFFFF;
8631 let hi16 = (word >> 16) & 0xFFFF;
8632
8633 result.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
8635 if hi16 != 0 {
8637 result.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
8638 }
8639
8640 let s_num = qd_num * 4 + i as u32;
8642 let (vn, n) = encode_sreg(s_num);
8643 let vmov: u32 = 0xEE000A10 | (vn << 16) | (12 << 12) | (n << 7);
8644 result.extend_from_slice(&vfp_to_thumb_bytes(vmov));
8645 }
8646
8647 Ok(result)
8648 }
8649
8650 fn encode_thumb_mve_lane_wise_f32_binop(
8652 &self,
8653 qd: &QReg,
8654 qn: &QReg,
8655 qm: &QReg,
8656 vfp_base: u32,
8657 ) -> Result<Vec<u8>> {
8658 let mut result = Vec::new();
8659 let qd_num = qreg_to_num(qd);
8660 let qn_num = qreg_to_num(qn);
8661 let qm_num = qreg_to_num(qm);
8662
8663 for i in 0..4u32 {
8665 let sd = qd_num * 4 + i;
8666 let sn = qn_num * 4 + i;
8667 let sm = qm_num * 4 + i;
8668
8669 let (vd, d) = encode_sreg(sd);
8670 let (vn, n) = encode_sreg(sn);
8671 let (vm, m) = encode_sreg(sm);
8672
8673 let instr = vfp_base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
8674 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8675 }
8676
8677 Ok(result)
8678 }
8679
8680 fn encode_thumb_mve_lane_wise_f32_sqrt(&self, qd: &QReg, qm: &QReg) -> Result<Vec<u8>> {
8682 let mut result = Vec::new();
8683 let qd_num = qreg_to_num(qd);
8684 let qm_num = qreg_to_num(qm);
8685
8686 for i in 0..4u32 {
8688 let sd = qd_num * 4 + i;
8689 let sm = qm_num * 4 + i;
8690
8691 let (vd, d) = encode_sreg(sd);
8692 let (vm, m) = encode_sreg(sm);
8693
8694 let instr: u32 = 0xEEB10AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
8695 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8696 }
8697
8698 Ok(result)
8699 }
8700}
8701
8702#[cfg(test)]
8703mod tests {
8704 use super::*;
8705
8706 #[test]
8707 fn test_encoder_creation() {
8708 let encoder_arm = ArmEncoder::new_arm32();
8709 assert!(!encoder_arm.thumb_mode);
8710
8711 let encoder_thumb = ArmEncoder::new_thumb2();
8712 assert!(encoder_thumb.thumb_mode);
8713 }
8714
8715 #[test]
8727 fn test_encode_i64setcond_high_reg_uses_mov_w_311() {
8728 use synth_synthesis::{ArmOp, Condition, Reg};
8729 let enc = ArmEncoder::new_thumb2();
8730 let bytes = enc
8731 .encode(&ArmOp::I64SetCond {
8732 rd: Reg::R8,
8733 rn_lo: Reg::R2,
8734 rn_hi: Reg::R3,
8735 rm_lo: Reg::R6,
8736 rm_hi: Reg::R7,
8737 cond: Condition::EQ,
8738 })
8739 .unwrap();
8740 let halfwords: Vec<u16> = bytes
8743 .chunks(2)
8744 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8745 .collect();
8746 assert!(
8747 halfwords.iter().filter(|&&h| h == 0xF04F).count() == 2,
8748 "high rd must use two MOV.W (T2) encodings, got {halfwords:04x?}"
8749 );
8750 assert!(
8751 !halfwords.contains(&0x2801) && !halfwords.contains(&0x2800),
8752 "no transmuted 16-bit CMP imm: {halfwords:04x?}"
8753 );
8754
8755 let bytes_z = enc
8756 .encode(&ArmOp::I64SetCondZ {
8757 rd: Reg::R8,
8758 rn_lo: Reg::R2,
8759 rn_hi: Reg::R3,
8760 })
8761 .unwrap();
8762 let hw_z: Vec<u16> = bytes_z
8763 .chunks(2)
8764 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8765 .collect();
8766 assert!(
8767 hw_z.iter().filter(|&&h| h == 0xF04F).count() == 2,
8768 "SetCondZ high rd MOV.W: {hw_z:04x?}"
8769 );
8770 assert!(
8772 hw_z.contains(&(0xF1B0 | 8)),
8773 "SetCondZ high rd must use CMP.W: {hw_z:04x?}"
8774 );
8775 }
8776
8777 #[test]
8778 fn test_encode_setcond_high_reg_uses_mov_w_204() {
8779 use synth_synthesis::{ArmOp, Condition, Reg};
8780 let enc = ArmEncoder::new_thumb2();
8781 let hi = enc
8783 .encode(&ArmOp::SetCond {
8784 rd: Reg::R12,
8785 cond: Condition::NE,
8786 })
8787 .unwrap();
8788 assert_eq!(hi.len(), 10, "ITE(2) + MOV.W(4) + MOV.W(4): {hi:02x?}");
8789 assert_eq!(&hi[2..4], &[0x4F, 0xF0], "then = MOV.W: {hi:02x?}");
8791 assert_eq!(&hi[6..8], &[0x4F, 0xF0], "else = MOV.W: {hi:02x?}");
8792 assert_eq!(hi[4] & 0x0F, 0x01, "then imm = #1");
8793 assert_eq!(hi[8] & 0x0F, 0x00, "else imm = #0");
8794 let lo = enc
8796 .encode(&ArmOp::SetCond {
8797 rd: Reg::R0,
8798 cond: Condition::NE,
8799 })
8800 .unwrap();
8801 assert_eq!(lo.len(), 6, "ITE(2) + MOVS(2) + MOVS(2): {lo:02x?}");
8802 assert_eq!(lo[2..4], [0x01, 0x20], "then = MOVS R0,#1");
8803 assert_eq!(lo[4..6], [0x00, 0x20], "else = MOVS R0,#0");
8804 }
8805
8806 #[test]
8810 fn test_encode_umull_209b() {
8811 use synth_synthesis::{ArmOp, Reg};
8812 let op = ArmOp::Umull {
8813 rdlo: Reg::R4,
8814 rdhi: Reg::R5,
8815 rn: Reg::R0,
8816 rm: Reg::R3,
8817 };
8818 let t = ArmEncoder::new_thumb2().encode(&op).unwrap();
8820 assert_eq!(
8821 t,
8822 vec![0xA0, 0xFB, 0x03, 0x45],
8823 "umull r4,r5,r0,r3 (T2): {t:02x?}"
8824 );
8825 let a = ArmEncoder::new_arm32().encode(&op).unwrap();
8827 assert_eq!(
8828 a,
8829 0xE085_4390u32.to_le_bytes().to_vec(),
8830 "umull (A32): {a:02x?}"
8831 );
8832 }
8833
8834 #[test]
8841 fn test_encode_arm32_indexed_load_keeps_index_206() {
8842 use synth_synthesis::{ArmOp, MemAddr, Reg};
8843 let enc = ArmEncoder::new_arm32();
8844 let bytes = enc
8846 .encode(&ArmOp::Ldr {
8847 rd: Reg::R0,
8848 addr: MemAddr::reg_imm(Reg::R11, Reg::R1, 8),
8849 })
8850 .unwrap();
8851 assert_eq!(
8852 bytes.len(),
8853 8,
8854 "expected ADD ip + LDR (2 words): {bytes:02x?}"
8855 );
8856 let add = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
8857 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
8858 assert_eq!(add, 0xE08B_C001, "ADD ip,r11,r1: {add:#010x}");
8860 assert_eq!(ldr, 0xE59C_0008, "LDR r0,[ip,#8]: {ldr:#010x}");
8862 assert_ne!(ldr, 0xE59B_0008, "index must not be dropped");
8864 }
8865
8866 #[test]
8874 fn test_encode_arm32_call_indirect_is_real_call_594() {
8875 use synth_synthesis::{ArmOp, Reg};
8876 let enc = ArmEncoder::new_arm32();
8877 let bytes = enc
8878 .encode(&ArmOp::CallIndirect {
8879 rd: Reg::R0,
8880 type_idx: 0,
8881 table_index_reg: Reg::R0,
8882 table_size: 4,
8883 table_byte_offset: 0,
8884 })
8885 .unwrap();
8886 assert_eq!(
8887 bytes.len(),
8888 28,
8889 "expected MOVW + CMP + BLO + UDF + MOV + LDR + BLX (7 words): {bytes:02x?}"
8890 );
8891 let words: Vec<u32> = bytes
8892 .chunks_exact(4)
8893 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
8894 .collect();
8895 assert_eq!(words[0], 0xE300_C004, "MOVW r12,#4: {:#010x}", words[0]);
8897 assert_eq!(words[1], 0xE150_000C, "CMP r0,r12: {:#010x}", words[1]);
8898 assert_eq!(words[2], 0x3A00_0000, "BLO +1 insn: {:#010x}", words[2]);
8899 assert_eq!(words[3], 0xE7F0_00F0, "UDF: {:#010x}", words[3]);
8900 assert_eq!(
8902 words[4], 0xE1A0_C100,
8903 "MOV r12,r0,LSL#2: {:#010x}",
8904 words[4]
8905 );
8906 assert_eq!(
8908 words[5], 0xE79B_C00C,
8909 "LDR r12,[r11,r12]: {:#010x}",
8910 words[5]
8911 );
8912 assert_eq!(words[6], 0xE12F_FF3C, "BLX r12: {:#010x}", words[6]);
8914 assert!(
8916 !bytes
8917 .chunks_exact(4)
8918 .any(|w| w == 0xE1A0_0000u32.to_le_bytes()),
8919 "call_indirect must not contain a NOP (#594): {bytes:02x?}"
8920 );
8921
8922 let bytes = enc
8924 .encode(&ArmOp::CallIndirect {
8925 rd: Reg::R0,
8926 type_idx: 0,
8927 table_index_reg: Reg::R4,
8928 table_size: 4,
8929 table_byte_offset: 0,
8930 })
8931 .unwrap();
8932 let cmp = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
8933 assert_eq!(cmp, 0xE154_000C, "CMP r4,r12: {cmp:#010x}");
8934 let mov = u32::from_le_bytes(bytes[16..20].try_into().unwrap());
8935 assert_eq!(mov, 0xE1A0_C104, "MOV r12,r4,LSL#2: {mov:#010x}");
8936 }
8937
8938 #[test]
8941 fn test_encode_arm32_call_indirect_wide_table_size_642() {
8942 use synth_synthesis::{ArmOp, Reg};
8943 let enc = ArmEncoder::new_arm32();
8944 let bytes = enc
8945 .encode(&ArmOp::CallIndirect {
8946 rd: Reg::R0,
8947 type_idx: 0,
8948 table_index_reg: Reg::R0,
8949 table_size: 0x0002_0003,
8950 table_byte_offset: 0,
8951 })
8952 .unwrap();
8953 assert_eq!(bytes.len(), 32, "MOVT arm adds one word: {bytes:02x?}");
8954 let movw = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
8955 let movt = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
8956 assert_eq!(movw, 0xE300_C003, "MOVW r12,#3: {movw:#010x}");
8957 assert_eq!(movt, 0xE340_C002, "MOVT r12,#2: {movt:#010x}");
8958 }
8959
8960 #[test]
8976 fn test_encode_thumb_call_indirect_lsl2_597() {
8977 use synth_synthesis::{ArmOp, Reg};
8978 let enc = ArmEncoder::new_thumb2();
8979 let bytes = enc
8980 .encode(&ArmOp::CallIndirect {
8981 rd: Reg::R0,
8982 type_idx: 0,
8983 table_index_reg: Reg::R0,
8984 table_size: 4,
8985 table_byte_offset: 0,
8986 })
8987 .unwrap();
8988 assert_eq!(
8989 bytes,
8990 vec![
8991 0x40, 0xF2, 0x04, 0x0C, 0x60, 0x45, 0x00, 0xD3, 0x00, 0xDE, 0x4F, 0xEA, 0x80, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47, ],
9001 "Thumb-2 CallIndirect: bounds guard + mov.w/ldr.w/blx dispatch: {bytes:02x?}"
9002 );
9003 assert!(
9005 !bytes.windows(4).any(|w| w == [0x4F, 0xEA, 0x20, 0x0C]),
9006 "mov.w ip, rm, ASR #32 — the #597 type-field bug"
9007 );
9008
9009 let bytes = enc
9012 .encode(&ArmOp::CallIndirect {
9013 rd: Reg::R0,
9014 type_idx: 0,
9015 table_index_reg: Reg::R4,
9016 table_size: 4,
9017 table_byte_offset: 0,
9018 })
9019 .unwrap();
9020 assert_eq!(&bytes[4..6], &[0x64, 0x45], "cmp r4, ip: {bytes:02x?}");
9021 assert_eq!(
9022 &bytes[10..14],
9023 &[0x4F, 0xEA, 0x84, 0x0C],
9024 "mov.w ip, r4, LSL #2: {bytes:02x?}"
9025 );
9026 }
9027
9028 #[test]
9032 fn test_encode_thumb_call_indirect_guard_shapes_642() {
9033 use synth_synthesis::{ArmOp, Reg};
9034 let enc = ArmEncoder::new_thumb2();
9035 let bytes = enc
9036 .encode(&ArmOp::CallIndirect {
9037 rd: Reg::R0,
9038 type_idx: 0,
9039 table_index_reg: Reg::R8,
9040 table_size: 3,
9041 table_byte_offset: 0,
9042 })
9043 .unwrap();
9044 assert_eq!(&bytes[4..6], &[0xE0, 0x45], "cmp r8, ip: {bytes:02x?}");
9046
9047 let bytes = enc
9048 .encode(&ArmOp::CallIndirect {
9049 rd: Reg::R0,
9050 type_idx: 0,
9051 table_index_reg: Reg::R0,
9052 table_size: 0x0002_0003,
9053 table_byte_offset: 0,
9054 })
9055 .unwrap();
9056 assert_eq!(
9058 &bytes[0..8],
9059 &[0x40, 0xF2, 0x03, 0x0C, 0xC0, 0xF2, 0x02, 0x0C],
9060 "movw ip,#3; movt ip,#2: {bytes:02x?}"
9061 );
9062 }
9063
9064 #[test]
9069 fn test_encode_thumb_call_indirect_table_offset_650() {
9070 use synth_synthesis::{ArmOp, Reg};
9071 let enc = ArmEncoder::new_thumb2();
9072 let bytes = enc
9075 .encode(&ArmOp::CallIndirect {
9076 rd: Reg::R0,
9077 type_idx: 0,
9078 table_index_reg: Reg::R1,
9079 table_size: 41,
9080 table_byte_offset: 28,
9081 })
9082 .unwrap();
9083 assert_eq!(
9084 bytes,
9085 vec![
9086 0x40, 0xF2, 0x29, 0x0C, 0x61, 0x45, 0x00, 0xD3, 0x00, 0xDE, 0x4F, 0xEA, 0x81, 0x0C, 0x0B, 0xEB, 0x0C, 0x0C, 0xDC, 0xF8, 0x1C, 0xC0, 0xE0, 0x47, ],
9097 "Thumb-2 table-1 dispatch (#650): {bytes:02x?}"
9098 );
9099
9100 let zero = enc
9103 .encode(&ArmOp::CallIndirect {
9104 rd: Reg::R0,
9105 type_idx: 0,
9106 table_index_reg: Reg::R1,
9107 table_size: 41,
9108 table_byte_offset: 0,
9109 })
9110 .unwrap();
9111 assert_eq!(
9112 &zero[10..],
9113 &[
9114 0x4F, 0xEA, 0x81, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47, ],
9118 "offset 0 keeps the pre-#650 dispatch bytes: {zero:02x?}"
9119 );
9120 }
9121
9122 #[test]
9125 fn test_encode_arm32_call_indirect_table_offset_650() {
9126 use synth_synthesis::{ArmOp, Reg};
9127 let enc = ArmEncoder::new_arm32();
9128 let bytes = enc
9129 .encode(&ArmOp::CallIndirect {
9130 rd: Reg::R0,
9131 type_idx: 0,
9132 table_index_reg: Reg::R1,
9133 table_size: 41,
9134 table_byte_offset: 28,
9135 })
9136 .unwrap();
9137 let words: Vec<u32> = bytes
9138 .chunks_exact(4)
9139 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9140 .collect();
9141 assert_eq!(words[0], 0xE300_C029, "MOVW r12,#41: {:#010x}", words[0]);
9142 assert_eq!(words[1], 0xE151_000C, "CMP r1,r12: {:#010x}", words[1]);
9143 assert_eq!(words[2], 0x3A00_0000, "BLO +1 insn: {:#010x}", words[2]);
9144 assert_eq!(words[3], 0xE7F0_00F0, "UDF: {:#010x}", words[3]);
9145 assert_eq!(
9146 words[4], 0xE1A0_C101,
9147 "MOV r12,r1,LSL#2: {:#010x}",
9148 words[4]
9149 );
9150 assert_eq!(
9151 words[5], 0xE08B_C00C,
9152 "ADD r12,r11,r12 (#650): {:#010x}",
9153 words[5]
9154 );
9155 assert_eq!(
9156 words[6], 0xE59C_C01C,
9157 "LDR r12,[r12,#28] (#650): {:#010x}",
9158 words[6]
9159 );
9160 assert_eq!(words[7], 0xE12F_FF3C, "BLX r12: {:#010x}", words[7]);
9161 }
9162
9163 #[test]
9170 fn test_encode_thumb_add_high_reg_uses_add_w_178_180() {
9171 let encoder = ArmEncoder::new_thumb2();
9172
9173 let code = encoder
9175 .encode(&ArmOp::Add {
9176 rd: Reg::R12,
9177 rn: Reg::R12,
9178 op2: Operand2::Reg(Reg::R0),
9179 })
9180 .unwrap();
9181 assert_eq!(
9183 code,
9184 vec![0x0C, 0xEB, 0x00, 0x0C],
9185 "high-reg Thumb ADD must be 32-bit ADD.W (EB0C 0C00), not corrupt 16-bit; got {code:02X?}"
9186 );
9187 assert_ne!(code, vec![0x6C, 0x18], "regressed to corrupt 16-bit ADDS");
9189
9190 let lo = encoder
9192 .encode(&ArmOp::Add {
9193 rd: Reg::R1,
9194 rn: Reg::R2,
9195 op2: Operand2::Reg(Reg::R3),
9196 })
9197 .unwrap();
9198 assert_eq!(
9199 lo.len(),
9200 2,
9201 "low-reg ADD should remain 16-bit, got {lo:02X?}"
9202 );
9203 }
9204
9205 #[test]
9208 fn test_encode_thumb_adds_subs_high_reg_use_32bit_178_180() {
9209 let encoder = ArmEncoder::new_thumb2();
9210
9211 let adds = encoder
9213 .encode(&ArmOp::Adds {
9214 rd: Reg::R10,
9215 rn: Reg::R10,
9216 op2: Operand2::Reg(Reg::R8),
9217 })
9218 .unwrap();
9219 assert_eq!(
9220 adds,
9221 vec![0x1A, 0xEB, 0x08, 0x0A],
9222 "high-reg ADDS must be 32-bit ADDS.W (EB1A 0A08); got {adds:02X?}"
9223 );
9224
9225 let subs = encoder
9227 .encode(&ArmOp::Subs {
9228 rd: Reg::R10,
9229 rn: Reg::R10,
9230 op2: Operand2::Reg(Reg::R8),
9231 })
9232 .unwrap();
9233 assert_eq!(
9234 subs,
9235 vec![0xBA, 0xEB, 0x08, 0x0A],
9236 "high-reg SUBS must be 32-bit SUBS.W (EBBA 0A08); got {subs:02X?}"
9237 );
9238 }
9239
9240 #[test]
9243 fn test_encode_thumb_cmn_high_reg_uses_cmn_w_184() {
9244 let encoder = ArmEncoder::new_thumb2();
9245
9246 let cmn = encoder
9248 .encode(&ArmOp::Cmn {
9249 rn: Reg::R10,
9250 op2: Operand2::Reg(Reg::R8),
9251 })
9252 .unwrap();
9253 assert_eq!(
9254 cmn,
9255 vec![0x1A, 0xEB, 0x08, 0x0F],
9256 "high-reg CMN must be 32-bit CMN.W (EB1A 0F08); got {cmn:02X?}"
9257 );
9258
9259 let lo = encoder
9261 .encode(&ArmOp::Cmn {
9262 rn: Reg::R1,
9263 op2: Operand2::Reg(Reg::R2),
9264 })
9265 .unwrap();
9266 assert_eq!(
9267 lo.len(),
9268 2,
9269 "low-reg CMN should remain 16-bit, got {lo:02X?}"
9270 );
9271 assert_eq!(lo, vec![0xD1, 0x42], "low-reg CMN bytes wrong: {lo:02X?}");
9272 }
9273
9274 #[test]
9278 fn test_encode_pc_operand_returns_err_not_panic_185() {
9279 let encoder = ArmEncoder::new_thumb2();
9280 for op in [
9281 ArmOp::Sdiv {
9282 rd: Reg::PC,
9283 rn: Reg::R0,
9284 rm: Reg::R1,
9285 },
9286 ArmOp::Udiv {
9287 rd: Reg::R0,
9288 rn: Reg::PC,
9289 rm: Reg::R1,
9290 },
9291 ArmOp::Sdiv {
9292 rd: Reg::R0,
9293 rn: Reg::R1,
9294 rm: Reg::PC,
9295 },
9296 ] {
9297 let r = encoder.encode(&op);
9298 assert!(
9299 r.is_err(),
9300 "encode({op:?}) must return Err for a PC operand, got {r:?}"
9301 );
9302 }
9303 assert!(
9305 encoder
9306 .encode(&ArmOp::Sdiv {
9307 rd: Reg::R0,
9308 rn: Reg::R1,
9309 rm: Reg::R2
9310 })
9311 .is_ok()
9312 );
9313 }
9314
9315 #[test]
9316 fn test_encode_nop_arm32() {
9317 let encoder = ArmEncoder::new_arm32();
9318 let code = encoder.encode(&ArmOp::Nop).unwrap();
9319
9320 assert_eq!(code.len(), 4); assert_eq!(code, vec![0x00, 0x00, 0xA0, 0xE1]); }
9323
9324 #[test]
9325 fn test_encode_nop_thumb() {
9326 let encoder = ArmEncoder::new_thumb2();
9327 let code = encoder.encode(&ArmOp::Nop).unwrap();
9328
9329 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]); }
9332
9333 #[test]
9334 fn test_encode_mov_immediate_arm32() {
9335 let encoder = ArmEncoder::new_arm32();
9336 let op = ArmOp::Mov {
9337 rd: Reg::R0,
9338 op2: Operand2::Imm(42),
9339 };
9340
9341 let code = encoder.encode(&op).unwrap();
9342 assert_eq!(code.len(), 4);
9343
9344 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9346 assert_eq!(instr & 0x0E000000, 0x02000000); }
9348
9349 #[test]
9350 fn test_encode_add_registers_arm32() {
9351 let encoder = ArmEncoder::new_arm32();
9352 let op = ArmOp::Add {
9353 rd: Reg::R0,
9354 rn: Reg::R1,
9355 op2: Operand2::Reg(Reg::R2),
9356 };
9357
9358 let code = encoder.encode(&op).unwrap();
9359 assert_eq!(code.len(), 4);
9360
9361 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9362 assert_eq!(instr & 0x0FE00000, 0x00800000);
9364 }
9365
9366 #[test]
9370 fn test_encode_add_imm_large_350() {
9371 let enc = ArmEncoder::new_thumb2();
9372
9373 let small = enc
9375 .encode_thumb32_add_imm(&Reg::R0, &Reg::R1, 0x123)
9376 .unwrap();
9377 assert_eq!(small.len(), 4, "small imm must stay a single instruction");
9378
9379 fn movx_imm16(b: &[u8]) -> u32 {
9381 let hw1 = u16::from_le_bytes([b[0], b[1]]) as u32;
9382 let hw2 = u16::from_le_bytes([b[2], b[3]]) as u32;
9383 let imm4 = hw1 & 0xF;
9384 let i = (hw1 >> 10) & 1;
9385 let imm3 = (hw2 >> 12) & 0x7;
9386 let imm8 = hw2 & 0xFF;
9387 (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8
9388 }
9389 fn movx_rd(b: &[u8]) -> u32 {
9390 (u16::from_le_bytes([b[2], b[3]]) as u32 >> 8) & 0xF
9391 }
9392
9393 let seq = enc
9396 .encode_thumb32_add_imm(&Reg::R12, &Reg::R0, 70000)
9397 .unwrap();
9398 assert_eq!(seq.len(), 12, "MOVW + MOVT + ADD = 12 bytes");
9399 assert_eq!(u16::from_le_bytes([seq[0], seq[1]]) & 0xFBF0, 0xF240);
9401 assert_eq!(movx_rd(&seq[0..4]), 12);
9402 assert_eq!(movx_imm16(&seq[0..4]), 0x1170);
9403 assert_eq!(u16::from_le_bytes([seq[4], seq[5]]) & 0xFBF0, 0xF2C0);
9405 assert_eq!(movx_rd(&seq[4..8]), 12);
9406 assert_eq!(movx_imm16(&seq[4..8]), 0x0001);
9407 let add1 = u16::from_le_bytes([seq[8], seq[9]]) as u32;
9409 let add2 = u16::from_le_bytes([seq[10], seq[11]]) as u32;
9410 assert_eq!(add1 & 0xFFF0, 0xEB00);
9411 assert_eq!(add1 & 0xF, 0); assert_eq!((add2 >> 8) & 0xF, 12); assert_eq!(add2 & 0xF, 12); assert_eq!(
9416 (movx_imm16(&seq[4..8]) << 16) | movx_imm16(&seq[0..4]),
9417 70000
9418 );
9419
9420 let seq16 = enc
9422 .encode_thumb32_add_imm(&Reg::R3, &Reg::R0, 0xABCD)
9423 .unwrap();
9424 assert_eq!(seq16.len(), 8, "imm <= 0xFFFF skips MOVT");
9425 assert_eq!(movx_imm16(&seq16[0..4]), 0xABCD);
9426 assert_eq!(movx_rd(&seq16[0..4]), 3); let inplace = enc
9431 .encode_thumb32_add_imm(&Reg::R5, &Reg::R5, 0x12345)
9432 .unwrap();
9433 assert_eq!(inplace.len(), 12);
9434 assert_eq!(movx_rd(&inplace[0..4]), 12, "rd==rn must use R12 scratch");
9435 assert_eq!(
9436 (movx_imm16(&inplace[4..8]) << 16) | movx_imm16(&inplace[0..4]),
9437 0x12345
9438 );
9439 let ip_add2 = u16::from_le_bytes([inplace[10], inplace[11]]) as u32;
9441 assert_eq!(ip_add2 & 0xF, 12);
9442 assert_eq!((ip_add2 >> 8) & 0xF, 5);
9443 }
9444
9445 #[test]
9453 fn test_encode_add_imm_large_rd_rn_r12_errs_not_panics_350() {
9454 let enc = ArmEncoder::new_thumb2();
9455 let r = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 70000);
9457 assert!(
9458 r.is_err(),
9459 "rd==rn==R12 with out-of-range imm must Err (no free scratch), got {r:?}"
9460 );
9461 let small = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 0x10);
9465 assert!(small.is_ok(), "small imm needs no scratch, must stay Ok");
9466 }
9467
9468 #[test]
9477 fn test_encode_operand2_non_rotatable_imm_errs_not_masks_378() {
9478 let enc = ArmEncoder::new_arm32();
9479 let bad = enc.encode(&ArmOp::Add {
9480 rd: Reg::R0,
9481 rn: Reg::R1,
9482 op2: Operand2::Imm(0x1FF),
9483 });
9484 assert!(
9485 bad.is_err(),
9486 "non-rotatable ARM32 immediate 0x1FF must Err (was silently masked \
9487 to 0xFF), got {bad:?}"
9488 );
9489 let ok = enc.encode(&ArmOp::Add {
9491 rd: Reg::R0,
9492 rn: Reg::R1,
9493 op2: Operand2::Imm(0xFF),
9494 });
9495 assert!(
9496 ok.is_ok(),
9497 "0xFF is a valid rotated immediate, must stay Ok"
9498 );
9499 }
9500
9501 #[test]
9502 fn test_encode_ldr_arm32() {
9503 let encoder = ArmEncoder::new_arm32();
9504 let op = ArmOp::Ldr {
9505 rd: Reg::R0,
9506 addr: MemAddr::imm(Reg::R1, 4),
9507 };
9508
9509 let code = encoder.encode(&op).unwrap();
9510 assert_eq!(code.len(), 4);
9511
9512 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9513 assert_eq!(instr & 0x00100000, 0x00100000);
9515 }
9516
9517 #[test]
9518 fn test_encode_str_arm32() {
9519 let encoder = ArmEncoder::new_arm32();
9520 let op = ArmOp::Str {
9521 rd: Reg::R0,
9522 addr: MemAddr::imm(Reg::SP, 0),
9523 };
9524
9525 let code = encoder.encode(&op).unwrap();
9526 assert_eq!(code.len(), 4);
9527 }
9528
9529 #[test]
9530 fn test_encode_branch_arm32() {
9531 let encoder = ArmEncoder::new_arm32();
9532 let op = ArmOp::Bl {
9533 label: "main".to_string(),
9534 };
9535
9536 let code = encoder.encode(&op).unwrap();
9537 assert_eq!(code.len(), 4);
9538
9539 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9540 assert_eq!(instr & 0x0F000000, 0x0B000000);
9542 }
9543
9544 #[test]
9554 fn test_encode_thumb_bl_placeholder_addend_167_174() {
9555 let encoder = ArmEncoder::new_thumb2();
9556 let op = ArmOp::Bl {
9557 label: "callee".to_string(),
9558 };
9559
9560 let code = encoder.encode(&op).unwrap();
9561 assert_eq!(code.len(), 4, "Thumb-2 BL is 32-bit");
9562
9563 let hw1 = u16::from_le_bytes([code[0], code[1]]);
9564 let hw2 = u16::from_le_bytes([code[2], code[3]]);
9565 assert_eq!(hw1, 0xF7FF, "BL first halfword (matches gas `bl <extern>`)");
9566 assert_eq!(
9567 hw2, 0xFFFE,
9568 "BL second halfword must be 0xFFFE (-4 addend → nets to S), not 0xF800 (→ S+4, #174) or 0xD000 (#167)"
9569 );
9570 assert_ne!(hw2, 0xF800, "0xF800 (addend 0) lands at S+4 (#174)");
9571 assert_ne!(hw2, 0xD000, "0xD000 bakes in a ~+0x600000 addend (#167)");
9572 }
9573
9574 #[test]
9575 fn test_encode_sequence() {
9576 let encoder = ArmEncoder::new_arm32();
9577 let ops = vec![
9578 ArmOp::Mov {
9579 rd: Reg::R0,
9580 op2: Operand2::Imm(42),
9581 },
9582 ArmOp::Mov {
9583 rd: Reg::R1,
9584 op2: Operand2::Imm(10),
9585 },
9586 ArmOp::Add {
9587 rd: Reg::R2,
9588 rn: Reg::R0,
9589 op2: Operand2::Reg(Reg::R1),
9590 },
9591 ];
9592
9593 let code = encoder.encode_sequence(&ops).unwrap();
9594 assert_eq!(code.len(), 12); }
9596
9597 #[test]
9598 fn test_reg_to_bits() {
9599 assert_eq!(reg_to_bits(&Reg::R0), 0);
9600 assert_eq!(reg_to_bits(&Reg::R7), 7);
9601 assert_eq!(reg_to_bits(&Reg::SP), 13);
9602 assert_eq!(reg_to_bits(&Reg::LR), 14);
9603 assert_eq!(reg_to_bits(&Reg::PC), 15);
9604 }
9605
9606 #[test]
9607 fn test_encode_bitwise_operations() {
9608 let encoder = ArmEncoder::new_arm32();
9609
9610 let and_op = ArmOp::And {
9611 rd: Reg::R0,
9612 rn: Reg::R1,
9613 op2: Operand2::Reg(Reg::R2),
9614 };
9615 let and_code = encoder.encode(&and_op).unwrap();
9616 assert_eq!(and_code.len(), 4);
9617
9618 let orr_op = ArmOp::Orr {
9619 rd: Reg::R0,
9620 rn: Reg::R1,
9621 op2: Operand2::Reg(Reg::R2),
9622 };
9623 let orr_code = encoder.encode(&orr_op).unwrap();
9624 assert_eq!(orr_code.len(), 4);
9625
9626 let eor_op = ArmOp::Eor {
9627 rd: Reg::R0,
9628 rn: Reg::R1,
9629 op2: Operand2::Reg(Reg::R2),
9630 };
9631 let eor_code = encoder.encode(&eor_op).unwrap();
9632 assert_eq!(eor_code.len(), 4);
9633 }
9634
9635 #[test]
9638 fn test_encode_sdiv_thumb2() {
9639 let encoder = ArmEncoder::new_thumb2();
9640 let op = ArmOp::Sdiv {
9641 rd: Reg::R0,
9642 rn: Reg::R1,
9643 rm: Reg::R2,
9644 };
9645
9646 let code = encoder.encode(&op).unwrap();
9647 assert_eq!(code.len(), 4); assert_eq!(code[0], 0x91);
9654 assert_eq!(code[1], 0xFB);
9655 assert_eq!(code[2], 0xF2);
9656 assert_eq!(code[3], 0xF0);
9657 }
9658
9659 #[test]
9660 fn test_encode_udiv_thumb2() {
9661 let encoder = ArmEncoder::new_thumb2();
9662 let op = ArmOp::Udiv {
9663 rd: Reg::R0,
9664 rn: Reg::R1,
9665 rm: Reg::R2,
9666 };
9667
9668 let code = encoder.encode(&op).unwrap();
9669 assert_eq!(code.len(), 4); assert_eq!(code[0], 0xB1);
9674 assert_eq!(code[1], 0xFB);
9675 assert_eq!(code[2], 0xF2);
9676 assert_eq!(code[3], 0xF0);
9677 }
9678
9679 #[test]
9680 fn test_encode_mul_thumb2() {
9681 let encoder = ArmEncoder::new_thumb2();
9682 let op = ArmOp::Mul {
9683 rd: Reg::R0,
9684 rn: Reg::R1,
9685 rm: Reg::R2,
9686 };
9687
9688 let code = encoder.encode(&op).unwrap();
9689 assert_eq!(code.len(), 4); }
9691
9692 #[test]
9693 fn test_encode_and_thumb2() {
9694 let encoder = ArmEncoder::new_thumb2();
9695 let op = ArmOp::And {
9696 rd: Reg::R0,
9697 rn: Reg::R1,
9698 op2: Operand2::Reg(Reg::R2),
9699 };
9700
9701 let code = encoder.encode(&op).unwrap();
9702 assert_eq!(code.len(), 4); }
9704
9705 #[test]
9706 fn test_encode_lsl_thumb2_low_regs() {
9707 let encoder = ArmEncoder::new_thumb2();
9708 let op = ArmOp::Lsl {
9709 rd: Reg::R0,
9710 rn: Reg::R1,
9711 shift: 5,
9712 };
9713
9714 let code = encoder.encode(&op).unwrap();
9715 assert_eq!(code.len(), 2); }
9717
9718 #[test]
9719 fn test_encode_clz_thumb2() {
9720 let encoder = ArmEncoder::new_thumb2();
9721 let op = ArmOp::Clz {
9722 rd: Reg::R0,
9723 rm: Reg::R1,
9724 };
9725
9726 let code = encoder.encode(&op).unwrap();
9727 assert_eq!(code.len(), 4); }
9729
9730 #[test]
9731 fn test_encode_bx_thumb2() {
9732 let encoder = ArmEncoder::new_thumb2();
9733 let op = ArmOp::Bx { rm: Reg::LR };
9734
9735 let code = encoder.encode(&op).unwrap();
9736 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x70, 0x47]);
9740 }
9741
9742 #[test]
9747 fn test_encode_f32_abs_arm32() {
9748 let encoder = ArmEncoder::new_arm32();
9749 let op = ArmOp::F32Abs {
9750 sd: VfpReg::S0,
9751 sm: VfpReg::S2,
9752 };
9753 let code = encoder.encode(&op).unwrap();
9754 assert_eq!(code.len(), 4); }
9756
9757 #[test]
9758 fn test_encode_f32_neg_arm32() {
9759 let encoder = ArmEncoder::new_arm32();
9760 let op = ArmOp::F32Neg {
9761 sd: VfpReg::S0,
9762 sm: VfpReg::S2,
9763 };
9764 let code = encoder.encode(&op).unwrap();
9765 assert_eq!(code.len(), 4);
9766 }
9767
9768 #[test]
9769 fn test_encode_f32_sqrt_arm32() {
9770 let encoder = ArmEncoder::new_arm32();
9771 let op = ArmOp::F32Sqrt {
9772 sd: VfpReg::S0,
9773 sm: VfpReg::S2,
9774 };
9775 let code = encoder.encode(&op).unwrap();
9776 assert_eq!(code.len(), 4);
9777 }
9778
9779 #[test]
9780 fn test_encode_f32_ceil_arm32() {
9781 let encoder = ArmEncoder::new_arm32();
9782 let op = ArmOp::F32Ceil {
9783 sd: VfpReg::S0,
9784 sm: VfpReg::S2,
9785 };
9786 let code = encoder.encode(&op).unwrap();
9787 assert_eq!(code.len(), 36);
9789 }
9790
9791 #[test]
9792 fn test_encode_f32_floor_thumb2() {
9793 let encoder = ArmEncoder::new_thumb2();
9794 let op = ArmOp::F32Floor {
9795 sd: VfpReg::S0,
9796 sm: VfpReg::S2,
9797 };
9798 let code = encoder.encode(&op).unwrap();
9799 assert_eq!(code.len(), 36);
9801 }
9802
9803 #[test]
9804 fn test_encode_f32_min_arm32() {
9805 let encoder = ArmEncoder::new_arm32();
9806 let op = ArmOp::F32Min {
9807 sd: VfpReg::S0,
9808 sn: VfpReg::S2,
9809 sm: VfpReg::S4,
9810 };
9811 let code = encoder.encode(&op).unwrap();
9812 assert_eq!(code.len(), 16); }
9814
9815 #[test]
9816 fn test_encode_f32_max_thumb2() {
9817 let encoder = ArmEncoder::new_thumb2();
9818 let op = ArmOp::F32Max {
9819 sd: VfpReg::S0,
9820 sn: VfpReg::S2,
9821 sm: VfpReg::S4,
9822 };
9823 let code = encoder.encode(&op).unwrap();
9824 assert_eq!(code.len(), 18);
9826 }
9827
9828 #[test]
9829 fn test_encode_f32_copysign_arm32() {
9830 let encoder = ArmEncoder::new_arm32();
9831 let op = ArmOp::F32Copysign {
9832 sd: VfpReg::S0,
9833 sn: VfpReg::S2,
9834 sm: VfpReg::S4,
9835 };
9836 let code = encoder.encode(&op).unwrap();
9837 assert_eq!(code.len(), 24);
9839 }
9840
9841 #[test]
9846 fn test_encode_f64_add_arm32() {
9847 let encoder = ArmEncoder::new_arm32();
9848 let op = ArmOp::F64Add {
9849 dd: VfpReg::D0,
9850 dn: VfpReg::D1,
9851 dm: VfpReg::D2,
9852 };
9853 let code = encoder.encode(&op).unwrap();
9854 assert_eq!(code.len(), 4);
9855 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9857 assert_eq!((instr >> 8) & 0xF, 0xB); }
9859
9860 #[test]
9861 fn test_encode_f64_sub_thumb2() {
9862 let encoder = ArmEncoder::new_thumb2();
9863 let op = ArmOp::F64Sub {
9864 dd: VfpReg::D0,
9865 dn: VfpReg::D1,
9866 dm: VfpReg::D2,
9867 };
9868 let code = encoder.encode(&op).unwrap();
9869 assert_eq!(code.len(), 4); }
9871
9872 #[test]
9873 fn test_encode_f64_mul_arm32() {
9874 let encoder = ArmEncoder::new_arm32();
9875 let op = ArmOp::F64Mul {
9876 dd: VfpReg::D0,
9877 dn: VfpReg::D1,
9878 dm: VfpReg::D2,
9879 };
9880 let code = encoder.encode(&op).unwrap();
9881 assert_eq!(code.len(), 4);
9882 }
9883
9884 #[test]
9885 fn test_encode_f64_div_arm32() {
9886 let encoder = ArmEncoder::new_arm32();
9887 let op = ArmOp::F64Div {
9888 dd: VfpReg::D0,
9889 dn: VfpReg::D1,
9890 dm: VfpReg::D2,
9891 };
9892 let code = encoder.encode(&op).unwrap();
9893 assert_eq!(code.len(), 4);
9894 }
9895
9896 #[test]
9897 fn test_encode_f64_abs_arm32() {
9898 let encoder = ArmEncoder::new_arm32();
9899 let op = ArmOp::F64Abs {
9900 dd: VfpReg::D0,
9901 dm: VfpReg::D2,
9902 };
9903 let code = encoder.encode(&op).unwrap();
9904 assert_eq!(code.len(), 4);
9905 }
9906
9907 #[test]
9908 fn test_encode_f64_neg_arm32() {
9909 let encoder = ArmEncoder::new_arm32();
9910 let op = ArmOp::F64Neg {
9911 dd: VfpReg::D0,
9912 dm: VfpReg::D2,
9913 };
9914 let code = encoder.encode(&op).unwrap();
9915 assert_eq!(code.len(), 4);
9916 }
9917
9918 #[test]
9919 fn test_encode_f64_sqrt_arm32() {
9920 let encoder = ArmEncoder::new_arm32();
9921 let op = ArmOp::F64Sqrt {
9922 dd: VfpReg::D0,
9923 dm: VfpReg::D2,
9924 };
9925 let code = encoder.encode(&op).unwrap();
9926 assert_eq!(code.len(), 4);
9927 }
9928
9929 #[test]
9930 fn test_encode_f64_load_arm32() {
9931 let encoder = ArmEncoder::new_arm32();
9932 let op = ArmOp::F64Load {
9933 dd: VfpReg::D0,
9934 addr: MemAddr::imm(Reg::R0, 8),
9935 };
9936 let code = encoder.encode(&op).unwrap();
9937 assert_eq!(code.len(), 4);
9938 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9939 assert_eq!((instr >> 8) & 0xF, 0xB); assert_eq!(instr & 0xFF, 2); }
9942
9943 #[test]
9944 fn test_encode_f64_store_thumb2() {
9945 let encoder = ArmEncoder::new_thumb2();
9946 let op = ArmOp::F64Store {
9947 dd: VfpReg::D0,
9948 addr: MemAddr::imm(Reg::SP, 0),
9949 };
9950 let code = encoder.encode(&op).unwrap();
9951 assert_eq!(code.len(), 4);
9952 }
9953
9954 #[test]
9955 fn test_encode_f64_compare_arm32() {
9956 let encoder = ArmEncoder::new_arm32();
9957 let op = ArmOp::F64Eq {
9958 rd: Reg::R0,
9959 dn: VfpReg::D0,
9960 dm: VfpReg::D1,
9961 };
9962 let code = encoder.encode(&op).unwrap();
9963 assert_eq!(code.len(), 16); }
9965
9966 #[test]
9967 fn test_encode_f64_compare_thumb2() {
9968 let encoder = ArmEncoder::new_thumb2();
9969 let op = ArmOp::F64Lt {
9970 rd: Reg::R0,
9971 dn: VfpReg::D0,
9972 dm: VfpReg::D1,
9973 };
9974 let code = encoder.encode(&op).unwrap();
9975 assert_eq!(code.len(), 14);
9977 }
9978
9979 #[test]
9980 fn test_encode_f64_const_arm32() {
9981 let encoder = ArmEncoder::new_arm32();
9982 let op = ArmOp::F64Const {
9983 dd: VfpReg::D0,
9984 value: 3.125,
9985 };
9986 let code = encoder.encode(&op).unwrap();
9987 assert_eq!(code.len(), 20);
9989 }
9990
9991 #[test]
9992 fn test_encode_f64_const_thumb2() {
9993 let encoder = ArmEncoder::new_thumb2();
9994 let op = ArmOp::F64Const {
9995 dd: VfpReg::D0,
9996 value: 2.5,
9997 };
9998 let code = encoder.encode(&op).unwrap();
9999 assert_eq!(code.len(), 20);
10001 }
10002
10003 #[test]
10004 fn test_encode_f64_convert_i32s_arm32() {
10005 let encoder = ArmEncoder::new_arm32();
10006 let op = ArmOp::F64ConvertI32S {
10007 dd: VfpReg::D0,
10008 rm: Reg::R0,
10009 };
10010 let code = encoder.encode(&op).unwrap();
10011 assert_eq!(code.len(), 8);
10013 }
10014
10015 #[test]
10016 fn test_encode_f64_promote_f32_arm32() {
10017 let encoder = ArmEncoder::new_arm32();
10018 let op = ArmOp::F64PromoteF32 {
10019 dd: VfpReg::D0,
10020 sm: VfpReg::S0,
10021 };
10022 let code = encoder.encode(&op).unwrap();
10023 assert_eq!(code.len(), 4); }
10025
10026 #[test]
10027 fn test_encode_f64_promote_f32_thumb2() {
10028 let encoder = ArmEncoder::new_thumb2();
10029 let op = ArmOp::F64PromoteF32 {
10030 dd: VfpReg::D0,
10031 sm: VfpReg::S0,
10032 };
10033 let code = encoder.encode(&op).unwrap();
10034 assert_eq!(code.len(), 4);
10035 }
10036
10037 #[test]
10038 fn test_encode_i32_trunc_f64s_arm32() {
10039 let encoder = ArmEncoder::new_arm32();
10040 let op = ArmOp::I32TruncF64S {
10041 rd: Reg::R0,
10042 dm: VfpReg::D0,
10043 };
10044 let code = encoder.encode(&op).unwrap();
10045 assert_eq!(code.len(), 8);
10047 }
10048
10049 #[test]
10050 fn test_encode_f64_reinterpret_i64_arm32() {
10051 let encoder = ArmEncoder::new_arm32();
10052 let op = ArmOp::F64ReinterpretI64 {
10053 dd: VfpReg::D0,
10054 rmlo: Reg::R0,
10055 rmhi: Reg::R1,
10056 };
10057 let code = encoder.encode(&op).unwrap();
10058 assert_eq!(code.len(), 4); }
10060
10061 #[test]
10062 fn test_encode_i64_reinterpret_f64_thumb2() {
10063 let encoder = ArmEncoder::new_thumb2();
10064 let op = ArmOp::I64ReinterpretF64 {
10065 rdlo: Reg::R0,
10066 rdhi: Reg::R1,
10067 dm: VfpReg::D0,
10068 };
10069 let code = encoder.encode(&op).unwrap();
10070 assert_eq!(code.len(), 4);
10071 }
10072
10073 #[test]
10074 fn test_encode_f64_trunc_thumb2() {
10075 let encoder = ArmEncoder::new_thumb2();
10076 let op = ArmOp::F64Trunc {
10077 dd: VfpReg::D0,
10078 dm: VfpReg::D1,
10079 };
10080 let code = encoder.encode(&op).unwrap();
10081 assert_eq!(code.len(), 8);
10083 }
10084
10085 #[test]
10086 fn test_encode_f64_min_arm32() {
10087 let encoder = ArmEncoder::new_arm32();
10088 let op = ArmOp::F64Min {
10089 dd: VfpReg::D0,
10090 dn: VfpReg::D1,
10091 dm: VfpReg::D2,
10092 };
10093 let code = encoder.encode(&op).unwrap();
10094 assert_eq!(code.len(), 16);
10096 }
10097
10098 #[test]
10099 fn test_f64_cp11_encoding() {
10100 let encoder = ArmEncoder::new_arm32();
10102
10103 let code = encoder
10105 .encode(&ArmOp::F64Add {
10106 dd: VfpReg::D0,
10107 dn: VfpReg::D0,
10108 dm: VfpReg::D0,
10109 })
10110 .unwrap();
10111 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10112 assert_eq!((instr >> 8) & 0xF, 0xB, "F64 should use cp11");
10113
10114 let code = encoder
10116 .encode(&ArmOp::F32Add {
10117 sd: VfpReg::S0,
10118 sn: VfpReg::S0,
10119 sm: VfpReg::S0,
10120 })
10121 .unwrap();
10122 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10123 assert_eq!((instr >> 8) & 0xF, 0xA, "F32 should use cp10");
10124 }
10125
10126 #[test]
10127 fn test_dreg_encoding_higher_registers() {
10128 let encoder = ArmEncoder::new_arm32();
10129
10130 let op = ArmOp::F64Add {
10132 dd: VfpReg::D15,
10133 dn: VfpReg::D14,
10134 dm: VfpReg::D13,
10135 };
10136 let code = encoder.encode(&op).unwrap();
10137 assert_eq!(code.len(), 4);
10138
10139 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10141 assert_eq!((instr >> 8) & 0xF, 0xB); }
10143
10144 #[test]
10149 fn test_encode_label_emits_no_bytes() {
10150 let encoder = ArmEncoder::new_thumb2();
10151 let op = ArmOp::Label {
10152 name: ".Lblock_end_0".to_string(),
10153 };
10154 let code = encoder.encode(&op).unwrap();
10155 assert!(code.is_empty(), "Label should emit zero bytes");
10156
10157 let encoder32 = ArmEncoder::new_arm32();
10158 let code32 = encoder32.encode(&op).unwrap();
10159 assert!(
10160 code32.is_empty(),
10161 "Label should emit zero bytes in ARM32 too"
10162 );
10163 }
10164
10165 #[test]
10166 fn test_encode_bcc_eq_thumb2() {
10167 use synth_synthesis::Condition;
10168 let encoder = ArmEncoder::new_thumb2();
10169 let op = ArmOp::Bcc {
10170 cond: Condition::EQ,
10171 label: "target".to_string(),
10172 };
10173 let code = encoder.encode(&op).unwrap();
10174 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xD0]);
10178 }
10179
10180 #[test]
10181 fn test_encode_bcc_ne_thumb2() {
10182 use synth_synthesis::Condition;
10183 let encoder = ArmEncoder::new_thumb2();
10184 let op = ArmOp::Bcc {
10185 cond: Condition::NE,
10186 label: "target".to_string(),
10187 };
10188 let code = encoder.encode(&op).unwrap();
10189 assert_eq!(code.len(), 2);
10190
10191 assert_eq!(code, vec![0x00, 0xD1]);
10193 }
10194
10195 #[test]
10196 fn test_encode_bcc_arm32() {
10197 use synth_synthesis::Condition;
10198 let encoder = ArmEncoder::new_arm32();
10199 let op = ArmOp::Bcc {
10200 cond: Condition::EQ,
10201 label: "target".to_string(),
10202 };
10203 let code = encoder.encode(&op).unwrap();
10204 assert_eq!(code.len(), 4); let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10207 assert_eq!(instr & 0xF0000000, 0x00000000); assert_eq!(instr & 0x0F000000, 0x0A000000); }
10211
10212 #[test]
10213 fn test_encode_udf_thumb2() {
10214 let encoder = ArmEncoder::new_thumb2();
10215 let op = ArmOp::Udf { imm: 0 };
10216 let code = encoder.encode(&op).unwrap();
10217 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xDE]);
10221 }
10222
10223 #[test]
10229 fn test_610_i64_rot_expansion_ends_with_rd_movs_and_restore() {
10230 let encoder = ArmEncoder::new_thumb2();
10231 for op in [
10232 ArmOp::I64Rotl {
10233 rdlo: Reg::R4,
10234 rdhi: Reg::R5,
10235 rnlo: Reg::R0,
10236 rnhi: Reg::R1,
10237 shift: Reg::R2,
10238 },
10239 ArmOp::I64Rotr {
10240 rdlo: Reg::R4,
10241 rdhi: Reg::R5,
10242 rnlo: Reg::R0,
10243 rnhi: Reg::R1,
10244 shift: Reg::R2,
10245 },
10246 ] {
10247 let code = encoder.encode(&op).unwrap();
10248 assert_eq!(code.len(), 102, "register-independent size (estimator pin)");
10249 let tail: Vec<u16> = code[code.len() - 12..]
10252 .chunks(2)
10253 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10254 .collect();
10255 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
10256 }
10257 }
10258
10259 #[test]
10262 fn test_610_i64_div_rem_expansion_guard_and_rd() {
10263 let encoder = ArmEncoder::new_thumb2();
10264 let mk = |which: u8| {
10265 let (rdlo, rdhi, rnlo, rnhi, rmlo, rmhi) =
10266 (Reg::R4, Reg::R5, Reg::R0, Reg::R1, Reg::R2, Reg::R3);
10267 match which {
10268 0 => ArmOp::I64DivU {
10269 rdlo,
10270 rdhi,
10271 rnlo,
10272 rnhi,
10273 rmlo,
10274 rmhi,
10275 elide_zero_guard: false,
10276 },
10277 1 => ArmOp::I64RemU {
10278 rdlo,
10279 rdhi,
10280 rnlo,
10281 rnhi,
10282 rmlo,
10283 rmhi,
10284 elide_zero_guard: false,
10285 },
10286 2 => ArmOp::I64DivS {
10287 rdlo,
10288 rdhi,
10289 rnlo,
10290 rnhi,
10291 rmlo,
10292 rmhi,
10293 elide_zero_guard: false,
10294 elide_overflow_guard: false,
10295 },
10296 _ => ArmOp::I64RemS {
10297 rdlo,
10298 rdhi,
10299 rnlo,
10300 rnhi,
10301 rmlo,
10302 rmhi,
10303 elide_zero_guard: false,
10304 },
10305 }
10306 };
10307 for which in 0..4u8 {
10308 let code = encoder.encode(&mk(which)).unwrap();
10309 let guard: Vec<u16> = code[26..34]
10311 .chunks(2)
10312 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10313 .collect();
10314 assert_eq!(
10315 guard,
10316 vec![0xEA52, 0x0C03, 0xD100, 0xDE00],
10317 "ORRS R12,R2,R3; BNE +0; UDF #0"
10318 );
10319 let tail: Vec<u16> = code[code.len() - 12..]
10321 .chunks(2)
10322 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10323 .collect();
10324 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
10325 }
10326 }
10327
10328 #[test]
10331 fn test_610_i64_divu_rd_in_r0_r1_skips_restore() {
10332 let encoder = ArmEncoder::new_thumb2();
10333 let code = encoder
10334 .encode(&ArmOp::I64DivU {
10335 rdlo: Reg::R0,
10336 rdhi: Reg::R1,
10337 rnlo: Reg::R0,
10338 rnhi: Reg::R1,
10339 rmlo: Reg::R2,
10340 rmhi: Reg::R3,
10341 elide_zero_guard: false,
10342 })
10343 .unwrap();
10344 let tail: Vec<u16> = code[code.len() - 12..]
10345 .chunks(2)
10346 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10347 .collect();
10348 assert_eq!(tail, vec![0x4609, 0x4600, 0xB001, 0xB001, 0xBC04, 0xBC08]);
10351 }
10352
10353 #[test]
10357 fn test_610_i64_swapped_rd_pair_rejected() {
10358 let encoder = ArmEncoder::new_thumb2();
10359 let result = encoder.encode(&ArmOp::I64RemU {
10360 rdlo: Reg::R1,
10361 rdhi: Reg::R0,
10362 rnlo: Reg::R2,
10363 rnhi: Reg::R3,
10364 rmlo: Reg::R4,
10365 rmhi: Reg::R5,
10366 elide_zero_guard: false,
10367 });
10368 assert!(result.is_err(), "swapped rd pair must be rejected loudly");
10369 }
10370
10371 #[test]
10378 fn test_632_i64_popcnt_result_survives_scratch_restore() {
10379 let encoder = ArmEncoder::new_thumb2();
10380 for rd in [
10382 Reg::R0,
10383 Reg::R2,
10384 Reg::R3,
10385 Reg::R4,
10386 Reg::R5,
10387 Reg::R6,
10388 Reg::R8,
10389 ] {
10390 let code = encoder
10391 .encode(&ArmOp::I64Popcnt {
10392 rd,
10393 rnlo: Reg::R6,
10394 rnhi: Reg::R7,
10395 })
10396 .unwrap();
10397 assert_eq!(code.len(), 180, "register-independent size (estimator pin)");
10398 let hw: Vec<u16> = code
10399 .chunks(2)
10400 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10401 .collect();
10402 let pop = hw
10403 .iter()
10404 .position(|&h| h == 0xBC38)
10405 .expect("POP {R3,R4,R5} present");
10406 assert_eq!(
10409 &hw[pop - 2..pop],
10410 &[0xEB04, 0x0C05],
10411 "total must be carried in R12 across the restore"
10412 );
10413 let rd_bits = match rd {
10415 Reg::R8 => 8u16,
10416 Reg::R6 => 6,
10417 Reg::R5 => 5,
10418 Reg::R4 => 4,
10419 Reg::R3 => 3,
10420 Reg::R2 => 2,
10421 _ => 0,
10422 };
10423 let expect_mov = 0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7);
10424 assert_eq!(hw[pop + 1], expect_mov, "MOV rd, R12 after the restore");
10425 assert!(
10428 !hw[..pop].contains(&(0x1800 | (5 << 6) | (4 << 3) | rd_bits)),
10429 "no ADDS rd, R4, R5 before the restore pop"
10430 );
10431 }
10432 }
10433
10434 #[test]
10438 fn test_632_i64_popcnt_marshal_pair_at_r3_r4() {
10439 let encoder = ArmEncoder::new_thumb2();
10440 let code = encoder
10441 .encode(&ArmOp::I64Popcnt {
10442 rd: Reg::R0,
10443 rnlo: Reg::R3,
10444 rnhi: Reg::R4,
10445 })
10446 .unwrap();
10447 let hw: Vec<u16> = code
10448 .chunks(2)
10449 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10450 .collect();
10451 assert_eq!(hw[0], 0xB438);
10454 assert_eq!(hw[1], 0x4600 | (1 << 7) | (3 << 3) | 4, "MOV R12, rnlo");
10455 assert_eq!(hw[2], 0x4600 | (4 << 3) | 5, "MOV R5, rnhi");
10456 assert_eq!(hw[3], 0x4664, "MOV R4, R12");
10457 }
10458
10459 #[test]
10462 fn test_632_a32_i64_popcnt_result_survives_scratch_restore() {
10463 let encoder = ArmEncoder::new_arm32();
10464 for rd in [Reg::R0, Reg::R3, Reg::R4, Reg::R5, Reg::R8] {
10465 let code = encoder
10466 .encode(&ArmOp::I64Popcnt {
10467 rd,
10468 rnlo: Reg::R6,
10469 rnhi: Reg::R7,
10470 })
10471 .unwrap();
10472 let words: Vec<u32> = code
10473 .chunks(4)
10474 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
10475 .collect();
10476 let pop = words
10477 .iter()
10478 .position(|&w| w == 0xE8BD_0038)
10479 .expect("POP {R3,R4,R5} present");
10480 assert_eq!(words[pop - 1], 0xE084_C005, "ADD R12, R4, R5 before POP");
10481 let rd_bits = match rd {
10482 Reg::R8 => 8u32,
10483 Reg::R5 => 5,
10484 Reg::R4 => 4,
10485 Reg::R3 => 3,
10486 _ => 0,
10487 };
10488 assert_eq!(
10489 words[pop + 1],
10490 0xE1A0_0000 | (rd_bits << 12) | 12,
10491 "MOV rd, R12 after the restore"
10492 );
10493 }
10494 }
10495
10496 #[test]
10500 fn test_633_i64_divs_overflow_guard_emitted() {
10501 let encoder = ArmEncoder::new_thumb2();
10502 let code = encoder
10503 .encode(&ArmOp::I64DivS {
10504 rdlo: Reg::R4,
10505 rdhi: Reg::R5,
10506 rnlo: Reg::R0,
10507 rnhi: Reg::R1,
10508 rmlo: Reg::R2,
10509 rmhi: Reg::R3,
10510 elide_zero_guard: false,
10511 elide_overflow_guard: false,
10512 })
10513 .unwrap();
10514 let guard: Vec<u16> = code[34..56]
10516 .chunks(2)
10517 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10518 .collect();
10519 assert_eq!(
10520 guard,
10521 vec![
10522 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100, 0xDE00, ],
10531 "INT64_MIN/-1 overflow guard after the zero-divisor guard"
10532 );
10533 }
10534
10535 #[test]
10539 fn test_633_i64_rems_has_no_overflow_guard() {
10540 let encoder = ArmEncoder::new_thumb2();
10541 for (is_rem_s, op) in [
10542 (
10543 true,
10544 ArmOp::I64RemS {
10545 rdlo: Reg::R4,
10546 rdhi: Reg::R5,
10547 rnlo: Reg::R0,
10548 rnhi: Reg::R1,
10549 rmlo: Reg::R2,
10550 rmhi: Reg::R3,
10551 elide_zero_guard: false,
10552 },
10553 ),
10554 (
10555 false,
10556 ArmOp::I64DivS {
10557 rdlo: Reg::R4,
10558 rdhi: Reg::R5,
10559 rnlo: Reg::R0,
10560 rnhi: Reg::R1,
10561 rmlo: Reg::R2,
10562 rmhi: Reg::R3,
10563 elide_zero_guard: false,
10564 elide_overflow_guard: false,
10565 },
10566 ),
10567 ] {
10568 let code = encoder.encode(&op).unwrap();
10569 let udfs = code
10570 .chunks(2)
10571 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
10572 .count();
10573 let want = if is_rem_s { 1 } else { 2 };
10574 assert_eq!(
10575 udfs, want,
10576 "rem_s: zero-trap only; div_s: zero-trap + overflow trap"
10577 );
10578 }
10579 }
10580
10581 #[test]
10585 fn test_494_i64_zero_guard_elision_is_exact_splice() {
10586 let encoder = ArmEncoder::new_thumb2();
10587 let mk = |elide_zero_guard: bool| {
10588 encoder
10589 .encode(&ArmOp::I64DivU {
10590 rdlo: Reg::R4,
10591 rdhi: Reg::R5,
10592 rnlo: Reg::R0,
10593 rnhi: Reg::R1,
10594 rmlo: Reg::R2,
10595 rmhi: Reg::R3,
10596 elide_zero_guard,
10597 })
10598 .unwrap()
10599 };
10600 let full = mk(false);
10601 let elided = mk(true);
10602 assert_eq!(full.len(), elided.len() + 8, "zero guard is 8 bytes");
10603 assert_eq!(&full[..26], &elided[..26]);
10605 assert_eq!(
10606 &full[26..34],
10607 &[0x52, 0xEA, 0x03, 0x0C, 0x00, 0xD1, 0x00, 0xDE],
10608 "the spliced-out bytes are exactly ORRS.W; BNE; UDF #0"
10609 );
10610 assert_eq!(&full[34..], &elided[26..]);
10611 }
10612
10613 #[test]
10618 fn test_494_i64_divs_overflow_guard_retained_when_only_zero_elided() {
10619 let encoder = ArmEncoder::new_thumb2();
10620 let mk = |zero: bool, ovf: bool| {
10621 encoder
10622 .encode(&ArmOp::I64DivS {
10623 rdlo: Reg::R4,
10624 rdhi: Reg::R5,
10625 rnlo: Reg::R0,
10626 rnhi: Reg::R1,
10627 rmlo: Reg::R2,
10628 rmhi: Reg::R3,
10629 elide_zero_guard: zero,
10630 elide_overflow_guard: ovf,
10631 })
10632 .unwrap()
10633 };
10634 let udf_count = |code: &[u8]| {
10635 code.chunks(2)
10636 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
10637 .count()
10638 };
10639 let full = mk(false, false);
10640 let zero_only = mk(true, false);
10641 let both = mk(true, true);
10642 assert_eq!(udf_count(&full), 2, "baseline: zero trap + overflow trap");
10643 assert_eq!(
10644 udf_count(&zero_only),
10645 1,
10646 "divisor-nonzero elides the zero trap ONLY — the #633 overflow \
10647 guard must be retained"
10648 );
10649 let guard: Vec<u16> = zero_only[26..48]
10652 .chunks(2)
10653 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10654 .collect();
10655 assert_eq!(
10656 guard,
10657 vec![
10658 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100,
10659 0xDE00,
10660 ],
10661 "the surviving guard is the INT64_MIN/-1 overflow trap"
10662 );
10663 assert_eq!(full.len(), zero_only.len() + 8);
10664 assert_eq!(zero_only.len(), both.len() + 22);
10665 assert_eq!(udf_count(&both), 0, "both obligations discharged ⇒ no UDF");
10666 }
10667
10668 #[test]
10671 fn test_494_a32_i64_guard_elision() {
10672 let encoder = ArmEncoder::new_arm32();
10673 let mk = |zero: bool, ovf: bool| {
10674 encoder
10675 .encode(&ArmOp::I64DivS {
10676 rdlo: Reg::R4,
10677 rdhi: Reg::R5,
10678 rnlo: Reg::R0,
10679 rnhi: Reg::R1,
10680 rmlo: Reg::R2,
10681 rmhi: Reg::R3,
10682 elide_zero_guard: zero,
10683 elide_overflow_guard: ovf,
10684 })
10685 .unwrap()
10686 };
10687 let full = mk(false, false);
10688 let zero_only = mk(true, false);
10689 let both = mk(true, true);
10690 assert_eq!(full.len(), zero_only.len() + 12);
10692 assert_eq!(zero_only.len(), both.len() + 24);
10693 let udf_count = |code: &[u8]| {
10694 code.chunks(4)
10695 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
10696 .count()
10697 };
10698 assert_eq!(udf_count(&full), 2);
10699 assert_eq!(
10700 udf_count(&zero_only),
10701 1,
10702 "A32: overflow guard retained under zero-only elision"
10703 );
10704 assert_eq!(udf_count(&both), 0);
10705 }
10706
10707 #[test]
10710 fn test_633_a32_i64_divs_overflow_guard() {
10711 let encoder = ArmEncoder::new_arm32();
10712 let mk_divs = ArmOp::I64DivS {
10713 rdlo: Reg::R4,
10714 rdhi: Reg::R5,
10715 rnlo: Reg::R0,
10716 rnhi: Reg::R1,
10717 rmlo: Reg::R2,
10718 rmhi: Reg::R3,
10719 elide_zero_guard: false,
10720 elide_overflow_guard: false,
10721 };
10722 let code = encoder.encode(&mk_divs).unwrap();
10723 let words: Vec<u32> = code
10724 .chunks(4)
10725 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
10726 .collect();
10727 let guard = [
10728 0xE002_C003u32, 0xE37C_0001, 0x0350_0000, 0x0351_0102, 0x1A00_0000, 0xE7F0_00F0, ];
10735 assert!(
10736 words.windows(6).any(|w| w == guard),
10737 "A32 I64DivS carries the INT64_MIN/-1 overflow guard"
10738 );
10739 let rems = encoder
10740 .encode(&ArmOp::I64RemS {
10741 rdlo: Reg::R4,
10742 rdhi: Reg::R5,
10743 rnlo: Reg::R0,
10744 rnhi: Reg::R1,
10745 rmlo: Reg::R2,
10746 rmhi: Reg::R3,
10747 elide_zero_guard: false,
10748 })
10749 .unwrap();
10750 let rems_udfs = rems
10751 .chunks(4)
10752 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
10753 .count();
10754 assert_eq!(rems_udfs, 1, "A32 I64RemS keeps only the zero-divisor trap");
10755 }
10756
10757 #[test]
10758 fn test_encode_nop_thumb2() {
10759 let encoder = ArmEncoder::new_thumb2();
10760 let op = ArmOp::Nop;
10761 let code = encoder.encode(&op).unwrap();
10762 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]);
10766 }
10767
10768 #[test]
10773 fn test_encode_i64_add_thumb2() {
10774 let encoder = ArmEncoder::new_thumb2();
10775 let op = ArmOp::I64Add {
10776 rdlo: Reg::R0,
10777 rdhi: Reg::R1,
10778 rnlo: Reg::R0,
10779 rnhi: Reg::R1,
10780 rmlo: Reg::R2,
10781 rmhi: Reg::R3,
10782 };
10783 let code = encoder.encode(&op).unwrap();
10784 assert_eq!(code.len(), 6, "I64Add should be 6 bytes (ADDS + ADC.W)");
10786 }
10787
10788 #[test]
10789 fn test_encode_i64_sub_thumb2() {
10790 let encoder = ArmEncoder::new_thumb2();
10791 let op = ArmOp::I64Sub {
10792 rdlo: Reg::R0,
10793 rdhi: Reg::R1,
10794 rnlo: Reg::R0,
10795 rnhi: Reg::R1,
10796 rmlo: Reg::R2,
10797 rmhi: Reg::R3,
10798 };
10799 let code = encoder.encode(&op).unwrap();
10800 assert_eq!(code.len(), 6, "I64Sub should be 6 bytes (SUBS + SBC.W)");
10802 }
10803
10804 #[test]
10805 fn test_encode_i64_and_thumb2() {
10806 let encoder = ArmEncoder::new_thumb2();
10807 let op = ArmOp::I64And {
10808 rdlo: Reg::R0,
10809 rdhi: Reg::R1,
10810 rnlo: Reg::R0,
10811 rnhi: Reg::R1,
10812 rmlo: Reg::R2,
10813 rmhi: Reg::R3,
10814 };
10815 let code = encoder.encode(&op).unwrap();
10816 assert!(code.len() >= 4, "I64And should emit at least 4 bytes");
10818 }
10819
10820 #[test]
10821 fn test_encode_i64_or_thumb2() {
10822 let encoder = ArmEncoder::new_thumb2();
10823 let op = ArmOp::I64Or {
10824 rdlo: Reg::R0,
10825 rdhi: Reg::R1,
10826 rnlo: Reg::R0,
10827 rnhi: Reg::R1,
10828 rmlo: Reg::R2,
10829 rmhi: Reg::R3,
10830 };
10831 let code = encoder.encode(&op).unwrap();
10832 assert!(code.len() >= 4, "I64Or should emit at least 4 bytes");
10833 }
10834
10835 #[test]
10836 fn test_encode_i64_xor_thumb2() {
10837 let encoder = ArmEncoder::new_thumb2();
10838 let op = ArmOp::I64Xor {
10839 rdlo: Reg::R0,
10840 rdhi: Reg::R1,
10841 rnlo: Reg::R0,
10842 rnhi: Reg::R1,
10843 rmlo: Reg::R2,
10844 rmhi: Reg::R3,
10845 };
10846 let code = encoder.encode(&op).unwrap();
10847 assert!(code.len() >= 4, "I64Xor should emit at least 4 bytes");
10848 }
10849
10850 #[test]
10851 fn test_encode_i64_const_small_thumb2() {
10852 let encoder = ArmEncoder::new_thumb2();
10853 let op = ArmOp::I64Const {
10855 rdlo: Reg::R0,
10856 rdhi: Reg::R1,
10857 value: 42,
10858 };
10859 let code = encoder.encode(&op).unwrap();
10860 assert!(code.len() >= 8, "I64Const should emit at least 8 bytes");
10862 }
10863
10864 #[test]
10865 fn test_encode_i64_const_large_thumb2() {
10866 let encoder = ArmEncoder::new_thumb2();
10867 let op = ArmOp::I64Const {
10869 rdlo: Reg::R0,
10870 rdhi: Reg::R1,
10871 value: 0x1234_5678_9ABC_DEF0_u64 as i64,
10872 };
10873 let code = encoder.encode(&op).unwrap();
10874 assert_eq!(
10876 code.len(),
10877 16,
10878 "I64Const with large value should be 16 bytes"
10879 );
10880 }
10881
10882 #[test]
10883 fn test_encode_i64_extend_i32_s_thumb2() {
10884 let encoder = ArmEncoder::new_thumb2();
10885 let op = ArmOp::I64ExtendI32S {
10886 rdlo: Reg::R0,
10887 rdhi: Reg::R1,
10888 rn: Reg::R0,
10889 };
10890 let code = encoder.encode(&op).unwrap();
10891 assert_eq!(
10893 code.len(),
10894 4,
10895 "I64ExtendI32S (same reg) should be 4 bytes (ASR only)"
10896 );
10897 }
10898
10899 #[test]
10900 fn test_encode_i64_extend_i32_s_diff_reg_thumb2() {
10901 let encoder = ArmEncoder::new_thumb2();
10902 let op = ArmOp::I64ExtendI32S {
10903 rdlo: Reg::R0,
10904 rdhi: Reg::R1,
10905 rn: Reg::R2,
10906 };
10907 let code = encoder.encode(&op).unwrap();
10908 assert!(
10910 code.len() >= 6,
10911 "I64ExtendI32S (diff reg) should be at least 6 bytes"
10912 );
10913 }
10914
10915 #[test]
10916 fn test_encode_i64_extend_i32_u_thumb2() {
10917 let encoder = ArmEncoder::new_thumb2();
10918 let op = ArmOp::I64ExtendI32U {
10919 rdlo: Reg::R0,
10920 rdhi: Reg::R1,
10921 rn: Reg::R0,
10922 };
10923 let code = encoder.encode(&op).unwrap();
10924 assert_eq!(
10926 code.len(),
10927 2,
10928 "I64ExtendI32U (same reg) should be 2 bytes (MOV #0 only)"
10929 );
10930 }
10931
10932 #[test]
10933 fn test_encode_i32_wrap_i64_nop_thumb2() {
10934 let encoder = ArmEncoder::new_thumb2();
10935 let op = ArmOp::I32WrapI64 {
10937 rd: Reg::R0,
10938 rnlo: Reg::R0,
10939 };
10940 let code = encoder.encode(&op).unwrap();
10941 assert_eq!(code.len(), 2, "I32WrapI64 same reg should be NOP (2 bytes)");
10942 assert_eq!(code, vec![0x00, 0xBF]); }
10944
10945 #[test]
10946 fn test_encode_i32_wrap_i64_diff_reg_thumb2() {
10947 let encoder = ArmEncoder::new_thumb2();
10948 let op = ArmOp::I32WrapI64 {
10949 rd: Reg::R2,
10950 rnlo: Reg::R0,
10951 };
10952 let code = encoder.encode(&op).unwrap();
10953 assert!(
10955 code.len() >= 2,
10956 "I32WrapI64 diff reg should emit at least 2 bytes"
10957 );
10958 }
10959
10960 #[test]
10961 fn test_encode_i64_eqz_thumb2() {
10962 let encoder = ArmEncoder::new_thumb2();
10963 let op = ArmOp::I64Eqz {
10964 rd: Reg::R0,
10965 rnlo: Reg::R0,
10966 rnhi: Reg::R1,
10967 };
10968 let code = encoder.encode(&op).unwrap();
10969 assert!(
10971 code.len() >= 6,
10972 "I64Eqz should emit at least 6 bytes for ORR+ITE+MOV+MOV"
10973 );
10974 }
10975
10976 #[test]
10977 fn test_encode_i64_eq_thumb2() {
10978 let encoder = ArmEncoder::new_thumb2();
10979 let op = ArmOp::I64Eq {
10980 rd: Reg::R0,
10981 rnlo: Reg::R0,
10982 rnhi: Reg::R1,
10983 rmlo: Reg::R2,
10984 rmhi: Reg::R3,
10985 };
10986 let code = encoder.encode(&op).unwrap();
10987 assert!(code.len() >= 10, "I64Eq should emit at least 10 bytes");
10989 }
10990
10991 #[test]
10992 fn test_encode_i64_ldr_thumb2() {
10993 let encoder = ArmEncoder::new_thumb2();
10994 let op = ArmOp::I64Ldr {
10995 rdlo: Reg::R0,
10996 rdhi: Reg::R1,
10997 addr: MemAddr::imm(Reg::SP, 0),
10998 };
10999 let code = encoder.encode(&op).unwrap();
11000 assert!(code.len() >= 4, "I64Ldr should emit at least 4 bytes");
11002 }
11003
11004 #[test]
11005 fn test_372_i64_ldr_indexed_materializes_address() {
11006 let encoder = ArmEncoder::new_thumb2();
11011 let indexed = encoder
11012 .encode(&ArmOp::I64Ldr {
11013 rdlo: Reg::R0,
11014 rdhi: Reg::R1,
11015 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 0),
11016 })
11017 .unwrap();
11018 assert_eq!(
11020 &indexed[0..4],
11021 &[0x0b, 0xeb, 0x00, 0x0c],
11022 "indexed I64Ldr must start with ADD.W ip, base, index"
11023 );
11024 let frame = encoder
11025 .encode(&ArmOp::I64Ldr {
11026 rdlo: Reg::R0,
11027 rdhi: Reg::R1,
11028 addr: MemAddr::imm(Reg::SP, 8),
11029 })
11030 .unwrap();
11031 assert_ne!(
11033 &frame[0..2],
11034 &[0x0b, 0xeb],
11035 "frame (non-indexed) I64Ldr must NOT emit an ADD.W"
11036 );
11037 }
11038
11039 #[test]
11040 fn test_382_i64_ldst_large_offset_materializes_not_skips() {
11041 let encoder = ArmEncoder::new_thumb2();
11047 let ld = encoder
11050 .encode(&ArmOp::I64Ldr {
11051 rdlo: Reg::R0,
11052 rdhi: Reg::R1,
11053 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
11054 })
11055 .expect("large-offset i64.load must lower, not skip");
11056 assert_eq!(ld.len(), 20, "expected MOVW + 2×ADD + 2×LDR");
11058 assert_ne!(
11061 &ld[0..2],
11062 &[0x0b, 0xeb],
11063 "must materialize the large offset"
11064 );
11065 assert_eq!(
11067 &ld[4..20],
11068 &[
11069 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xdc, 0xf8, 0x00, 0x00, 0xdc, 0xf8, 0x04, 0x10, ],
11074 "large-offset i64.load must fold offset into ip and access [ip,#0]/[ip,#4]"
11075 );
11076
11077 let st = encoder
11079 .encode(&ArmOp::I64Str {
11080 rdlo: Reg::R2,
11081 rdhi: Reg::R3,
11082 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
11083 })
11084 .expect("large-offset i64.store must lower, not skip");
11085 assert_eq!(st.len(), 20);
11086 assert_eq!(
11087 &st[4..20],
11088 &[
11089 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xcc, 0xf8, 0x00, 0x20, 0xcc, 0xf8, 0x04, 0x30, ],
11094 "large-offset i64.store must fold offset into ip and access [ip,#0]/[ip,#4]"
11095 );
11096
11097 let small = encoder
11101 .encode(&ArmOp::I64Ldr {
11102 rdlo: Reg::R0,
11103 rdhi: Reg::R1,
11104 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 8),
11105 })
11106 .unwrap();
11107 assert_eq!(
11108 &small[0..4],
11109 &[0x0b, 0xeb, 0x00, 0x0c],
11110 "small-offset indexed i64 must keep the single ADD.W ip, fp, r0"
11111 );
11112 assert_eq!(small.len(), 12, "ADD.W + 2×LDR.W (offset folded in imm12)");
11113 }
11114
11115 #[test]
11116 fn test_encode_i64_str_thumb2() {
11117 let encoder = ArmEncoder::new_thumb2();
11118 let op = ArmOp::I64Str {
11119 rdlo: Reg::R0,
11120 rdhi: Reg::R1,
11121 addr: MemAddr::imm(Reg::SP, 0),
11122 };
11123 let code = encoder.encode(&op).unwrap();
11124 assert!(code.len() >= 4, "I64Str should emit at least 4 bytes");
11126 }
11127
11128 #[test]
11129 fn test_encode_i64_all_comparisons_thumb2() {
11130 let encoder = ArmEncoder::new_thumb2();
11131
11132 let ops = vec![
11133 ArmOp::I64Ne {
11134 rd: Reg::R0,
11135 rnlo: Reg::R0,
11136 rnhi: Reg::R1,
11137 rmlo: Reg::R2,
11138 rmhi: Reg::R3,
11139 },
11140 ArmOp::I64LtS {
11141 rd: Reg::R0,
11142 rnlo: Reg::R0,
11143 rnhi: Reg::R1,
11144 rmlo: Reg::R2,
11145 rmhi: Reg::R3,
11146 },
11147 ArmOp::I64LtU {
11148 rd: Reg::R0,
11149 rnlo: Reg::R0,
11150 rnhi: Reg::R1,
11151 rmlo: Reg::R2,
11152 rmhi: Reg::R3,
11153 },
11154 ArmOp::I64LeS {
11155 rd: Reg::R0,
11156 rnlo: Reg::R0,
11157 rnhi: Reg::R1,
11158 rmlo: Reg::R2,
11159 rmhi: Reg::R3,
11160 },
11161 ArmOp::I64LeU {
11162 rd: Reg::R0,
11163 rnlo: Reg::R0,
11164 rnhi: Reg::R1,
11165 rmlo: Reg::R2,
11166 rmhi: Reg::R3,
11167 },
11168 ArmOp::I64GtS {
11169 rd: Reg::R0,
11170 rnlo: Reg::R0,
11171 rnhi: Reg::R1,
11172 rmlo: Reg::R2,
11173 rmhi: Reg::R3,
11174 },
11175 ArmOp::I64GtU {
11176 rd: Reg::R0,
11177 rnlo: Reg::R0,
11178 rnhi: Reg::R1,
11179 rmlo: Reg::R2,
11180 rmhi: Reg::R3,
11181 },
11182 ArmOp::I64GeS {
11183 rd: Reg::R0,
11184 rnlo: Reg::R0,
11185 rnhi: Reg::R1,
11186 rmlo: Reg::R2,
11187 rmhi: Reg::R3,
11188 },
11189 ArmOp::I64GeU {
11190 rd: Reg::R0,
11191 rnlo: Reg::R0,
11192 rnhi: Reg::R1,
11193 rmlo: Reg::R2,
11194 rmhi: Reg::R3,
11195 },
11196 ];
11197
11198 for op in &ops {
11199 let code = encoder.encode(op).unwrap();
11200 assert!(
11201 code.len() >= 8,
11202 "i64 comparison {:?} should emit at least 8 bytes, got {}",
11203 op,
11204 code.len()
11205 );
11206 }
11207 }
11208
11209 #[test]
11210 fn test_encode_i64_const_zero_thumb2() {
11211 let encoder = ArmEncoder::new_thumb2();
11212 let op = ArmOp::I64Const {
11213 rdlo: Reg::R0,
11214 rdhi: Reg::R1,
11215 value: 0,
11216 };
11217 let code = encoder.encode(&op).unwrap();
11218 assert_eq!(code.len(), 8, "I64Const(0) should be 8 bytes");
11220 }
11221
11222 #[test]
11223 fn test_encode_i64_const_negative_one_thumb2() {
11224 let encoder = ArmEncoder::new_thumb2();
11225 let op = ArmOp::I64Const {
11226 rdlo: Reg::R0,
11227 rdhi: Reg::R1,
11228 value: -1, };
11230 let code = encoder.encode(&op).unwrap();
11231 assert_eq!(code.len(), 16, "I64Const(-1) should be 16 bytes");
11233 }
11234
11235 #[test]
11240 fn test_encode_ldrb_arm32() {
11241 let encoder = ArmEncoder::new_arm32();
11242 let op = ArmOp::Ldrb {
11243 rd: Reg::R0,
11244 addr: MemAddr::imm(Reg::R1, 4),
11245 };
11246 let code = encoder.encode(&op).unwrap();
11247 assert_eq!(code.len(), 4, "ARM32 LDRB should be 4 bytes");
11248 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11250 assert_eq!(encoded, 0xE5D10004, "Should encode LDRB R0, [R1, #4]");
11251 }
11252
11253 #[test]
11254 fn test_encode_strb_arm32() {
11255 let encoder = ArmEncoder::new_arm32();
11256 let op = ArmOp::Strb {
11257 rd: Reg::R0,
11258 addr: MemAddr::imm(Reg::R1, 0),
11259 };
11260 let code = encoder.encode(&op).unwrap();
11261 assert_eq!(code.len(), 4, "ARM32 STRB should be 4 bytes");
11262 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11264 assert_eq!(encoded, 0xE5C10000, "Should encode STRB R0, [R1, #0]");
11265 }
11266
11267 #[test]
11268 fn test_encode_ldrh_arm32() {
11269 let encoder = ArmEncoder::new_arm32();
11270 let op = ArmOp::Ldrh {
11271 rd: Reg::R0,
11272 addr: MemAddr::imm(Reg::R1, 2),
11273 };
11274 let code = encoder.encode(&op).unwrap();
11275 assert_eq!(code.len(), 4, "ARM32 LDRH should be 4 bytes");
11276 }
11277
11278 #[test]
11279 fn test_encode_strh_arm32() {
11280 let encoder = ArmEncoder::new_arm32();
11281 let op = ArmOp::Strh {
11282 rd: Reg::R0,
11283 addr: MemAddr::imm(Reg::R1, 0),
11284 };
11285 let code = encoder.encode(&op).unwrap();
11286 assert_eq!(code.len(), 4, "ARM32 STRH should be 4 bytes");
11287 }
11288
11289 #[test]
11290 fn test_encode_ldrsb_arm32() {
11291 let encoder = ArmEncoder::new_arm32();
11292 let op = ArmOp::Ldrsb {
11293 rd: Reg::R0,
11294 addr: MemAddr::imm(Reg::R1, 0),
11295 };
11296 let code = encoder.encode(&op).unwrap();
11297 assert_eq!(code.len(), 4, "ARM32 LDRSB should be 4 bytes");
11298 }
11299
11300 #[test]
11301 fn test_encode_ldrsh_arm32() {
11302 let encoder = ArmEncoder::new_arm32();
11303 let op = ArmOp::Ldrsh {
11304 rd: Reg::R0,
11305 addr: MemAddr::imm(Reg::R1, 0),
11306 };
11307 let code = encoder.encode(&op).unwrap();
11308 assert_eq!(code.len(), 4, "ARM32 LDRSH should be 4 bytes");
11309 }
11310
11311 #[test]
11312 fn test_encode_ldrb_thumb2_16bit() {
11313 let encoder = ArmEncoder::new_thumb2();
11314 let op = ArmOp::Ldrb {
11315 rd: Reg::R0,
11316 addr: MemAddr::imm(Reg::R1, 4),
11317 };
11318 let code = encoder.encode(&op).unwrap();
11319 assert_eq!(
11321 code.len(),
11322 2,
11323 "Thumb-2 LDRB with small offset should be 16-bit"
11324 );
11325 }
11326
11327 #[test]
11328 fn test_encode_ldrb_thumb2_32bit() {
11329 let encoder = ArmEncoder::new_thumb2();
11330 let op = ArmOp::Ldrb {
11331 rd: Reg::R0,
11332 addr: MemAddr::imm(Reg::R1, 100), };
11334 let code = encoder.encode(&op).unwrap();
11335 assert_eq!(
11336 code.len(),
11337 4,
11338 "Thumb-2 LDRB with large offset should be 32-bit"
11339 );
11340 }
11341
11342 #[test]
11343 fn test_encode_strb_thumb2_16bit() {
11344 let encoder = ArmEncoder::new_thumb2();
11345 let op = ArmOp::Strb {
11346 rd: Reg::R0,
11347 addr: MemAddr::imm(Reg::R1, 10),
11348 };
11349 let code = encoder.encode(&op).unwrap();
11350 assert_eq!(
11351 code.len(),
11352 2,
11353 "Thumb-2 STRB with small offset should be 16-bit"
11354 );
11355 }
11356
11357 #[test]
11358 fn test_encode_ldrh_thumb2_16bit() {
11359 let encoder = ArmEncoder::new_thumb2();
11360 let op = ArmOp::Ldrh {
11361 rd: Reg::R0,
11362 addr: MemAddr::imm(Reg::R1, 4), };
11364 let code = encoder.encode(&op).unwrap();
11365 assert_eq!(
11366 code.len(),
11367 2,
11368 "Thumb-2 LDRH with small aligned offset should be 16-bit"
11369 );
11370 }
11371
11372 #[test]
11373 fn test_encode_strh_thumb2_16bit() {
11374 let encoder = ArmEncoder::new_thumb2();
11375 let op = ArmOp::Strh {
11376 rd: Reg::R0,
11377 addr: MemAddr::imm(Reg::R1, 4),
11378 };
11379 let code = encoder.encode(&op).unwrap();
11380 assert_eq!(
11381 code.len(),
11382 2,
11383 "Thumb-2 STRH with small aligned offset should be 16-bit"
11384 );
11385 }
11386
11387 #[test]
11388 fn test_encode_ldrsb_thumb2() {
11389 let encoder = ArmEncoder::new_thumb2();
11390 let op = ArmOp::Ldrsb {
11391 rd: Reg::R0,
11392 addr: MemAddr::imm(Reg::R1, 0),
11393 };
11394 let code = encoder.encode(&op).unwrap();
11395 assert_eq!(code.len(), 4, "Thumb-2 LDRSB should be 32-bit");
11397 }
11398
11399 #[test]
11400 fn test_encode_ldrsh_thumb2() {
11401 let encoder = ArmEncoder::new_thumb2();
11402 let op = ArmOp::Ldrsh {
11403 rd: Reg::R0,
11404 addr: MemAddr::imm(Reg::R1, 0),
11405 };
11406 let code = encoder.encode(&op).unwrap();
11407 assert_eq!(code.len(), 4, "Thumb-2 LDRSH should be 32-bit");
11408 }
11409
11410 #[test]
11411 fn test_encode_memory_size_thumb2() {
11412 let encoder = ArmEncoder::new_thumb2();
11413 let op = ArmOp::MemorySize { rd: Reg::R0 };
11414 let code = encoder.encode(&op).unwrap();
11415 assert!(!code.is_empty(), "MemorySize should produce code");
11417 }
11418
11419 #[test]
11420 fn test_encode_memory_grow_thumb2() {
11421 let encoder = ArmEncoder::new_thumb2();
11422 let op = ArmOp::MemoryGrow {
11423 rd: Reg::R0,
11424 rn: Reg::R0,
11425 };
11426 let code = encoder.encode(&op).unwrap();
11427 assert_eq!(code.len(), 4, "MemoryGrow (MVN) should be 32-bit Thumb-2");
11428 }
11429
11430 #[test]
11431 fn test_encode_subword_reg_offset_thumb2() {
11432 let encoder = ArmEncoder::new_thumb2();
11433
11434 let op = ArmOp::Ldrb {
11436 rd: Reg::R0,
11437 addr: MemAddr::reg(Reg::R1, Reg::R2),
11438 };
11439 let code = encoder.encode(&op).unwrap();
11440 assert_eq!(
11441 code.len(),
11442 4,
11443 "Thumb-2 LDRB with reg offset should be 32-bit"
11444 );
11445
11446 let op = ArmOp::Strb {
11448 rd: Reg::R0,
11449 addr: MemAddr::reg(Reg::R1, Reg::R2),
11450 };
11451 let code = encoder.encode(&op).unwrap();
11452 assert_eq!(
11453 code.len(),
11454 4,
11455 "Thumb-2 STRB with reg offset should be 32-bit"
11456 );
11457
11458 let op = ArmOp::Ldrh {
11460 rd: Reg::R0,
11461 addr: MemAddr::reg(Reg::R1, Reg::R2),
11462 };
11463 let code = encoder.encode(&op).unwrap();
11464 assert_eq!(
11465 code.len(),
11466 4,
11467 "Thumb-2 LDRH with reg offset should be 32-bit"
11468 );
11469
11470 let op = ArmOp::Strh {
11472 rd: Reg::R0,
11473 addr: MemAddr::reg(Reg::R1, Reg::R2),
11474 };
11475 let code = encoder.encode(&op).unwrap();
11476 assert_eq!(
11477 code.len(),
11478 4,
11479 "Thumb-2 STRH with reg offset should be 32-bit"
11480 );
11481 }
11482
11483 #[test]
11484 fn test_encode_subword_reg_imm_offset_thumb2() {
11485 let encoder = ArmEncoder::new_thumb2();
11486
11487 let op = ArmOp::Ldrb {
11489 rd: Reg::R0,
11490 addr: MemAddr::reg_imm(Reg::R1, Reg::R2, 4),
11491 };
11492 let code = encoder.encode(&op).unwrap();
11493 assert_eq!(
11495 code.len(),
11496 8,
11497 "Thumb-2 LDRB with reg+imm offset should be 8 bytes"
11498 );
11499 }
11500
11501 #[test]
11506 fn test_encode_mve_addi32_thumb2() {
11507 let encoder = ArmEncoder::new_thumb2();
11508 let op = ArmOp::MveAddI {
11509 qd: QReg::Q0,
11510 qn: QReg::Q1,
11511 qm: QReg::Q2,
11512 size: MveSize::S32,
11513 };
11514 let code = encoder.encode(&op).unwrap();
11515 assert_eq!(
11516 code.len(),
11517 4,
11518 "MVE VADD.I32 should be 4 bytes (Thumb-2 32-bit)"
11519 );
11520 }
11521
11522 #[test]
11523 fn test_encode_mve_subi16_thumb2() {
11524 let encoder = ArmEncoder::new_thumb2();
11525 let op = ArmOp::MveSubI {
11526 qd: QReg::Q0,
11527 qn: QReg::Q1,
11528 qm: QReg::Q2,
11529 size: MveSize::S16,
11530 };
11531 let code = encoder.encode(&op).unwrap();
11532 assert_eq!(code.len(), 4, "MVE VSUB.I16 should be 4 bytes");
11533 }
11534
11535 #[test]
11536 fn test_encode_mve_muli8_thumb2() {
11537 let encoder = ArmEncoder::new_thumb2();
11538 let op = ArmOp::MveMulI {
11539 qd: QReg::Q0,
11540 qn: QReg::Q1,
11541 qm: QReg::Q2,
11542 size: MveSize::S8,
11543 };
11544 let code = encoder.encode(&op).unwrap();
11545 assert_eq!(code.len(), 4, "MVE VMUL.I8 should be 4 bytes");
11546 }
11547
11548 #[test]
11549 fn test_encode_mve_bitwise_thumb2() {
11550 let encoder = ArmEncoder::new_thumb2();
11551
11552 let ops = vec![
11553 ArmOp::MveAnd {
11554 qd: QReg::Q0,
11555 qn: QReg::Q1,
11556 qm: QReg::Q2,
11557 },
11558 ArmOp::MveOrr {
11559 qd: QReg::Q0,
11560 qn: QReg::Q1,
11561 qm: QReg::Q2,
11562 },
11563 ArmOp::MveEor {
11564 qd: QReg::Q0,
11565 qn: QReg::Q1,
11566 qm: QReg::Q2,
11567 },
11568 ArmOp::MveBic {
11569 qd: QReg::Q0,
11570 qn: QReg::Q1,
11571 qm: QReg::Q2,
11572 },
11573 ];
11574 for op in ops {
11575 let code = encoder.encode(&op).unwrap();
11576 assert_eq!(code.len(), 4, "MVE bitwise op should be 4 bytes");
11577 }
11578 }
11579
11580 #[test]
11581 fn test_encode_mve_mvn_thumb2() {
11582 let encoder = ArmEncoder::new_thumb2();
11583 let op = ArmOp::MveMvn {
11584 qd: QReg::Q0,
11585 qm: QReg::Q1,
11586 };
11587 let code = encoder.encode(&op).unwrap();
11588 assert_eq!(code.len(), 4, "MVE VMVN should be 4 bytes");
11589 }
11590
11591 #[test]
11592 fn test_encode_mve_load_store_thumb2() {
11593 let encoder = ArmEncoder::new_thumb2();
11594
11595 let load = ArmOp::MveLoad {
11596 qd: QReg::Q0,
11597 addr: MemAddr::imm(Reg::R0, 16),
11598 };
11599 let code = encoder.encode(&load).unwrap();
11600 assert_eq!(code.len(), 4, "MVE VLDRW.32 should be 4 bytes");
11601
11602 let store = ArmOp::MveStore {
11603 qd: QReg::Q1,
11604 addr: MemAddr::imm(Reg::R1, 0),
11605 };
11606 let code = encoder.encode(&store).unwrap();
11607 assert_eq!(code.len(), 4, "MVE VSTRW.32 should be 4 bytes");
11608 }
11609
11610 #[test]
11611 fn test_encode_mve_const_thumb2() {
11612 let encoder = ArmEncoder::new_thumb2();
11613 let op = ArmOp::MveConst {
11614 qd: QReg::Q0,
11615 bytes: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0],
11616 };
11617 let code = encoder.encode(&op).unwrap();
11618 assert!(
11621 code.len() >= 24,
11622 "MVE const should produce multiple instructions"
11623 );
11624 }
11625
11626 #[test]
11627 fn test_encode_mve_dup_thumb2() {
11628 let encoder = ArmEncoder::new_thumb2();
11629 let op = ArmOp::MveDup {
11630 qd: QReg::Q0,
11631 rn: Reg::R0,
11632 size: MveSize::S32,
11633 };
11634 let code = encoder.encode(&op).unwrap();
11635 assert_eq!(code.len(), 4, "MVE VDUP.32 should be 4 bytes");
11636 }
11637
11638 #[test]
11639 fn test_encode_mve_extract_lane_thumb2() {
11640 let encoder = ArmEncoder::new_thumb2();
11641 let op = ArmOp::MveExtractLane {
11642 rd: Reg::R0,
11643 qn: QReg::Q1,
11644 lane: 2,
11645 size: MveSize::S32,
11646 };
11647 let code = encoder.encode(&op).unwrap();
11648 assert_eq!(code.len(), 4, "MVE extract lane should be 4 bytes");
11649 }
11650
11651 #[test]
11652 fn test_encode_mve_insert_lane_thumb2() {
11653 let encoder = ArmEncoder::new_thumb2();
11654 let op = ArmOp::MveInsertLane {
11655 qd: QReg::Q0,
11656 rn: Reg::R1,
11657 lane: 3,
11658 size: MveSize::S32,
11659 };
11660 let code = encoder.encode(&op).unwrap();
11661 assert_eq!(code.len(), 4, "MVE insert lane should be 4 bytes");
11662 }
11663
11664 #[test]
11665 fn test_encode_mve_addf32_thumb2() {
11666 let encoder = ArmEncoder::new_thumb2();
11667 let op = ArmOp::MveAddF32 {
11668 qd: QReg::Q0,
11669 qn: QReg::Q1,
11670 qm: QReg::Q2,
11671 };
11672 let code = encoder.encode(&op).unwrap();
11673 assert_eq!(code.len(), 4, "MVE VADD.F32 should be 4 bytes");
11674 }
11675
11676 #[test]
11677 fn test_encode_mve_divf32_thumb2() {
11678 let encoder = ArmEncoder::new_thumb2();
11679 let op = ArmOp::MveDivF32 {
11680 qd: QReg::Q0,
11681 qn: QReg::Q1,
11682 qm: QReg::Q2,
11683 };
11684 let code = encoder.encode(&op).unwrap();
11685 assert_eq!(
11687 code.len(),
11688 16,
11689 "MVE VDIV.F32 (lane-wise) should be 16 bytes"
11690 );
11691 }
11692
11693 #[test]
11694 fn test_encode_mve_sqrtf32_thumb2() {
11695 let encoder = ArmEncoder::new_thumb2();
11696 let op = ArmOp::MveSqrtF32 {
11697 qd: QReg::Q0,
11698 qm: QReg::Q1,
11699 };
11700 let code = encoder.encode(&op).unwrap();
11701 assert_eq!(
11703 code.len(),
11704 16,
11705 "MVE VSQRT.F32 (lane-wise) should be 16 bytes"
11706 );
11707 }
11708
11709 #[test]
11710 fn test_encode_mve_negf32_thumb2() {
11711 let encoder = ArmEncoder::new_thumb2();
11712 let op = ArmOp::MveNegF32 {
11713 qd: QReg::Q0,
11714 qm: QReg::Q1,
11715 };
11716 let code = encoder.encode(&op).unwrap();
11717 assert_eq!(code.len(), 4, "MVE VNEG.F32 should be 4 bytes");
11718 }
11719
11720 #[test]
11721 fn test_encode_mve_absf32_thumb2() {
11722 let encoder = ArmEncoder::new_thumb2();
11723 let op = ArmOp::MveAbsF32 {
11724 qd: QReg::Q0,
11725 qm: QReg::Q1,
11726 };
11727 let code = encoder.encode(&op).unwrap();
11728 assert_eq!(code.len(), 4, "MVE VABS.F32 should be 4 bytes");
11729 }
11730
11731 #[test]
11746 fn and_immediate_encodes_correctly_in_byte_range_documents_fold_bound() {
11747 let encoder = ArmEncoder::new_thumb2();
11748 let op = ArmOp::And {
11749 rd: Reg::R2,
11750 rn: Reg::R0,
11751 op2: Operand2::Imm(0x7e),
11752 };
11753 let code = encoder.encode(&op).unwrap();
11754 assert_eq!(
11755 code,
11756 vec![0x00, 0xf0, 0x7e, 0x02],
11757 "and r2, r0, #0x7e must encode to the canonical AND.W T1 (imm8=0x7e)"
11758 );
11759 }
11760
11761 #[test]
11768 fn try_thumb_expand_imm_encodes_modified_immediates() {
11769 assert_eq!(try_thumb_expand_imm(0x7e), Some(0x07e)); assert_eq!(try_thumb_expand_imm(0xff), Some(0x0ff));
11771 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);
11779 assert_eq!(try_thumb_expand_imm(0x12345), None);
11780 }
11781
11782 #[test]
11787 fn cmp_adds_subs_immediate_error_on_non_modified_imm() {
11788 let encoder = ArmEncoder::new_thumb2();
11789 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 0xff).is_ok());
11791 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 1000).is_ok());
11792 assert!(
11794 encoder.encode_thumb32_cmp_imm(&Reg::R0, 0x101).is_err(),
11795 "cmp #0x101 must error, not compare the wrong constant"
11796 );
11797 assert!(
11798 encoder
11799 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x101)
11800 .is_err()
11801 );
11802 assert!(
11803 encoder
11804 .encode_thumb32_subs(&Reg::R0, &Reg::R0, 0x101)
11805 .is_err()
11806 );
11807 assert!(
11809 encoder
11810 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x80)
11811 .is_ok()
11812 );
11813 }
11814
11815 #[test]
11818 fn mla_thumb2_encodes_correctly() {
11819 let encoder = ArmEncoder::new_thumb2();
11820 let code = encoder
11821 .encode(&ArmOp::Mla {
11822 rd: Reg::R2,
11823 rn: Reg::R3,
11824 rm: Reg::R4,
11825 ra: Reg::R8,
11826 })
11827 .unwrap();
11828 assert_eq!(code, vec![0x03, 0xfb, 0x04, 0x82]);
11830 }
11831
11832 #[test]
11837 fn ldst_imm12_offset_errors_when_out_of_range() {
11838 let encoder = ArmEncoder::new_thumb2();
11839 assert!(
11841 encoder
11842 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0xFFF)
11843 .is_ok()
11844 );
11845 assert!(
11847 encoder
11848 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0x1000)
11849 .is_err(),
11850 "ldr offset 4096 must error, not wrap to 0"
11851 );
11852 assert!(
11853 encoder
11854 .encode_thumb32_str(&Reg::R0, &Reg::R1, 0x1000)
11855 .is_err()
11856 );
11857 assert!(
11858 encoder
11859 .encode_thumb32_ldrb_imm(&Reg::R0, &Reg::R1, 5000)
11860 .is_err()
11861 );
11862 assert!(
11863 encoder
11864 .encode_thumb32_strh_imm(&Reg::R0, &Reg::R1, 5000)
11865 .is_err()
11866 );
11867 }
11868
11869 #[test]
11876 fn add_sub_large_immediate_use_addw_subw_not_misencoded() {
11877 let encoder = ArmEncoder::new_thumb2();
11878 assert_eq!(
11880 encoder
11881 .encode(&ArmOp::Add {
11882 rd: Reg::SP,
11883 rn: Reg::SP,
11884 op2: Operand2::Imm(256),
11885 })
11886 .unwrap(),
11887 vec![0x0d, 0xf2, 0x00, 0x1d],
11888 "add sp,sp,#256 must be ADDW (plain imm12), not a mis-encoded ADD.W"
11889 );
11890 assert_eq!(
11892 encoder
11893 .encode(&ArmOp::Sub {
11894 rd: Reg::SP,
11895 rn: Reg::SP,
11896 op2: Operand2::Imm(256),
11897 })
11898 .unwrap(),
11899 vec![0xad, 0xf2, 0x00, 0x1d],
11900 );
11901 assert!(
11903 encoder
11904 .encode(&ArmOp::Add {
11905 rd: Reg::SP,
11906 rn: Reg::SP,
11907 op2: Operand2::Imm(5000),
11908 })
11909 .is_err(),
11910 "add #5000 must error (no single ADDW), not mis-encode"
11911 );
11912 }
11913
11914 #[test]
11919 fn and_cmn_immediate_thumb_expand_else_error() {
11920 let encoder = ArmEncoder::new_thumb2();
11921 assert_eq!(
11923 encoder
11924 .encode(&ArmOp::And {
11925 rd: Reg::R2,
11926 rn: Reg::R0,
11927 op2: Operand2::Imm(0x7e),
11928 })
11929 .unwrap(),
11930 vec![0x00, 0xf0, 0x7e, 0x02],
11931 );
11932 assert!(
11934 encoder
11935 .encode(&ArmOp::And {
11936 rd: Reg::R2,
11937 rn: Reg::R0,
11938 op2: Operand2::Imm(0xff00ff00u32 as i32),
11939 })
11940 .is_ok()
11941 );
11942 assert!(
11944 encoder
11945 .encode(&ArmOp::And {
11946 rd: Reg::R2,
11947 rn: Reg::R0,
11948 op2: Operand2::Imm(0x101),
11949 })
11950 .is_err()
11951 );
11952 assert!(
11953 encoder
11954 .encode(&ArmOp::Cmn {
11955 rn: Reg::R0,
11956 op2: Operand2::Imm(0x101),
11957 })
11958 .is_err(),
11959 "CMN #0x101 must error, not emit a NOP"
11960 );
11961 }
11962
11963 #[test]
11967 fn orr_eor_immediate_encode_in_byte_range_else_error() {
11968 let encoder = ArmEncoder::new_thumb2();
11969 assert_eq!(
11971 encoder
11972 .encode(&ArmOp::Orr {
11973 rd: Reg::R2,
11974 rn: Reg::R0,
11975 op2: Operand2::Imm(0x7e),
11976 })
11977 .unwrap(),
11978 vec![0x40, 0xf0, 0x7e, 0x02],
11979 );
11980 assert_eq!(
11982 encoder
11983 .encode(&ArmOp::Eor {
11984 rd: Reg::R2,
11985 rn: Reg::R0,
11986 op2: Operand2::Imm(0x7e),
11987 })
11988 .unwrap(),
11989 vec![0x80, 0xf0, 0x7e, 0x02],
11990 );
11991 assert!(
11993 encoder
11994 .encode(&ArmOp::Orr {
11995 rd: Reg::R2,
11996 rn: Reg::R0,
11997 op2: Operand2::Imm(0x140),
11998 })
11999 .is_err(),
12000 "ORR #0x140 must error, not emit a NOP"
12001 );
12002 }
12003
12004 #[test]
12005 fn test_encode_mve_different_qregs() {
12006 let encoder = ArmEncoder::new_thumb2();
12007
12008 let op1 = ArmOp::MveAddI {
12010 qd: QReg::Q0,
12011 qn: QReg::Q0,
12012 qm: QReg::Q0,
12013 size: MveSize::S32,
12014 };
12015 let op2 = ArmOp::MveAddI {
12016 qd: QReg::Q3,
12017 qn: QReg::Q5,
12018 qm: QReg::Q7,
12019 size: MveSize::S32,
12020 };
12021 let code1 = encoder.encode(&op1).unwrap();
12022 let code2 = encoder.encode(&op2).unwrap();
12023 assert_ne!(
12024 code1, code2,
12025 "Different Q-registers should produce different encodings"
12026 );
12027 }
12028
12029 #[test]
12030 fn test_encode_mve_arm32_loud_err() {
12031 let encoder = ArmEncoder::new_arm32();
12035 let op = ArmOp::MveAddI {
12036 qd: QReg::Q0,
12037 qn: QReg::Q1,
12038 qm: QReg::Q2,
12039 size: MveSize::S32,
12040 };
12041 let err = encoder
12042 .encode(&op)
12043 .expect_err("ARM32 MVE must be a loud Err, not a silent NOP (#615)");
12044 assert!(
12045 err.to_string().contains("Thumb-2 only"),
12046 "unexpected error message: {err}"
12047 );
12048 }
12049}