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(table_index_reg: &Reg, table_size: u32) -> Vec<u8> {
144 let idx = reg_to_bits(table_index_reg);
145 let mut bytes = Vec::with_capacity(32);
146 let size_lo = table_size & 0xFFFF;
148 let movw: u32 = 0xE300_0000 | ((size_lo >> 12) << 16) | (12 << 12) | (size_lo & 0xFFF);
149 bytes.extend_from_slice(&movw.to_le_bytes());
150 let size_hi = table_size >> 16;
152 if size_hi != 0 {
153 let movt: u32 = 0xE340_0000 | ((size_hi >> 12) << 16) | (12 << 12) | (size_hi & 0xFFF);
154 bytes.extend_from_slice(&movt.to_le_bytes());
155 }
156 let cmp: u32 = 0xE150_000C | (idx << 16);
158 bytes.extend_from_slice(&cmp.to_le_bytes());
159 bytes.extend_from_slice(&0x3A00_0000u32.to_le_bytes());
162 bytes.extend_from_slice(&0xE7F0_00F0u32.to_le_bytes());
165 let mov: u32 = 0xE1A0C000 | (2 << 7) | idx;
168 bytes.extend_from_slice(&mov.to_le_bytes());
169 let ldr: u32 = 0xE79BC00C;
171 bytes.extend_from_slice(&ldr.to_le_bytes());
172 let blx: u32 = 0xE12FFF3C;
174 bytes.extend_from_slice(&blx.to_le_bytes());
175 bytes
176 }
177
178 fn encode_arm_expanded(&self, op: &ArmOp) -> Result<Option<Vec<u8>>> {
187 use synth_synthesis::Condition;
188
189 fn cond_bits(cond: &Condition) -> u32 {
191 match cond {
192 Condition::EQ => 0x0,
193 Condition::NE => 0x1,
194 Condition::HS => 0x2, Condition::LO => 0x3, Condition::HI => 0x8, Condition::LS => 0x9, Condition::GE => 0xA,
199 Condition::LT => 0xB,
200 Condition::GT => 0xC,
201 Condition::LE => 0xD,
202 }
203 }
204 fn w(b: &mut Vec<u8>, word: u32) {
205 b.extend_from_slice(&word.to_le_bytes());
206 }
207 fn mov_cond_imm(b: &mut Vec<u8>, cond: u32, rd: u32, imm: u32) {
209 w(b, (cond << 28) | 0x03A0_0000 | (rd << 12) | imm);
210 }
211 fn set_cond(b: &mut Vec<u8>, cond: &Condition, rd: u32) {
213 mov_cond_imm(b, cond_bits(cond), rd, 1);
214 mov_cond_imm(b, cond_bits(&cond.invert()), rd, 0);
215 }
216 fn cmp_reg(b: &mut Vec<u8>, rn: u32, rm: u32) {
218 w(b, 0xE150_0000 | (rn << 16) | rm);
219 }
220 fn sbcs(b: &mut Vec<u8>, rd: u32, rn: u32, rm: u32) {
222 w(b, 0xE0D0_0000 | (rn << 16) | (rd << 12) | rm);
223 }
224 fn movw(b: &mut Vec<u8>, rd: u32, v: u32) {
226 w(
227 b,
228 0xE300_0000 | (((v >> 12) & 0xF) << 16) | (rd << 12) | (v & 0xFFF),
229 );
230 }
231 fn movt(b: &mut Vec<u8>, rd: u32, v: u32) {
233 w(
234 b,
235 0xE340_0000 | (((v >> 12) & 0xF) << 16) | (rd << 12) | (v & 0xFFF),
236 );
237 }
238 fn shift_reg(b: &mut Vec<u8>, ty: u32, rd: u32, rn: u32, rs: u32) {
243 w(b, 0xE1A0_0010 | (rd << 12) | (rs << 8) | (ty << 5) | rn);
244 }
245 const LSL: u32 = 0;
246 const LSR: u32 = 1;
247 const ASR: u32 = 2;
248 fn shift_imm(b: &mut Vec<u8>, ty: u32, rd: u32, rn: u32, imm: u32) {
250 w(
251 b,
252 0xE1A0_0000 | (rd << 12) | ((imm & 0x1F) << 7) | (ty << 5) | rn,
253 );
254 }
255 fn dp_reg(b: &mut Vec<u8>, base: u32, rd: u32, rn: u32, rm: u32) {
258 w(b, base | (rn << 16) | (rd << 12) | rm);
259 }
260 fn orr_lsr31(b: &mut Vec<u8>, rd: u32, rm: u32) {
263 w(
264 b,
265 0xE180_0000 | (rd << 16) | (rd << 12) | (31 << 7) | (1 << 5) | rm,
266 );
267 }
268 fn negate64(b: &mut Vec<u8>, lo: u32, hi: u32) {
270 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)); }
275 fn skip_negate_if_positive(b: &mut Vec<u8>, x: u32) {
278 w(b, 0xE110_0000 | (x << 16) | x); w(b, 0x5A00_0003); }
281 fn div_loop(b: &mut Vec<u8>, counter: u32) {
285 w(b, 0xE3A0_0040 | (counter << 12)); let loop_start = b.len();
287 shift_imm(b, LSL, 5, 5, 1);
289 orr_lsr31(b, 5, 4);
290 shift_imm(b, LSL, 4, 4, 1);
291 shift_imm(b, LSL, 7, 7, 1);
293 orr_lsr31(b, 7, 6);
294 shift_imm(b, LSL, 6, 6, 1);
295 orr_lsr31(b, 6, 1);
296 shift_imm(b, LSL, 1, 1, 1);
298 orr_lsr31(b, 1, 0);
299 shift_imm(b, LSL, 0, 0, 1);
300 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);
312 w(b, 0x1A00_0000 | (((diff / 4) as u32) & 0x00FF_FFFF)); }
314 fn popcnt_word(b: &mut Vec<u8>, x: u32, c: u32) {
318 shift_imm(b, LSR, 12, x, 1);
320 movw(b, c, 0x5555);
321 movt(b, c, 0x5555);
322 dp_reg(b, 0xE000_0000, 12, 12, c); dp_reg(b, 0xE040_0000, x, x, 12); movw(b, c, 0x3333);
326 movt(b, c, 0x3333);
327 dp_reg(b, 0xE000_0000, 12, x, c); shift_imm(b, LSR, x, x, 2);
329 dp_reg(b, 0xE000_0000, x, x, c); dp_reg(b, 0xE080_0000, x, x, 12); shift_imm(b, LSR, 12, x, 4);
333 dp_reg(b, 0xE080_0000, x, x, 12); movw(b, c, 0x0F0F);
335 movt(b, c, 0x0F0F);
336 dp_reg(b, 0xE000_0000, x, x, c); movw(b, c, 0x0101);
339 movt(b, c, 0x0101);
340 w(b, 0xE000_0090 | (x << 16) | (c << 8) | x); shift_imm(b, LSR, x, x, 24);
342 }
343
344 let mut b: Vec<u8> = Vec::new();
345 match op {
346 ArmOp::SetCond { rd, cond } => {
349 set_cond(&mut b, cond, reg_to_bits(rd));
350 }
351
352 ArmOp::SelectMove { rd, rm, cond } => {
354 w(
355 &mut b,
356 (cond_bits(cond) << 28)
357 | 0x01A0_0000
358 | (reg_to_bits(rd) << 12)
359 | reg_to_bits(rm),
360 );
361 }
362
363 ArmOp::I64SetCond {
368 rd,
369 rn_lo,
370 rn_hi,
371 rm_lo,
372 rm_hi,
373 cond,
374 } => {
375 let rd_b = reg_to_bits(rd);
376 let (n_lo, n_hi, m_lo, m_hi) = (
377 reg_to_bits(rn_lo),
378 reg_to_bits(rn_hi),
379 reg_to_bits(rm_lo),
380 reg_to_bits(rm_hi),
381 );
382 match cond {
383 Condition::EQ | Condition::NE => {
384 cmp_reg(&mut b, n_lo, m_lo);
385 w(&mut b, 0x0150_0000 | (n_hi << 16) | m_hi);
387 set_cond(&mut b, cond, rd_b);
388 }
389 Condition::LT => {
392 cmp_reg(&mut b, n_lo, m_lo);
393 sbcs(&mut b, rd_b, n_hi, m_hi);
394 set_cond(&mut b, &Condition::LT, rd_b);
395 }
396 Condition::GE => {
397 cmp_reg(&mut b, n_lo, m_lo);
398 sbcs(&mut b, rd_b, n_hi, m_hi);
399 set_cond(&mut b, &Condition::GE, rd_b);
400 }
401 Condition::GT => {
402 cmp_reg(&mut b, m_lo, n_lo);
403 sbcs(&mut b, rd_b, m_hi, n_hi);
404 set_cond(&mut b, &Condition::LT, rd_b);
405 }
406 Condition::LE => {
407 cmp_reg(&mut b, m_lo, n_lo);
408 sbcs(&mut b, rd_b, m_hi, n_hi);
409 set_cond(&mut b, &Condition::GE, rd_b);
410 }
411 Condition::LO => {
412 cmp_reg(&mut b, n_lo, m_lo);
413 sbcs(&mut b, rd_b, n_hi, m_hi);
414 set_cond(&mut b, &Condition::LO, rd_b);
415 }
416 Condition::HS => {
417 cmp_reg(&mut b, n_lo, m_lo);
418 sbcs(&mut b, rd_b, n_hi, m_hi);
419 set_cond(&mut b, &Condition::HS, rd_b);
420 }
421 Condition::HI => {
422 cmp_reg(&mut b, m_lo, n_lo);
423 sbcs(&mut b, rd_b, m_hi, n_hi);
424 set_cond(&mut b, &Condition::LO, rd_b);
425 }
426 Condition::LS => {
427 cmp_reg(&mut b, m_lo, n_lo);
428 sbcs(&mut b, rd_b, m_hi, n_hi);
429 set_cond(&mut b, &Condition::HS, rd_b);
430 }
431 }
432 }
433
434 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
436 let rd_b = reg_to_bits(rd);
437 w(
438 &mut b,
439 0xE190_0000 | (reg_to_bits(rn_lo) << 16) | (rd_b << 12) | reg_to_bits(rn_hi),
440 );
441 set_cond(&mut b, &Condition::EQ, rd_b);
442 }
443
444 ArmOp::I64Eqz { rd, rnlo, rnhi } => {
447 return self
448 .encode_arm(&ArmOp::I64SetCondZ {
449 rd: *rd,
450 rn_lo: *rnlo,
451 rn_hi: *rnhi,
452 })
453 .map(Some);
454 }
455 ArmOp::I64Eq {
456 rd,
457 rnlo,
458 rnhi,
459 rmlo,
460 rmhi,
461 }
462 | ArmOp::I64Ne {
463 rd,
464 rnlo,
465 rnhi,
466 rmlo,
467 rmhi,
468 }
469 | ArmOp::I64LtS {
470 rd,
471 rnlo,
472 rnhi,
473 rmlo,
474 rmhi,
475 }
476 | ArmOp::I64LtU {
477 rd,
478 rnlo,
479 rnhi,
480 rmlo,
481 rmhi,
482 }
483 | ArmOp::I64LeS {
484 rd,
485 rnlo,
486 rnhi,
487 rmlo,
488 rmhi,
489 }
490 | ArmOp::I64LeU {
491 rd,
492 rnlo,
493 rnhi,
494 rmlo,
495 rmhi,
496 }
497 | ArmOp::I64GtS {
498 rd,
499 rnlo,
500 rnhi,
501 rmlo,
502 rmhi,
503 }
504 | ArmOp::I64GtU {
505 rd,
506 rnlo,
507 rnhi,
508 rmlo,
509 rmhi,
510 }
511 | ArmOp::I64GeS {
512 rd,
513 rnlo,
514 rnhi,
515 rmlo,
516 rmhi,
517 }
518 | ArmOp::I64GeU {
519 rd,
520 rnlo,
521 rnhi,
522 rmlo,
523 rmhi,
524 } => {
525 let cond = match op {
526 ArmOp::I64Eq { .. } => Condition::EQ,
527 ArmOp::I64Ne { .. } => Condition::NE,
528 ArmOp::I64LtS { .. } => Condition::LT,
529 ArmOp::I64LtU { .. } => Condition::LO,
530 ArmOp::I64LeS { .. } => Condition::LE,
531 ArmOp::I64LeU { .. } => Condition::LS,
532 ArmOp::I64GtS { .. } => Condition::GT,
533 ArmOp::I64GtU { .. } => Condition::HI,
534 ArmOp::I64GeS { .. } => Condition::GE,
535 _ => Condition::HS,
536 };
537 return self
538 .encode_arm(&ArmOp::I64SetCond {
539 rd: *rd,
540 rn_lo: *rnlo,
541 rn_hi: *rnhi,
542 rm_lo: *rmlo,
543 rm_hi: *rmhi,
544 cond,
545 })
546 .map(Some);
547 }
548
549 ArmOp::I64Mul {
552 rd_lo,
553 rd_hi,
554 rn_lo,
555 rn_hi,
556 rm_lo,
557 rm_hi,
558 } => {
559 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
560 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
561 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
562 w(&mut b, 0xE000_0090 | (12 << 16) | (mh << 8) | nl);
564 w(
566 &mut b,
567 0xE020_0090 | (12 << 16) | (12 << 12) | (ml << 8) | nh,
568 );
569 w(
571 &mut b,
572 0xE080_0090 | (dh << 16) | (dl << 12) | (ml << 8) | nl,
573 );
574 w(&mut b, 0xE080_0000 | (dh << 16) | (dh << 12) | 12);
576 }
577
578 ArmOp::I64Shl {
583 rd_lo,
584 rd_hi,
585 rn_lo,
586 rn_hi,
587 rm_lo,
588 rm_hi,
589 } => {
590 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
591 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
592 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
593 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)); }
605 ArmOp::I64ShrU {
606 rd_lo,
607 rd_hi,
608 rn_lo,
609 rn_hi,
610 rm_lo,
611 rm_hi,
612 } => {
613 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
614 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
615 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
616 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)); }
628 ArmOp::I64ShrS {
629 rd_lo,
630 rd_hi,
631 rn_lo,
632 rn_hi,
633 rm_lo,
634 rm_hi,
635 } => {
636 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
637 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
638 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
639 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); }
651
652 ArmOp::I64Rotl {
656 rdlo,
657 rdhi,
658 rnlo,
659 rnhi,
660 shift,
661 } => {
662 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, shift]);
663 for word in [
664 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, ] {
686 w(&mut b, word);
687 }
688 emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
689 }
690 ArmOp::I64Rotr {
691 rdlo,
692 rdhi,
693 rnlo,
694 rnhi,
695 shift,
696 } => {
697 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, shift]);
698 for word in [
699 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, ] {
721 w(&mut b, word);
722 }
723 emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
724 }
725
726 ArmOp::I64Clz { rd, rnlo, rnhi } => {
730 let (rd_b, lo, hi) = (reg_to_bits(rd), reg_to_bits(rnlo), reg_to_bits(rnhi));
731 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)); }
737
738 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
742 let (rd_b, lo, hi) = (reg_to_bits(rd), reg_to_bits(rnlo), reg_to_bits(rnhi));
743 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)); }
750
751 ArmOp::I64Const { rdlo, rdhi, value } => {
754 let lo32 = *value as u32;
755 let hi32 = (*value >> 32) as u32;
756 movw(&mut b, reg_to_bits(rdlo), lo32 & 0xFFFF);
757 if lo32 > 0xFFFF {
758 movt(&mut b, reg_to_bits(rdlo), lo32 >> 16);
759 }
760 movw(&mut b, reg_to_bits(rdhi), hi32 & 0xFFFF);
761 if hi32 > 0xFFFF {
762 movt(&mut b, reg_to_bits(rdhi), hi32 >> 16);
763 }
764 }
765
766 ArmOp::I64Ldr { rdlo, rdhi, addr } | ArmOp::I64Str { rdlo, rdhi, addr } => {
770 let base = if let Some(rm) = addr.offset_reg {
771 w(
773 &mut b,
774 0xE080_0000
775 | (reg_to_bits(&addr.base) << 16)
776 | (12 << 12)
777 | reg_to_bits(&rm),
778 );
779 12
780 } else {
781 reg_to_bits(&addr.base)
782 };
783 if addr.offset < 0 || addr.offset > 0xFFB {
784 return Err(synth_core::Error::synthesis(format!(
785 "i64 load/store offset {} out of the A32 imm12 range (0..=4091) — materialize the offset into a register",
786 addr.offset
787 )));
788 }
789 let off = addr.offset as u32;
790 let opc: u32 = if matches!(op, ArmOp::I64Ldr { .. }) {
791 0xE590_0000 } else {
793 0xE580_0000 };
795 w(&mut b, opc | (base << 16) | (reg_to_bits(rdlo) << 12) | off);
796 w(
797 &mut b,
798 opc | (base << 16) | (reg_to_bits(rdhi) << 12) | (off + 4),
799 );
800 }
801
802 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
804 if rdlo != rn {
805 w(
806 &mut b,
807 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rn),
808 );
809 }
810 w(
811 &mut b,
812 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
813 );
814 }
815
816 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
818 if rdlo != rn {
819 w(
820 &mut b,
821 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rn),
822 );
823 }
824 w(&mut b, 0xE3A0_0000 | (reg_to_bits(rdhi) << 12));
825 }
826
827 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
829 w(
830 &mut b,
831 0xE6AF_0070 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
832 );
833 w(
834 &mut b,
835 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
836 );
837 }
838 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
839 w(
840 &mut b,
841 0xE6BF_0070 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
842 );
843 w(
844 &mut b,
845 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
846 );
847 }
848 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
849 if rdlo != rnlo {
850 w(
851 &mut b,
852 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
853 );
854 }
855 w(
856 &mut b,
857 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rnlo),
858 );
859 }
860
861 ArmOp::I32WrapI64 { rd, rnlo } => {
864 w(
865 &mut b,
866 0xE1A0_0000 | (reg_to_bits(rd) << 12) | reg_to_bits(rnlo),
867 );
868 }
869
870 ArmOp::I64Add {
874 rdlo,
875 rdhi,
876 rnlo,
877 rnhi,
878 rmlo,
879 rmhi,
880 } => {
881 dp_reg(
882 &mut b,
883 0xE090_0000, reg_to_bits(rdlo),
885 reg_to_bits(rnlo),
886 reg_to_bits(rmlo),
887 );
888 dp_reg(
889 &mut b,
890 0xE0A0_0000, reg_to_bits(rdhi),
892 reg_to_bits(rnhi),
893 reg_to_bits(rmhi),
894 );
895 }
896 ArmOp::I64Sub {
897 rdlo,
898 rdhi,
899 rnlo,
900 rnhi,
901 rmlo,
902 rmhi,
903 } => {
904 dp_reg(
905 &mut b,
906 0xE050_0000, reg_to_bits(rdlo),
908 reg_to_bits(rnlo),
909 reg_to_bits(rmlo),
910 );
911 dp_reg(
912 &mut b,
913 0xE0C0_0000, reg_to_bits(rdhi),
915 reg_to_bits(rnhi),
916 reg_to_bits(rmhi),
917 );
918 }
919
920 ArmOp::I64And {
922 rdlo,
923 rdhi,
924 rnlo,
925 rnhi,
926 rmlo,
927 rmhi,
928 }
929 | ArmOp::I64Or {
930 rdlo,
931 rdhi,
932 rnlo,
933 rnhi,
934 rmlo,
935 rmhi,
936 }
937 | ArmOp::I64Xor {
938 rdlo,
939 rdhi,
940 rnlo,
941 rnhi,
942 rmlo,
943 rmhi,
944 } => {
945 let base = match op {
946 ArmOp::I64And { .. } => 0xE000_0000, ArmOp::I64Or { .. } => 0xE180_0000, _ => 0xE020_0000, };
950 dp_reg(
951 &mut b,
952 base,
953 reg_to_bits(rdlo),
954 reg_to_bits(rnlo),
955 reg_to_bits(rmlo),
956 );
957 dp_reg(
958 &mut b,
959 base,
960 reg_to_bits(rdhi),
961 reg_to_bits(rnhi),
962 reg_to_bits(rmhi),
963 );
964 }
965
966 ArmOp::I64DivU {
970 rdlo,
971 rdhi,
972 rnlo,
973 rnhi,
974 rmlo,
975 rmhi,
976 elide_zero_guard,
977 } => {
978 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
979 if !elide_zero_guard {
982 emit_a32_i64_divisor_zero_trap(&mut b);
983 }
984 w(&mut b, 0xE92D_00F0); for r in 4..8u32 {
986 w(&mut b, 0xE3A0_0000 | (r << 12)); }
988 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)?;
993 }
994
995 ArmOp::I64DivS {
998 rdlo,
999 rdhi,
1000 rnlo,
1001 rnhi,
1002 rmlo,
1003 rmhi,
1004 elide_zero_guard,
1005 elide_overflow_guard,
1006 } => {
1007 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1008 if !elide_zero_guard {
1014 emit_a32_i64_divisor_zero_trap(&mut b);
1015 }
1016 if !elide_overflow_guard {
1017 emit_a32_i64_divs_overflow_trap(&mut b);
1020 }
1021 w(&mut b, 0xE92D_0FF0); w(&mut b, 0xE021_9003); skip_negate_if_positive(&mut b, 1);
1024 negate64(&mut b, 0, 1);
1025 skip_negate_if_positive(&mut b, 3);
1026 negate64(&mut b, 2, 3);
1027 for r in 4..8u32 {
1028 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1030 div_loop(&mut b, 8); w(&mut b, 0xE1A0_0004); w(&mut b, 0xE1A0_1005); skip_negate_if_positive(&mut b, 9);
1034 negate64(&mut b, 0, 1);
1035 w(&mut b, 0xE8BD_0FF0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
1037 }
1038
1039 ArmOp::I64RemU {
1041 rdlo,
1042 rdhi,
1043 rnlo,
1044 rnhi,
1045 rmlo,
1046 rmhi,
1047 elide_zero_guard,
1048 } => {
1049 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1050 if !elide_zero_guard {
1051 emit_a32_i64_divisor_zero_trap(&mut b);
1052 }
1053 w(&mut b, 0xE92D_01F0); for r in 4..8u32 {
1055 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1057 div_loop(&mut b, 8);
1058 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)?;
1062 }
1063
1064 ArmOp::I64RemS {
1066 rdlo,
1067 rdhi,
1068 rnlo,
1069 rnhi,
1070 rmlo,
1071 rmhi,
1072 elide_zero_guard,
1073 } => {
1074 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1075 if !elide_zero_guard {
1076 emit_a32_i64_divisor_zero_trap(&mut b);
1077 }
1078 w(&mut b, 0xE92D_0FF0); w(&mut b, 0xE1A0_9001); skip_negate_if_positive(&mut b, 1);
1081 negate64(&mut b, 0, 1);
1082 skip_negate_if_positive(&mut b, 3);
1083 negate64(&mut b, 2, 3);
1084 for r in 4..8u32 {
1085 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1087 div_loop(&mut b, 8);
1088 w(&mut b, 0xE1A0_0006); w(&mut b, 0xE1A0_1007); skip_negate_if_positive(&mut b, 9);
1091 negate64(&mut b, 0, 1);
1092 w(&mut b, 0xE8BD_0FF0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
1094 }
1095
1096 ArmOp::Popcnt { rd, rm } => {
1100 let rd_b = reg_to_bits(rd);
1101 if rd != rm {
1102 w(&mut b, 0xE1A0_0000 | (rd_b << 12) | reg_to_bits(rm)); }
1104 movw(&mut b, 12, 0x5555);
1106 movt(&mut b, 12, 0x5555);
1107 shift_imm(&mut b, LSR, 11, rd_b, 1);
1108 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);
1112 movt(&mut b, 12, 0x3333);
1113 dp_reg(&mut b, 0xE000_0000, 11, rd_b, 12); shift_imm(&mut b, LSR, rd_b, rd_b, 2);
1115 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);
1119 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11); movw(&mut b, 12, 0x0F0F);
1121 movt(&mut b, 12, 0x0F0F);
1122 dp_reg(&mut b, 0xE000_0000, rd_b, rd_b, 12); shift_imm(&mut b, LSR, 11, rd_b, 8);
1125 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11);
1126 shift_imm(&mut b, LSR, 11, rd_b, 16);
1127 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11);
1128 w(&mut b, 0xE200_003F | (rd_b << 16) | (rd_b << 12)); }
1130
1131 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
1135 let hi = reg_to_bits(rnhi);
1136 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);
1144 popcnt_word(&mut b, 5, 3);
1145 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)); }
1154
1155 _ => return Ok(None),
1156 }
1157 Ok(Some(b))
1158 }
1159
1160 fn encode_arm(&self, op: &ArmOp) -> Result<Vec<u8>> {
1161 if let Some(bytes) = self.encode_arm_expanded(op)? {
1168 return Ok(bytes);
1169 }
1170 if let Some(bytes) = self.encode_arm_reg_offset_mem(op)? {
1177 return Ok(bytes);
1178 }
1179 if let ArmOp::CallIndirect {
1185 table_index_reg,
1186 table_size,
1187 ..
1188 } = op
1189 {
1190 return Ok(Self::encode_arm_call_indirect(table_index_reg, *table_size));
1191 }
1192 let instr: u32 = match op {
1193 ArmOp::Add { rd, rn, op2 } => {
1195 let rd_bits = reg_to_bits(rd);
1196 let rn_bits = reg_to_bits(rn);
1197 let (op2_bits, i_flag) = encode_operand2(op2)?;
1198
1199 0xE0800000 | (i_flag << 25)
1202 | (rn_bits << 16)
1203 | (rd_bits << 12)
1204 | op2_bits
1205 }
1206
1207 ArmOp::Sub { rd, rn, op2 } => {
1208 let rd_bits = reg_to_bits(rd);
1209 let rn_bits = reg_to_bits(rn);
1210 let (op2_bits, i_flag) = encode_operand2(op2)?;
1211
1212 0xE0400000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1214 }
1215
1216 ArmOp::Adds { rd, rn, op2 } => {
1218 let rd_bits = reg_to_bits(rd);
1219 let rn_bits = reg_to_bits(rn);
1220 let (op2_bits, i_flag) = encode_operand2(op2)?;
1221
1222 0xE0900000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1224 }
1225
1226 ArmOp::Adc { rd, rn, op2 } => {
1227 let rd_bits = reg_to_bits(rd);
1228 let rn_bits = reg_to_bits(rn);
1229 let (op2_bits, i_flag) = encode_operand2(op2)?;
1230
1231 0xE0A00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1233 }
1234
1235 ArmOp::Subs { rd, rn, op2 } => {
1236 let rd_bits = reg_to_bits(rd);
1237 let rn_bits = reg_to_bits(rn);
1238 let (op2_bits, i_flag) = encode_operand2(op2)?;
1239
1240 0xE0500000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1242 }
1243
1244 ArmOp::Sbc { rd, rn, op2 } => {
1245 let rd_bits = reg_to_bits(rd);
1246 let rn_bits = reg_to_bits(rn);
1247 let (op2_bits, i_flag) = encode_operand2(op2)?;
1248
1249 0xE0C00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1251 }
1252
1253 ArmOp::Mul { rd, rn, rm } => {
1254 let rd_bits = reg_to_bits(rd);
1255 let rn_bits = reg_to_bits(rn);
1256 let rm_bits = reg_to_bits(rm);
1257
1258 0xE0000090 | (rd_bits << 16) | (rn_bits << 8) | rm_bits
1260 }
1261
1262 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
1263 let rdlo_bits = reg_to_bits(rdlo);
1264 let rdhi_bits = reg_to_bits(rdhi);
1265 let rn_bits = reg_to_bits(rn);
1266 let rm_bits = reg_to_bits(rm);
1267
1268 0xE0800090 | (rdhi_bits << 16) | (rdlo_bits << 12) | (rm_bits << 8) | rn_bits
1270 }
1271
1272 ArmOp::Sdiv { rd, rn, rm } => {
1273 let rd_bits = reg_to_bits(rd);
1274 let rn_bits = reg_to_bits(rn);
1275 let rm_bits = reg_to_bits(rm);
1276
1277 0xE710F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
1280 }
1281
1282 ArmOp::Udiv { rd, rn, rm } => {
1283 let rd_bits = reg_to_bits(rd);
1284 let rn_bits = reg_to_bits(rn);
1285 let rm_bits = reg_to_bits(rm);
1286
1287 0xE730F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
1290 }
1291
1292 ArmOp::Mls { rd, rn, rm, ra } => {
1293 let rd_bits = reg_to_bits(rd);
1294 let rn_bits = reg_to_bits(rn);
1295 let rm_bits = reg_to_bits(rm);
1296 let ra_bits = reg_to_bits(ra);
1297
1298 0xE0600090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
1301 }
1302
1303 ArmOp::Mla { rd, rn, rm, ra } => {
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 let ra_bits = reg_to_bits(ra);
1308
1309 0xE0200090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
1312 }
1313
1314 ArmOp::And { rd, rn, op2 } => {
1315 let rd_bits = reg_to_bits(rd);
1316 let rn_bits = reg_to_bits(rn);
1317 let (op2_bits, i_flag) = encode_operand2(op2)?;
1318
1319 0xE0000000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1321 }
1322
1323 ArmOp::Orr { rd, rn, op2 } => {
1324 let rd_bits = reg_to_bits(rd);
1325 let rn_bits = reg_to_bits(rn);
1326 let (op2_bits, i_flag) = encode_operand2(op2)?;
1327
1328 0xE1800000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1330 }
1331
1332 ArmOp::Eor { rd, rn, op2 } => {
1333 let rd_bits = reg_to_bits(rd);
1334 let rn_bits = reg_to_bits(rn);
1335 let (op2_bits, i_flag) = encode_operand2(op2)?;
1336
1337 0xE0200000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1339 }
1340
1341 ArmOp::Lsl { rd, rn, shift } => {
1343 let rd_bits = reg_to_bits(rd);
1344 let rn_bits = reg_to_bits(rn);
1345 let shift_bits = *shift & 0x1F;
1346
1347 0xE1A00000 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1349 }
1350
1351 ArmOp::Lsr { rd, rn, shift } => {
1352 let rd_bits = reg_to_bits(rd);
1353 let rn_bits = reg_to_bits(rn);
1354 let shift_bits = *shift & 0x1F;
1355
1356 0xE1A00020 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1358 }
1359
1360 ArmOp::Asr { rd, rn, shift } => {
1361 let rd_bits = reg_to_bits(rd);
1362 let rn_bits = reg_to_bits(rn);
1363 let shift_bits = *shift & 0x1F;
1364
1365 0xE1A00040 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1367 }
1368
1369 ArmOp::Ror { rd, rn, shift } => {
1370 let rd_bits = reg_to_bits(rd);
1371 let rn_bits = reg_to_bits(rn);
1372 let shift_bits = *shift & 0x1F;
1373
1374 0xE1A00060 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1376 }
1377
1378 ArmOp::LslReg { rd, rn, rm } => {
1381 let rd_bits = reg_to_bits(rd);
1382 let rn_bits = reg_to_bits(rn);
1383 let rm_bits = reg_to_bits(rm);
1384 0xE1A00010 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1385 }
1386 ArmOp::LsrReg { rd, rn, rm } => {
1387 let rd_bits = reg_to_bits(rd);
1388 let rn_bits = reg_to_bits(rn);
1389 let rm_bits = reg_to_bits(rm);
1390 0xE1A00030 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1391 }
1392 ArmOp::AsrReg { rd, rn, rm } => {
1393 let rd_bits = reg_to_bits(rd);
1394 let rn_bits = reg_to_bits(rn);
1395 let rm_bits = reg_to_bits(rm);
1396 0xE1A00050 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1397 }
1398 ArmOp::RorReg { rd, rn, rm } => {
1399 let rd_bits = reg_to_bits(rd);
1400 let rn_bits = reg_to_bits(rn);
1401 let rm_bits = reg_to_bits(rm);
1402 0xE1A00070 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1403 }
1404
1405 ArmOp::Rsb { rd, rn, imm } => {
1407 let rd_bits = reg_to_bits(rd);
1408 let rn_bits = reg_to_bits(rn);
1409 0xE2600000 | (rn_bits << 16) | (rd_bits << 12) | (*imm & 0xFF)
1412 }
1413
1414 ArmOp::Clz { rd, rm } => {
1416 let rd_bits = reg_to_bits(rd);
1417 let rm_bits = reg_to_bits(rm);
1418
1419 0xE16F0F10 | (rd_bits << 12) | rm_bits
1422 }
1423
1424 ArmOp::Rbit { rd, rm } => {
1425 let rd_bits = reg_to_bits(rd);
1426 let rm_bits = reg_to_bits(rm);
1427
1428 0xE6FF0F30 | (rd_bits << 12) | rm_bits
1431 }
1432
1433 ArmOp::Sxtb { rd, rm } => {
1434 let rd_bits = reg_to_bits(rd);
1435 let rm_bits = reg_to_bits(rm);
1436
1437 0xE6AF0070 | (rd_bits << 12) | rm_bits
1440 }
1441
1442 ArmOp::Sxth { rd, rm } => {
1443 let rd_bits = reg_to_bits(rd);
1444 let rm_bits = reg_to_bits(rm);
1445
1446 0xE6BF0070 | (rd_bits << 12) | rm_bits
1449 }
1450
1451 ArmOp::Uxtb { rd, rm } => {
1452 let rd_bits = reg_to_bits(rd);
1453 let rm_bits = reg_to_bits(rm);
1454 0xE6EF0070 | (rd_bits << 12) | rm_bits
1456 }
1457
1458 ArmOp::Uxth { rd, rm } => {
1459 let rd_bits = reg_to_bits(rd);
1460 let rm_bits = reg_to_bits(rm);
1461 0xE6FF0070 | (rd_bits << 12) | rm_bits
1463 }
1464
1465 ArmOp::Mov { rd, op2 } => {
1467 let rd_bits = reg_to_bits(rd);
1468 let (op2_bits, i_flag) = encode_operand2(op2)?;
1469
1470 0xE1A00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
1472 }
1473
1474 ArmOp::Mvn { rd, op2 } => {
1475 let rd_bits = reg_to_bits(rd);
1476 let (op2_bits, i_flag) = encode_operand2(op2)?;
1477
1478 0xE1E00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
1480 }
1481
1482 ArmOp::Movw { rd, imm16 } => {
1485 let rd_bits = reg_to_bits(rd);
1486 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
1487 let imm12 = (*imm16 as u32) & 0xFFF;
1488 0xE3000000 | (imm4 << 16) | (rd_bits << 12) | imm12
1489 }
1490
1491 ArmOp::Movt { rd, imm16 } => {
1494 let rd_bits = reg_to_bits(rd);
1495 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
1496 let imm12 = (*imm16 as u32) & 0xFFF;
1497 0xE3400000 | (imm4 << 16) | (rd_bits << 12) | imm12
1498 }
1499
1500 ArmOp::MovwSym { rd, addend, .. } => {
1503 let rd_bits = reg_to_bits(rd);
1504 let v = (*addend as u32) & 0xffff;
1505 0xE3000000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
1506 }
1507 ArmOp::MovtSym { rd, addend, .. } => {
1508 let rd_bits = reg_to_bits(rd);
1509 let v = ((*addend as u32) >> 16) & 0xffff;
1510 0xE3400000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
1511 }
1512
1513 ArmOp::LdrSym { .. } => {
1517 return Err(synth_core::Error::synthesis(
1518 "LdrSym (literal-pool address load) is Thumb-2-only",
1519 ));
1520 }
1521
1522 ArmOp::Cmp { rn, op2 } => {
1524 let rn_bits = reg_to_bits(rn);
1525 let (op2_bits, i_flag) = encode_operand2(op2)?;
1526
1527 0xE1500000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
1529 }
1530
1531 ArmOp::Cmn { rn, op2 } => {
1533 let rn_bits = reg_to_bits(rn);
1534 let (op2_bits, i_flag) = encode_operand2(op2)?;
1535
1536 0xE1700000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
1538 }
1539
1540 ArmOp::Ldr { rd, addr } => {
1542 let rd_bits = reg_to_bits(rd);
1543 let (base_bits, offset_bits) = encode_mem_addr(addr);
1544
1545 0xE5900000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1548 }
1549
1550 ArmOp::Str { rd, addr } => {
1551 let rd_bits = reg_to_bits(rd);
1552 let (base_bits, offset_bits) = encode_mem_addr(addr);
1553
1554 0xE5800000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1556 }
1557
1558 ArmOp::Ldrb { rd, addr } => {
1560 let rd_bits = reg_to_bits(rd);
1561 let (base_bits, offset_bits) = encode_mem_addr(addr);
1562 0xE5D00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1564 }
1565
1566 ArmOp::Ldrsb { rd, addr } => {
1567 let rd_bits = reg_to_bits(rd);
1568 let (base_bits, offset_bits) = encode_mem_addr(addr);
1569 let offset_val = offset_bits & 0xFF;
1572 let imm4h = (offset_val >> 4) & 0xF;
1573 let imm4l = offset_val & 0xF;
1574 0xE1D000D0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1575 }
1576
1577 ArmOp::Ldrh { rd, addr } => {
1578 let rd_bits = reg_to_bits(rd);
1579 let (base_bits, offset_bits) = encode_mem_addr(addr);
1580 let offset_val = offset_bits & 0xFF;
1582 let imm4h = (offset_val >> 4) & 0xF;
1583 let imm4l = offset_val & 0xF;
1584 0xE1D000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1585 }
1586
1587 ArmOp::Ldrsh { rd, addr } => {
1588 let rd_bits = reg_to_bits(rd);
1589 let (base_bits, offset_bits) = encode_mem_addr(addr);
1590 let offset_val = offset_bits & 0xFF;
1592 let imm4h = (offset_val >> 4) & 0xF;
1593 let imm4l = offset_val & 0xF;
1594 0xE1D000F0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1595 }
1596
1597 ArmOp::Strb { rd, addr } => {
1599 let rd_bits = reg_to_bits(rd);
1600 let (base_bits, offset_bits) = encode_mem_addr(addr);
1601 0xE5C00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1603 }
1604
1605 ArmOp::Strh { rd, addr } => {
1606 let rd_bits = reg_to_bits(rd);
1607 let (base_bits, offset_bits) = encode_mem_addr(addr);
1608 let offset_val = offset_bits & 0xFF;
1610 let imm4h = (offset_val >> 4) & 0xF;
1611 let imm4l = offset_val & 0xF;
1612 0xE1C000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1613 }
1614
1615 ArmOp::MemorySize { rd } => {
1617 let rd_bits = reg_to_bits(rd);
1618 0xE1A00820 | (rd_bits << 12) | 0x0A }
1623
1624 ArmOp::MemoryGrow { rd, .. } => {
1625 let rd_bits = reg_to_bits(rd);
1626 0xE3E00000 | (rd_bits << 12) }
1629
1630 ArmOp::Label { .. } => {
1632 return Ok(Vec::new());
1633 }
1634
1635 ArmOp::B { label: _ } => {
1637 0xEA000000
1640 }
1641
1642 ArmOp::Bcc { cond, label: _ } => {
1644 use synth_synthesis::Condition;
1645 let cond_bits: u32 = match cond {
1646 Condition::EQ => 0x0,
1647 Condition::NE => 0x1,
1648 Condition::HS => 0x2,
1649 Condition::LO => 0x3,
1650 Condition::HI => 0x8,
1651 Condition::LS => 0x9,
1652 Condition::GE => 0xA,
1653 Condition::LT => 0xB,
1654 Condition::GT => 0xC,
1655 Condition::LE => 0xD,
1656 };
1657 (cond_bits << 28) | 0x0A000000
1659 }
1660
1661 ArmOp::Bhs { label: _ } => {
1663 0x2A000000 }
1666
1667 ArmOp::Blo { label: _ } => {
1669 0x3A000000 }
1672
1673 ArmOp::BOffset { offset } => {
1677 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
1687 0xEA000000 | offset_bits
1688 }
1689
1690 ArmOp::BCondOffset { cond, offset } => {
1692 use synth_synthesis::Condition;
1693 let cond_bits: u32 = match cond {
1694 Condition::EQ => 0x0,
1695 Condition::NE => 0x1,
1696 Condition::HS => 0x2,
1697 Condition::LO => 0x3,
1698 Condition::HI => 0x8,
1699 Condition::LS => 0x9,
1700 Condition::GE => 0xA,
1701 Condition::LT => 0xB,
1702 Condition::GT => 0xC,
1703 Condition::LE => 0xD,
1704 };
1705 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
1709 (cond_bits << 28) | 0x0A000000 | offset_bits
1710 }
1711
1712 ArmOp::Bl { label: _ } => {
1713 0xEB000000
1715 }
1716
1717 ArmOp::Bx { rm } => {
1718 let rm_bits = reg_to_bits(rm);
1719
1720 0xE12FFF10 | rm_bits
1722 }
1723
1724 ArmOp::Blx { rm } => {
1725 let rm_bits = reg_to_bits(rm);
1726
1727 0xE12FFF30 | rm_bits
1729 }
1730
1731 ArmOp::Push { regs } => {
1732 let mut reg_list: u32 = 0;
1734 for r in regs {
1735 reg_list |= 1 << reg_to_bits(r);
1736 }
1737 0xE92D0000 | reg_list
1738 }
1739
1740 ArmOp::Pop { regs } => {
1741 let mut reg_list: u32 = 0;
1743 for r in regs {
1744 reg_list |= 1 << reg_to_bits(r);
1745 }
1746 0xE8BD0000 | reg_list
1747 }
1748
1749 ArmOp::Nop => {
1750 0xE1A00000
1752 }
1753
1754 ArmOp::Udf { imm } => {
1755 let imm8 = *imm as u32;
1758 0xE7F000F0 | ((imm8 & 0xF0) << 4) | (imm8 & 0x0F)
1759 }
1760
1761 ArmOp::Popcnt { .. } | ArmOp::SetCond { .. } | ArmOp::SelectMove { .. } => {
1765 unreachable!("handled by encode_arm_expanded (#615)")
1766 }
1767
1768 ArmOp::Select { .. }
1776 | ArmOp::LocalGet { .. }
1777 | ArmOp::LocalSet { .. }
1778 | ArmOp::LocalTee { .. }
1779 | ArmOp::GlobalGet { .. }
1780 | ArmOp::GlobalSet { .. }
1781 | ArmOp::BrTable { .. }
1782 | ArmOp::Call { .. } => {
1783 return Err(synth_core::Error::synthesis(format!(
1784 "verification-only pseudo-op {op:?} reached the A32 encoder — \
1785 codegen lowers it before encoding; refusing to emit a silent NOP (#615)"
1786 )));
1787 }
1788
1789 ArmOp::CallIndirect { .. } => {
1793 unreachable!("CallIndirect handled by encode_arm_call_indirect (#594)")
1794 }
1795
1796 ArmOp::I64Add { .. }
1801 | ArmOp::I64Sub { .. }
1802 | ArmOp::I64DivS { .. }
1803 | ArmOp::I64DivU { .. }
1804 | ArmOp::I64RemS { .. }
1805 | ArmOp::I64RemU { .. }
1806 | ArmOp::I64Clz { .. }
1807 | ArmOp::I64Ctz { .. }
1808 | ArmOp::I64Popcnt { .. }
1809 | ArmOp::I64And { .. }
1810 | ArmOp::I64Or { .. }
1811 | ArmOp::I64Xor { .. }
1812 | ArmOp::I64Eqz { .. }
1813 | ArmOp::I64Eq { .. }
1814 | ArmOp::I64Ne { .. }
1815 | ArmOp::I64LtS { .. }
1816 | ArmOp::I64LtU { .. }
1817 | ArmOp::I64LeS { .. }
1818 | ArmOp::I64LeU { .. }
1819 | ArmOp::I64GtS { .. }
1820 | ArmOp::I64GtU { .. }
1821 | ArmOp::I64GeS { .. }
1822 | ArmOp::I64GeU { .. }
1823 | ArmOp::I64Const { .. }
1824 | ArmOp::I64Ldr { .. }
1825 | ArmOp::I64Str { .. }
1826 | ArmOp::I64ExtendI32S { .. }
1827 | ArmOp::I64ExtendI32U { .. }
1828 | ArmOp::I64Extend8S { .. }
1829 | ArmOp::I64Extend16S { .. }
1830 | ArmOp::I64Extend32S { .. }
1831 | ArmOp::I32WrapI64 { .. } => {
1832 unreachable!("handled by encode_arm_expanded (#615)")
1833 }
1834
1835 ArmOp::F32Add { sd, sn, sm } => encode_vfp_3reg(0xEE300A00, sd, sn, sm)?,
1837 ArmOp::F32Sub { sd, sn, sm } => encode_vfp_3reg(0xEE300A40, sd, sn, sm)?,
1838 ArmOp::F32Mul { sd, sn, sm } => encode_vfp_3reg(0xEE200A00, sd, sn, sm)?,
1839 ArmOp::F32Div { sd, sn, sm } => encode_vfp_3reg(0xEE800A00, sd, sn, sm)?,
1840 ArmOp::F32Abs { sd, sm } => encode_vfp_2reg(0xEEB00AC0, sd, sm)?,
1841 ArmOp::F32Neg { sd, sm } => encode_vfp_2reg(0xEEB10A40, sd, sm)?,
1842 ArmOp::F32Sqrt { sd, sm } => encode_vfp_2reg(0xEEB10AC0, sd, sm)?,
1843
1844 ArmOp::F32Ceil { sd, sm } => {
1847 return self.encode_arm_f32_rounding(sd, sm, 0b01); }
1849 ArmOp::F32Floor { sd, sm } => {
1850 return self.encode_arm_f32_rounding(sd, sm, 0b10); }
1852 ArmOp::F32Trunc { sd, sm } => {
1853 return self.encode_arm_f32_rounding(sd, sm, 0b11); }
1855 ArmOp::F32Nearest { sd, sm } => {
1856 return self.encode_arm_f32_rounding(sd, sm, 0b00); }
1858 ArmOp::F32Min { sd, sn, sm } => {
1859 return self.encode_arm_f32_minmax(sd, sn, sm, true);
1860 }
1861 ArmOp::F32Max { sd, sn, sm } => {
1862 return self.encode_arm_f32_minmax(sd, sn, sm, false);
1863 }
1864 ArmOp::F32Copysign { sd, sn, sm } => {
1865 return self.encode_arm_f32_copysign(sd, sn, sm);
1866 }
1867
1868 ArmOp::F32Eq { rd, sn, sm } => {
1870 return self.encode_arm_f32_compare(rd, sn, sm, 0x0); }
1872 ArmOp::F32Ne { rd, sn, sm } => {
1873 return self.encode_arm_f32_compare(rd, sn, sm, 0x1); }
1875 ArmOp::F32Lt { rd, sn, sm } => {
1876 return self.encode_arm_f32_compare(rd, sn, sm, 0x4); }
1878 ArmOp::F32Le { rd, sn, sm } => {
1879 return self.encode_arm_f32_compare(rd, sn, sm, 0x9); }
1881 ArmOp::F32Gt { rd, sn, sm } => {
1882 return self.encode_arm_f32_compare(rd, sn, sm, 0xC); }
1884 ArmOp::F32Ge { rd, sn, sm } => {
1885 return self.encode_arm_f32_compare(rd, sn, sm, 0xA); }
1887
1888 ArmOp::F32Const { sd, value } => {
1890 return self.encode_arm_f32_const(sd, *value);
1891 }
1892
1893 ArmOp::F32Load { sd, addr } => encode_vfp_ldst(0xED900A00, sd, addr)?,
1894 ArmOp::F32Store { sd, addr } => encode_vfp_ldst(0xED800A00, sd, addr)?,
1895
1896 ArmOp::F32ConvertI32S { sd, rm } => {
1898 return self.encode_arm_f32_convert_i32(sd, rm, true);
1899 }
1900 ArmOp::F32ConvertI32U { sd, rm } => {
1901 return self.encode_arm_f32_convert_i32(sd, rm, false);
1902 }
1903 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
1904 return Err(synth_core::Error::synthesis(
1905 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
1906 ));
1907 }
1908 ArmOp::F32ReinterpretI32 { sd, rm } => encode_vmov_core_sreg(true, sd, rm)?,
1909 ArmOp::I32ReinterpretF32 { rd, sm } => encode_vmov_core_sreg(false, sm, rd)?,
1910 ArmOp::I32TruncF32S { rd, sm } => {
1911 return self.encode_arm_i32_trunc_f32(rd, sm, true);
1912 }
1913 ArmOp::I32TruncF32U { rd, sm } => {
1914 return self.encode_arm_i32_trunc_f32(rd, sm, false);
1915 }
1916
1917 ArmOp::F64Add { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B00, dd, dn, dm)?,
1920 ArmOp::F64Sub { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B40, dd, dn, dm)?,
1921 ArmOp::F64Mul { dd, dn, dm } => encode_vfp_3reg_f64(0xEE200B00, dd, dn, dm)?,
1922 ArmOp::F64Div { dd, dn, dm } => encode_vfp_3reg_f64(0xEE800B00, dd, dn, dm)?,
1923 ArmOp::F64Abs { dd, dm } => encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?,
1924 ArmOp::F64Neg { dd, dm } => encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?,
1925 ArmOp::F64Sqrt { dd, dm } => encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?,
1926
1927 ArmOp::F64Ceil { dd, dm } => {
1930 return self.encode_arm_f64_rounding(dd, dm, 0b01);
1931 }
1932 ArmOp::F64Floor { dd, dm } => {
1933 return self.encode_arm_f64_rounding(dd, dm, 0b10);
1934 }
1935 ArmOp::F64Trunc { dd, dm } => {
1936 return self.encode_arm_f64_rounding(dd, dm, 0b11);
1937 }
1938 ArmOp::F64Nearest { dd, dm } => {
1939 return self.encode_arm_f64_rounding(dd, dm, 0b00);
1940 }
1941 ArmOp::F64Min { dd, dn, dm } => {
1942 return self.encode_arm_f64_minmax(dd, dn, dm, true);
1943 }
1944 ArmOp::F64Max { dd, dn, dm } => {
1945 return self.encode_arm_f64_minmax(dd, dn, dm, false);
1946 }
1947 ArmOp::F64Copysign { dd, dn, dm } => {
1948 return self.encode_arm_f64_copysign(dd, dn, dm);
1949 }
1950
1951 ArmOp::F64Eq { rd, dn, dm } => {
1953 return self.encode_arm_f64_compare(rd, dn, dm, 0x0);
1954 }
1955 ArmOp::F64Ne { rd, dn, dm } => {
1956 return self.encode_arm_f64_compare(rd, dn, dm, 0x1);
1957 }
1958 ArmOp::F64Lt { rd, dn, dm } => {
1959 return self.encode_arm_f64_compare(rd, dn, dm, 0x4);
1960 }
1961 ArmOp::F64Le { rd, dn, dm } => {
1962 return self.encode_arm_f64_compare(rd, dn, dm, 0x9);
1963 }
1964 ArmOp::F64Gt { rd, dn, dm } => {
1965 return self.encode_arm_f64_compare(rd, dn, dm, 0xC);
1966 }
1967 ArmOp::F64Ge { rd, dn, dm } => {
1968 return self.encode_arm_f64_compare(rd, dn, dm, 0xA);
1969 }
1970
1971 ArmOp::F64Const { dd, value } => {
1972 return self.encode_arm_f64_const(dd, *value);
1973 }
1974
1975 ArmOp::F64Load { dd, addr } => encode_vfp_ldst_f64(0xED900B00, dd, addr)?,
1976 ArmOp::F64Store { dd, addr } => encode_vfp_ldst_f64(0xED800B00, dd, addr)?,
1977
1978 ArmOp::F64ConvertI32S { dd, rm } => {
1979 return self.encode_arm_f64_convert_i32(dd, rm, true);
1980 }
1981 ArmOp::F64ConvertI32U { dd, rm } => {
1982 return self.encode_arm_f64_convert_i32(dd, rm, false);
1983 }
1984 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
1985 return Err(synth_core::Error::synthesis(
1986 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
1987 ));
1988 }
1989 ArmOp::F64PromoteF32 { dd, sm } => {
1990 return self.encode_arm_f64_promote_f32(dd, sm);
1991 }
1992 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => {
1993 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?
1994 }
1995 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => {
1996 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?
1997 }
1998 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
1999 return Err(synth_core::Error::synthesis(
2000 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
2001 ));
2002 }
2003 ArmOp::I32TruncF64S { rd, dm } => {
2004 return self.encode_arm_i32_trunc_f64(rd, dm, true);
2005 }
2006 ArmOp::I32TruncF64U { rd, dm } => {
2007 return self.encode_arm_i32_trunc_f64(rd, dm, false);
2008 }
2009 ArmOp::I64SetCond { .. }
2012 | ArmOp::I64SetCondZ { .. }
2013 | ArmOp::I64Mul { .. }
2014 | ArmOp::I64Shl { .. }
2015 | ArmOp::I64ShrS { .. }
2016 | ArmOp::I64ShrU { .. }
2017 | ArmOp::I64Rotl { .. }
2018 | ArmOp::I64Rotr { .. } => {
2019 unreachable!("handled by encode_arm_expanded (#615)")
2020 }
2021
2022 ArmOp::MveLoad { .. }
2024 | ArmOp::MveStore { .. }
2025 | ArmOp::MveConst { .. }
2026 | ArmOp::MveAnd { .. }
2027 | ArmOp::MveOrr { .. }
2028 | ArmOp::MveEor { .. }
2029 | ArmOp::MveMvn { .. }
2030 | ArmOp::MveBic { .. }
2031 | ArmOp::MveAddI { .. }
2032 | ArmOp::MveSubI { .. }
2033 | ArmOp::MveMulI { .. }
2034 | ArmOp::MveNegI { .. }
2035 | ArmOp::MveCmpEqI { .. }
2036 | ArmOp::MveCmpNeI { .. }
2037 | ArmOp::MveCmpLtS { .. }
2038 | ArmOp::MveCmpLtU { .. }
2039 | ArmOp::MveCmpGtS { .. }
2040 | ArmOp::MveCmpGtU { .. }
2041 | ArmOp::MveCmpLeS { .. }
2042 | ArmOp::MveCmpLeU { .. }
2043 | ArmOp::MveCmpGeS { .. }
2044 | ArmOp::MveCmpGeU { .. }
2045 | ArmOp::MveDup { .. }
2046 | ArmOp::MveExtractLane { .. }
2047 | ArmOp::MveInsertLane { .. }
2048 | ArmOp::MveAddF32 { .. }
2049 | ArmOp::MveSubF32 { .. }
2050 | ArmOp::MveMulF32 { .. }
2051 | ArmOp::MveNegF32 { .. }
2052 | ArmOp::MveAbsF32 { .. }
2053 | ArmOp::MveCmpEqF32 { .. }
2054 | ArmOp::MveCmpNeF32 { .. }
2055 | ArmOp::MveCmpLtF32 { .. }
2056 | ArmOp::MveCmpLeF32 { .. }
2057 | ArmOp::MveCmpGtF32 { .. }
2058 | ArmOp::MveCmpGeF32 { .. }
2059 | ArmOp::MveDupF32 { .. }
2060 | ArmOp::MveExtractLaneF32 { .. }
2061 | ArmOp::MveReplaceLaneF32 { .. }
2062 | ArmOp::MveDivF32 { .. }
2063 | ArmOp::MveSqrtF32 { .. } => {
2064 return Err(synth_core::Error::synthesis(format!(
2070 "MVE op {op:?} has no A32 (ARM-mode) encoding — MVE is Thumb-2 only (#615)"
2071 )));
2072 }
2073 };
2074
2075 Ok(instr.to_le_bytes().to_vec())
2077 }
2078
2079 fn encode_arm_f32_compare(
2083 &self,
2084 rd: &Reg,
2085 sn: &VfpReg,
2086 sm: &VfpReg,
2087 cond_code: u32,
2088 ) -> Result<Vec<u8>> {
2089 let mut bytes = Vec::new();
2090
2091 let sn_num = vfp_sreg_to_num(sn)?;
2093 let sm_num = vfp_sreg_to_num(sm)?;
2094 let (vd, d) = encode_sreg(sn_num);
2095 let (vm, m) = encode_sreg(sm_num);
2096 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2097 bytes.extend_from_slice(&vcmp.to_le_bytes());
2098
2099 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2101
2102 let rd_bits = reg_to_bits(rd);
2104 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2105 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2106
2107 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2109 bytes.extend_from_slice(&mov_one.to_le_bytes());
2110
2111 Ok(bytes)
2112 }
2113
2114 fn encode_arm_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
2116 let mut bytes = Vec::new();
2117 let bits = value.to_bits();
2118
2119 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
2124 let movw = 0xE3000000 | (rt << 12) | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2125 bytes.extend_from_slice(&movw.to_le_bytes());
2126
2127 let hi16 = (bits >> 16) & 0xFFFF;
2129 let movt = 0xE3400000 | (rt << 12) | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2130 bytes.extend_from_slice(&movt.to_le_bytes());
2131
2132 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
2134 bytes.extend_from_slice(&vmov.to_le_bytes());
2135
2136 Ok(bytes)
2137 }
2138
2139 fn encode_arm_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2141 let mut bytes = Vec::new();
2142
2143 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
2145 bytes.extend_from_slice(&vmov.to_le_bytes());
2146
2147 let sd_num = vfp_sreg_to_num(sd)?;
2150 let (vd, d) = encode_sreg(sd_num);
2151 let (vm, m) = encode_sreg(sd_num); let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
2153 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2154 bytes.extend_from_slice(&vcvt.to_le_bytes());
2155
2156 Ok(bytes)
2157 }
2158
2159 fn encode_arm_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2171 let mut bytes = Vec::new();
2172 let sm_num = vfp_sreg_to_num(sm)?;
2173 let sd_num = vfp_sreg_to_num(sd)?;
2174 let (vd_s, d_s) = encode_sreg(sd_num);
2175 let (vm_s, m_s) = encode_sreg(sm_num);
2176
2177 if mode == 0b11 {
2178 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2181 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2182 } else {
2183 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
2188 bytes.extend_from_slice(&vmrs.to_le_bytes());
2189
2190 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2193 bytes.extend_from_slice(&bic.to_le_bytes());
2194
2195 if mode != 0 {
2197 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2199 bytes.extend_from_slice(&orr.to_le_bytes());
2200 }
2201
2202 let vmsr = 0xEEE10A10 | (rt << 12);
2204 bytes.extend_from_slice(&vmsr.to_le_bytes());
2205
2206 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2208 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2209
2210 bytes.extend_from_slice(&vmrs.to_le_bytes());
2212 bytes.extend_from_slice(&bic.to_le_bytes());
2213 bytes.extend_from_slice(&vmsr.to_le_bytes());
2214 }
2215
2216 let (vd2, d2) = encode_sreg(sd_num);
2218 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
2219 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2220
2221 Ok(bytes)
2222 }
2223
2224 fn encode_arm_f32_minmax(
2226 &self,
2227 sd: &VfpReg,
2228 sn: &VfpReg,
2229 sm: &VfpReg,
2230 is_min: bool,
2231 ) -> Result<Vec<u8>> {
2232 let mut bytes = Vec::new();
2233 let sn_num = vfp_sreg_to_num(sn)?;
2234 let sm_num = vfp_sreg_to_num(sm)?;
2235 let sd_num = vfp_sreg_to_num(sd)?;
2236
2237 let (vd, d) = encode_sreg(sd_num);
2239 let (vn, n) = encode_sreg(sn_num);
2240 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2241 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2242
2243 let (vm, m) = encode_sreg(sm_num);
2245 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2246 bytes.extend_from_slice(&vcmp.to_le_bytes());
2247
2248 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2250
2251 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2254
2255 let vmov_cond = (cond << 28) | 0x0EB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2257 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2258
2259 Ok(bytes)
2260 }
2261
2262 fn encode_arm_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2264 let mut bytes = Vec::new();
2265
2266 let vmov_sm = encode_vmov_core_sreg(false, sm, &Reg::R12)?;
2268 bytes.extend_from_slice(&vmov_sm.to_le_bytes());
2269
2270 let vmov_sn = encode_vmov_core_sreg(false, sn, &Reg::R0)?;
2272 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2273
2274 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2278 bytes.extend_from_slice(&and_sign.to_le_bytes());
2279
2280 let bic_sign = 0xE3C00000u32 | (1 << 8) | 0x02;
2283 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2284
2285 let orr = 0xE1800000u32 | 12;
2288 bytes.extend_from_slice(&orr.to_le_bytes());
2289
2290 let vmov_result = encode_vmov_core_sreg(true, sd, &Reg::R0)?;
2292 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2293
2294 Ok(bytes)
2295 }
2296
2297 fn encode_arm_f64_compare(
2299 &self,
2300 rd: &Reg,
2301 dn: &VfpReg,
2302 dm: &VfpReg,
2303 cond_code: u32,
2304 ) -> Result<Vec<u8>> {
2305 let mut bytes = Vec::new();
2306
2307 let dn_num = vfp_dreg_to_num(dn)?;
2309 let dm_num = vfp_dreg_to_num(dm)?;
2310 let (vd, d) = encode_dreg(dn_num);
2311 let (vm, m) = encode_dreg(dm_num);
2312 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2313 bytes.extend_from_slice(&vcmp.to_le_bytes());
2314
2315 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2317
2318 let rd_bits = reg_to_bits(rd);
2320 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2321 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2322
2323 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2325 bytes.extend_from_slice(&mov_one.to_le_bytes());
2326
2327 Ok(bytes)
2328 }
2329
2330 fn encode_arm_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
2332 let mut bytes = Vec::new();
2333 let bits = value.to_bits();
2334 let lo32 = bits as u32;
2335 let hi32 = (bits >> 32) as u32;
2336
2337 let lo16 = lo32 & 0xFFFF;
2339 let movw_r0 = 0xE3000000 | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2340 bytes.extend_from_slice(&movw_r0.to_le_bytes());
2341 let hi16 = (lo32 >> 16) & 0xFFFF;
2342 let movt_r0 = 0xE3400000 | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2343 bytes.extend_from_slice(&movt_r0.to_le_bytes());
2344
2345 let lo16 = hi32 & 0xFFFF;
2347 let movw_r12 = 0xE3000000 | ((lo16 >> 12) << 16) | (12 << 12) | (lo16 & 0xFFF);
2348 bytes.extend_from_slice(&movw_r12.to_le_bytes());
2349 let hi16 = (hi32 >> 16) & 0xFFFF;
2350 let movt_r12 = 0xE3400000 | ((hi16 >> 12) << 16) | (12 << 12) | (hi16 & 0xFFF);
2351 bytes.extend_from_slice(&movt_r12.to_le_bytes());
2352
2353 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
2355 bytes.extend_from_slice(&vmov.to_le_bytes());
2356
2357 Ok(bytes)
2358 }
2359
2360 fn encode_arm_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2362 let mut bytes = Vec::new();
2363
2364 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
2366 bytes.extend_from_slice(&vmov.to_le_bytes());
2367
2368 let dd_num = vfp_dreg_to_num(dd)?;
2371 let (vd, d) = encode_dreg(dd_num);
2372 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
2373 let vcvt = base | (d << 22) | (vd << 12);
2375 bytes.extend_from_slice(&vcvt.to_le_bytes());
2376
2377 Ok(bytes)
2378 }
2379
2380 fn encode_arm_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2382 let dd_num = vfp_dreg_to_num(dd)?;
2383 let sm_num = vfp_sreg_to_num(sm)?;
2384 let (vd, d) = encode_dreg(dd_num);
2385 let (vm, m) = encode_sreg(sm_num);
2386
2387 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
2389 Ok(vcvt.to_le_bytes().to_vec())
2390 }
2391
2392 fn encode_arm_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2394 let mut bytes = Vec::new();
2395 let dm_num = vfp_dreg_to_num(dm)?;
2396 let (vm, m) = encode_dreg(dm_num);
2397
2398 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
2401 let vcvt = base | (m << 5) | vm;
2402 bytes.extend_from_slice(&vcvt.to_le_bytes());
2403
2404 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
2406 bytes.extend_from_slice(&vmov.to_le_bytes());
2407
2408 Ok(bytes)
2409 }
2410
2411 fn encode_arm_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2419 let mut bytes = Vec::new();
2420 let dm_num = vfp_dreg_to_num(dm)?;
2421 let dd_num = vfp_dreg_to_num(dd)?;
2422 let (vm, m) = encode_dreg(dm_num);
2423 let (vd, d) = encode_dreg(dd_num);
2424
2425 if mode == 0b11 {
2426 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
2428 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2429 } else {
2430 let rt: u32 = 12;
2432
2433 let vmrs = 0xEEF10A10 | (rt << 12);
2435 bytes.extend_from_slice(&vmrs.to_le_bytes());
2436
2437 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2439 bytes.extend_from_slice(&bic.to_le_bytes());
2440
2441 if mode != 0 {
2443 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2444 bytes.extend_from_slice(&orr.to_le_bytes());
2445 }
2446
2447 let vmsr = 0xEEE10A10 | (rt << 12);
2449 bytes.extend_from_slice(&vmsr.to_le_bytes());
2450
2451 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
2453 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2454
2455 bytes.extend_from_slice(&vmrs.to_le_bytes());
2457 bytes.extend_from_slice(&bic.to_le_bytes());
2458 bytes.extend_from_slice(&vmsr.to_le_bytes());
2459 }
2460
2461 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
2463 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2464
2465 Ok(bytes)
2466 }
2467
2468 fn encode_arm_f64_minmax(
2470 &self,
2471 dd: &VfpReg,
2472 dn: &VfpReg,
2473 dm: &VfpReg,
2474 is_min: bool,
2475 ) -> Result<Vec<u8>> {
2476 let mut bytes = Vec::new();
2477 let dn_num = vfp_dreg_to_num(dn)?;
2478 let dm_num = vfp_dreg_to_num(dm)?;
2479 let dd_num = vfp_dreg_to_num(dd)?;
2480
2481 let (vd, d) = encode_dreg(dd_num);
2483 let (vn, n) = encode_dreg(dn_num);
2484 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2485 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2486
2487 let (vm, m) = encode_dreg(dm_num);
2489 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2490 bytes.extend_from_slice(&vcmp.to_le_bytes());
2491
2492 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2494
2495 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2496 let vmov_cond = (cond << 28) | 0x0EB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2497 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2498
2499 Ok(bytes)
2500 }
2501
2502 fn encode_arm_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
2504 let mut bytes = Vec::new();
2505
2506 let vmov_dm = encode_vmov_core_dreg(false, dm, &Reg::R0, &Reg::R12)?;
2508 bytes.extend_from_slice(&vmov_dm.to_le_bytes());
2509
2510 let vmov_dn = encode_vmov_core_dreg(false, dn, &Reg::R1, &Reg::R2)?;
2513 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2514
2515 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2517 bytes.extend_from_slice(&and_sign.to_le_bytes());
2518
2519 let bic_sign = 0xE3C00000u32 | (2 << 16) | (2 << 12) | (1 << 8) | 0x02;
2521 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2522
2523 let orr = 0xE1800000u32 | (2 << 16) | (2 << 12) | 12;
2525 bytes.extend_from_slice(&orr.to_le_bytes());
2526
2527 let vmov_result = encode_vmov_core_dreg(true, dd, &Reg::R1, &Reg::R2)?;
2529 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2530
2531 Ok(bytes)
2532 }
2533
2534 fn encode_arm_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2536 let mut bytes = Vec::new();
2537
2538 let sm_num = vfp_sreg_to_num(sm)?;
2541 let (vd, d) = encode_sreg(sm_num);
2542 let (vm, m) = encode_sreg(sm_num);
2543 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
2544 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2545 bytes.extend_from_slice(&vcvt.to_le_bytes());
2546
2547 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
2549 bytes.extend_from_slice(&vmov.to_le_bytes());
2550
2551 Ok(bytes)
2552 }
2553
2554 fn encode_thumb(&self, op: &ArmOp) -> Result<Vec<u8>> {
2556 match op {
2559 ArmOp::Add { rd, rn, op2 } => {
2561 let rd_bits = reg_to_bits(rd) as u16;
2562 let rn_bits = reg_to_bits(rn) as u16;
2563
2564 if let Operand2::Reg(rm) = op2 {
2565 let rm_bits = reg_to_bits(rm) as u16;
2566 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2574 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2576 Ok(instr.to_le_bytes().to_vec())
2577 } else {
2578 self.encode_thumb32_add_reg_raw(
2580 rd_bits as u32,
2581 rn_bits as u32,
2582 rm_bits as u32,
2583 )
2584 }
2585 } else if let Operand2::Imm(imm) = op2 {
2586 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2587 let instr: u16 = 0x1C00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2589 Ok(instr.to_le_bytes().to_vec())
2590 } else {
2591 self.encode_thumb32_add(rd, rn, *imm as u32)
2593 }
2594 } else {
2595 self.encode_thumb32_add(rd, rn, 0)
2597 }
2598 }
2599
2600 ArmOp::Sub { rd, rn, op2 } => {
2601 let rd_bits = reg_to_bits(rd) as u16;
2602 let rn_bits = reg_to_bits(rn) as u16;
2603
2604 if let Operand2::Reg(rm) = op2 {
2605 let rm_bits = reg_to_bits(rm) as u16;
2606 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2608 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2610 Ok(instr.to_le_bytes().to_vec())
2611 } else {
2612 self.encode_thumb32_sub_reg_raw(
2614 rd_bits as u32,
2615 rn_bits as u32,
2616 rm_bits as u32,
2617 )
2618 }
2619 } else if let Operand2::Imm(imm) = op2 {
2620 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2621 let instr: u16 = 0x1E00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2623 Ok(instr.to_le_bytes().to_vec())
2624 } else {
2625 self.encode_thumb32_sub(rd, rn, *imm as u32)
2626 }
2627 } else {
2628 self.encode_thumb32_sub(rd, rn, 0)
2629 }
2630 }
2631
2632 ArmOp::Mov { rd, op2 } => {
2633 let rd_bits = reg_to_bits(rd) as u16;
2634
2635 if let Operand2::Imm(imm) = op2 {
2636 let uimm = *imm as u32;
2649 if uimm <= 255 && rd_bits < 8 {
2650 let imm_bits = (*imm as u16) & 0xFF;
2652 let instr: u16 = 0x2000 | (rd_bits << 8) | imm_bits;
2653 Ok(instr.to_le_bytes().to_vec())
2654 } else if uimm <= 0xFFFF {
2655 self.encode_thumb32_movw(rd, uimm)
2657 } else {
2658 let mut bytes = self.encode_thumb32_movw(rd, uimm & 0xFFFF)?;
2660 bytes.extend(self.encode_thumb32_movt_raw(reg_to_bits(rd), uimm >> 16)?);
2661 Ok(bytes)
2662 }
2663 } else if let Operand2::Reg(rm) = op2 {
2664 let rm_bits = reg_to_bits(rm) as u16;
2665 let d_bit = (rd_bits >> 3) & 1;
2668 let instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
2669 Ok(instr.to_le_bytes().to_vec())
2670 } else {
2671 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2673 }
2674 }
2675
2676 ArmOp::Push { regs } => {
2677 let mut reg_list: u16 = 0;
2681 let mut need_32bit = false;
2682 for r in regs {
2683 let bit = reg_to_bits(r);
2684 if bit >= 8 && *r != Reg::LR {
2685 need_32bit = true;
2686 }
2687 reg_list |= 1 << bit;
2688 }
2689 if !need_32bit {
2690 let m_bit = if reg_list & (1 << 14) != 0 {
2692 1u16
2693 } else {
2694 0u16
2695 };
2696 let low_regs = reg_list & 0xFF;
2697 let instr: u16 = 0xB400 | (m_bit << 8) | low_regs;
2698 Ok(instr.to_le_bytes().to_vec())
2699 } else {
2700 let hw1: u16 = 0xE92D;
2702 let hw2: u16 = reg_list;
2703 let mut bytes = hw1.to_le_bytes().to_vec();
2704 bytes.extend_from_slice(&hw2.to_le_bytes());
2705 Ok(bytes)
2706 }
2707 }
2708
2709 ArmOp::Pop { regs } => {
2710 let mut reg_list: u16 = 0;
2714 let mut need_32bit = false;
2715 for r in regs {
2716 let bit = reg_to_bits(r);
2717 if bit >= 8 && *r != Reg::PC {
2718 need_32bit = true;
2719 }
2720 reg_list |= 1 << bit;
2721 }
2722 if !need_32bit {
2723 let p_bit = if reg_list & (1 << 15) != 0 {
2725 1u16
2726 } else {
2727 0u16
2728 };
2729 let low_regs = reg_list & 0xFF;
2730 let instr: u16 = 0xBC00 | (p_bit << 8) | low_regs;
2731 Ok(instr.to_le_bytes().to_vec())
2732 } else {
2733 let hw1: u16 = 0xE8BD;
2735 let hw2: u16 = reg_list;
2736 let mut bytes = hw1.to_le_bytes().to_vec();
2737 bytes.extend_from_slice(&hw2.to_le_bytes());
2738 Ok(bytes)
2739 }
2740 }
2741
2742 ArmOp::Nop => {
2743 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2745 }
2746
2747 ArmOp::Udf { imm } => {
2748 let instr: u16 = 0xDE00 | (*imm as u16);
2751 let bytes = instr.to_le_bytes().to_vec();
2752 encoding_contracts::verify_thumb16(&bytes);
2753 Ok(bytes)
2754 }
2755
2756 ArmOp::Adds { rd, rn, op2 } => {
2759 let rd_bits = reg_to_bits(rd) as u16;
2760 let rn_bits = reg_to_bits(rn) as u16;
2761
2762 if let Operand2::Reg(rm) = op2 {
2763 let rm_bits = reg_to_bits(rm) as u16;
2764 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2769 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2771 Ok(instr.to_le_bytes().to_vec())
2772 } else {
2773 self.encode_thumb32_adds_reg_raw(
2774 rd_bits as u32,
2775 rn_bits as u32,
2776 rm_bits as u32,
2777 )
2778 }
2779 } else {
2780 self.encode_thumb32_adds(rd, rn, 0)
2782 }
2783 }
2784
2785 ArmOp::Adc { rd, rn, op2 } => {
2788 let rd_bits = reg_to_bits(rd);
2789 let rn_bits = reg_to_bits(rn);
2790
2791 if let Operand2::Reg(rm) = op2 {
2792 let rm_bits = reg_to_bits(rm);
2793 let hw1: u16 = (0xEB40 | rn_bits) as u16;
2795 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2796
2797 let mut bytes = hw1.to_le_bytes().to_vec();
2798 bytes.extend_from_slice(&hw2.to_le_bytes());
2799 Ok(bytes)
2800 } else {
2801 let hw1: u16 = (0xF140 | rn_bits) as u16;
2803 let hw2: u16 = (rd_bits << 8) as u16;
2804 let mut bytes = hw1.to_le_bytes().to_vec();
2805 bytes.extend_from_slice(&hw2.to_le_bytes());
2806 Ok(bytes)
2807 }
2808 }
2809
2810 ArmOp::Subs { rd, rn, op2 } => {
2812 let rd_bits = reg_to_bits(rd) as u16;
2813 let rn_bits = reg_to_bits(rn) as u16;
2814
2815 if let Operand2::Reg(rm) = op2 {
2816 let rm_bits = reg_to_bits(rm) as u16;
2817 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2821 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2823 Ok(instr.to_le_bytes().to_vec())
2824 } else {
2825 self.encode_thumb32_subs_reg_raw(
2826 rd_bits as u32,
2827 rn_bits as u32,
2828 rm_bits as u32,
2829 )
2830 }
2831 } else {
2832 self.encode_thumb32_subs(rd, rn, 0)
2834 }
2835 }
2836
2837 ArmOp::Sbc { rd, rn, op2 } => {
2840 let rd_bits = reg_to_bits(rd);
2841 let rn_bits = reg_to_bits(rn);
2842
2843 if let Operand2::Reg(rm) = op2 {
2844 let rm_bits = reg_to_bits(rm);
2845 let hw1: u16 = (0xEB60 | rn_bits) as u16;
2847 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2848
2849 let mut bytes = hw1.to_le_bytes().to_vec();
2850 bytes.extend_from_slice(&hw2.to_le_bytes());
2851 Ok(bytes)
2852 } else {
2853 let hw1: u16 = (0xF160 | rn_bits) as u16;
2855 let hw2: u16 = (rd_bits << 8) as u16;
2856 let mut bytes = hw1.to_le_bytes().to_vec();
2857 bytes.extend_from_slice(&hw2.to_le_bytes());
2858 Ok(bytes)
2859 }
2860 }
2861
2862 ArmOp::Sdiv { rd, rn, rm } => {
2866 let rd_bits = reg_to_bits(rd);
2867 let rn_bits = reg_to_bits(rn);
2868 let rm_bits = reg_to_bits(rm);
2869 reg_bits_checked(rd_bits)?;
2870 reg_bits_checked(rn_bits)?;
2871 reg_bits_checked(rm_bits)?;
2872
2873 let hw1: u16 = (0xFB90 | rn_bits) as u16;
2877 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2878
2879 let mut bytes = hw1.to_le_bytes().to_vec();
2881 bytes.extend_from_slice(&hw2.to_le_bytes());
2882 encoding_contracts::verify_thumb32(&bytes);
2883 Ok(bytes)
2884 }
2885
2886 ArmOp::Udiv { rd, rn, rm } => {
2888 let rd_bits = reg_to_bits(rd);
2889 let rn_bits = reg_to_bits(rn);
2890 let rm_bits = reg_to_bits(rm);
2891 reg_bits_checked(rd_bits)?;
2892 reg_bits_checked(rn_bits)?;
2893 reg_bits_checked(rm_bits)?;
2894
2895 let hw1: u16 = (0xFBB0 | rn_bits) as u16;
2897 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2898
2899 let mut bytes = hw1.to_le_bytes().to_vec();
2900 bytes.extend_from_slice(&hw2.to_le_bytes());
2901 encoding_contracts::verify_thumb32(&bytes);
2902 Ok(bytes)
2903 }
2904
2905 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
2906 let rdlo_bits = reg_to_bits(rdlo);
2907 let rdhi_bits = reg_to_bits(rdhi);
2908 let rn_bits = reg_to_bits(rn);
2909 let rm_bits = reg_to_bits(rm);
2910 reg_bits_checked(rdlo_bits)?;
2911 reg_bits_checked(rdhi_bits)?;
2912 reg_bits_checked(rn_bits)?;
2913 reg_bits_checked(rm_bits)?;
2914
2915 let hw1: u16 = (0xFBA0 | rn_bits) as u16;
2917 let hw2: u16 = ((rdlo_bits << 12) | (rdhi_bits << 8) | rm_bits) as u16;
2918
2919 let mut bytes = hw1.to_le_bytes().to_vec();
2920 bytes.extend_from_slice(&hw2.to_le_bytes());
2921 encoding_contracts::verify_thumb32(&bytes);
2922 Ok(bytes)
2923 }
2924
2925 ArmOp::Mul { rd, rn, rm } => {
2927 let rd_bits = reg_to_bits(rd);
2928 let rn_bits = reg_to_bits(rn);
2929 let rm_bits = reg_to_bits(rm);
2930
2931 let hw1: u16 = (0xFB00 | rn_bits) as u16;
2934 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
2935
2936 let mut bytes = hw1.to_le_bytes().to_vec();
2937 bytes.extend_from_slice(&hw2.to_le_bytes());
2938 Ok(bytes)
2939 }
2940
2941 ArmOp::Mls { rd, rn, rm, ra } => {
2943 let rd_bits = reg_to_bits(rd);
2944 let rn_bits = reg_to_bits(rn);
2945 let rm_bits = reg_to_bits(rm);
2946 let ra_bits = reg_to_bits(ra);
2947
2948 let hw1: u16 = (0xFB00 | rn_bits) as u16;
2951 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | 0x10 | rm_bits) as u16;
2952
2953 let mut bytes = hw1.to_le_bytes().to_vec();
2954 bytes.extend_from_slice(&hw2.to_le_bytes());
2955 Ok(bytes)
2956 }
2957
2958 ArmOp::Mla { rd, rn, rm, ra } => {
2959 let rd_bits = reg_to_bits(rd);
2960 let rn_bits = reg_to_bits(rn);
2961 let rm_bits = reg_to_bits(rm);
2962 let ra_bits = reg_to_bits(ra);
2963
2964 let hw1: u16 = (0xFB00 | rn_bits) as u16;
2967 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | rm_bits) as u16;
2968
2969 let mut bytes = hw1.to_le_bytes().to_vec();
2970 bytes.extend_from_slice(&hw2.to_le_bytes());
2971 Ok(bytes)
2972 }
2973
2974 ArmOp::And { rd, rn, op2 } => {
2976 if let Operand2::Reg(rm) = op2 {
2977 let rd_bits = reg_to_bits(rd);
2978 let rn_bits = reg_to_bits(rn);
2979 let rm_bits = reg_to_bits(rm);
2980
2981 let hw1: u16 = (0xEA00 | rn_bits) as u16;
2983 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2984
2985 let mut bytes = hw1.to_le_bytes().to_vec();
2986 bytes.extend_from_slice(&hw2.to_le_bytes());
2987 Ok(bytes)
2988 } else if let Operand2::Imm(imm) = op2 {
2989 let rd_bits = reg_to_bits(rd);
2990 let rn_bits = reg_to_bits(rn);
2991
2992 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
2999 synth_core::Error::synthesis(
3000 "AND immediate is not a valid ThumbExpandImm — materialize into a register",
3001 )
3002 })?;
3003 let i_bit = (field >> 11) & 1;
3004 let imm3 = (field >> 8) & 0x7;
3005 let imm8 = field & 0xFF;
3006
3007 let hw1: u16 = (0xF000 | (i_bit << 10) | rn_bits) as u16;
3008 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
3009
3010 let mut bytes = hw1.to_le_bytes().to_vec();
3011 bytes.extend_from_slice(&hw2.to_le_bytes());
3012 Ok(bytes)
3013 } else {
3014 let instr: u16 = 0xBF00;
3016 Ok(instr.to_le_bytes().to_vec())
3017 }
3018 }
3019
3020 ArmOp::Orr { rd, rn, op2 } => {
3022 if let Operand2::Reg(rm) = op2 {
3023 let rd_bits = reg_to_bits(rd);
3024 let rn_bits = reg_to_bits(rn);
3025 let rm_bits = reg_to_bits(rm);
3026
3027 let hw1: u16 = (0xEA40 | rn_bits) as u16;
3029 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3030
3031 let mut bytes = hw1.to_le_bytes().to_vec();
3032 bytes.extend_from_slice(&hw2.to_le_bytes());
3033 Ok(bytes)
3034 } else if let Operand2::Imm(imm) = op2 {
3035 let imm_val = *imm as u32;
3040 if imm_val > 0xFF {
3041 return Err(synth_core::Error::synthesis(
3042 "ORR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
3043 ));
3044 }
3045 let rd_bits = reg_to_bits(rd);
3046 let rn_bits = reg_to_bits(rn);
3047 let hw1: u16 = (0xF040 | rn_bits) as u16;
3048 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
3049 let mut bytes = hw1.to_le_bytes().to_vec();
3050 bytes.extend_from_slice(&hw2.to_le_bytes());
3051 Ok(bytes)
3052 } else {
3053 let instr: u16 = 0xBF00;
3054 Ok(instr.to_le_bytes().to_vec())
3055 }
3056 }
3057
3058 ArmOp::Eor { rd, rn, op2 } => {
3060 if let Operand2::Reg(rm) = op2 {
3061 let rd_bits = reg_to_bits(rd);
3062 let rn_bits = reg_to_bits(rn);
3063 let rm_bits = reg_to_bits(rm);
3064
3065 let hw1: u16 = (0xEA80 | rn_bits) as u16;
3067 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3068
3069 let mut bytes = hw1.to_le_bytes().to_vec();
3070 bytes.extend_from_slice(&hw2.to_le_bytes());
3071 Ok(bytes)
3072 } else if let Operand2::Imm(imm) = op2 {
3073 let imm_val = *imm as u32;
3077 if imm_val > 0xFF {
3078 return Err(synth_core::Error::synthesis(
3079 "EOR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
3080 ));
3081 }
3082 let rd_bits = reg_to_bits(rd);
3083 let rn_bits = reg_to_bits(rn);
3084 let hw1: u16 = (0xF080 | rn_bits) as u16;
3085 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
3086 let mut bytes = hw1.to_le_bytes().to_vec();
3087 bytes.extend_from_slice(&hw2.to_le_bytes());
3088 Ok(bytes)
3089 } else {
3090 let instr: u16 = 0xBF00;
3091 Ok(instr.to_le_bytes().to_vec())
3092 }
3093 }
3094
3095 ArmOp::Lsl { rd, rn, shift } => {
3097 let rd_bits = reg_to_bits(rd) as u16;
3098 let rn_bits = reg_to_bits(rn) as u16;
3099 let shift_bits = (*shift as u16) & 0x1F;
3100
3101 if rd_bits < 8 && rn_bits < 8 {
3102 let instr: u16 = (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3104 Ok(instr.to_le_bytes().to_vec())
3105 } else {
3106 self.encode_thumb32_shift(rd, rn, *shift, 0b00) }
3109 }
3110
3111 ArmOp::Lsr { rd, rn, shift } => {
3112 let rd_bits = reg_to_bits(rd) as u16;
3113 let rn_bits = reg_to_bits(rn) as u16;
3114 let shift_bits = (*shift as u16) & 0x1F;
3115
3116 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3117 let instr: u16 = 0x0800 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3119 Ok(instr.to_le_bytes().to_vec())
3120 } else {
3121 self.encode_thumb32_shift(rd, rn, *shift, 0b01) }
3123 }
3124
3125 ArmOp::Asr { rd, rn, shift } => {
3126 let rd_bits = reg_to_bits(rd) as u16;
3127 let rn_bits = reg_to_bits(rn) as u16;
3128 let shift_bits = (*shift as u16) & 0x1F;
3129
3130 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3131 let instr: u16 = 0x1000 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3133 Ok(instr.to_le_bytes().to_vec())
3134 } else {
3135 self.encode_thumb32_shift(rd, rn, *shift, 0b10) }
3137 }
3138
3139 ArmOp::Ror { rd, rn, shift } => {
3140 self.encode_thumb32_shift(rd, rn, *shift, 0b11) }
3143
3144 ArmOp::LslReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b00),
3148 ArmOp::LsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b01),
3149 ArmOp::AsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b10),
3150 ArmOp::RorReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b11),
3151
3152 ArmOp::Rsb { rd, rn, imm } => {
3155 let rd_bits = reg_to_bits(rd);
3156 let rn_bits = reg_to_bits(rn);
3157 let imm_val = *imm;
3158
3159 let i_bit = (imm_val >> 11) & 1;
3160 let imm3 = (imm_val >> 8) & 0x7;
3161 let imm8 = imm_val & 0xFF;
3162
3163 let hw1: u16 = (0xF1C0 | (i_bit << 10) | rn_bits) as u16;
3165 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
3167
3168 let mut bytes = hw1.to_le_bytes().to_vec();
3169 bytes.extend_from_slice(&hw2.to_le_bytes());
3170 Ok(bytes)
3171 }
3172
3173 ArmOp::Clz { rd, rm } => {
3175 let rd_bits = reg_to_bits(rd);
3176 let rm_bits = reg_to_bits(rm);
3177
3178 let hw1: u16 = (0xFAB0 | rm_bits) as u16;
3181 let hw2: u16 = (0xF080 | (rd_bits << 8) | rm_bits) as u16;
3182
3183 let mut bytes = hw1.to_le_bytes().to_vec();
3184 bytes.extend_from_slice(&hw2.to_le_bytes());
3185 Ok(bytes)
3186 }
3187
3188 ArmOp::Rbit { rd, rm } => {
3190 let rd_bits = reg_to_bits(rd);
3191 let rm_bits = reg_to_bits(rm);
3192
3193 let hw1: u16 = (0xFA90 | rm_bits) as u16;
3196 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rm_bits) as u16;
3197
3198 let mut bytes = hw1.to_le_bytes().to_vec();
3199 bytes.extend_from_slice(&hw2.to_le_bytes());
3200 Ok(bytes)
3201 }
3202
3203 ArmOp::Sxtb { rd, rm } => {
3205 let rd_bits = reg_to_bits(rd) as u16;
3206 let rm_bits = reg_to_bits(rm) as u16;
3207
3208 if rd_bits < 8 && rm_bits < 8 {
3209 let instr: u16 = 0xB240 | (rm_bits << 3) | rd_bits;
3211 Ok(instr.to_le_bytes().to_vec())
3212 } else {
3213 let rd_bits32 = rd_bits as u32;
3216 let rm_bits32 = rm_bits as u32;
3217 let hw1: u16 = 0xFA4F;
3218 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3219 let mut bytes = hw1.to_le_bytes().to_vec();
3220 bytes.extend_from_slice(&hw2.to_le_bytes());
3221 Ok(bytes)
3222 }
3223 }
3224
3225 ArmOp::Sxth { rd, rm } => {
3227 let rd_bits = reg_to_bits(rd) as u16;
3228 let rm_bits = reg_to_bits(rm) as u16;
3229
3230 if rd_bits < 8 && rm_bits < 8 {
3231 let instr: u16 = 0xB200 | (rm_bits << 3) | rd_bits;
3233 Ok(instr.to_le_bytes().to_vec())
3234 } else {
3235 let rd_bits32 = rd_bits as u32;
3238 let rm_bits32 = rm_bits as u32;
3239 let hw1: u16 = 0xFA0F;
3240 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3241 let mut bytes = hw1.to_le_bytes().to_vec();
3242 bytes.extend_from_slice(&hw2.to_le_bytes());
3243 Ok(bytes)
3244 }
3245 }
3246
3247 ArmOp::Uxtb { rd, rm } => {
3249 let rd_bits = reg_to_bits(rd) as u16;
3250 let rm_bits = reg_to_bits(rm) as u16;
3251 if rd_bits < 8 && rm_bits < 8 {
3252 let instr: u16 = 0xB2C0 | (rm_bits << 3) | rd_bits;
3254 Ok(instr.to_le_bytes().to_vec())
3255 } else {
3256 let hw1: u16 = 0xFA5F;
3258 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3259 let mut bytes = hw1.to_le_bytes().to_vec();
3260 bytes.extend_from_slice(&hw2.to_le_bytes());
3261 Ok(bytes)
3262 }
3263 }
3264
3265 ArmOp::Uxth { rd, rm } => {
3267 let rd_bits = reg_to_bits(rd) as u16;
3268 let rm_bits = reg_to_bits(rm) as u16;
3269 if rd_bits < 8 && rm_bits < 8 {
3270 let instr: u16 = 0xB280 | (rm_bits << 3) | rd_bits;
3272 Ok(instr.to_le_bytes().to_vec())
3273 } else {
3274 let hw1: u16 = 0xFA1F;
3276 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3277 let mut bytes = hw1.to_le_bytes().to_vec();
3278 bytes.extend_from_slice(&hw2.to_le_bytes());
3279 Ok(bytes)
3280 }
3281 }
3282
3283 ArmOp::Cmp { rn, op2 } => {
3285 let rn_bits = reg_to_bits(rn) as u16;
3286
3287 if let Operand2::Imm(imm) = op2 {
3288 if *imm >= 0 && *imm <= 255 && rn_bits < 8 {
3291 let instr: u16 = 0x2800 | (rn_bits << 8) | (*imm as u16 & 0xFF);
3293 Ok(instr.to_le_bytes().to_vec())
3294 } else {
3295 self.encode_thumb32_cmp_imm(rn, *imm as u32)
3296 }
3297 } else if let Operand2::Reg(rm) = op2 {
3298 let rm_bits = reg_to_bits(rm) as u16;
3299 if rn_bits < 8 && rm_bits < 8 {
3300 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
3302 Ok(instr.to_le_bytes().to_vec())
3303 } else {
3304 let n_bit = (rn_bits >> 3) & 1;
3306 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
3307 Ok(instr.to_le_bytes().to_vec())
3308 }
3309 } else {
3310 let instr: u16 = 0xBF00;
3311 Ok(instr.to_le_bytes().to_vec())
3312 }
3313 }
3314
3315 ArmOp::Cmn { rn, op2 } => {
3318 let rn_bits = reg_to_bits(rn) as u16;
3319
3320 if let Operand2::Imm(imm) = op2 {
3321 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
3327 synth_core::Error::synthesis(
3328 "CMN immediate is not a valid ThumbExpandImm — materialize into a register",
3329 )
3330 })?;
3331 let i_bit = (field >> 11) & 1;
3332 let imm3 = (field >> 8) & 0x7;
3333 let imm8 = field & 0xFF;
3334 let hw1: u16 = (0xF110 | (i_bit << 10) as u16) | rn_bits;
3335 let hw2: u16 = (imm3 << 12) as u16 | 0x0F00 | imm8 as u16;
3336 let mut bytes = hw1.to_le_bytes().to_vec();
3337 bytes.extend_from_slice(&hw2.to_le_bytes());
3338 Ok(bytes)
3339 } else if let Operand2::Reg(rm) = op2 {
3340 let rm_bits = reg_to_bits(rm) as u16;
3341 if rn_bits < 8 && rm_bits < 8 {
3347 let instr: u16 = 0x42C0 | (rm_bits << 3) | rn_bits;
3349 Ok(instr.to_le_bytes().to_vec())
3350 } else {
3351 let hw1: u16 = 0xEB10 | rn_bits;
3352 let hw2: u16 = 0x0F00 | rm_bits;
3353 let mut bytes = hw1.to_le_bytes().to_vec();
3354 bytes.extend_from_slice(&hw2.to_le_bytes());
3355 Ok(bytes)
3356 }
3357 } else {
3358 Ok(vec![0xBF, 0x00])
3359 }
3360 }
3361
3362 ArmOp::Ldr { rd, addr } => {
3364 let rd_bits = reg_to_bits(rd);
3365 let base_bits = reg_to_bits(&addr.base);
3366
3367 if let Some(offset_reg) = &addr.offset_reg {
3369 let rm_bits = reg_to_bits(offset_reg);
3370
3371 if addr.offset != 0 {
3373 let scratch = Reg::R12;
3376 let mut bytes =
3377 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3378 bytes.extend(self.encode_thumb32_ldr_reg(rd, &addr.base, &scratch)?);
3379 return Ok(bytes);
3380 }
3381
3382 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3385 let instr: u16 = 0x5800
3387 | ((rm_bits as u16) << 6)
3388 | ((base_bits as u16) << 3)
3389 | (rd_bits as u16);
3390 return Ok(instr.to_le_bytes().to_vec());
3391 }
3392
3393 return self.encode_thumb32_ldr_reg(rd, &addr.base, offset_reg);
3395 }
3396
3397 let offset = addr.offset as u32;
3399
3400 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3401 let imm5 = (offset >> 2) as u16;
3403 let instr: u16 =
3404 0x6800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3405 Ok(instr.to_le_bytes().to_vec())
3406 } else {
3407 self.encode_thumb32_ldr(rd, &addr.base, offset)
3408 }
3409 }
3410
3411 ArmOp::Str { rd, addr } => {
3413 let rd_bits = reg_to_bits(rd);
3414 let base_bits = reg_to_bits(&addr.base);
3415
3416 if let Some(offset_reg) = &addr.offset_reg {
3418 let rm_bits = reg_to_bits(offset_reg);
3419
3420 if addr.offset != 0 {
3422 let scratch = Reg::R12;
3425 let mut bytes =
3426 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3427 bytes.extend(self.encode_thumb32_str_reg(rd, &addr.base, &scratch)?);
3428 return Ok(bytes);
3429 }
3430
3431 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3434 let instr: u16 = 0x5000
3436 | ((rm_bits as u16) << 6)
3437 | ((base_bits as u16) << 3)
3438 | (rd_bits as u16);
3439 return Ok(instr.to_le_bytes().to_vec());
3440 }
3441
3442 return self.encode_thumb32_str_reg(rd, &addr.base, offset_reg);
3444 }
3445
3446 let offset = addr.offset as u32;
3448
3449 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3450 let imm5 = (offset >> 2) as u16;
3452 let instr: u16 =
3453 0x6000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3454 Ok(instr.to_le_bytes().to_vec())
3455 } else {
3456 self.encode_thumb32_str(rd, &addr.base, offset)
3457 }
3458 }
3459
3460 ArmOp::Ldrb { rd, addr } => {
3462 let rd_bits = reg_to_bits(rd);
3463 let base_bits = reg_to_bits(&addr.base);
3464
3465 if let Some(offset_reg) = &addr.offset_reg {
3466 if addr.offset != 0 {
3467 let scratch = Reg::R12;
3468 let mut bytes =
3469 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3470 bytes.extend(self.encode_thumb32_ldrb_reg(rd, &addr.base, &scratch)?);
3471 return Ok(bytes);
3472 }
3473 return self.encode_thumb32_ldrb_reg(rd, &addr.base, offset_reg);
3474 }
3475
3476 let offset = addr.offset as u32;
3477 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3478 let instr: u16 = 0x7800
3480 | ((offset as u16) << 6)
3481 | ((base_bits as u16) << 3)
3482 | (rd_bits as u16);
3483 Ok(instr.to_le_bytes().to_vec())
3484 } else {
3485 self.encode_thumb32_ldrb_imm(rd, &addr.base, offset)
3486 }
3487 }
3488
3489 ArmOp::Ldrsb { rd, addr } => {
3491 let rd_bits = reg_to_bits(rd);
3492 let base_bits = reg_to_bits(&addr.base);
3493
3494 if let Some(offset_reg) = &addr.offset_reg {
3495 if addr.offset != 0 {
3496 let scratch = Reg::R12;
3497 let mut bytes =
3498 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3499 bytes.extend(self.encode_thumb32_ldrsb_reg(rd, &addr.base, &scratch)?);
3500 return Ok(bytes);
3501 }
3502 return self.encode_thumb32_ldrsb_reg(rd, &addr.base, offset_reg);
3503 }
3504
3505 let offset = addr.offset as u32;
3506 if rd_bits < 8 && base_bits < 8 && offset == 0 {
3509 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3511 } else {
3512 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3513 }
3514 }
3515
3516 ArmOp::Ldrh { rd, addr } => {
3518 let rd_bits = reg_to_bits(rd);
3519 let base_bits = reg_to_bits(&addr.base);
3520
3521 if let Some(offset_reg) = &addr.offset_reg {
3522 if addr.offset != 0 {
3523 let scratch = Reg::R12;
3524 let mut bytes =
3525 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3526 bytes.extend(self.encode_thumb32_ldrh_reg(rd, &addr.base, &scratch)?);
3527 return Ok(bytes);
3528 }
3529 return self.encode_thumb32_ldrh_reg(rd, &addr.base, offset_reg);
3530 }
3531
3532 let offset = addr.offset as u32;
3533 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3534 let imm5 = (offset >> 1) as u16;
3536 let instr: u16 =
3537 0x8800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3538 Ok(instr.to_le_bytes().to_vec())
3539 } else {
3540 self.encode_thumb32_ldrh_imm(rd, &addr.base, offset)
3541 }
3542 }
3543
3544 ArmOp::Ldrsh { rd, addr } => {
3546 if let Some(offset_reg) = &addr.offset_reg {
3547 if addr.offset != 0 {
3548 let scratch = Reg::R12;
3549 let mut bytes =
3550 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3551 bytes.extend(self.encode_thumb32_ldrsh_reg(rd, &addr.base, &scratch)?);
3552 return Ok(bytes);
3553 }
3554 return self.encode_thumb32_ldrsh_reg(rd, &addr.base, offset_reg);
3555 }
3556
3557 let offset = addr.offset as u32;
3558 self.encode_thumb32_ldrsh_imm(rd, &addr.base, offset)
3559 }
3560
3561 ArmOp::Strb { rd, addr } => {
3563 let rd_bits = reg_to_bits(rd);
3564 let base_bits = reg_to_bits(&addr.base);
3565
3566 if let Some(offset_reg) = &addr.offset_reg {
3567 if addr.offset != 0 {
3568 let scratch = Reg::R12;
3569 let mut bytes =
3570 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3571 bytes.extend(self.encode_thumb32_strb_reg(rd, &addr.base, &scratch)?);
3572 return Ok(bytes);
3573 }
3574 return self.encode_thumb32_strb_reg(rd, &addr.base, offset_reg);
3575 }
3576
3577 let offset = addr.offset as u32;
3578 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3579 let instr: u16 = 0x7000
3581 | ((offset as u16) << 6)
3582 | ((base_bits as u16) << 3)
3583 | (rd_bits as u16);
3584 Ok(instr.to_le_bytes().to_vec())
3585 } else {
3586 self.encode_thumb32_strb_imm(rd, &addr.base, offset)
3587 }
3588 }
3589
3590 ArmOp::Strh { rd, addr } => {
3592 let rd_bits = reg_to_bits(rd);
3593 let base_bits = reg_to_bits(&addr.base);
3594
3595 if let Some(offset_reg) = &addr.offset_reg {
3596 if addr.offset != 0 {
3597 let scratch = Reg::R12;
3598 let mut bytes =
3599 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3600 bytes.extend(self.encode_thumb32_strh_reg(rd, &addr.base, &scratch)?);
3601 return Ok(bytes);
3602 }
3603 return self.encode_thumb32_strh_reg(rd, &addr.base, offset_reg);
3604 }
3605
3606 let offset = addr.offset as u32;
3607 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3608 let imm5 = (offset >> 1) as u16;
3610 let instr: u16 =
3611 0x8000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3612 Ok(instr.to_le_bytes().to_vec())
3613 } else {
3614 self.encode_thumb32_strh_imm(rd, &addr.base, offset)
3615 }
3616 }
3617
3618 ArmOp::MemorySize { rd } => {
3620 let rd_bits = reg_to_bits(rd);
3623 let r10_bits = reg_to_bits(&Reg::R10);
3624 if rd_bits < 8 && r10_bits < 8 {
3625 let instr: u16 =
3626 0x0800 | (16u16 << 6) | ((r10_bits as u16) << 3) | (rd_bits as u16);
3627 Ok(instr.to_le_bytes().to_vec())
3628 } else {
3629 let imm5: u32 = 16;
3631 let imm3 = (imm5 >> 2) & 0x7;
3632 let imm2 = imm5 & 0x3;
3633 let hw1: u16 = 0xEA4F;
3634 let hw2: u16 =
3635 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | 0x10 | r10_bits) as u16;
3636 let mut bytes = hw1.to_le_bytes().to_vec();
3637 bytes.extend_from_slice(&hw2.to_le_bytes());
3638 Ok(bytes)
3639 }
3640 }
3641
3642 ArmOp::MemoryGrow { rd, .. } => {
3644 let rd_bits = reg_to_bits(rd);
3648 let hw1: u16 = 0xF06F; let hw2: u16 = (rd_bits << 8) as u16; let mut bytes = hw1.to_le_bytes().to_vec();
3651 bytes.extend_from_slice(&hw2.to_le_bytes());
3652 Ok(bytes)
3653 }
3654
3655 ArmOp::Bx { rm } => {
3657 let rm_bits = reg_to_bits(rm) as u16;
3658 let instr: u16 = 0x4700 | (rm_bits << 3);
3660 Ok(instr.to_le_bytes().to_vec())
3661 }
3662
3663 ArmOp::Blx { rm } => {
3666 let rm_bits = reg_to_bits(rm) as u16;
3667 let instr: u16 = 0x4780 | (rm_bits << 3);
3668 Ok(instr.to_le_bytes().to_vec())
3669 }
3670
3671 ArmOp::CallIndirect {
3676 rd: _,
3677 type_idx: _,
3678 table_index_reg,
3679 table_size,
3680 } => {
3681 let idx_reg = reg_to_bits(table_index_reg);
3682 let mut bytes = Vec::new();
3683
3684 let size_lo = *table_size & 0xFFFF;
3703 let hw1: u16 =
3704 (0xF240 | (((size_lo >> 11) & 1) << 10) | ((size_lo >> 12) & 0xF)) as u16;
3705 let hw2: u16 =
3706 ((((size_lo >> 8) & 0x7) << 12) | (12 << 8) | (size_lo & 0xFF)) as u16;
3707 bytes.extend_from_slice(&hw1.to_le_bytes());
3708 bytes.extend_from_slice(&hw2.to_le_bytes());
3709 let size_hi = *table_size >> 16;
3713 if size_hi != 0 {
3714 let hw1: u16 =
3715 (0xF2C0 | (((size_hi >> 11) & 1) << 10) | ((size_hi >> 12) & 0xF)) as u16;
3716 let hw2: u16 =
3717 ((((size_hi >> 8) & 0x7) << 12) | (12 << 8) | (size_hi & 0xFF)) as u16;
3718 bytes.extend_from_slice(&hw1.to_le_bytes());
3719 bytes.extend_from_slice(&hw2.to_le_bytes());
3720 }
3721 let cmp: u16 = (0x4500 | ((idx_reg & 8) << 4) | (12 << 3) | (idx_reg & 7)) as u16;
3724 bytes.extend_from_slice(&cmp.to_le_bytes());
3725 bytes.extend_from_slice(&0xD300u16.to_le_bytes());
3728 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
3731
3732 let hw1: u16 = 0xEA4F_u16; let hw2: u16 = ((0x0C00 | (0b10 << 6)) | idx_reg) as u16;
3741 bytes.extend_from_slice(&hw1.to_le_bytes());
3742 bytes.extend_from_slice(&hw2.to_le_bytes());
3743
3744 let ldr_hw1: u16 = 0xF85B; let ldr_hw2: u16 = 0xC00C; bytes.extend_from_slice(&ldr_hw1.to_le_bytes());
3750 bytes.extend_from_slice(&ldr_hw2.to_le_bytes());
3751
3752 let blx: u16 = 0x47E0; bytes.extend_from_slice(&blx.to_le_bytes());
3756
3757 Ok(bytes)
3758 }
3759
3760 ArmOp::Label { .. } => Ok(Vec::new()),
3762
3763 ArmOp::Bcc { cond, label: _ } => {
3765 use synth_synthesis::Condition;
3766 let cond_bits: u16 = match cond {
3767 Condition::EQ => 0x0,
3768 Condition::NE => 0x1,
3769 Condition::HS => 0x2,
3770 Condition::LO => 0x3,
3771 Condition::HI => 0x8,
3772 Condition::LS => 0x9,
3773 Condition::GE => 0xA,
3774 Condition::LT => 0xB,
3775 Condition::GT => 0xC,
3776 Condition::LE => 0xD,
3777 };
3778 let instr: u16 = 0xD000 | (cond_bits << 8);
3780 Ok(instr.to_le_bytes().to_vec())
3781 }
3782
3783 ArmOp::B { label: _ } => {
3785 let instr: u16 = 0xE000; Ok(instr.to_le_bytes().to_vec())
3789 }
3790
3791 ArmOp::Bhs { label: _ } => {
3794 let instr: u16 = 0xD200; Ok(instr.to_le_bytes().to_vec())
3798 }
3799
3800 ArmOp::Blo { label: _ } => {
3803 let instr: u16 = 0xD300; Ok(instr.to_le_bytes().to_vec())
3807 }
3808
3809 ArmOp::BOffset { offset } => {
3812 let halfword_offset = *offset;
3815
3816 if (-1024..=1022).contains(&halfword_offset) {
3819 let imm11 = (halfword_offset as u16) & 0x7FF;
3821 let instr: u16 = 0xE000 | imm11;
3822 Ok(instr.to_le_bytes().to_vec())
3823 } else {
3824 let signed_offset = halfword_offset << 1; let s = if signed_offset < 0 { 1u32 } else { 0u32 };
3840 let uoffset = signed_offset as u32;
3841 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;
3849 let hw2: u16 = (0x9000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
3850
3851 let mut bytes = hw1.to_le_bytes().to_vec();
3852 bytes.extend_from_slice(&hw2.to_le_bytes());
3853 Ok(bytes)
3854 }
3855 }
3856
3857 ArmOp::BCondOffset { cond, offset } => {
3859 use synth_synthesis::Condition;
3860 let cond_bits: u16 = match cond {
3861 Condition::EQ => 0x0,
3862 Condition::NE => 0x1,
3863 Condition::HS => 0x2,
3864 Condition::LO => 0x3,
3865 Condition::HI => 0x8,
3866 Condition::LS => 0x9,
3867 Condition::GE => 0xA,
3868 Condition::LT => 0xB,
3869 Condition::GT => 0xC,
3870 Condition::LE => 0xD,
3871 };
3872
3873 let halfword_offset = *offset;
3876
3877 if (-128..=127).contains(&halfword_offset) {
3880 let imm8 = (halfword_offset as u16) & 0xFF;
3881 let instr: u16 = 0xD000 | (cond_bits << 8) | imm8;
3882 Ok(instr.to_le_bytes().to_vec())
3883 } else {
3884 let offset = halfword_offset >> 1;
3888 let s = if offset < 0 { 1u32 } else { 0u32 };
3889 let imm6 = ((offset >> 11) as u32) & 0x3F;
3890 let imm11 = (offset as u32) & 0x7FF;
3891 let j1 = if s == 1 { 1 } else { 0 };
3892 let j2 = if s == 1 { 1 } else { 0 };
3893
3894 let hw1: u16 = (0xF000 | (s << 10) | ((cond_bits as u32) << 6) | imm6) as u16;
3895 let hw2: u16 = (0x8000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
3896
3897 let mut bytes = hw1.to_le_bytes().to_vec();
3898 bytes.extend_from_slice(&hw2.to_le_bytes());
3899 Ok(bytes)
3900 }
3901 }
3902
3903 ArmOp::Bl { label: _ } => {
3904 let hw1: u16 = 0xF7FF;
3919 let hw2: u16 = 0xFFFE;
3920 let mut bytes = hw1.to_le_bytes().to_vec();
3921 bytes.extend_from_slice(&hw2.to_le_bytes());
3922 Ok(bytes)
3923 }
3924
3925 ArmOp::Mvn { rd, op2 } => {
3927 if let Operand2::Reg(rm) = op2 {
3928 let rd_bits = reg_to_bits(rd) as u16;
3929 let rm_bits = reg_to_bits(rm) as u16;
3930
3931 if rd_bits < 8 && rm_bits < 8 {
3932 let instr: u16 = 0x43C0 | (rm_bits << 3) | rd_bits;
3934 Ok(instr.to_le_bytes().to_vec())
3935 } else {
3936 let hw1: u16 = 0xEA6F_u16;
3938 let hw2: u16 = ((reg_to_bits(rd) << 8) | reg_to_bits(rm)) as u16;
3939 let mut bytes = hw1.to_le_bytes().to_vec();
3940 bytes.extend_from_slice(&hw2.to_le_bytes());
3941 Ok(bytes)
3942 }
3943 } else {
3944 let instr: u16 = 0xBF00;
3945 Ok(instr.to_le_bytes().to_vec())
3946 }
3947 }
3948
3949 ArmOp::Movw { rd, imm16 } => {
3951 self.encode_thumb32_movw_raw(reg_to_bits(rd), *imm16 as u32)
3952 }
3953
3954 ArmOp::Movt { rd, imm16 } => {
3956 self.encode_thumb32_movt_raw(reg_to_bits(rd), *imm16 as u32)
3957 }
3958
3959 ArmOp::MovwSym { rd, addend, .. } => {
3964 self.encode_thumb32_movw_raw(reg_to_bits(rd), (*addend as u32) & 0xffff)
3965 }
3966 ArmOp::MovtSym { rd, addend, .. } => {
3967 self.encode_thumb32_movt_raw(reg_to_bits(rd), ((*addend as u32) >> 16) & 0xffff)
3968 }
3969
3970 ArmOp::LdrSym { rd, .. } => {
3978 let rt = reg_to_bits(rd) as u16;
3979 let hw1: u16 = 0xF8DF; let hw2: u16 = rt << 12; let mut bytes = Vec::with_capacity(4);
3982 bytes.extend_from_slice(&hw1.to_le_bytes());
3983 bytes.extend_from_slice(&hw2.to_le_bytes());
3984 Ok(bytes)
3985 }
3986
3987 ArmOp::SetCond { rd, cond } => {
3993 let rd_bits = reg_to_bits(rd) as u16;
3994
3995 use synth_synthesis::Condition;
3997 let cond_bits: u16 = match cond {
3998 Condition::EQ => 0x0,
3999 Condition::NE => 0x1,
4000 Condition::LT => 0xB,
4001 Condition::LE => 0xD,
4002 Condition::GT => 0xC,
4003 Condition::GE => 0xA,
4004 Condition::LO => 0x3, Condition::LS => 0x9, Condition::HI => 0x8, Condition::HS => 0x2, };
4009
4010 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
4015 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
4016
4017 let mut bytes = ite_instr.to_le_bytes().to_vec();
4028 let push_mov = |bytes: &mut Vec<u8>, imm: u16| {
4029 if rd_bits <= 7 {
4030 let m: u16 = 0x2000 | (rd_bits << 8) | imm; bytes.extend_from_slice(&m.to_le_bytes());
4032 } else {
4033 let hw1: u16 = 0xF04F;
4035 let hw2: u16 = (rd_bits << 8) | imm;
4036 bytes.extend_from_slice(&hw1.to_le_bytes());
4037 bytes.extend_from_slice(&hw2.to_le_bytes());
4038 }
4039 };
4040 push_mov(&mut bytes, 1); push_mov(&mut bytes, 0); Ok(bytes)
4043 }
4044
4045 ArmOp::I64SetCond {
4050 rd,
4051 rn_lo,
4052 rn_hi,
4053 rm_lo,
4054 rm_hi,
4055 cond,
4056 } => {
4057 use synth_synthesis::Condition;
4058 let rd_bits = reg_to_bits(rd) as u16;
4059 let mut bytes = Vec::new();
4060
4061 let encode_cmp_reg = |rn: &synth_synthesis::Reg,
4063 rm: &synth_synthesis::Reg|
4064 -> Vec<u8> {
4065 let rn_bits = reg_to_bits(rn) as u16;
4066 let rm_bits = reg_to_bits(rm) as u16;
4067 if rn_bits < 8 && rm_bits < 8 {
4068 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
4069 instr.to_le_bytes().to_vec()
4070 } else {
4071 let n_bit = (rn_bits >> 3) & 1;
4072 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
4073 instr.to_le_bytes().to_vec()
4074 }
4075 };
4076
4077 let encode_ite = |cond_bits: u16| -> Vec<u8> {
4079 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
4080 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
4081 ite_instr.to_le_bytes().to_vec()
4082 };
4083
4084 let encode_setcond = |cond_bits: u16, rd_bits: u16| -> Vec<u8> {
4086 let mut b = encode_ite(cond_bits);
4087 if rd_bits < 8 {
4088 let mov_one: u16 = 0x2001 | (rd_bits << 8);
4089 let mov_zero: u16 = 0x2000 | (rd_bits << 8);
4090 b.extend_from_slice(&mov_one.to_le_bytes());
4091 b.extend_from_slice(&mov_zero.to_le_bytes());
4092 } else {
4093 for imm in [1u16, 0u16] {
4101 let hw1: u16 = 0xF04F;
4102 let hw2: u16 = (rd_bits << 8) | imm;
4103 b.extend_from_slice(&hw1.to_le_bytes());
4104 b.extend_from_slice(&hw2.to_le_bytes());
4105 }
4106 }
4107 b
4108 };
4109
4110 match cond {
4111 Condition::EQ | Condition::NE => {
4112 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4114
4115 let it_eq: u16 = 0xBF08; bytes.extend_from_slice(&it_eq.to_le_bytes());
4118
4119 bytes.extend_from_slice(&encode_cmp_reg(rn_hi, rm_hi));
4121
4122 let cond_bits: u16 = match cond {
4124 Condition::EQ => 0x0,
4125 Condition::NE => 0x1,
4126 _ => unreachable!(),
4127 };
4128 bytes.extend_from_slice(&encode_setcond(cond_bits, rd_bits));
4129 }
4130
4131 Condition::LT => {
4132 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4134
4135 let rn_hi_bits = reg_to_bits(rn_hi);
4138 let rm_hi_bits = reg_to_bits(rm_hi);
4139 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4140 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4141 bytes.extend_from_slice(&hw1.to_le_bytes());
4142 bytes.extend_from_slice(&hw2.to_le_bytes());
4143
4144 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4147
4148 Condition::GT => {
4149 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4152
4153 let rm_hi_bits = reg_to_bits(rm_hi);
4155 let rn_hi_bits = reg_to_bits(rn_hi);
4156 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4157 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4158 bytes.extend_from_slice(&hw1.to_le_bytes());
4159 bytes.extend_from_slice(&hw2.to_le_bytes());
4160
4161 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4164
4165 Condition::LE => {
4166 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4170
4171 let rm_hi_bits = reg_to_bits(rm_hi);
4173 let rn_hi_bits = reg_to_bits(rn_hi);
4174 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4175 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4176 bytes.extend_from_slice(&hw1.to_le_bytes());
4177 bytes.extend_from_slice(&hw2.to_le_bytes());
4178
4179 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4182
4183 Condition::GE => {
4184 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4187
4188 let rn_hi_bits = reg_to_bits(rn_hi);
4190 let rm_hi_bits = reg_to_bits(rm_hi);
4191 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4192 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4193 bytes.extend_from_slice(&hw1.to_le_bytes());
4194 bytes.extend_from_slice(&hw2.to_le_bytes());
4195
4196 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4199
4200 Condition::LO => {
4202 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4204 let rn_hi_bits = reg_to_bits(rn_hi);
4205 let rm_hi_bits = reg_to_bits(rm_hi);
4206 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4207 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4208 bytes.extend_from_slice(&hw1.to_le_bytes());
4209 bytes.extend_from_slice(&hw2.to_le_bytes());
4210 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4212
4213 Condition::HI => {
4214 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4216 let rm_hi_bits = reg_to_bits(rm_hi);
4217 let rn_hi_bits = reg_to_bits(rn_hi);
4218 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4219 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4220 bytes.extend_from_slice(&hw1.to_le_bytes());
4221 bytes.extend_from_slice(&hw2.to_le_bytes());
4222 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4224
4225 Condition::LS => {
4226 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4228 let rm_hi_bits = reg_to_bits(rm_hi);
4229 let rn_hi_bits = reg_to_bits(rn_hi);
4230 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4231 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4232 bytes.extend_from_slice(&hw1.to_le_bytes());
4233 bytes.extend_from_slice(&hw2.to_le_bytes());
4234 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
4236
4237 Condition::HS => {
4238 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4240 let rn_hi_bits = reg_to_bits(rn_hi);
4241 let rm_hi_bits = reg_to_bits(rm_hi);
4242 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4243 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4244 bytes.extend_from_slice(&hw1.to_le_bytes());
4245 bytes.extend_from_slice(&hw2.to_le_bytes());
4246 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
4248 }
4249
4250 Ok(bytes)
4251 }
4252
4253 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
4256 let rd_bits = reg_to_bits(rd);
4257 let rn_lo_bits = reg_to_bits(rn_lo);
4258 let rn_hi_bits = reg_to_bits(rn_hi);
4259 let mut bytes = Vec::new();
4260
4261 let hw1: u16 = (0xEA40 | rn_lo_bits) as u16;
4263 let hw2: u16 = ((rd_bits << 8) | rn_hi_bits) as u16;
4264 bytes.extend_from_slice(&hw1.to_le_bytes());
4265 bytes.extend_from_slice(&hw2.to_le_bytes());
4266
4267 if rd_bits < 8 {
4272 let cmp_instr: u16 = 0x2800 | ((rd_bits as u16) << 8);
4273 bytes.extend_from_slice(&cmp_instr.to_le_bytes());
4274 } else {
4275 let hw1: u16 = 0xF1B0 | (rd_bits as u16);
4276 let hw2: u16 = 0x0F00;
4277 bytes.extend_from_slice(&hw1.to_le_bytes());
4278 bytes.extend_from_slice(&hw2.to_le_bytes());
4279 }
4280
4281 let mask = 0xC_u16; let ite_instr: u16 = 0xBF00 | mask;
4285 bytes.extend_from_slice(&ite_instr.to_le_bytes());
4286 if rd_bits < 8 {
4287 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
4288 let mov_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
4289 bytes.extend_from_slice(&mov_one.to_le_bytes());
4290 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4291 } else {
4292 for imm in [1u16, 0u16] {
4293 let hw1: u16 = 0xF04F;
4294 let hw2: u16 = ((rd_bits as u16) << 8) | imm;
4295 bytes.extend_from_slice(&hw1.to_le_bytes());
4296 bytes.extend_from_slice(&hw2.to_le_bytes());
4297 }
4298 }
4299
4300 Ok(bytes)
4301 }
4302
4303 ArmOp::I64Mul {
4307 rd_lo,
4308 rd_hi,
4309 rn_lo,
4310 rn_hi,
4311 rm_lo,
4312 rm_hi,
4313 } => {
4314 let rd_lo_bits = reg_to_bits(rd_lo);
4315 let rd_hi_bits = reg_to_bits(rd_hi);
4316 let rn_lo_bits = reg_to_bits(rn_lo);
4317 let rn_hi_bits = reg_to_bits(rn_hi);
4318 let rm_lo_bits = reg_to_bits(rm_lo);
4319 let rm_hi_bits = reg_to_bits(rm_hi);
4320 let r12: u32 = 12; let mut bytes = Vec::new();
4322
4323 let hw1: u16 = (0xFB00 | rn_lo_bits) as u16;
4326 let hw2: u16 = (0xF000 | (r12 << 8) | rm_hi_bits) as u16;
4327 bytes.extend_from_slice(&hw1.to_le_bytes());
4328 bytes.extend_from_slice(&hw2.to_le_bytes());
4329
4330 let hw1: u16 = (0xFB00 | rn_hi_bits) as u16;
4333 let hw2: u16 = ((r12 << 12) | (r12 << 8) | rm_lo_bits) as u16;
4334 bytes.extend_from_slice(&hw1.to_le_bytes());
4335 bytes.extend_from_slice(&hw2.to_le_bytes());
4336
4337 let hw1: u16 = (0xFBA0 | rn_lo_bits) as u16;
4340 let hw2: u16 = ((rd_lo_bits << 12) | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4341 bytes.extend_from_slice(&hw1.to_le_bytes());
4342 bytes.extend_from_slice(&hw2.to_le_bytes());
4343
4344 let d_bit = (rd_hi_bits >> 3) & 1;
4347 let add_instr: u16 =
4348 (0x4400 | (d_bit << 7) | (r12 << 3) | (rd_hi_bits & 0x7)) as u16;
4349 bytes.extend_from_slice(&add_instr.to_le_bytes());
4350
4351 Ok(bytes)
4352 }
4353
4354 ArmOp::I64Shl {
4357 rd_lo,
4358 rd_hi,
4359 rn_lo,
4360 rn_hi,
4361 rm_lo,
4362 rm_hi,
4363 } => {
4364 let rd_lo_bits = reg_to_bits(rd_lo);
4365 let rd_hi_bits = reg_to_bits(rd_hi);
4366 let rn_lo_bits = reg_to_bits(rn_lo);
4367 let rn_hi_bits = reg_to_bits(rn_hi);
4368 let rm_lo_bits = reg_to_bits(rm_lo);
4369 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4371
4372 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4374 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4375 bytes.extend_from_slice(&hw1.to_le_bytes());
4376 bytes.extend_from_slice(&hw2.to_le_bytes());
4377
4378 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4380 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4381 bytes.extend_from_slice(&hw1.to_le_bytes());
4382 bytes.extend_from_slice(&hw2.to_le_bytes());
4383
4384 let bpl: u16 = 0xD50A;
4386 bytes.extend_from_slice(&bpl.to_le_bytes());
4387
4388 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4391 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4392 bytes.extend_from_slice(&hw1.to_le_bytes());
4393 bytes.extend_from_slice(&hw2.to_le_bytes());
4394
4395 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4397 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4398 bytes.extend_from_slice(&hw1.to_le_bytes());
4399 bytes.extend_from_slice(&hw2.to_le_bytes());
4400
4401 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4403 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4404 bytes.extend_from_slice(&hw1.to_le_bytes());
4405 bytes.extend_from_slice(&hw2.to_le_bytes());
4406
4407 let hw1: u16 = (0xEA40 | rd_hi_bits) as u16;
4409 let hw2: u16 = ((rd_hi_bits << 8) | rm_hi_bits) as u16;
4410 bytes.extend_from_slice(&hw1.to_le_bytes());
4411 bytes.extend_from_slice(&hw2.to_le_bytes());
4412
4413 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4415 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4416 bytes.extend_from_slice(&hw1.to_le_bytes());
4417 bytes.extend_from_slice(&hw2.to_le_bytes());
4418
4419 let b_done: u16 = 0xE002;
4421 bytes.extend_from_slice(&b_done.to_le_bytes());
4422
4423 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4426 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_hi_bits) as u16;
4427 bytes.extend_from_slice(&hw1.to_le_bytes());
4428 bytes.extend_from_slice(&hw2.to_le_bytes());
4429
4430 let mov_zero: u16 = 0x2000 | ((rd_lo_bits as u16) << 8);
4432 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4433
4434 Ok(bytes) }
4436
4437 ArmOp::I64ShrU {
4439 rd_lo,
4440 rd_hi,
4441 rn_lo,
4442 rn_hi,
4443 rm_lo,
4444 rm_hi,
4445 } => {
4446 let rd_lo_bits = reg_to_bits(rd_lo);
4447 let rd_hi_bits = reg_to_bits(rd_hi);
4448 let rn_lo_bits = reg_to_bits(rn_lo);
4449 let rn_hi_bits = reg_to_bits(rn_hi);
4450 let rm_lo_bits = reg_to_bits(rm_lo);
4451 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4453
4454 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4456 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4457 bytes.extend_from_slice(&hw1.to_le_bytes());
4458 bytes.extend_from_slice(&hw2.to_le_bytes());
4459
4460 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4462 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4463 bytes.extend_from_slice(&hw1.to_le_bytes());
4464 bytes.extend_from_slice(&hw2.to_le_bytes());
4465
4466 let bpl: u16 = 0xD50A;
4468 bytes.extend_from_slice(&bpl.to_le_bytes());
4469
4470 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4473 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4474 bytes.extend_from_slice(&hw1.to_le_bytes());
4475 bytes.extend_from_slice(&hw2.to_le_bytes());
4476
4477 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4479 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4480 bytes.extend_from_slice(&hw1.to_le_bytes());
4481 bytes.extend_from_slice(&hw2.to_le_bytes());
4482
4483 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4485 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4486 bytes.extend_from_slice(&hw1.to_le_bytes());
4487 bytes.extend_from_slice(&hw2.to_le_bytes());
4488
4489 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4491 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4492 bytes.extend_from_slice(&hw1.to_le_bytes());
4493 bytes.extend_from_slice(&hw2.to_le_bytes());
4494
4495 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4497 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4498 bytes.extend_from_slice(&hw1.to_le_bytes());
4499 bytes.extend_from_slice(&hw2.to_le_bytes());
4500
4501 let b_done: u16 = 0xE002;
4503 bytes.extend_from_slice(&b_done.to_le_bytes());
4504
4505 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4508 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4509 bytes.extend_from_slice(&hw1.to_le_bytes());
4510 bytes.extend_from_slice(&hw2.to_le_bytes());
4511
4512 let mov_zero: u16 = 0x2000 | ((rd_hi_bits as u16) << 8);
4514 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4515
4516 Ok(bytes) }
4518
4519 ArmOp::I64ShrS {
4521 rd_lo,
4522 rd_hi,
4523 rn_lo,
4524 rn_hi,
4525 rm_lo,
4526 rm_hi,
4527 } => {
4528 let rd_lo_bits = reg_to_bits(rd_lo);
4529 let rd_hi_bits = reg_to_bits(rd_hi);
4530 let rn_lo_bits = reg_to_bits(rn_lo);
4531 let rn_hi_bits = reg_to_bits(rn_hi);
4532 let rm_lo_bits = reg_to_bits(rm_lo);
4533 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4535
4536 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4538 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4539 bytes.extend_from_slice(&hw1.to_le_bytes());
4540 bytes.extend_from_slice(&hw2.to_le_bytes());
4541
4542 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4544 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4545 bytes.extend_from_slice(&hw1.to_le_bytes());
4546 bytes.extend_from_slice(&hw2.to_le_bytes());
4547
4548 let bpl: u16 = 0xD50A;
4550 bytes.extend_from_slice(&bpl.to_le_bytes());
4551
4552 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4555 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4556 bytes.extend_from_slice(&hw1.to_le_bytes());
4557 bytes.extend_from_slice(&hw2.to_le_bytes());
4558
4559 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4561 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4562 bytes.extend_from_slice(&hw1.to_le_bytes());
4563 bytes.extend_from_slice(&hw2.to_le_bytes());
4564
4565 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4567 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4568 bytes.extend_from_slice(&hw1.to_le_bytes());
4569 bytes.extend_from_slice(&hw2.to_le_bytes());
4570
4571 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4573 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4574 bytes.extend_from_slice(&hw1.to_le_bytes());
4575 bytes.extend_from_slice(&hw2.to_le_bytes());
4576
4577 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4579 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4580 bytes.extend_from_slice(&hw1.to_le_bytes());
4581 bytes.extend_from_slice(&hw2.to_le_bytes());
4582
4583 let b_done: u16 = 0xE003;
4585 bytes.extend_from_slice(&b_done.to_le_bytes());
4586
4587 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4590 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4591 bytes.extend_from_slice(&hw1.to_le_bytes());
4592 bytes.extend_from_slice(&hw2.to_le_bytes());
4593
4594 let hw1: u16 = 0xEA4F;
4598 let hw2: u16 = (0x7000 | (rd_hi_bits << 8) | 0x00E0 | rn_hi_bits) as u16;
4599 bytes.extend_from_slice(&hw1.to_le_bytes());
4600 bytes.extend_from_slice(&hw2.to_le_bytes());
4601
4602 Ok(bytes) }
4604
4605 ArmOp::I64Rotl {
4616 rdlo,
4617 rdhi,
4618 rnlo,
4619 rnhi,
4620 shift,
4621 } => {
4622 let mut bytes = Vec::new();
4623 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4624
4625 let core: [u16; 35] = [
4626 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, ];
4649 for hw in core {
4650 bytes.extend_from_slice(&hw.to_le_bytes());
4651 }
4652
4653 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4654 Ok(bytes) }
4656
4657 ArmOp::I64Rotr {
4664 rdlo,
4665 rdhi,
4666 rnlo,
4667 rnhi,
4668 shift,
4669 } => {
4670 let mut bytes = Vec::new();
4671 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4672
4673 let core: [u16; 35] = [
4674 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, ];
4697 for hw in core {
4698 bytes.extend_from_slice(&hw.to_le_bytes());
4699 }
4700
4701 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4702 Ok(bytes) }
4704
4705 ArmOp::I64Clz { rd, rnlo, rnhi } => {
4719 let rd_bits = reg_to_bits(rd);
4720 let rn_lo_bits = reg_to_bits(rnlo);
4721 let rn_hi_bits = reg_to_bits(rnhi);
4722 let mut bytes = Vec::new();
4723
4724 let hw1: u16 = (0xF1B0 | rn_hi_bits) as u16;
4726 let hw2: u16 = 0x0F00;
4727 bytes.extend_from_slice(&hw1.to_le_bytes());
4728 bytes.extend_from_slice(&hw2.to_le_bytes());
4729
4730 let beq: u16 = 0xD003;
4733 bytes.extend_from_slice(&beq.to_le_bytes());
4734
4735 let hw1: u16 = (0xFAB0 | rn_hi_bits) as u16;
4738 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_hi_bits) as u16;
4739 bytes.extend_from_slice(&hw1.to_le_bytes());
4740 bytes.extend_from_slice(&hw2.to_le_bytes());
4741
4742 let b_done: u16 = 0xE004;
4745 bytes.extend_from_slice(&b_done.to_le_bytes());
4746
4747 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
4749
4750 let hw1: u16 = (0xFAB0 | rn_lo_bits) as u16;
4754 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_lo_bits) as u16;
4755 bytes.extend_from_slice(&hw1.to_le_bytes());
4756 bytes.extend_from_slice(&hw2.to_le_bytes());
4757
4758 let hw1: u16 = (0xF100 | rd_bits) as u16;
4760 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
4761 bytes.extend_from_slice(&hw1.to_le_bytes());
4762 bytes.extend_from_slice(&hw2.to_le_bytes());
4763
4764 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4768 bytes.extend_from_slice(&mov0.to_le_bytes());
4769
4770 Ok(bytes)
4771 }
4772
4773 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
4789 let rd_bits = reg_to_bits(rd);
4790 let rn_lo_bits = reg_to_bits(rnlo);
4791 let rn_hi_bits = reg_to_bits(rnhi);
4792 let mut bytes = Vec::new();
4793
4794 let hw1: u16 = (0xF1B0 | rn_lo_bits) as u16;
4796 let hw2: u16 = 0x0F00;
4797 bytes.extend_from_slice(&hw1.to_le_bytes());
4798 bytes.extend_from_slice(&hw2.to_le_bytes());
4799
4800 let beq: u16 = 0xD005;
4803 bytes.extend_from_slice(&beq.to_le_bytes());
4804
4805 let hw1: u16 = (0xFA90 | rn_lo_bits) as u16;
4808 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_lo_bits) as u16;
4809 bytes.extend_from_slice(&hw1.to_le_bytes());
4810 bytes.extend_from_slice(&hw2.to_le_bytes());
4811
4812 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
4815 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
4816 bytes.extend_from_slice(&hw1.to_le_bytes());
4817 bytes.extend_from_slice(&hw2.to_le_bytes());
4818
4819 let b_done: u16 = 0xE006;
4822 bytes.extend_from_slice(&b_done.to_le_bytes());
4823
4824 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
4826
4827 let hw1: u16 = (0xFA90 | rn_hi_bits) as u16;
4831 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_hi_bits) as u16;
4832 bytes.extend_from_slice(&hw1.to_le_bytes());
4833 bytes.extend_from_slice(&hw2.to_le_bytes());
4834
4835 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
4838 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
4839 bytes.extend_from_slice(&hw1.to_le_bytes());
4840 bytes.extend_from_slice(&hw2.to_le_bytes());
4841
4842 let hw1: u16 = (0xF100 | rd_bits) as u16;
4844 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
4845 bytes.extend_from_slice(&hw1.to_le_bytes());
4846 bytes.extend_from_slice(&hw2.to_le_bytes());
4847
4848 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4851 bytes.extend_from_slice(&mov0.to_le_bytes());
4852
4853 Ok(bytes)
4854 }
4855
4856 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
4860 let rd_bits = reg_to_bits(rd);
4861 let rn_lo_bits = reg_to_bits(rnlo);
4862 let rn_hi_bits = reg_to_bits(rnhi);
4863 let r12: u32 = 12; let r3: u32 = 3; let mut bytes = Vec::new();
4866
4867 bytes.extend_from_slice(&0xB438u16.to_le_bytes());
4869
4870 let mov: u16 = (0x4600 | (1 << 7) | (rn_lo_bits << 3) | 4) as u16;
4883 bytes.extend_from_slice(&mov.to_le_bytes());
4884 let mov: u16 = (0x4600 | (rn_hi_bits << 3) | 5) as u16;
4886 bytes.extend_from_slice(&mov.to_le_bytes());
4887 bytes.extend_from_slice(&0x4664u16.to_le_bytes());
4889
4890 let hw1: u16 = 0xEA4F;
4894 let hw2: u16 = ((r12 << 8) | 0x50 | 4) as u16;
4895 bytes.extend_from_slice(&hw1.to_le_bytes());
4896 bytes.extend_from_slice(&hw2.to_le_bytes());
4897
4898 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
4901 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4902 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
4904 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4905
4906 let hw1: u16 = (0xEA00 | r12) as u16;
4908 let hw2: u16 = ((r12 << 8) | r3) as u16;
4909 bytes.extend_from_slice(&hw1.to_le_bytes());
4910 bytes.extend_from_slice(&hw2.to_le_bytes());
4911
4912 let hw1: u16 = (0xEBA0 | 4) as u16;
4914 let hw2: u16 = ((4 << 8) | r12) as u16;
4915 bytes.extend_from_slice(&hw1.to_le_bytes());
4916 bytes.extend_from_slice(&hw2.to_le_bytes());
4917
4918 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
4922 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4923 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
4925 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4926
4927 let hw1: u16 = (0xEA00 | 4) as u16;
4929 let hw2: u16 = ((r12 << 8) | r3) as u16;
4930 bytes.extend_from_slice(&hw1.to_le_bytes());
4931 bytes.extend_from_slice(&hw2.to_le_bytes());
4932
4933 let hw1: u16 = 0xEA4F;
4935 let hw2: u16 = ((4 << 8) | 0x90 | 4) as u16;
4936 bytes.extend_from_slice(&hw1.to_le_bytes());
4937 bytes.extend_from_slice(&hw2.to_le_bytes());
4938
4939 let hw1: u16 = (0xEA00 | 4) as u16;
4941 let hw2: u16 = ((4 << 8) | r3) as u16;
4942 bytes.extend_from_slice(&hw1.to_le_bytes());
4943 bytes.extend_from_slice(&hw2.to_le_bytes());
4944
4945 let hw1: u16 = (0xEB00 | 4) as u16;
4947 let hw2: u16 = ((4 << 8) | r12) as u16;
4948 bytes.extend_from_slice(&hw1.to_le_bytes());
4949 bytes.extend_from_slice(&hw2.to_le_bytes());
4950
4951 let hw1: u16 = 0xEA4F;
4956 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 4) as u16;
4957 bytes.extend_from_slice(&hw1.to_le_bytes());
4958 bytes.extend_from_slice(&hw2.to_le_bytes());
4959
4960 let hw1: u16 = (0xEB00 | 4) as u16;
4962 let hw2: u16 = ((4 << 8) | r12) as u16;
4963 bytes.extend_from_slice(&hw1.to_le_bytes());
4964 bytes.extend_from_slice(&hw2.to_le_bytes());
4965
4966 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
4971 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4972 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
4974 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4975
4976 let hw1: u16 = (0xEA00 | 4) as u16;
4978 let hw2: u16 = ((4 << 8) | r3) as u16;
4979 bytes.extend_from_slice(&hw1.to_le_bytes());
4980 bytes.extend_from_slice(&hw2.to_le_bytes());
4981
4982 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
4986 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4987 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
4989 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4990
4991 let hw1: u16 = (0xFB00 | 4) as u16;
4994 let hw2: u16 = (0xF000 | (4 << 8) | r3) as u16;
4995 bytes.extend_from_slice(&hw1.to_le_bytes());
4996 bytes.extend_from_slice(&hw2.to_le_bytes());
4997
4998 let hw1: u16 = 0xEA4F;
5001 let hw2: u16 = (0x6000 | (4 << 8) | 0x10 | 4) 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 = 0xEA4F;
5008 let hw2: u16 = ((r12 << 8) | 0x50 | 5) as u16;
5009 bytes.extend_from_slice(&hw1.to_le_bytes());
5010 bytes.extend_from_slice(&hw2.to_le_bytes());
5011
5012 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
5014 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5015 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
5016 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5017
5018 let hw1: u16 = (0xEA00 | r12) as u16;
5019 let hw2: u16 = ((r12 << 8) | r3) as u16;
5020 bytes.extend_from_slice(&hw1.to_le_bytes());
5021 bytes.extend_from_slice(&hw2.to_le_bytes());
5022
5023 let hw1: u16 = (0xEBA0 | 5) as u16;
5024 let hw2: u16 = ((5 << 8) | r12) as u16;
5025 bytes.extend_from_slice(&hw1.to_le_bytes());
5026 bytes.extend_from_slice(&hw2.to_le_bytes());
5027
5028 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
5030 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5031 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
5032 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5033
5034 let hw1: u16 = (0xEA00 | 5) as u16;
5035 let hw2: u16 = ((r12 << 8) | r3) as u16;
5036 bytes.extend_from_slice(&hw1.to_le_bytes());
5037 bytes.extend_from_slice(&hw2.to_le_bytes());
5038
5039 let hw1: u16 = 0xEA4F;
5040 let hw2: u16 = ((5 << 8) | 0x90 | 5) as u16;
5041 bytes.extend_from_slice(&hw1.to_le_bytes());
5042 bytes.extend_from_slice(&hw2.to_le_bytes());
5043
5044 let hw1: u16 = (0xEA00 | 5) as u16;
5045 let hw2: u16 = ((5 << 8) | r3) as u16;
5046 bytes.extend_from_slice(&hw1.to_le_bytes());
5047 bytes.extend_from_slice(&hw2.to_le_bytes());
5048
5049 let hw1: u16 = (0xEB00 | 5) as u16;
5050 let hw2: u16 = ((5 << 8) | r12) as u16;
5051 bytes.extend_from_slice(&hw1.to_le_bytes());
5052 bytes.extend_from_slice(&hw2.to_le_bytes());
5053
5054 let hw1: u16 = 0xEA4F;
5057 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 5) as u16;
5058 bytes.extend_from_slice(&hw1.to_le_bytes());
5059 bytes.extend_from_slice(&hw2.to_le_bytes());
5060
5061 let hw1: u16 = (0xEB00 | 5) as u16;
5062 let hw2: u16 = ((5 << 8) | r12) as u16;
5063 bytes.extend_from_slice(&hw1.to_le_bytes());
5064 bytes.extend_from_slice(&hw2.to_le_bytes());
5065
5066 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
5068 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5069 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
5070 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5071
5072 let hw1: u16 = (0xEA00 | 5) as u16;
5073 let hw2: u16 = ((5 << 8) | r3) as u16;
5074 bytes.extend_from_slice(&hw1.to_le_bytes());
5075 bytes.extend_from_slice(&hw2.to_le_bytes());
5076
5077 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
5079 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5080 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
5081 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5082
5083 let hw1: u16 = (0xFB00 | 5) as u16;
5086 let hw2: u16 = (0xF000 | (5 << 8) | r3) as u16;
5087 bytes.extend_from_slice(&hw1.to_le_bytes());
5088 bytes.extend_from_slice(&hw2.to_le_bytes());
5089
5090 let hw1: u16 = 0xEA4F;
5093 let hw2: u16 = (0x6000 | (5 << 8) | 0x10 | 5) as u16;
5094 bytes.extend_from_slice(&hw1.to_le_bytes());
5095 bytes.extend_from_slice(&hw2.to_le_bytes());
5096
5097 bytes.extend_from_slice(&0xEB04u16.to_le_bytes());
5106 bytes.extend_from_slice(&0x0C05u16.to_le_bytes());
5107
5108 bytes.extend_from_slice(&0xBC38u16.to_le_bytes());
5110
5111 let mov: u16 =
5115 (0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7)) as u16;
5116 bytes.extend_from_slice(&mov.to_le_bytes());
5117
5118 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5122 bytes.extend_from_slice(&(((rn_hi_bits & 0xF) << 8) as u16).to_le_bytes());
5123
5124 Ok(bytes)
5125 }
5126
5127 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
5130 let rdlo_bits = reg_to_bits(rdlo);
5131 let rdhi_bits = reg_to_bits(rdhi);
5132 let rnlo_bits = reg_to_bits(rnlo);
5133 let mut bytes = Vec::new();
5134
5135 let hw1: u16 = 0xFA4F_u16;
5138 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5139 bytes.extend_from_slice(&hw1.to_le_bytes());
5140 bytes.extend_from_slice(&hw2.to_le_bytes());
5141
5142 let hw1: u16 = 0xEA4F;
5147 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5148 bytes.extend_from_slice(&hw1.to_le_bytes());
5149 bytes.extend_from_slice(&hw2.to_le_bytes());
5150
5151 Ok(bytes)
5152 }
5153
5154 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
5157 let rdlo_bits = reg_to_bits(rdlo);
5158 let rdhi_bits = reg_to_bits(rdhi);
5159 let rnlo_bits = reg_to_bits(rnlo);
5160 let mut bytes = Vec::new();
5161
5162 let hw1: u16 = 0xFA0F_u16;
5165 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5166 bytes.extend_from_slice(&hw1.to_le_bytes());
5167 bytes.extend_from_slice(&hw2.to_le_bytes());
5168
5169 let hw1: u16 = 0xEA4F;
5171 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5172 bytes.extend_from_slice(&hw1.to_le_bytes());
5173 bytes.extend_from_slice(&hw2.to_le_bytes());
5174
5175 Ok(bytes)
5176 }
5177
5178 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
5181 let rdlo_bits = reg_to_bits(rdlo);
5182 let rdhi_bits = reg_to_bits(rdhi);
5183 let rnlo_bits = reg_to_bits(rnlo);
5184 let mut bytes = Vec::new();
5185
5186 if rdlo_bits != rnlo_bits {
5188 let d_bit = ((rdlo_bits >> 3) & 1) as u16;
5190 let mov: u16 = 0x4600
5191 | (d_bit << 7)
5192 | ((rnlo_bits as u16) << 3)
5193 | ((rdlo_bits & 0x7) as u16);
5194 bytes.extend_from_slice(&mov.to_le_bytes());
5195 }
5196
5197 let hw1: u16 = 0xEA4F;
5199 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rnlo_bits) as u16;
5200 bytes.extend_from_slice(&hw1.to_le_bytes());
5201 bytes.extend_from_slice(&hw2.to_le_bytes());
5202
5203 Ok(bytes)
5204 }
5205
5206 ArmOp::SelectMove { rd, rm, cond } => {
5209 let rd_bits = reg_to_bits(rd) as u16;
5210 let rm_bits = reg_to_bits(rm) as u16;
5211
5212 use synth_synthesis::Condition;
5214 let cond_bits: u16 = match cond {
5215 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, };
5226
5227 let it_instr: u16 = 0xBF00 | (cond_bits << 4) | 0x8;
5230
5231 let d_bit = (rd_bits >> 3) & 1;
5234 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5235
5236 let mut bytes = it_instr.to_le_bytes().to_vec();
5238 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5239 Ok(bytes)
5240 }
5241
5242 ArmOp::Popcnt { rd, rm } => {
5253 let mut bytes = Vec::new();
5254
5255 if rd != rm {
5257 let rd_bits = reg_to_bits(rd) as u16;
5258 let rm_bits = reg_to_bits(rm) as u16;
5259 let d_bit = (rd_bits >> 3) & 1;
5261 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5262 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5263 }
5264
5265 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x5555)?);
5268 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x5555)?);
5269
5270 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 1)?);
5273
5274 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(11, 11, 12)?);
5276
5277 bytes.extend_from_slice(&self.encode_thumb32_sub_reg_raw(
5279 reg_to_bits(rd),
5280 reg_to_bits(rd),
5281 11,
5282 )?);
5283
5284 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x3333)?);
5287 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x3333)?);
5288
5289 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5291 11,
5292 reg_to_bits(rd),
5293 12,
5294 )?);
5295
5296 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(
5298 reg_to_bits(rd),
5299 reg_to_bits(rd),
5300 2,
5301 )?);
5302
5303 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5305 reg_to_bits(rd),
5306 reg_to_bits(rd),
5307 12,
5308 )?);
5309
5310 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5312 reg_to_bits(rd),
5313 reg_to_bits(rd),
5314 11,
5315 )?);
5316
5317 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 4)?);
5320
5321 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5323 reg_to_bits(rd),
5324 reg_to_bits(rd),
5325 11,
5326 )?);
5327
5328 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x0F0F)?);
5330 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x0F0F)?);
5331
5332 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5334 reg_to_bits(rd),
5335 reg_to_bits(rd),
5336 12,
5337 )?);
5338
5339 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 8)?);
5342
5343 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5345 reg_to_bits(rd),
5346 reg_to_bits(rd),
5347 11,
5348 )?);
5349
5350 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 16)?);
5353
5354 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5356 reg_to_bits(rd),
5357 reg_to_bits(rd),
5358 11,
5359 )?);
5360
5361 bytes.extend_from_slice(&self.encode_thumb32_and_imm_raw(
5364 reg_to_bits(rd),
5365 reg_to_bits(rd),
5366 0x3F,
5367 )?);
5368
5369 Ok(bytes)
5370 }
5371
5372 ArmOp::I64DivU {
5383 rdlo,
5384 rdhi,
5385 rnlo,
5386 rnhi,
5387 rmlo,
5388 rmhi,
5389 elide_zero_guard,
5390 } => {
5391 let mut bytes = Vec::new();
5392 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5393 if !elide_zero_guard {
5396 emit_i64_divisor_zero_trap(&mut bytes);
5397 }
5398
5399 bytes.extend_from_slice(&0xB4F0u16.to_le_bytes());
5403
5404 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());
5415 bytes.extend_from_slice(&0x0C40u16.to_le_bytes());
5416
5417 let loop_start = bytes.len();
5419
5420 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes());
5431 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());
5440 bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
5441 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes());
5445 bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5446
5447 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes());
5452 bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5453 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());
5484 bytes.extend_from_slice(&0x0703u16.to_le_bytes());
5485 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5488
5489 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
5493 bytes.extend_from_slice(&0x0C01u16.to_le_bytes());
5494
5495 let branch_offset_bytes = bytes.len() - loop_start + 4; let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5498 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5499 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5500
5501 bytes.extend_from_slice(&0x4620u16.to_le_bytes()); bytes.extend_from_slice(&0x4629u16.to_le_bytes()); bytes.extend_from_slice(&0xBCF0u16.to_le_bytes());
5509
5510 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5511 Ok(bytes)
5512 }
5513
5514 ArmOp::I64DivS {
5520 rdlo,
5521 rdhi,
5522 rnlo,
5523 rnhi,
5524 rmlo,
5525 rmhi,
5526 elide_zero_guard,
5527 elide_overflow_guard,
5528 } => {
5529 let mut bytes = Vec::new();
5530 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5531 if !elide_zero_guard {
5537 emit_i64_divisor_zero_trap(&mut bytes);
5538 }
5539 if !elide_overflow_guard {
5540 emit_i64_divs_overflow_trap(&mut bytes);
5543 }
5544
5545 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5547 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5548
5549 bytes.extend_from_slice(&0xEA81u16.to_le_bytes());
5552 bytes.extend_from_slice(&0x0903u16.to_le_bytes());
5553
5554 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());
5567
5568 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());
5578
5579 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5582 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5583 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5585 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5586 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5588 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5589
5590 let loop_start = bytes.len();
5591
5592 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5596 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());
5602 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5605
5606 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5610 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());
5623 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5625
5626 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5629
5630 let branch_offset_bytes = bytes.len() - loop_start + 4;
5631 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5632 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5633 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5634
5635 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());
5642 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());
5650
5651 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5653 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5654
5655 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5656 Ok(bytes)
5657 }
5658
5659 ArmOp::I64RemU {
5664 rdlo,
5665 rdhi,
5666 rnlo,
5667 rnhi,
5668 rmlo,
5669 rmhi,
5670 elide_zero_guard,
5671 } => {
5672 let mut bytes = Vec::new();
5673 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5674 if !elide_zero_guard {
5675 emit_i64_divisor_zero_trap(&mut bytes);
5676 }
5677
5678 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5680 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5681
5682 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5684 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5685 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5687 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5688 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5690 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5691
5692 let loop_start = bytes.len();
5693
5694 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5698 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());
5704 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5707
5708 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5712 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());
5725 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5727
5728 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5731
5732 let branch_offset_bytes = bytes.len() - loop_start + 4;
5733 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5734 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5735 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5736
5737 bytes.extend_from_slice(&0x4630u16.to_le_bytes()); bytes.extend_from_slice(&0x4639u16.to_le_bytes()); bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5743 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5744
5745 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5746 Ok(bytes)
5747 }
5748
5749 ArmOp::I64RemS {
5755 rdlo,
5756 rdhi,
5757 rnlo,
5758 rnhi,
5759 rmlo,
5760 rmhi,
5761 elide_zero_guard,
5762 } => {
5763 let mut bytes = Vec::new();
5764 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5765 if !elide_zero_guard {
5766 emit_i64_divisor_zero_trap(&mut bytes);
5767 }
5768
5769 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5771 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5772
5773 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());
5787
5788 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());
5798
5799 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5802 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5803 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5805 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5806 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5808 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5809
5810 let loop_start = bytes.len();
5811
5812 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5816 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());
5822 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5825
5826 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5830 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());
5843 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5845
5846 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5849
5850 let branch_offset_bytes = bytes.len() - loop_start + 4;
5851 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5852 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5853 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5854
5855 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());
5862 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());
5870
5871 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5873 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5874
5875 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5876 Ok(bytes)
5877 }
5878
5879 ArmOp::F32Add { sd, sn, sm } => {
5882 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A00, sd, sn, sm)?))
5883 }
5884 ArmOp::F32Sub { sd, sn, sm } => {
5885 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A40, sd, sn, sm)?))
5886 }
5887 ArmOp::F32Mul { sd, sn, sm } => {
5888 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE200A00, sd, sn, sm)?))
5889 }
5890 ArmOp::F32Div { sd, sn, sm } => {
5891 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE800A00, sd, sn, sm)?))
5892 }
5893 ArmOp::F32Abs { sd, sm } => {
5894 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB00AC0, sd, sm)?))
5895 }
5896 ArmOp::F32Neg { sd, sm } => {
5897 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10A40, sd, sm)?))
5898 }
5899 ArmOp::F32Sqrt { sd, sm } => {
5900 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10AC0, sd, sm)?))
5901 }
5902
5903 ArmOp::F32Ceil { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b01),
5906 ArmOp::F32Floor { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b10),
5907 ArmOp::F32Trunc { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b11),
5908 ArmOp::F32Nearest { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b00),
5909 ArmOp::F32Min { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, true),
5910 ArmOp::F32Max { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, false),
5911 ArmOp::F32Copysign { sd, sn, sm } => self.encode_thumb_f32_copysign(sd, sn, sm),
5912
5913 ArmOp::F32Eq { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x0),
5915 ArmOp::F32Ne { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x1),
5916 ArmOp::F32Lt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x4),
5917 ArmOp::F32Le { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x9),
5918 ArmOp::F32Gt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xC),
5919 ArmOp::F32Ge { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xA),
5920
5921 ArmOp::F32Const { sd, value } => self.encode_thumb_f32_const(sd, *value),
5922
5923 ArmOp::F32Load { sd, addr } => {
5924 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED900A00, sd, addr)?))
5925 }
5926 ArmOp::F32Store { sd, addr } => {
5927 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED800A00, sd, addr)?))
5928 }
5929
5930 ArmOp::F32ConvertI32S { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, true),
5931 ArmOp::F32ConvertI32U { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, false),
5932 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
5933 Err(synth_core::Error::synthesis(
5934 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
5935 ))
5936 }
5937 ArmOp::F32ReinterpretI32 { sd, rm } => {
5938 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(true, sd, rm)?))
5939 }
5940 ArmOp::I32ReinterpretF32 { rd, sm } => {
5941 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(false, sm, rd)?))
5942 }
5943 ArmOp::I32TruncF32S { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, true),
5944 ArmOp::I32TruncF32U { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, false),
5945
5946 ArmOp::F64Add { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5949 0xEE300B00, dd, dn, dm,
5950 )?)),
5951 ArmOp::F64Sub { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5952 0xEE300B40, dd, dn, dm,
5953 )?)),
5954 ArmOp::F64Mul { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5955 0xEE200B00, dd, dn, dm,
5956 )?)),
5957 ArmOp::F64Div { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5958 0xEE800B00, dd, dn, dm,
5959 )?)),
5960 ArmOp::F64Abs { dd, dm } => {
5961 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?))
5962 }
5963 ArmOp::F64Neg { dd, dm } => {
5964 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?))
5965 }
5966 ArmOp::F64Sqrt { dd, dm } => {
5967 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?))
5968 }
5969
5970 ArmOp::F64Ceil { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b01),
5973 ArmOp::F64Floor { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b10),
5974 ArmOp::F64Trunc { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b11),
5975 ArmOp::F64Nearest { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b00),
5976 ArmOp::F64Min { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, true),
5977 ArmOp::F64Max { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, false),
5978 ArmOp::F64Copysign { dd, dn, dm } => self.encode_thumb_f64_copysign(dd, dn, dm),
5979
5980 ArmOp::F64Eq { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x0),
5982 ArmOp::F64Ne { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x1),
5983 ArmOp::F64Lt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x4),
5984 ArmOp::F64Le { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x9),
5985 ArmOp::F64Gt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xC),
5986 ArmOp::F64Ge { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xA),
5987
5988 ArmOp::F64Const { dd, value } => self.encode_thumb_f64_const(dd, *value),
5989
5990 ArmOp::F64Load { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
5991 0xED900B00, dd, addr,
5992 )?)),
5993 ArmOp::F64Store { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
5994 0xED800B00, dd, addr,
5995 )?)),
5996
5997 ArmOp::F64ConvertI32S { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, true),
5998 ArmOp::F64ConvertI32U { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, false),
5999 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
6000 Err(synth_core::Error::synthesis(
6001 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
6002 ))
6003 }
6004 ArmOp::F64PromoteF32 { dd, sm } => self.encode_thumb_f64_promote_f32(dd, sm),
6005 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => Ok(vfp_to_thumb_bytes(
6006 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?,
6007 )),
6008 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => Ok(vfp_to_thumb_bytes(
6009 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?,
6010 )),
6011 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
6012 Err(synth_core::Error::synthesis(
6013 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
6014 ))
6015 }
6016 ArmOp::I32TruncF64S { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, true),
6017 ArmOp::I32TruncF64U { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, false),
6018
6019 ArmOp::I64Add {
6023 rdlo,
6024 rdhi,
6025 rnlo,
6026 rnhi,
6027 rmlo,
6028 rmhi,
6029 } => {
6030 let mut bytes = Vec::new();
6031 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adds {
6033 rd: *rdlo,
6034 rn: *rnlo,
6035 op2: Operand2::Reg(*rmlo),
6036 })?);
6037 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adc {
6039 rd: *rdhi,
6040 rn: *rnhi,
6041 op2: Operand2::Reg(*rmhi),
6042 })?);
6043 Ok(bytes)
6044 }
6045
6046 ArmOp::I64Sub {
6048 rdlo,
6049 rdhi,
6050 rnlo,
6051 rnhi,
6052 rmlo,
6053 rmhi,
6054 } => {
6055 let mut bytes = Vec::new();
6056 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Subs {
6058 rd: *rdlo,
6059 rn: *rnlo,
6060 op2: Operand2::Reg(*rmlo),
6061 })?);
6062 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Sbc {
6064 rd: *rdhi,
6065 rn: *rnhi,
6066 op2: Operand2::Reg(*rmhi),
6067 })?);
6068 Ok(bytes)
6069 }
6070
6071 ArmOp::I64And {
6073 rdlo,
6074 rdhi,
6075 rnlo,
6076 rnhi,
6077 rmlo,
6078 rmhi,
6079 } => {
6080 let mut bytes = Vec::new();
6081 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
6082 rd: *rdlo,
6083 rn: *rnlo,
6084 op2: Operand2::Reg(*rmlo),
6085 })?);
6086 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
6087 rd: *rdhi,
6088 rn: *rnhi,
6089 op2: Operand2::Reg(*rmhi),
6090 })?);
6091 Ok(bytes)
6092 }
6093
6094 ArmOp::I64Or {
6096 rdlo,
6097 rdhi,
6098 rnlo,
6099 rnhi,
6100 rmlo,
6101 rmhi,
6102 } => {
6103 let mut bytes = Vec::new();
6104 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
6105 rd: *rdlo,
6106 rn: *rnlo,
6107 op2: Operand2::Reg(*rmlo),
6108 })?);
6109 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
6110 rd: *rdhi,
6111 rn: *rnhi,
6112 op2: Operand2::Reg(*rmhi),
6113 })?);
6114 Ok(bytes)
6115 }
6116
6117 ArmOp::I64Xor {
6119 rdlo,
6120 rdhi,
6121 rnlo,
6122 rnhi,
6123 rmlo,
6124 rmhi,
6125 } => {
6126 let mut bytes = Vec::new();
6127 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6128 rd: *rdlo,
6129 rn: *rnlo,
6130 op2: Operand2::Reg(*rmlo),
6131 })?);
6132 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6133 rd: *rdhi,
6134 rn: *rnhi,
6135 op2: Operand2::Reg(*rmhi),
6136 })?);
6137 Ok(bytes)
6138 }
6139
6140 ArmOp::I64Eqz { rd, rnlo, rnhi } => self.encode_thumb(&ArmOp::I64SetCondZ {
6142 rd: *rd,
6143 rn_lo: *rnlo,
6144 rn_hi: *rnhi,
6145 }),
6146
6147 ArmOp::I64Eq {
6149 rd,
6150 rnlo,
6151 rnhi,
6152 rmlo,
6153 rmhi,
6154 } => self.encode_thumb(&ArmOp::I64SetCond {
6155 rd: *rd,
6156 rn_lo: *rnlo,
6157 rn_hi: *rnhi,
6158 rm_lo: *rmlo,
6159 rm_hi: *rmhi,
6160 cond: synth_synthesis::Condition::EQ,
6161 }),
6162
6163 ArmOp::I64Ne {
6164 rd,
6165 rnlo,
6166 rnhi,
6167 rmlo,
6168 rmhi,
6169 } => self.encode_thumb(&ArmOp::I64SetCond {
6170 rd: *rd,
6171 rn_lo: *rnlo,
6172 rn_hi: *rnhi,
6173 rm_lo: *rmlo,
6174 rm_hi: *rmhi,
6175 cond: synth_synthesis::Condition::NE,
6176 }),
6177
6178 ArmOp::I64LtS {
6179 rd,
6180 rnlo,
6181 rnhi,
6182 rmlo,
6183 rmhi,
6184 } => self.encode_thumb(&ArmOp::I64SetCond {
6185 rd: *rd,
6186 rn_lo: *rnlo,
6187 rn_hi: *rnhi,
6188 rm_lo: *rmlo,
6189 rm_hi: *rmhi,
6190 cond: synth_synthesis::Condition::LT,
6191 }),
6192
6193 ArmOp::I64LtU {
6194 rd,
6195 rnlo,
6196 rnhi,
6197 rmlo,
6198 rmhi,
6199 } => self.encode_thumb(&ArmOp::I64SetCond {
6200 rd: *rd,
6201 rn_lo: *rnlo,
6202 rn_hi: *rnhi,
6203 rm_lo: *rmlo,
6204 rm_hi: *rmhi,
6205 cond: synth_synthesis::Condition::LO,
6206 }),
6207
6208 ArmOp::I64LeS {
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::LE,
6221 }),
6222
6223 ArmOp::I64LeU {
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::LS,
6236 }),
6237
6238 ArmOp::I64GtS {
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::GT,
6251 }),
6252
6253 ArmOp::I64GtU {
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::HI,
6266 }),
6267
6268 ArmOp::I64GeS {
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::GE,
6281 }),
6282
6283 ArmOp::I64GeU {
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::HS,
6296 }),
6297
6298 ArmOp::I64Const { rdlo, rdhi, value } => {
6300 let lo32 = *value as u32;
6301 let hi32 = (*value >> 32) as u32;
6302 let mut bytes = Vec::new();
6303 bytes.extend_from_slice(
6305 &self.encode_thumb32_movw_raw(reg_to_bits(rdlo), lo32 & 0xFFFF)?,
6306 );
6307 if lo32 > 0xFFFF {
6308 bytes.extend_from_slice(
6309 &self.encode_thumb32_movt_raw(reg_to_bits(rdlo), lo32 >> 16)?,
6310 );
6311 }
6312 bytes.extend_from_slice(
6314 &self.encode_thumb32_movw_raw(reg_to_bits(rdhi), hi32 & 0xFFFF)?,
6315 );
6316 if hi32 > 0xFFFF {
6317 bytes.extend_from_slice(
6318 &self.encode_thumb32_movt_raw(reg_to_bits(rdhi), hi32 >> 16)?,
6319 );
6320 }
6321 Ok(bytes)
6322 }
6323
6324 ArmOp::I64Ldr { rdlo, rdhi, addr } => {
6326 let mut bytes = Vec::new();
6327 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6338 bytes.extend_from_slice(&self.encode_thumb32_ldr(rdlo, &base, offset)?);
6339 bytes.extend_from_slice(&self.encode_thumb32_ldr(
6340 rdhi,
6341 &base,
6342 offset.wrapping_add(4),
6343 )?);
6344 Ok(bytes)
6345 }
6346
6347 ArmOp::I64Str { rdlo, rdhi, addr } => {
6349 let mut bytes = Vec::new();
6350 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6353 bytes.extend_from_slice(&self.encode_thumb32_str(rdlo, &base, offset)?);
6354 bytes.extend_from_slice(&self.encode_thumb32_str(
6355 rdhi,
6356 &base,
6357 offset.wrapping_add(4),
6358 )?);
6359 Ok(bytes)
6360 }
6361
6362 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
6364 let mut bytes = Vec::new();
6365 if rdlo != rn {
6366 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6368 rd: *rdlo,
6369 op2: Operand2::Reg(*rn),
6370 })?);
6371 }
6372 bytes.extend_from_slice(
6374 &self.encode_thumb32_shift(rdhi, rdlo, 31, 0b10)?, );
6376 Ok(bytes)
6377 }
6378
6379 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
6381 let mut bytes = Vec::new();
6382 if rdlo != rn {
6383 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6385 rd: *rdlo,
6386 op2: Operand2::Reg(*rn),
6387 })?);
6388 }
6389 let rdhi_bits = reg_to_bits(rdhi) as u16;
6391 let instr: u16 = 0x2000 | (rdhi_bits << 8);
6392 bytes.extend_from_slice(&instr.to_le_bytes());
6393 Ok(bytes)
6394 }
6395
6396 ArmOp::I32WrapI64 { rd, rnlo } => {
6398 if rd == rnlo {
6399 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6402 } else {
6403 self.encode_thumb(&ArmOp::Mov {
6405 rd: *rd,
6406 op2: Operand2::Reg(*rnlo),
6407 })
6408 }
6409 }
6410
6411 ArmOp::MveLoad { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vldrw(qd, addr))),
6413 ArmOp::MveStore { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vstrw(qd, addr))),
6414 ArmOp::MveConst { qd, bytes } => self.encode_thumb_mve_const(qd, bytes),
6415 ArmOp::MveAnd { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6416 0xEF000150, qd, qn, qm,
6417 ))),
6418 ArmOp::MveOrr { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6419 0xEF200150, qd, qn, qm,
6420 ))),
6421 ArmOp::MveEor { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6422 0xFF000150, qd, qn, qm,
6423 ))),
6424 ArmOp::MveMvn { qd, qm } => {
6425 let qd_enc = qreg_to_num(qd);
6427 let qm_enc = qreg_to_num(qm);
6428 let instr: u32 = 0xFFB005C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6429 Ok(vfp_to_thumb_bytes(instr))
6430 }
6431 ArmOp::MveBic { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6432 0xEF100150, qd, qn, qm,
6433 ))),
6434 ArmOp::MveAddI { qd, qn, qm, size } => {
6435 let sz = mve_size_bits(size);
6436 let base: u32 = 0xEF000840 | (sz << 20);
6437 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6438 }
6439 ArmOp::MveSubI { qd, qn, qm, size } => {
6440 let sz = mve_size_bits(size);
6441 let base: u32 = 0xFF000840 | (sz << 20);
6442 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6443 }
6444 ArmOp::MveMulI { qd, qn, qm, size } => {
6445 let sz = mve_size_bits(size);
6446 let base: u32 = 0xEF000950 | (sz << 20);
6447 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6448 }
6449 ArmOp::MveNegI { qd, qm, size } => {
6450 let sz = mve_size_bits(size);
6451 let qd_enc = qreg_to_num(qd);
6453 let qm_enc = qreg_to_num(qm);
6454 let base: u32 = 0xFFB103C0 | (sz << 18);
6455 let instr = base | ((qd_enc * 2) << 12) | (qm_enc * 2);
6456 Ok(vfp_to_thumb_bytes(instr))
6457 }
6458 ArmOp::MveDup { qd, rn, size } => {
6459 let sz = mve_size_bits(size);
6460 let qd_enc = qreg_to_num(qd);
6461 let rn_bits = reg_to_bits(rn);
6462 let be = match sz {
6465 0 => 0b00u32, 1 => 0b01, _ => 0b00, };
6469 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12) | (be << 5);
6470 Ok(vfp_to_thumb_bytes(instr))
6471 }
6472 ArmOp::MveExtractLane { rd, qn, lane, size } => {
6473 let qn_enc = qreg_to_num(qn);
6474 let rd_bits = reg_to_bits(rd);
6475 let d_reg = qn_enc * 2 + ((*lane as u32) >> 1);
6478 let lane_in_d = (*lane as u32) & 1;
6479 let _sz = mve_size_bits(size);
6480 let instr: u32 = 0xEE100B10 | (d_reg << 16) | (rd_bits << 12) | (lane_in_d << 21);
6482 Ok(vfp_to_thumb_bytes(instr))
6483 }
6484 ArmOp::MveInsertLane { qd, rn, lane, size } => {
6485 let qd_enc = qreg_to_num(qd);
6486 let rn_bits = reg_to_bits(rn);
6487 let d_reg = qd_enc * 2 + ((*lane as u32) >> 1);
6488 let lane_in_d = (*lane as u32) & 1;
6489 let _sz = mve_size_bits(size);
6490 let instr: u32 = 0xEE000B10 | (d_reg << 16) | (rn_bits << 12) | (lane_in_d << 21);
6492 Ok(vfp_to_thumb_bytes(instr))
6493 }
6494
6495 ArmOp::MveCmpEqI { qd, qn, qm, size }
6497 | ArmOp::MveCmpNeI { qd, qn, qm, size }
6498 | ArmOp::MveCmpLtS { qd, qn, qm, size }
6499 | ArmOp::MveCmpLtU { qd, qn, qm, size }
6500 | ArmOp::MveCmpGtS { qd, qn, qm, size }
6501 | ArmOp::MveCmpGtU { qd, qn, qm, size }
6502 | ArmOp::MveCmpLeS { qd, qn, qm, size }
6503 | ArmOp::MveCmpLeU { qd, qn, qm, size }
6504 | ArmOp::MveCmpGeS { qd, qn, qm, size }
6505 | ArmOp::MveCmpGeU { qd, qn, qm, size } => {
6506 let sz = mve_size_bits(size);
6509 let base: u32 = 0xEF000840 | (sz << 20);
6510 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6511 }
6512
6513 ArmOp::MveAddF32 { qd, qn, qm } => {
6515 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6517 }
6518 ArmOp::MveSubF32 { qd, qn, qm } => {
6519 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF200D40, qd, qn, qm)))
6521 }
6522 ArmOp::MveMulF32 { qd, qn, qm } => {
6523 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xFF000D50, qd, qn, qm)))
6525 }
6526 ArmOp::MveNegF32 { qd, qm } => {
6527 let qd_enc = qreg_to_num(qd);
6528 let qm_enc = qreg_to_num(qm);
6529 let instr: u32 = 0xFFB907C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6531 Ok(vfp_to_thumb_bytes(instr))
6532 }
6533 ArmOp::MveAbsF32 { qd, qm } => {
6534 let qd_enc = qreg_to_num(qd);
6535 let qm_enc = qreg_to_num(qm);
6536 let instr: u32 = 0xFFB90740 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6538 Ok(vfp_to_thumb_bytes(instr))
6539 }
6540 ArmOp::MveCmpEqF32 { qd, qn, qm }
6541 | ArmOp::MveCmpNeF32 { qd, qn, qm }
6542 | ArmOp::MveCmpLtF32 { qd, qn, qm }
6543 | ArmOp::MveCmpLeF32 { qd, qn, qm }
6544 | ArmOp::MveCmpGtF32 { qd, qn, qm }
6545 | ArmOp::MveCmpGeF32 { qd, qn, qm } => {
6546 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6548 }
6549 ArmOp::MveDupF32 { qd, rn } => {
6550 let qd_enc = qreg_to_num(qd);
6551 let rn_bits = reg_to_bits(rn);
6552 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12);
6554 Ok(vfp_to_thumb_bytes(instr))
6555 }
6556 ArmOp::MveExtractLaneF32 { rd, qn, lane } => {
6557 let qn_enc = qreg_to_num(qn);
6558 let rd_bits = reg_to_bits(rd);
6559 let s_num = qn_enc * 4 + (*lane as u32);
6561 let (vn, n) = encode_sreg(s_num);
6562 let instr: u32 = 0xEE100A10 | (vn << 16) | (rd_bits << 12) | (n << 7);
6563 Ok(vfp_to_thumb_bytes(instr))
6564 }
6565 ArmOp::MveReplaceLaneF32 { qd, rn, lane } => {
6566 let qd_enc = qreg_to_num(qd);
6567 let rn_bits = reg_to_bits(rn);
6568 let s_num = qd_enc * 4 + (*lane as u32);
6570 let (vn, n) = encode_sreg(s_num);
6571 let instr: u32 = 0xEE000A10 | (vn << 16) | (rn_bits << 12) | (n << 7);
6572 Ok(vfp_to_thumb_bytes(instr))
6573 }
6574 ArmOp::MveDivF32 { qd, qn, qm } => {
6575 self.encode_thumb_mve_lane_wise_f32_binop(qd, qn, qm, 0xEE800A00)
6577 }
6578 ArmOp::MveSqrtF32 { qd, qm } => {
6579 self.encode_thumb_mve_lane_wise_f32_sqrt(qd, qm)
6581 }
6582
6583 _ => {
6585 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6587 }
6588 }
6589 }
6590
6591 fn encode_thumb_f32_compare(
6595 &self,
6596 rd: &Reg,
6597 sn: &VfpReg,
6598 sm: &VfpReg,
6599 cond_code: u32,
6600 ) -> Result<Vec<u8>> {
6601 let mut bytes = Vec::new();
6602 let rd_bits = reg_to_bits(rd);
6603
6604 let sn_num = vfp_sreg_to_num(sn)?;
6606 let sm_num = vfp_sreg_to_num(sm)?;
6607 let (vd, d) = encode_sreg(sn_num);
6608 let (vm, m) = encode_sreg(sm_num);
6609 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6610 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6611
6612 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6614
6615 if rd_bits < 8 {
6617 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
6618 bytes.extend_from_slice(&movs_zero.to_le_bytes());
6619 } else {
6620 let hw1: u16 = 0xF04F;
6622 let hw2: u16 = (rd_bits as u16) << 8;
6623 bytes.extend_from_slice(&hw1.to_le_bytes());
6624 bytes.extend_from_slice(&hw2.to_le_bytes());
6625 }
6626
6627 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
6631 bytes.extend_from_slice(&it.to_le_bytes());
6632
6633 if rd_bits < 8 {
6635 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
6636 bytes.extend_from_slice(&mov_one.to_le_bytes());
6637 } else {
6638 let hw1: u16 = 0xF04F;
6640 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
6641 bytes.extend_from_slice(&hw1.to_le_bytes());
6642 bytes.extend_from_slice(&hw2.to_le_bytes());
6643 }
6644
6645 Ok(bytes)
6646 }
6647
6648 fn encode_thumb_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
6650 let mut bytes = Vec::new();
6651 let bits = value.to_bits();
6652 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
6657 let imm4 = (lo16 >> 12) & 0xF;
6658 let i_bit = (lo16 >> 11) & 1;
6659 let imm3 = (lo16 >> 8) & 0x7;
6660 let imm8 = lo16 & 0xFF;
6661 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
6662 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6663 bytes.extend_from_slice(&hw1.to_le_bytes());
6664 bytes.extend_from_slice(&hw2.to_le_bytes());
6665
6666 let hi16 = (bits >> 16) & 0xFFFF;
6668 let imm4 = (hi16 >> 12) & 0xF;
6669 let i_bit = (hi16 >> 11) & 1;
6670 let imm3 = (hi16 >> 8) & 0x7;
6671 let imm8 = hi16 & 0xFF;
6672 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
6673 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6674 bytes.extend_from_slice(&hw1.to_le_bytes());
6675 bytes.extend_from_slice(&hw2.to_le_bytes());
6676
6677 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
6679 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6680
6681 Ok(bytes)
6682 }
6683
6684 fn encode_thumb_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
6686 let mut bytes = Vec::new();
6687
6688 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
6690 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6691
6692 let sd_num = vfp_sreg_to_num(sd)?;
6694 let (vd, d) = encode_sreg(sd_num);
6695 let (vm, m) = encode_sreg(sd_num);
6696 let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
6697 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
6698 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6699
6700 Ok(bytes)
6701 }
6702
6703 fn encode_thumb_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
6711 let mut bytes = Vec::new();
6712 let sm_num = vfp_sreg_to_num(sm)?;
6713 let sd_num = vfp_sreg_to_num(sd)?;
6714 let (vd_s, d_s) = encode_sreg(sd_num);
6715 let (vm_s, m_s) = encode_sreg(sm_num);
6716
6717 if mode == 0b11 {
6718 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6720 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6721 } else {
6722 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
6727 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6728
6729 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF); let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
6735 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6736 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6737
6738 if mode != 0 {
6740 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF); let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
6742 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
6743 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
6744 }
6745
6746 let vmsr = 0xEEE10A10 | (rt << 12);
6748 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6749
6750 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6752 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6753
6754 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6756 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6757 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6758 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6759 }
6760
6761 let (vd2, d2) = encode_sreg(sd_num);
6763 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
6764 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
6765
6766 Ok(bytes)
6767 }
6768
6769 fn encode_thumb_f32_minmax(
6771 &self,
6772 sd: &VfpReg,
6773 sn: &VfpReg,
6774 sm: &VfpReg,
6775 is_min: bool,
6776 ) -> Result<Vec<u8>> {
6777 let mut bytes = Vec::new();
6778 let sn_num = vfp_sreg_to_num(sn)?;
6779 let sm_num = vfp_sreg_to_num(sm)?;
6780 let sd_num = vfp_sreg_to_num(sd)?;
6781
6782 let (vd, d) = encode_sreg(sd_num);
6784 let (vn, n) = encode_sreg(sn_num);
6785 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
6786 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sn));
6787
6788 let (vm, m) = encode_sreg(sm_num);
6790 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
6791 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6792
6793 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6795
6796 let cond: u16 = if is_min { 0xC } else { 0x4 };
6798 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
6799 bytes.extend_from_slice(&it.to_le_bytes());
6800
6801 let vmov_sm = 0xEEB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6803 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sm));
6804
6805 Ok(bytes)
6806 }
6807
6808 fn encode_thumb_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
6810 let mut bytes = Vec::new();
6811
6812 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
6814 false,
6815 sm,
6816 &Reg::R12,
6817 )?));
6818
6819 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
6821 false,
6822 sn,
6823 &Reg::R0,
6824 )?));
6825
6826 let hw1: u16 = 0xF000 | 12; let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
6838 bytes.extend_from_slice(&hw2.to_le_bytes());
6839
6840 let hw1: u16 = 0xF020; let hw2: u16 = (0x1 << 12) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
6844 bytes.extend_from_slice(&hw2.to_le_bytes());
6845
6846 let hw1: u16 = 0xEA40; let hw2: u16 = 12; bytes.extend_from_slice(&hw1.to_le_bytes());
6850 bytes.extend_from_slice(&hw2.to_le_bytes());
6851
6852 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
6854 true,
6855 sd,
6856 &Reg::R0,
6857 )?));
6858
6859 Ok(bytes)
6860 }
6861
6862 fn encode_thumb_f64_compare(
6864 &self,
6865 rd: &Reg,
6866 dn: &VfpReg,
6867 dm: &VfpReg,
6868 cond_code: u32,
6869 ) -> Result<Vec<u8>> {
6870 let mut bytes = Vec::new();
6871 let rd_bits = reg_to_bits(rd);
6872
6873 let dn_num = vfp_dreg_to_num(dn)?;
6875 let dm_num = vfp_dreg_to_num(dm)?;
6876 let (vd, d) = encode_dreg(dn_num);
6877 let (vm, m) = encode_dreg(dm_num);
6878 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6879 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6880
6881 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6883
6884 if rd_bits < 8 {
6886 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
6887 bytes.extend_from_slice(&movs_zero.to_le_bytes());
6888 } else {
6889 let hw1: u16 = 0xF04F;
6890 let hw2: u16 = (rd_bits as u16) << 8;
6891 bytes.extend_from_slice(&hw1.to_le_bytes());
6892 bytes.extend_from_slice(&hw2.to_le_bytes());
6893 }
6894
6895 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
6897 bytes.extend_from_slice(&it.to_le_bytes());
6898
6899 if rd_bits < 8 {
6901 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
6902 bytes.extend_from_slice(&mov_one.to_le_bytes());
6903 } else {
6904 let hw1: u16 = 0xF04F;
6905 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
6906 bytes.extend_from_slice(&hw1.to_le_bytes());
6907 bytes.extend_from_slice(&hw2.to_le_bytes());
6908 }
6909
6910 Ok(bytes)
6911 }
6912
6913 fn encode_thumb_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
6915 let mut bytes = Vec::new();
6916 let bits = value.to_bits();
6917 let lo32 = bits as u32;
6918 let hi32 = (bits >> 32) as u32;
6919
6920 let lo16 = lo32 & 0xFFFF;
6922 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(0, lo16)?);
6923
6924 let hi16 = (lo32 >> 16) & 0xFFFF;
6926 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(0, hi16)?);
6927
6928 let lo16 = hi32 & 0xFFFF;
6930 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
6931
6932 let hi16 = (hi32 >> 16) & 0xFFFF;
6934 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
6935
6936 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
6938 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6939
6940 Ok(bytes)
6941 }
6942
6943 fn encode_thumb_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
6945 let mut bytes = Vec::new();
6946
6947 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
6949 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6950
6951 let dd_num = vfp_dreg_to_num(dd)?;
6953 let (vd, d) = encode_dreg(dd_num);
6954 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
6955 let vcvt = base | (d << 22) | (vd << 12);
6956 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6957
6958 Ok(bytes)
6959 }
6960
6961 fn encode_thumb_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
6963 let dd_num = vfp_dreg_to_num(dd)?;
6964 let sm_num = vfp_sreg_to_num(sm)?;
6965 let (vd, d) = encode_dreg(dd_num);
6966 let (vm, m) = encode_sreg(sm_num);
6967
6968 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
6969 Ok(vfp_to_thumb_bytes(vcvt))
6970 }
6971
6972 fn encode_thumb_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
6974 let mut bytes = Vec::new();
6975 let dm_num = vfp_dreg_to_num(dm)?;
6976 let (vm, m) = encode_dreg(dm_num);
6977
6978 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
6980 let vcvt = base | (m << 5) | vm;
6981 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6982
6983 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
6985 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6986
6987 Ok(bytes)
6988 }
6989
6990 fn encode_thumb_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
6994 let mut bytes = Vec::new();
6995 let dm_num = vfp_dreg_to_num(dm)?;
6996 let dd_num = vfp_dreg_to_num(dd)?;
6997 let (vm, m) = encode_dreg(dm_num);
6998 let (vd, d) = encode_dreg(dd_num);
6999
7000 if mode == 0b11 {
7001 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
7003 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
7004 } else {
7005 let rt: u32 = 12;
7006
7007 let vmrs = 0xEEF10A10 | (rt << 12);
7009 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
7010
7011 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF);
7013 let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
7014 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
7015 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
7016
7017 if mode != 0 {
7019 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF);
7020 let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
7021 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
7022 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
7023 }
7024
7025 let vmsr = 0xEEE10A10 | (rt << 12);
7027 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
7028
7029 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
7031 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
7032
7033 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
7035 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
7036 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
7037 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
7038 }
7039
7040 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
7042 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
7043
7044 Ok(bytes)
7045 }
7046
7047 fn encode_thumb_f64_minmax(
7049 &self,
7050 dd: &VfpReg,
7051 dn: &VfpReg,
7052 dm: &VfpReg,
7053 is_min: bool,
7054 ) -> Result<Vec<u8>> {
7055 let mut bytes = Vec::new();
7056 let dn_num = vfp_dreg_to_num(dn)?;
7057 let dm_num = vfp_dreg_to_num(dm)?;
7058 let dd_num = vfp_dreg_to_num(dd)?;
7059
7060 let (vd, d) = encode_dreg(dd_num);
7062 let (vn, n) = encode_dreg(dn_num);
7063 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
7064 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dn));
7065
7066 let (vm, m) = encode_dreg(dm_num);
7068 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
7069 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7070
7071 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7073
7074 let cond: u16 = if is_min { 0xC } else { 0x4 };
7076 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
7077 bytes.extend_from_slice(&it.to_le_bytes());
7078
7079 let vmov_dm = 0xEEB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7081 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dm));
7082
7083 Ok(bytes)
7084 }
7085
7086 fn encode_thumb_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
7088 let mut bytes = Vec::new();
7089
7090 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7092 false,
7093 dm,
7094 &Reg::R0,
7095 &Reg::R12,
7096 )?));
7097
7098 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7100 false,
7101 dn,
7102 &Reg::R1,
7103 &Reg::R2,
7104 )?));
7105
7106 let hw1: u16 = 0xF000 | 12;
7108 let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02;
7109 bytes.extend_from_slice(&hw1.to_le_bytes());
7110 bytes.extend_from_slice(&hw2.to_le_bytes());
7111
7112 let hw1: u16 = 0xF020 | 2;
7114 let hw2: u16 = (0x1 << 12) | (2 << 8) | 0x02;
7115 bytes.extend_from_slice(&hw1.to_le_bytes());
7116 bytes.extend_from_slice(&hw2.to_le_bytes());
7117
7118 let hw1: u16 = 0xEA40 | 2;
7120 let hw2: u16 = (2 << 8) | 12;
7121 bytes.extend_from_slice(&hw1.to_le_bytes());
7122 bytes.extend_from_slice(&hw2.to_le_bytes());
7123
7124 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7126 true,
7127 dd,
7128 &Reg::R1,
7129 &Reg::R2,
7130 )?));
7131
7132 Ok(bytes)
7133 }
7134
7135 fn encode_thumb_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7137 let mut bytes = Vec::new();
7138
7139 let sm_num = vfp_sreg_to_num(sm)?;
7140 let (vd, d) = encode_sreg(sm_num);
7141 let (vm, m) = encode_sreg(sm_num);
7142 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
7143 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
7144 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7145
7146 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
7148 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7149
7150 Ok(bytes)
7151 }
7152
7153 fn encode_thumb32_add(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7157 let rd_bits = reg_to_bits(rd);
7158 let rn_bits = reg_to_bits(rn);
7159
7160 let i_bit = (imm >> 11) & 1;
7162 let imm3 = (imm >> 8) & 0x7;
7163 let imm8 = imm & 0xFF;
7164
7165 let hw1_base = if imm <= 0xFF {
7166 0xF100
7170 } else if imm <= 0xFFF {
7171 0xF200
7175 } else {
7176 return Err(synth_core::Error::synthesis(
7177 "ADD immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7178 ));
7179 };
7180
7181 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7182 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7183
7184 let mut bytes = hw1.to_le_bytes().to_vec();
7185 bytes.extend_from_slice(&hw2.to_le_bytes());
7186 Ok(bytes)
7187 }
7188
7189 fn encode_thumb32_sub(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7191 let rd_bits = reg_to_bits(rd);
7192 let rn_bits = reg_to_bits(rn);
7193
7194 let i_bit = (imm >> 11) & 1;
7195 let imm3 = (imm >> 8) & 0x7;
7196 let imm8 = imm & 0xFF;
7197
7198 let hw1_base = if imm <= 0xFF {
7199 0xF1A0
7202 } else if imm <= 0xFFF {
7203 0xF2A0
7206 } else {
7207 return Err(synth_core::Error::synthesis(
7208 "SUB immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7209 ));
7210 };
7211
7212 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7213 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7214
7215 let mut bytes = hw1.to_le_bytes().to_vec();
7216 bytes.extend_from_slice(&hw2.to_le_bytes());
7217 Ok(bytes)
7218 }
7219
7220 fn encode_thumb32_adds(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7222 let rd_bits = reg_to_bits(rd);
7223 let rn_bits = reg_to_bits(rn);
7224
7225 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7228 synth_core::Error::synthesis(
7229 "ADDS immediate is not a valid ThumbExpandImm — materialize into a register",
7230 )
7231 })?;
7232 let i_bit = (field >> 11) & 1;
7233 let imm3 = (field >> 8) & 0x7;
7234 let imm8 = field & 0xFF;
7235
7236 let hw1: u16 = (0xF110 | (i_bit << 10) | rn_bits) as u16;
7239 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7240
7241 let mut bytes = hw1.to_le_bytes().to_vec();
7242 bytes.extend_from_slice(&hw2.to_le_bytes());
7243 Ok(bytes)
7244 }
7245
7246 fn encode_thumb32_subs(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7248 let rd_bits = reg_to_bits(rd);
7249 let rn_bits = reg_to_bits(rn);
7250
7251 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7254 synth_core::Error::synthesis(
7255 "SUBS immediate is not a valid ThumbExpandImm — materialize into a register",
7256 )
7257 })?;
7258 let i_bit = (field >> 11) & 1;
7259 let imm3 = (field >> 8) & 0x7;
7260 let imm8 = field & 0xFF;
7261
7262 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7265 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7266
7267 let mut bytes = hw1.to_le_bytes().to_vec();
7268 bytes.extend_from_slice(&hw2.to_le_bytes());
7269 Ok(bytes)
7270 }
7271
7272 fn encode_thumb32_movw(&self, rd: &Reg, imm: u32) -> Result<Vec<u8>> {
7281 let rd_bits = reg_to_bits(rd);
7282 reg_bits_checked(rd_bits)?;
7283 let imm16 = imm & 0xFFFF;
7284
7285 let imm4 = (imm16 >> 12) & 0xF;
7288 let i_bit = (imm16 >> 11) & 1;
7289 let imm3 = (imm16 >> 8) & 0x7;
7290 let imm8 = imm16 & 0xFF;
7291
7292 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7293 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7294
7295 let mut bytes = hw1.to_le_bytes().to_vec();
7296 bytes.extend_from_slice(&hw2.to_le_bytes());
7297 encoding_contracts::verify_thumb32(&bytes);
7298 Ok(bytes)
7299 }
7300
7301 fn encode_thumb32_shift(
7309 &self,
7310 rd: &Reg,
7311 rm: &Reg,
7312 shift: u32,
7313 shift_type: u8,
7314 ) -> Result<Vec<u8>> {
7315 let rd_bits = reg_to_bits(rd);
7316 let rm_bits = reg_to_bits(rm);
7317 reg_bits_checked(rd_bits)?;
7318 reg_bits_checked(rm_bits)?;
7319 let imm5 = shift & 0x1F;
7320 let imm2 = imm5 & 0x3;
7321 let imm3 = (imm5 >> 2) & 0x7;
7322
7323 let hw1: u16 = 0xEA4F;
7326 let hw2: u16 =
7327 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | ((shift_type as u32) << 4) | rm_bits)
7328 as u16;
7329
7330 let mut bytes = hw1.to_le_bytes().to_vec();
7331 bytes.extend_from_slice(&hw2.to_le_bytes());
7332 Ok(bytes)
7333 }
7334
7335 fn encode_thumb32_shift_reg(
7339 &self,
7340 rd: &Reg,
7341 rn: &Reg,
7342 rm: &Reg,
7343 shift_type: u8,
7344 ) -> Result<Vec<u8>> {
7345 let rd_bits = reg_to_bits(rd);
7346 let rn_bits = reg_to_bits(rn);
7347 let rm_bits = reg_to_bits(rm);
7348
7349 let hw1: u16 = (0xFA00 | ((shift_type as u32) << 5) | rn_bits) as u16;
7351 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
7353
7354 let mut bytes = hw1.to_le_bytes().to_vec();
7355 bytes.extend_from_slice(&hw2.to_le_bytes());
7356 Ok(bytes)
7357 }
7358
7359 fn encode_thumb32_cmp_imm(&self, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7361 let rn_bits = reg_to_bits(rn);
7362
7363 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7367 synth_core::Error::synthesis(
7368 "CMP immediate is not a valid ThumbExpandImm — materialize into a register",
7369 )
7370 })?;
7371 let i_bit = (field >> 11) & 1;
7372 let imm3 = (field >> 8) & 0x7;
7373 let imm8 = field & 0xFF;
7374
7375 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7377 let hw2: u16 = ((imm3 << 12) | 0x0F00 | imm8) as u16;
7378
7379 let mut bytes = hw1.to_le_bytes().to_vec();
7380 bytes.extend_from_slice(&hw2.to_le_bytes());
7381 Ok(bytes)
7382 }
7383
7384 fn i64_effective_base(&self, bytes: &mut Vec<u8>, addr: &MemAddr) -> Result<(Reg, u32)> {
7406 let offset = if addr.offset < 0 {
7407 0u32
7408 } else {
7409 addr.offset as u32
7410 };
7411 match addr.offset_reg {
7412 Some(idx) => {
7413 let ip = Reg::R12;
7414 if offset.wrapping_add(4) > 0xFFF {
7415 bytes.extend_from_slice(&self.encode_thumb32_add_imm(&ip, &idx, offset)?);
7419 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
7421 reg_to_bits(&ip),
7422 reg_to_bits(&ip),
7423 reg_to_bits(&addr.base),
7424 )?);
7425 Ok((ip, 0))
7426 } else {
7427 let hw1: u16 = 0xEB00 | reg_to_bits(&addr.base) as u16;
7429 let hw2: u16 = 0x0C00 | reg_to_bits(&idx) as u16;
7430 bytes.extend_from_slice(&hw1.to_le_bytes());
7431 bytes.extend_from_slice(&hw2.to_le_bytes());
7432 Ok((ip, offset))
7433 }
7434 }
7435 None => Ok((addr.base, offset)),
7436 }
7437 }
7438
7439 fn encode_thumb32_ldr(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7441 let rd_bits = reg_to_bits(rd);
7442 let base_bits = reg_to_bits(base);
7443
7444 check_ldst_imm12(offset)?;
7446 let hw1: u16 = (0xF8D0 | base_bits) as u16;
7447 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7448
7449 let mut bytes = hw1.to_le_bytes().to_vec();
7450 bytes.extend_from_slice(&hw2.to_le_bytes());
7451 Ok(bytes)
7452 }
7453
7454 fn encode_thumb32_str(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7456 let rd_bits = reg_to_bits(rd);
7457 let base_bits = reg_to_bits(base);
7458
7459 check_ldst_imm12(offset)?;
7461 let hw1: u16 = (0xF8C0 | base_bits) as u16;
7462 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7463
7464 let mut bytes = hw1.to_le_bytes().to_vec();
7465 bytes.extend_from_slice(&hw2.to_le_bytes());
7466 Ok(bytes)
7467 }
7468
7469 fn encode_thumb32_ldr_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7471 let rd_bits = reg_to_bits(rd);
7472 let base_bits = reg_to_bits(base);
7473 let rm_bits = reg_to_bits(offset_reg);
7474
7475 let hw1: u16 = (0xF850 | base_bits) as u16;
7479 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7480
7481 let mut bytes = hw1.to_le_bytes().to_vec();
7482 bytes.extend_from_slice(&hw2.to_le_bytes());
7483 Ok(bytes)
7484 }
7485
7486 fn encode_thumb32_str_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7488 let rd_bits = reg_to_bits(rd);
7489 let base_bits = reg_to_bits(base);
7490 let rm_bits = reg_to_bits(offset_reg);
7491
7492 let hw1: u16 = (0xF840 | base_bits) as u16;
7496 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7497
7498 let mut bytes = hw1.to_le_bytes().to_vec();
7499 bytes.extend_from_slice(&hw2.to_le_bytes());
7500 Ok(bytes)
7501 }
7502
7503 fn encode_thumb32_ldrb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7507 let rd_bits = reg_to_bits(rd);
7508 let base_bits = reg_to_bits(base);
7509 check_ldst_imm12(offset)?;
7511 let hw1: u16 = (0xF890 | base_bits) as u16;
7512 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7513 let mut bytes = hw1.to_le_bytes().to_vec();
7514 bytes.extend_from_slice(&hw2.to_le_bytes());
7515 Ok(bytes)
7516 }
7517
7518 fn encode_thumb32_ldrb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7520 let rd_bits = reg_to_bits(rd);
7521 let base_bits = reg_to_bits(base);
7522 let rm_bits = reg_to_bits(offset_reg);
7523 let hw1: u16 = (0xF810 | base_bits) as u16;
7525 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7526 let mut bytes = hw1.to_le_bytes().to_vec();
7527 bytes.extend_from_slice(&hw2.to_le_bytes());
7528 Ok(bytes)
7529 }
7530
7531 fn encode_thumb32_ldrsb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7533 let rd_bits = reg_to_bits(rd);
7534 let base_bits = reg_to_bits(base);
7535 check_ldst_imm12(offset)?;
7537 let hw1: u16 = (0xF990 | base_bits) as u16;
7538 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7539 let mut bytes = hw1.to_le_bytes().to_vec();
7540 bytes.extend_from_slice(&hw2.to_le_bytes());
7541 Ok(bytes)
7542 }
7543
7544 fn encode_thumb32_ldrsb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7546 let rd_bits = reg_to_bits(rd);
7547 let base_bits = reg_to_bits(base);
7548 let rm_bits = reg_to_bits(offset_reg);
7549 let hw1: u16 = (0xF910 | base_bits) as u16;
7551 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7552 let mut bytes = hw1.to_le_bytes().to_vec();
7553 bytes.extend_from_slice(&hw2.to_le_bytes());
7554 Ok(bytes)
7555 }
7556
7557 fn encode_thumb32_ldrh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7559 let rd_bits = reg_to_bits(rd);
7560 let base_bits = reg_to_bits(base);
7561 check_ldst_imm12(offset)?;
7563 let hw1: u16 = (0xF8B0 | base_bits) as u16;
7564 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7565 let mut bytes = hw1.to_le_bytes().to_vec();
7566 bytes.extend_from_slice(&hw2.to_le_bytes());
7567 Ok(bytes)
7568 }
7569
7570 fn encode_thumb32_ldrh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7572 let rd_bits = reg_to_bits(rd);
7573 let base_bits = reg_to_bits(base);
7574 let rm_bits = reg_to_bits(offset_reg);
7575 let hw1: u16 = (0xF830 | base_bits) as u16;
7577 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7578 let mut bytes = hw1.to_le_bytes().to_vec();
7579 bytes.extend_from_slice(&hw2.to_le_bytes());
7580 Ok(bytes)
7581 }
7582
7583 fn encode_thumb32_ldrsh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7585 let rd_bits = reg_to_bits(rd);
7586 let base_bits = reg_to_bits(base);
7587 check_ldst_imm12(offset)?;
7589 let hw1: u16 = (0xF9B0 | base_bits) as u16;
7590 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7591 let mut bytes = hw1.to_le_bytes().to_vec();
7592 bytes.extend_from_slice(&hw2.to_le_bytes());
7593 Ok(bytes)
7594 }
7595
7596 fn encode_thumb32_ldrsh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7598 let rd_bits = reg_to_bits(rd);
7599 let base_bits = reg_to_bits(base);
7600 let rm_bits = reg_to_bits(offset_reg);
7601 let hw1: u16 = (0xF930 | base_bits) as u16;
7603 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7604 let mut bytes = hw1.to_le_bytes().to_vec();
7605 bytes.extend_from_slice(&hw2.to_le_bytes());
7606 Ok(bytes)
7607 }
7608
7609 fn encode_thumb32_strb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7611 let rd_bits = reg_to_bits(rd);
7612 let base_bits = reg_to_bits(base);
7613 check_ldst_imm12(offset)?;
7615 let hw1: u16 = (0xF880 | base_bits) as u16;
7616 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7617 let mut bytes = hw1.to_le_bytes().to_vec();
7618 bytes.extend_from_slice(&hw2.to_le_bytes());
7619 Ok(bytes)
7620 }
7621
7622 fn encode_thumb32_strb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7624 let rd_bits = reg_to_bits(rd);
7625 let base_bits = reg_to_bits(base);
7626 let rm_bits = reg_to_bits(offset_reg);
7627 let hw1: u16 = (0xF800 | base_bits) as u16;
7629 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7630 let mut bytes = hw1.to_le_bytes().to_vec();
7631 bytes.extend_from_slice(&hw2.to_le_bytes());
7632 Ok(bytes)
7633 }
7634
7635 fn encode_thumb32_strh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7637 let rd_bits = reg_to_bits(rd);
7638 let base_bits = reg_to_bits(base);
7639 check_ldst_imm12(offset)?;
7641 let hw1: u16 = (0xF8A0 | base_bits) as u16;
7642 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7643 let mut bytes = hw1.to_le_bytes().to_vec();
7644 bytes.extend_from_slice(&hw2.to_le_bytes());
7645 Ok(bytes)
7646 }
7647
7648 fn encode_thumb32_strh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7650 let rd_bits = reg_to_bits(rd);
7651 let base_bits = reg_to_bits(base);
7652 let rm_bits = reg_to_bits(offset_reg);
7653 let hw1: u16 = (0xF820 | base_bits) as u16;
7655 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7656 let mut bytes = hw1.to_le_bytes().to_vec();
7657 bytes.extend_from_slice(&hw2.to_le_bytes());
7658 Ok(bytes)
7659 }
7660
7661 fn encode_thumb32_add_imm(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7663 let rd_bits = reg_to_bits(rd);
7664 let rn_bits = reg_to_bits(rn);
7665
7666 if imm <= 0xFFF {
7672 let i_bit = (imm >> 11) & 1;
7673 let imm3 = (imm >> 8) & 0x7;
7674 let imm8 = imm & 0xFF;
7675
7676 let hw1: u16 = (0xF100 | (i_bit << 10) | rn_bits) as u16;
7677 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7678
7679 let mut bytes = hw1.to_le_bytes().to_vec();
7680 bytes.extend_from_slice(&hw2.to_le_bytes());
7681 Ok(bytes)
7682 } else {
7683 let scratch: u32 = if rd_bits == rn_bits {
7697 12 } else {
7699 rd_bits };
7701 if scratch == rn_bits {
7709 return Err(synth_core::Error::synthesis(format!(
7710 "ADD #imm: cannot lower #{imm:#x} for Rd==Rn==R12 — no free scratch \
7711 register (R12 is the reserved encoder scratch and aliases Rn here)"
7712 )));
7713 }
7714
7715 let lo16 = imm & 0xFFFF;
7716 let hi16 = (imm >> 16) & 0xFFFF;
7717
7718 let mut bytes = self.encode_thumb32_movw_raw(scratch, lo16)?;
7719 if hi16 != 0 {
7720 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(scratch, hi16)?);
7721 }
7722 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(rd_bits, rn_bits, scratch)?);
7723 Ok(bytes)
7724 }
7725 }
7726
7727 fn encode_thumb32_movw_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7737 reg_bits_checked(rd)?;
7738 encoding_contracts::verify_imm16(imm16);
7739 let imm16 = imm16 & 0xFFFF;
7742 let imm4 = (imm16 >> 12) & 0xF;
7743 let i_bit = (imm16 >> 11) & 1;
7744 let imm3 = (imm16 >> 8) & 0x7;
7745 let imm8 = imm16 & 0xFF;
7746
7747 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7748 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7749
7750 let mut bytes = hw1.to_le_bytes().to_vec();
7751 bytes.extend_from_slice(&hw2.to_le_bytes());
7752 encoding_contracts::verify_thumb32(&bytes);
7753 Ok(bytes)
7754 }
7755
7756 fn encode_thumb32_movt_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7764 reg_bits_checked(rd)?;
7765 encoding_contracts::verify_imm16(imm16);
7766 let imm16 = imm16 & 0xFFFF;
7769 let imm4 = (imm16 >> 12) & 0xF;
7770 let i_bit = (imm16 >> 11) & 1;
7771 let imm3 = (imm16 >> 8) & 0x7;
7772 let imm8 = imm16 & 0xFF;
7773
7774 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
7775 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7776
7777 let mut bytes = hw1.to_le_bytes().to_vec();
7778 bytes.extend_from_slice(&hw2.to_le_bytes());
7779 encoding_contracts::verify_thumb32(&bytes);
7780 Ok(bytes)
7781 }
7782
7783 fn encode_thumb32_lsr_raw(&self, rd: u32, rm: u32, shift: u32) -> Result<Vec<u8>> {
7785 let imm5 = shift & 0x1F;
7788 let imm2 = imm5 & 0x3;
7789 let imm3 = (imm5 >> 2) & 0x7;
7790
7791 let hw1: u16 = 0xEA4F;
7792 let hw2: u16 = ((imm3 << 12) | (rd << 8) | (imm2 << 6) | (0b01 << 4) | rm) as u16;
7793
7794 let mut bytes = hw1.to_le_bytes().to_vec();
7795 bytes.extend_from_slice(&hw2.to_le_bytes());
7796 Ok(bytes)
7797 }
7798
7799 fn encode_thumb32_and_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7801 let hw1: u16 = (0xEA00 | rn) as u16;
7804 let hw2: u16 = ((rd << 8) | rm) as u16;
7805
7806 let mut bytes = hw1.to_le_bytes().to_vec();
7807 bytes.extend_from_slice(&hw2.to_le_bytes());
7808 Ok(bytes)
7809 }
7810
7811 fn encode_thumb32_and_imm_raw(&self, rd: u32, rn: u32, imm: u32) -> Result<Vec<u8>> {
7813 let i_bit = (imm >> 11) & 1;
7817 let imm3 = (imm >> 8) & 0x7;
7818 let imm8 = imm & 0xFF;
7819
7820 let hw1: u16 = (0xF000 | (i_bit << 10) | rn) as u16;
7821 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7822
7823 let mut bytes = hw1.to_le_bytes().to_vec();
7824 bytes.extend_from_slice(&hw2.to_le_bytes());
7825 Ok(bytes)
7826 }
7827
7828 fn encode_thumb32_sub_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7830 let hw1: u16 = (0xEBA0 | rn) as u16;
7833 let hw2: u16 = ((rd << 8) | rm) as u16;
7834
7835 let mut bytes = hw1.to_le_bytes().to_vec();
7836 bytes.extend_from_slice(&hw2.to_le_bytes());
7837 Ok(bytes)
7838 }
7839
7840 fn encode_thumb32_add_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7842 let hw1: u16 = (0xEB00 | rn) as u16;
7845 let hw2: u16 = ((rd << 8) | rm) as u16;
7846
7847 let mut bytes = hw1.to_le_bytes().to_vec();
7848 bytes.extend_from_slice(&hw2.to_le_bytes());
7849 Ok(bytes)
7850 }
7851
7852 fn encode_thumb32_adds_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7856 let hw1: u16 = (0xEB10 | rn) as u16;
7858 let hw2: u16 = ((rd << 8) | rm) as u16;
7859 let mut bytes = hw1.to_le_bytes().to_vec();
7860 bytes.extend_from_slice(&hw2.to_le_bytes());
7861 Ok(bytes)
7862 }
7863
7864 fn encode_thumb32_subs_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7867 let hw1: u16 = (0xEBB0 | rn) as u16;
7869 let hw2: u16 = ((rd << 8) | rm) as u16;
7870 let mut bytes = hw1.to_le_bytes().to_vec();
7871 bytes.extend_from_slice(&hw2.to_le_bytes());
7872 Ok(bytes)
7873 }
7874
7875 pub fn encode_sequence(&self, ops: &[ArmOp]) -> Result<Vec<u8>> {
7877 let mut code = Vec::new();
7878
7879 for op in ops {
7880 let encoded = self.encode(op)?;
7881 code.extend_from_slice(&encoded);
7882 }
7883
7884 Ok(code)
7885 }
7886}
7887
7888fn try_thumb_expand_imm(value: u32) -> Option<u32> {
7896 if value <= 0xFF {
7898 return Some(value);
7899 }
7900 let b0 = value & 0xFF; let b1 = (value >> 8) & 0xFF; if value == (b0 << 16) | b0 {
7904 return Some(0x100 | b0);
7905 }
7906 if value == (b1 << 24) | (b1 << 8) {
7908 return Some(0x200 | b1);
7909 }
7910 if value == (b0 << 24) | (b0 << 16) | (b0 << 8) | b0 {
7912 return Some(0x300 | b0);
7913 }
7914 for rot in 8..=31u32 {
7918 let unrot = value.rotate_left(rot);
7919 if (0x80..=0xFF).contains(&unrot) {
7920 return Some((rot << 7) | (unrot & 0x7F));
7921 }
7922 }
7923 None
7924}
7925
7926fn check_ldst_imm12(offset: u32) -> Result<()> {
7932 if offset > 0xFFF {
7933 Err(synth_core::Error::synthesis(
7934 "load/store immediate offset > 0xFFF (4095) — materialize the offset into a register",
7935 ))
7936 } else {
7937 Ok(())
7938 }
7939}
7940
7941fn reg_to_bits(reg: &Reg) -> u32 {
7942 match reg {
7943 Reg::R0 => 0,
7944 Reg::R1 => 1,
7945 Reg::R2 => 2,
7946 Reg::R3 => 3,
7947 Reg::R4 => 4,
7948 Reg::R5 => 5,
7949 Reg::R6 => 6,
7950 Reg::R7 => 7,
7951 Reg::R8 => 8,
7952 Reg::R9 => 9,
7953 Reg::R10 => 10,
7954 Reg::R11 => 11,
7955 Reg::R12 => 12,
7956 Reg::SP => 13,
7957 Reg::LR => 14,
7958 Reg::PC => 15,
7959 }
7960}
7961
7962fn emit_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
7993 debug_assert!(srcs.len() <= 4);
7994 bytes.extend_from_slice(&0xB40Fu16.to_le_bytes());
7996 for src in srcs.iter().rev() {
7998 let rt = reg_to_bits(src) as u16;
7999 bytes.extend_from_slice(&0xF84Du16.to_le_bytes());
8000 bytes.extend_from_slice(&((rt << 12) | 0x0D04).to_le_bytes());
8001 }
8002 for i in 0..srcs.len() as u16 {
8004 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes());
8005 }
8006}
8007
8008fn emit_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8012 let lo = reg_to_bits(rdlo);
8013 let hi = reg_to_bits(rdhi);
8014 if lo == 1 && hi == 0 {
8015 return Err(synth_core::Error::synthesis(
8018 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8019 ));
8020 }
8021 let mov16 = |bytes: &mut Vec<u8>, rd: u32, rm: u32| {
8022 let d = ((rd >> 3) & 1) as u16;
8023 bytes.extend_from_slice(
8024 &(0x4600u16 | (d << 7) | ((rm as u16) << 3) | ((rd & 7) as u16)).to_le_bytes(),
8025 );
8026 };
8027 if hi == 0 {
8028 mov16(bytes, lo, 0);
8030 mov16(bytes, hi, 1);
8031 } else {
8032 mov16(bytes, hi, 1);
8034 mov16(bytes, lo, 0);
8035 }
8036 for i in 0..4u32 {
8037 if i == lo || i == hi {
8038 bytes.extend_from_slice(&0xB001u16.to_le_bytes()); } else {
8041 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes()); }
8043 }
8044 Ok(())
8045}
8046
8047fn emit_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8051 bytes.extend_from_slice(&0xEA52u16.to_le_bytes()); bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8053 bytes.extend_from_slice(&0xD100u16.to_le_bytes()); bytes.extend_from_slice(&0xDE00u16.to_le_bytes()); }
8056
8057fn emit_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8067 bytes.extend_from_slice(&0xEA02u16.to_le_bytes());
8069 bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8070 bytes.extend_from_slice(&0xF11Cu16.to_le_bytes());
8072 bytes.extend_from_slice(&0x0F01u16.to_le_bytes());
8073 bytes.extend_from_slice(&0xD105u16.to_le_bytes());
8075 bytes.extend_from_slice(&0x2800u16.to_le_bytes());
8077 bytes.extend_from_slice(&0xD103u16.to_le_bytes());
8079 bytes.extend_from_slice(&0xF1B1u16.to_le_bytes());
8081 bytes.extend_from_slice(&0x4F00u16.to_le_bytes());
8082 bytes.extend_from_slice(&0xD100u16.to_le_bytes());
8084 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
8086 }
8088
8089fn emit_a32_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
8103 debug_assert!(srcs.len() <= 4);
8104 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8105 w(bytes, 0xE92D_000F);
8107 for src in srcs.iter().rev() {
8109 w(bytes, 0xE52D_0004 | (reg_to_bits(src) << 12));
8110 }
8111 for i in 0..srcs.len() as u32 {
8113 w(bytes, 0xE49D_0004 | (i << 12));
8114 }
8115}
8116
8117fn emit_a32_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8121 let lo = reg_to_bits(rdlo);
8122 let hi = reg_to_bits(rdhi);
8123 if lo == 1 && hi == 0 {
8124 return Err(synth_core::Error::synthesis(
8127 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8128 ));
8129 }
8130 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8131 let mov = |bytes: &mut Vec<u8>, rd: u32, rm: u32| w(bytes, 0xE1A0_0000 | (rd << 12) | rm);
8132 if hi == 0 {
8133 mov(bytes, lo, 0);
8135 mov(bytes, hi, 1);
8136 } else {
8137 mov(bytes, hi, 1);
8139 mov(bytes, lo, 0);
8140 }
8141 for i in 0..4u32 {
8142 if i == lo || i == hi {
8143 w(bytes, 0xE28D_D004); } else {
8146 w(bytes, 0xE49D_0004 | (i << 12)); }
8148 }
8149 Ok(())
8150}
8151
8152fn emit_a32_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8156 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8157 w(bytes, 0xE192_C003); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8161
8162fn emit_a32_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8167 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8168 w(bytes, 0xE002_C003); w(bytes, 0xE37C_0001); w(bytes, 0x0350_0000); w(bytes, 0x0351_0102); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8175
8176fn reg_bits_checked(bits: u32) -> Result<()> {
8184 if bits > 14 {
8185 return Err(synth_core::Error::synthesis(format!(
8186 "register bits {bits} (PC/R15) is not a valid operand for this Thumb-2 encoding"
8187 )));
8188 }
8189 Ok(())
8190}
8191
8192fn try_encode_rotated_imm(val: u32) -> Option<(u32, u32)> {
8195 if val == 0 {
8196 return Some((0, 1));
8197 }
8198 for rot in 0..16u32 {
8199 let shift = rot * 2;
8200 let unrotated = val.rotate_left(shift);
8202 if unrotated <= 0xFF {
8203 return Some(((rot << 8) | unrotated, 1));
8205 }
8206 }
8207 None
8208}
8209
8210fn encode_operand2(op2: &Operand2) -> Result<(u32, u32)> {
8215 match op2 {
8216 Operand2::Imm(val) => {
8217 let uval = *val as u32;
8218 if let Some(encoded) = try_encode_rotated_imm(uval) {
8220 Ok(encoded)
8221 } else {
8222 Err(synth_core::Error::synthesis(format!(
8231 "encode_operand2: immediate {uval:#x} ({val}) is not an ARM32 \
8232 rotated immediate — the selector must materialize large \
8233 constants via MOVW/MOVT"
8234 )))
8235 }
8236 }
8237
8238 Operand2::Reg(reg) => {
8239 let reg_bits = reg_to_bits(reg);
8240 Ok((reg_bits, 0)) }
8242
8243 Operand2::RegShift {
8244 rm,
8245 shift: _,
8246 amount,
8247 } => {
8248 let rm_bits = reg_to_bits(rm);
8250 let shift_bits = (*amount & 0x1F) << 7;
8251 Ok((shift_bits | rm_bits, 0))
8252 }
8253 }
8254}
8255
8256fn encode_mem_addr(addr: &MemAddr) -> (u32, u32) {
8258 let base_bits = reg_to_bits(&addr.base);
8259 let offset_bits = (addr.offset as u32) & 0xFFF; (base_bits, offset_bits)
8261}
8262
8263fn vfp_sreg_to_num(reg: &VfpReg) -> Result<u32> {
8265 match reg {
8266 VfpReg::S0 => Ok(0),
8267 VfpReg::S1 => Ok(1),
8268 VfpReg::S2 => Ok(2),
8269 VfpReg::S3 => Ok(3),
8270 VfpReg::S4 => Ok(4),
8271 VfpReg::S5 => Ok(5),
8272 VfpReg::S6 => Ok(6),
8273 VfpReg::S7 => Ok(7),
8274 VfpReg::S8 => Ok(8),
8275 VfpReg::S9 => Ok(9),
8276 VfpReg::S10 => Ok(10),
8277 VfpReg::S11 => Ok(11),
8278 VfpReg::S12 => Ok(12),
8279 VfpReg::S13 => Ok(13),
8280 VfpReg::S14 => Ok(14),
8281 VfpReg::S15 => Ok(15),
8282 VfpReg::S16 => Ok(16),
8283 VfpReg::S17 => Ok(17),
8284 VfpReg::S18 => Ok(18),
8285 VfpReg::S19 => Ok(19),
8286 VfpReg::S20 => Ok(20),
8287 VfpReg::S21 => Ok(21),
8288 VfpReg::S22 => Ok(22),
8289 VfpReg::S23 => Ok(23),
8290 VfpReg::S24 => Ok(24),
8291 VfpReg::S25 => Ok(25),
8292 VfpReg::S26 => Ok(26),
8293 VfpReg::S27 => Ok(27),
8294 VfpReg::S28 => Ok(28),
8295 VfpReg::S29 => Ok(29),
8296 VfpReg::S30 => Ok(30),
8297 VfpReg::S31 => Ok(31),
8298 _ => Err(synth_core::Error::SynthesisError(
8300 "D-register not supported in single-precision VFP encoding".to_string(),
8301 )),
8302 }
8303}
8304
8305fn vfp_dreg_to_num(reg: &VfpReg) -> Result<u32> {
8307 match reg {
8308 VfpReg::D0 => Ok(0),
8309 VfpReg::D1 => Ok(1),
8310 VfpReg::D2 => Ok(2),
8311 VfpReg::D3 => Ok(3),
8312 VfpReg::D4 => Ok(4),
8313 VfpReg::D5 => Ok(5),
8314 VfpReg::D6 => Ok(6),
8315 VfpReg::D7 => Ok(7),
8316 VfpReg::D8 => Ok(8),
8317 VfpReg::D9 => Ok(9),
8318 VfpReg::D10 => Ok(10),
8319 VfpReg::D11 => Ok(11),
8320 VfpReg::D12 => Ok(12),
8321 VfpReg::D13 => Ok(13),
8322 VfpReg::D14 => Ok(14),
8323 VfpReg::D15 => Ok(15),
8324 _ => Err(synth_core::Error::SynthesisError(
8326 "S-register not supported in double-precision VFP encoding".to_string(),
8327 )),
8328 }
8329}
8330
8331fn encode_sreg(s: u32) -> (u32, u32) {
8335 (s >> 1, s & 1)
8336}
8337
8338fn encode_dreg(d: u32) -> (u32, u32) {
8342 (d & 0xF, (d >> 4) & 1)
8343}
8344
8345fn encode_vfp_3reg(base: u32, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<u32> {
8351 let sd_num = vfp_sreg_to_num(sd)?;
8352 let sn_num = vfp_sreg_to_num(sn)?;
8353 let sm_num = vfp_sreg_to_num(sm)?;
8354 let (vd, d) = encode_sreg(sd_num);
8355 let (vn, n) = encode_sreg(sn_num);
8356 let (vm, m) = encode_sreg(sm_num);
8357
8358 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8359}
8360
8361fn encode_vfp_2reg(base: u32, sd: &VfpReg, sm: &VfpReg) -> Result<u32> {
8364 let sd_num = vfp_sreg_to_num(sd)?;
8365 let sm_num = vfp_sreg_to_num(sm)?;
8366 let (vd, d) = encode_sreg(sd_num);
8367 let (vm, m) = encode_sreg(sm_num);
8368
8369 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8370}
8371
8372fn encode_vfp_ldst(base: u32, sd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8376 let sd_num = vfp_sreg_to_num(sd)?;
8377 let (vd, d) = encode_sreg(sd_num);
8378 let rn = reg_to_bits(&addr.base);
8379
8380 let offset = addr.offset;
8381 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8382 let abs_offset = offset.unsigned_abs();
8383 let imm8 = (abs_offset / 4) & 0xFF;
8384
8385 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8386}
8387
8388fn encode_vmov_core_sreg(to_sreg: bool, sreg: &VfpReg, core: &Reg) -> Result<u32> {
8392 let s_num = vfp_sreg_to_num(sreg)?;
8393 let (vn, n) = encode_sreg(s_num);
8394 let rt = reg_to_bits(core);
8395
8396 let base = if to_sreg { 0xEE000A10 } else { 0xEE100A10 };
8397 Ok(base | (vn << 16) | (rt << 12) | (n << 7))
8398}
8399
8400fn encode_vfp_3reg_f64(base: u32, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<u32> {
8404 let dd_num = vfp_dreg_to_num(dd)?;
8405 let dn_num = vfp_dreg_to_num(dn)?;
8406 let dm_num = vfp_dreg_to_num(dm)?;
8407 let (vd, d) = encode_dreg(dd_num);
8408 let (vn, n) = encode_dreg(dn_num);
8409 let (vm, m) = encode_dreg(dm_num);
8410
8411 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8412}
8413
8414fn encode_vfp_2reg_f64(base: u32, dd: &VfpReg, dm: &VfpReg) -> Result<u32> {
8416 let dd_num = vfp_dreg_to_num(dd)?;
8417 let dm_num = vfp_dreg_to_num(dm)?;
8418 let (vd, d) = encode_dreg(dd_num);
8419 let (vm, m) = encode_dreg(dm_num);
8420
8421 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8422}
8423
8424fn encode_vfp_ldst_f64(base: u32, dd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8427 let dd_num = vfp_dreg_to_num(dd)?;
8428 let (vd, d) = encode_dreg(dd_num);
8429 let rn = reg_to_bits(&addr.base);
8430
8431 let offset = addr.offset;
8432 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8433 let abs_offset = offset.unsigned_abs();
8434 let imm8 = (abs_offset / 4) & 0xFF;
8435
8436 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8437}
8438
8439fn encode_vmov_core_dreg(
8443 to_dreg: bool,
8444 dreg: &VfpReg,
8445 core_lo: &Reg,
8446 core_hi: &Reg,
8447) -> Result<u32> {
8448 let d_num = vfp_dreg_to_num(dreg)?;
8449 let (vm, m) = encode_dreg(d_num);
8450 let rt = reg_to_bits(core_lo);
8451 let rt2 = reg_to_bits(core_hi);
8452
8453 let base = if to_dreg { 0xEC400B10 } else { 0xEC500B10 };
8454 Ok(base | (rt2 << 16) | (rt << 12) | (m << 5) | vm)
8455}
8456
8457fn vfp_to_thumb_bytes(instr: u32) -> Vec<u8> {
8459 let hw1 = ((instr >> 16) & 0xFFFF) as u16;
8460 let hw2 = (instr & 0xFFFF) as u16;
8461 let mut bytes = hw1.to_le_bytes().to_vec();
8462 bytes.extend_from_slice(&hw2.to_le_bytes());
8463 bytes
8464}
8465
8466fn qreg_to_num(reg: &QReg) -> u32 {
8472 match reg {
8473 QReg::Q0 => 0,
8474 QReg::Q1 => 1,
8475 QReg::Q2 => 2,
8476 QReg::Q3 => 3,
8477 QReg::Q4 => 4,
8478 QReg::Q5 => 5,
8479 QReg::Q6 => 6,
8480 QReg::Q7 => 7,
8481 }
8482}
8483
8484fn mve_size_bits(size: &MveSize) -> u32 {
8486 match size {
8487 MveSize::S8 => 0b00,
8488 MveSize::S16 => 0b01,
8489 MveSize::S32 => 0b10,
8490 }
8491}
8492
8493fn encode_mve_3reg(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8497 let d = qreg_to_num(qd) * 2;
8498 let n = qreg_to_num(qn) * 2;
8499 let m = qreg_to_num(qm) * 2;
8500
8501 let vd = d & 0xF;
8506 let d_bit = (d >> 4) & 1;
8507 let vn = n & 0xF;
8508 let n_bit = (n >> 4) & 1;
8509 let vm = m & 0xF;
8510 let m_bit = (m >> 4) & 1;
8511
8512 base | (d_bit << 22) | (vn << 16) | (vd << 12) | (n_bit << 7) | (m_bit << 5) | vm
8513}
8514
8515fn encode_mve_3reg_bitwise(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8517 encode_mve_3reg(base, qd, qn, qm)
8518}
8519
8520fn encode_mve_vldrw(qd: &QReg, addr: &MemAddr) -> u32 {
8523 let qd_enc = qreg_to_num(qd) * 2;
8524 let rn = reg_to_bits(&addr.base);
8525 let offset = addr.offset;
8526 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8527 let abs_offset = offset.unsigned_abs();
8528 let imm7 = (abs_offset / 4) & 0x7F; 0xED100E80
8532 | (u_bit << 23)
8533 | ((qd_enc >> 4) << 22)
8534 | (rn << 16)
8535 | ((qd_enc & 0xF) << 12)
8536 | (imm7 & 0x7F)
8537}
8538
8539fn encode_mve_vstrw(qd: &QReg, addr: &MemAddr) -> u32 {
8541 let qd_enc = qreg_to_num(qd) * 2;
8542 let rn = reg_to_bits(&addr.base);
8543 let offset = addr.offset;
8544 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8545 let abs_offset = offset.unsigned_abs();
8546 let imm7 = (abs_offset / 4) & 0x7F;
8547
8548 0xED000E80
8549 | (u_bit << 23)
8550 | ((qd_enc >> 4) << 22)
8551 | (rn << 16)
8552 | ((qd_enc & 0xF) << 12)
8553 | (imm7 & 0x7F)
8554}
8555
8556impl ArmEncoder {
8557 fn encode_thumb_mve_const(&self, qd: &QReg, bytes: &[u8; 16]) -> Result<Vec<u8>> {
8559 let mut result = Vec::new();
8560 let qd_num = qreg_to_num(qd);
8561
8562 for i in 0..4 {
8564 let word = u32::from_le_bytes([
8565 bytes[i * 4],
8566 bytes[i * 4 + 1],
8567 bytes[i * 4 + 2],
8568 bytes[i * 4 + 3],
8569 ]);
8570 let lo16 = word & 0xFFFF;
8571 let hi16 = (word >> 16) & 0xFFFF;
8572
8573 result.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
8575 if hi16 != 0 {
8577 result.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
8578 }
8579
8580 let s_num = qd_num * 4 + i as u32;
8582 let (vn, n) = encode_sreg(s_num);
8583 let vmov: u32 = 0xEE000A10 | (vn << 16) | (12 << 12) | (n << 7);
8584 result.extend_from_slice(&vfp_to_thumb_bytes(vmov));
8585 }
8586
8587 Ok(result)
8588 }
8589
8590 fn encode_thumb_mve_lane_wise_f32_binop(
8592 &self,
8593 qd: &QReg,
8594 qn: &QReg,
8595 qm: &QReg,
8596 vfp_base: u32,
8597 ) -> Result<Vec<u8>> {
8598 let mut result = Vec::new();
8599 let qd_num = qreg_to_num(qd);
8600 let qn_num = qreg_to_num(qn);
8601 let qm_num = qreg_to_num(qm);
8602
8603 for i in 0..4u32 {
8605 let sd = qd_num * 4 + i;
8606 let sn = qn_num * 4 + i;
8607 let sm = qm_num * 4 + i;
8608
8609 let (vd, d) = encode_sreg(sd);
8610 let (vn, n) = encode_sreg(sn);
8611 let (vm, m) = encode_sreg(sm);
8612
8613 let instr = vfp_base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
8614 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8615 }
8616
8617 Ok(result)
8618 }
8619
8620 fn encode_thumb_mve_lane_wise_f32_sqrt(&self, qd: &QReg, qm: &QReg) -> Result<Vec<u8>> {
8622 let mut result = Vec::new();
8623 let qd_num = qreg_to_num(qd);
8624 let qm_num = qreg_to_num(qm);
8625
8626 for i in 0..4u32 {
8628 let sd = qd_num * 4 + i;
8629 let sm = qm_num * 4 + i;
8630
8631 let (vd, d) = encode_sreg(sd);
8632 let (vm, m) = encode_sreg(sm);
8633
8634 let instr: u32 = 0xEEB10AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
8635 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8636 }
8637
8638 Ok(result)
8639 }
8640}
8641
8642#[cfg(test)]
8643mod tests {
8644 use super::*;
8645
8646 #[test]
8647 fn test_encoder_creation() {
8648 let encoder_arm = ArmEncoder::new_arm32();
8649 assert!(!encoder_arm.thumb_mode);
8650
8651 let encoder_thumb = ArmEncoder::new_thumb2();
8652 assert!(encoder_thumb.thumb_mode);
8653 }
8654
8655 #[test]
8667 fn test_encode_i64setcond_high_reg_uses_mov_w_311() {
8668 use synth_synthesis::{ArmOp, Condition, Reg};
8669 let enc = ArmEncoder::new_thumb2();
8670 let bytes = enc
8671 .encode(&ArmOp::I64SetCond {
8672 rd: Reg::R8,
8673 rn_lo: Reg::R2,
8674 rn_hi: Reg::R3,
8675 rm_lo: Reg::R6,
8676 rm_hi: Reg::R7,
8677 cond: Condition::EQ,
8678 })
8679 .unwrap();
8680 let halfwords: Vec<u16> = bytes
8683 .chunks(2)
8684 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8685 .collect();
8686 assert!(
8687 halfwords.iter().filter(|&&h| h == 0xF04F).count() == 2,
8688 "high rd must use two MOV.W (T2) encodings, got {halfwords:04x?}"
8689 );
8690 assert!(
8691 !halfwords.contains(&0x2801) && !halfwords.contains(&0x2800),
8692 "no transmuted 16-bit CMP imm: {halfwords:04x?}"
8693 );
8694
8695 let bytes_z = enc
8696 .encode(&ArmOp::I64SetCondZ {
8697 rd: Reg::R8,
8698 rn_lo: Reg::R2,
8699 rn_hi: Reg::R3,
8700 })
8701 .unwrap();
8702 let hw_z: Vec<u16> = bytes_z
8703 .chunks(2)
8704 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8705 .collect();
8706 assert!(
8707 hw_z.iter().filter(|&&h| h == 0xF04F).count() == 2,
8708 "SetCondZ high rd MOV.W: {hw_z:04x?}"
8709 );
8710 assert!(
8712 hw_z.contains(&(0xF1B0 | 8)),
8713 "SetCondZ high rd must use CMP.W: {hw_z:04x?}"
8714 );
8715 }
8716
8717 #[test]
8718 fn test_encode_setcond_high_reg_uses_mov_w_204() {
8719 use synth_synthesis::{ArmOp, Condition, Reg};
8720 let enc = ArmEncoder::new_thumb2();
8721 let hi = enc
8723 .encode(&ArmOp::SetCond {
8724 rd: Reg::R12,
8725 cond: Condition::NE,
8726 })
8727 .unwrap();
8728 assert_eq!(hi.len(), 10, "ITE(2) + MOV.W(4) + MOV.W(4): {hi:02x?}");
8729 assert_eq!(&hi[2..4], &[0x4F, 0xF0], "then = MOV.W: {hi:02x?}");
8731 assert_eq!(&hi[6..8], &[0x4F, 0xF0], "else = MOV.W: {hi:02x?}");
8732 assert_eq!(hi[4] & 0x0F, 0x01, "then imm = #1");
8733 assert_eq!(hi[8] & 0x0F, 0x00, "else imm = #0");
8734 let lo = enc
8736 .encode(&ArmOp::SetCond {
8737 rd: Reg::R0,
8738 cond: Condition::NE,
8739 })
8740 .unwrap();
8741 assert_eq!(lo.len(), 6, "ITE(2) + MOVS(2) + MOVS(2): {lo:02x?}");
8742 assert_eq!(lo[2..4], [0x01, 0x20], "then = MOVS R0,#1");
8743 assert_eq!(lo[4..6], [0x00, 0x20], "else = MOVS R0,#0");
8744 }
8745
8746 #[test]
8750 fn test_encode_umull_209b() {
8751 use synth_synthesis::{ArmOp, Reg};
8752 let op = ArmOp::Umull {
8753 rdlo: Reg::R4,
8754 rdhi: Reg::R5,
8755 rn: Reg::R0,
8756 rm: Reg::R3,
8757 };
8758 let t = ArmEncoder::new_thumb2().encode(&op).unwrap();
8760 assert_eq!(
8761 t,
8762 vec![0xA0, 0xFB, 0x03, 0x45],
8763 "umull r4,r5,r0,r3 (T2): {t:02x?}"
8764 );
8765 let a = ArmEncoder::new_arm32().encode(&op).unwrap();
8767 assert_eq!(
8768 a,
8769 0xE085_4390u32.to_le_bytes().to_vec(),
8770 "umull (A32): {a:02x?}"
8771 );
8772 }
8773
8774 #[test]
8781 fn test_encode_arm32_indexed_load_keeps_index_206() {
8782 use synth_synthesis::{ArmOp, MemAddr, Reg};
8783 let enc = ArmEncoder::new_arm32();
8784 let bytes = enc
8786 .encode(&ArmOp::Ldr {
8787 rd: Reg::R0,
8788 addr: MemAddr::reg_imm(Reg::R11, Reg::R1, 8),
8789 })
8790 .unwrap();
8791 assert_eq!(
8792 bytes.len(),
8793 8,
8794 "expected ADD ip + LDR (2 words): {bytes:02x?}"
8795 );
8796 let add = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
8797 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
8798 assert_eq!(add, 0xE08B_C001, "ADD ip,r11,r1: {add:#010x}");
8800 assert_eq!(ldr, 0xE59C_0008, "LDR r0,[ip,#8]: {ldr:#010x}");
8802 assert_ne!(ldr, 0xE59B_0008, "index must not be dropped");
8804 }
8805
8806 #[test]
8814 fn test_encode_arm32_call_indirect_is_real_call_594() {
8815 use synth_synthesis::{ArmOp, Reg};
8816 let enc = ArmEncoder::new_arm32();
8817 let bytes = enc
8818 .encode(&ArmOp::CallIndirect {
8819 rd: Reg::R0,
8820 type_idx: 0,
8821 table_index_reg: Reg::R0,
8822 table_size: 4,
8823 })
8824 .unwrap();
8825 assert_eq!(
8826 bytes.len(),
8827 28,
8828 "expected MOVW + CMP + BLO + UDF + MOV + LDR + BLX (7 words): {bytes:02x?}"
8829 );
8830 let words: Vec<u32> = bytes
8831 .chunks_exact(4)
8832 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
8833 .collect();
8834 assert_eq!(words[0], 0xE300_C004, "MOVW r12,#4: {:#010x}", words[0]);
8836 assert_eq!(words[1], 0xE150_000C, "CMP r0,r12: {:#010x}", words[1]);
8837 assert_eq!(words[2], 0x3A00_0000, "BLO +1 insn: {:#010x}", words[2]);
8838 assert_eq!(words[3], 0xE7F0_00F0, "UDF: {:#010x}", words[3]);
8839 assert_eq!(
8841 words[4], 0xE1A0_C100,
8842 "MOV r12,r0,LSL#2: {:#010x}",
8843 words[4]
8844 );
8845 assert_eq!(
8847 words[5], 0xE79B_C00C,
8848 "LDR r12,[r11,r12]: {:#010x}",
8849 words[5]
8850 );
8851 assert_eq!(words[6], 0xE12F_FF3C, "BLX r12: {:#010x}", words[6]);
8853 assert!(
8855 !bytes
8856 .chunks_exact(4)
8857 .any(|w| w == 0xE1A0_0000u32.to_le_bytes()),
8858 "call_indirect must not contain a NOP (#594): {bytes:02x?}"
8859 );
8860
8861 let bytes = enc
8863 .encode(&ArmOp::CallIndirect {
8864 rd: Reg::R0,
8865 type_idx: 0,
8866 table_index_reg: Reg::R4,
8867 table_size: 4,
8868 })
8869 .unwrap();
8870 let cmp = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
8871 assert_eq!(cmp, 0xE154_000C, "CMP r4,r12: {cmp:#010x}");
8872 let mov = u32::from_le_bytes(bytes[16..20].try_into().unwrap());
8873 assert_eq!(mov, 0xE1A0_C104, "MOV r12,r4,LSL#2: {mov:#010x}");
8874 }
8875
8876 #[test]
8879 fn test_encode_arm32_call_indirect_wide_table_size_642() {
8880 use synth_synthesis::{ArmOp, Reg};
8881 let enc = ArmEncoder::new_arm32();
8882 let bytes = enc
8883 .encode(&ArmOp::CallIndirect {
8884 rd: Reg::R0,
8885 type_idx: 0,
8886 table_index_reg: Reg::R0,
8887 table_size: 0x0002_0003,
8888 })
8889 .unwrap();
8890 assert_eq!(bytes.len(), 32, "MOVT arm adds one word: {bytes:02x?}");
8891 let movw = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
8892 let movt = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
8893 assert_eq!(movw, 0xE300_C003, "MOVW r12,#3: {movw:#010x}");
8894 assert_eq!(movt, 0xE340_C002, "MOVT r12,#2: {movt:#010x}");
8895 }
8896
8897 #[test]
8913 fn test_encode_thumb_call_indirect_lsl2_597() {
8914 use synth_synthesis::{ArmOp, Reg};
8915 let enc = ArmEncoder::new_thumb2();
8916 let bytes = enc
8917 .encode(&ArmOp::CallIndirect {
8918 rd: Reg::R0,
8919 type_idx: 0,
8920 table_index_reg: Reg::R0,
8921 table_size: 4,
8922 })
8923 .unwrap();
8924 assert_eq!(
8925 bytes,
8926 vec![
8927 0x40, 0xF2, 0x04, 0x0C, 0x60, 0x45, 0x00, 0xD3, 0x00, 0xDE, 0x4F, 0xEA, 0x80, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47, ],
8937 "Thumb-2 CallIndirect: bounds guard + mov.w/ldr.w/blx dispatch: {bytes:02x?}"
8938 );
8939 assert!(
8941 !bytes.windows(4).any(|w| w == [0x4F, 0xEA, 0x20, 0x0C]),
8942 "mov.w ip, rm, ASR #32 — the #597 type-field bug"
8943 );
8944
8945 let bytes = enc
8948 .encode(&ArmOp::CallIndirect {
8949 rd: Reg::R0,
8950 type_idx: 0,
8951 table_index_reg: Reg::R4,
8952 table_size: 4,
8953 })
8954 .unwrap();
8955 assert_eq!(&bytes[4..6], &[0x64, 0x45], "cmp r4, ip: {bytes:02x?}");
8956 assert_eq!(
8957 &bytes[10..14],
8958 &[0x4F, 0xEA, 0x84, 0x0C],
8959 "mov.w ip, r4, LSL #2: {bytes:02x?}"
8960 );
8961 }
8962
8963 #[test]
8967 fn test_encode_thumb_call_indirect_guard_shapes_642() {
8968 use synth_synthesis::{ArmOp, Reg};
8969 let enc = ArmEncoder::new_thumb2();
8970 let bytes = enc
8971 .encode(&ArmOp::CallIndirect {
8972 rd: Reg::R0,
8973 type_idx: 0,
8974 table_index_reg: Reg::R8,
8975 table_size: 3,
8976 })
8977 .unwrap();
8978 assert_eq!(&bytes[4..6], &[0xE0, 0x45], "cmp r8, ip: {bytes:02x?}");
8980
8981 let bytes = enc
8982 .encode(&ArmOp::CallIndirect {
8983 rd: Reg::R0,
8984 type_idx: 0,
8985 table_index_reg: Reg::R0,
8986 table_size: 0x0002_0003,
8987 })
8988 .unwrap();
8989 assert_eq!(
8991 &bytes[0..8],
8992 &[0x40, 0xF2, 0x03, 0x0C, 0xC0, 0xF2, 0x02, 0x0C],
8993 "movw ip,#3; movt ip,#2: {bytes:02x?}"
8994 );
8995 }
8996
8997 #[test]
9004 fn test_encode_thumb_add_high_reg_uses_add_w_178_180() {
9005 let encoder = ArmEncoder::new_thumb2();
9006
9007 let code = encoder
9009 .encode(&ArmOp::Add {
9010 rd: Reg::R12,
9011 rn: Reg::R12,
9012 op2: Operand2::Reg(Reg::R0),
9013 })
9014 .unwrap();
9015 assert_eq!(
9017 code,
9018 vec![0x0C, 0xEB, 0x00, 0x0C],
9019 "high-reg Thumb ADD must be 32-bit ADD.W (EB0C 0C00), not corrupt 16-bit; got {code:02X?}"
9020 );
9021 assert_ne!(code, vec![0x6C, 0x18], "regressed to corrupt 16-bit ADDS");
9023
9024 let lo = encoder
9026 .encode(&ArmOp::Add {
9027 rd: Reg::R1,
9028 rn: Reg::R2,
9029 op2: Operand2::Reg(Reg::R3),
9030 })
9031 .unwrap();
9032 assert_eq!(
9033 lo.len(),
9034 2,
9035 "low-reg ADD should remain 16-bit, got {lo:02X?}"
9036 );
9037 }
9038
9039 #[test]
9042 fn test_encode_thumb_adds_subs_high_reg_use_32bit_178_180() {
9043 let encoder = ArmEncoder::new_thumb2();
9044
9045 let adds = encoder
9047 .encode(&ArmOp::Adds {
9048 rd: Reg::R10,
9049 rn: Reg::R10,
9050 op2: Operand2::Reg(Reg::R8),
9051 })
9052 .unwrap();
9053 assert_eq!(
9054 adds,
9055 vec![0x1A, 0xEB, 0x08, 0x0A],
9056 "high-reg ADDS must be 32-bit ADDS.W (EB1A 0A08); got {adds:02X?}"
9057 );
9058
9059 let subs = encoder
9061 .encode(&ArmOp::Subs {
9062 rd: Reg::R10,
9063 rn: Reg::R10,
9064 op2: Operand2::Reg(Reg::R8),
9065 })
9066 .unwrap();
9067 assert_eq!(
9068 subs,
9069 vec![0xBA, 0xEB, 0x08, 0x0A],
9070 "high-reg SUBS must be 32-bit SUBS.W (EBBA 0A08); got {subs:02X?}"
9071 );
9072 }
9073
9074 #[test]
9077 fn test_encode_thumb_cmn_high_reg_uses_cmn_w_184() {
9078 let encoder = ArmEncoder::new_thumb2();
9079
9080 let cmn = encoder
9082 .encode(&ArmOp::Cmn {
9083 rn: Reg::R10,
9084 op2: Operand2::Reg(Reg::R8),
9085 })
9086 .unwrap();
9087 assert_eq!(
9088 cmn,
9089 vec![0x1A, 0xEB, 0x08, 0x0F],
9090 "high-reg CMN must be 32-bit CMN.W (EB1A 0F08); got {cmn:02X?}"
9091 );
9092
9093 let lo = encoder
9095 .encode(&ArmOp::Cmn {
9096 rn: Reg::R1,
9097 op2: Operand2::Reg(Reg::R2),
9098 })
9099 .unwrap();
9100 assert_eq!(
9101 lo.len(),
9102 2,
9103 "low-reg CMN should remain 16-bit, got {lo:02X?}"
9104 );
9105 assert_eq!(lo, vec![0xD1, 0x42], "low-reg CMN bytes wrong: {lo:02X?}");
9106 }
9107
9108 #[test]
9112 fn test_encode_pc_operand_returns_err_not_panic_185() {
9113 let encoder = ArmEncoder::new_thumb2();
9114 for op in [
9115 ArmOp::Sdiv {
9116 rd: Reg::PC,
9117 rn: Reg::R0,
9118 rm: Reg::R1,
9119 },
9120 ArmOp::Udiv {
9121 rd: Reg::R0,
9122 rn: Reg::PC,
9123 rm: Reg::R1,
9124 },
9125 ArmOp::Sdiv {
9126 rd: Reg::R0,
9127 rn: Reg::R1,
9128 rm: Reg::PC,
9129 },
9130 ] {
9131 let r = encoder.encode(&op);
9132 assert!(
9133 r.is_err(),
9134 "encode({op:?}) must return Err for a PC operand, got {r:?}"
9135 );
9136 }
9137 assert!(
9139 encoder
9140 .encode(&ArmOp::Sdiv {
9141 rd: Reg::R0,
9142 rn: Reg::R1,
9143 rm: Reg::R2
9144 })
9145 .is_ok()
9146 );
9147 }
9148
9149 #[test]
9150 fn test_encode_nop_arm32() {
9151 let encoder = ArmEncoder::new_arm32();
9152 let code = encoder.encode(&ArmOp::Nop).unwrap();
9153
9154 assert_eq!(code.len(), 4); assert_eq!(code, vec![0x00, 0x00, 0xA0, 0xE1]); }
9157
9158 #[test]
9159 fn test_encode_nop_thumb() {
9160 let encoder = ArmEncoder::new_thumb2();
9161 let code = encoder.encode(&ArmOp::Nop).unwrap();
9162
9163 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]); }
9166
9167 #[test]
9168 fn test_encode_mov_immediate_arm32() {
9169 let encoder = ArmEncoder::new_arm32();
9170 let op = ArmOp::Mov {
9171 rd: Reg::R0,
9172 op2: Operand2::Imm(42),
9173 };
9174
9175 let code = encoder.encode(&op).unwrap();
9176 assert_eq!(code.len(), 4);
9177
9178 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9180 assert_eq!(instr & 0x0E000000, 0x02000000); }
9182
9183 #[test]
9184 fn test_encode_add_registers_arm32() {
9185 let encoder = ArmEncoder::new_arm32();
9186 let op = ArmOp::Add {
9187 rd: Reg::R0,
9188 rn: Reg::R1,
9189 op2: Operand2::Reg(Reg::R2),
9190 };
9191
9192 let code = encoder.encode(&op).unwrap();
9193 assert_eq!(code.len(), 4);
9194
9195 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9196 assert_eq!(instr & 0x0FE00000, 0x00800000);
9198 }
9199
9200 #[test]
9204 fn test_encode_add_imm_large_350() {
9205 let enc = ArmEncoder::new_thumb2();
9206
9207 let small = enc
9209 .encode_thumb32_add_imm(&Reg::R0, &Reg::R1, 0x123)
9210 .unwrap();
9211 assert_eq!(small.len(), 4, "small imm must stay a single instruction");
9212
9213 fn movx_imm16(b: &[u8]) -> u32 {
9215 let hw1 = u16::from_le_bytes([b[0], b[1]]) as u32;
9216 let hw2 = u16::from_le_bytes([b[2], b[3]]) as u32;
9217 let imm4 = hw1 & 0xF;
9218 let i = (hw1 >> 10) & 1;
9219 let imm3 = (hw2 >> 12) & 0x7;
9220 let imm8 = hw2 & 0xFF;
9221 (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8
9222 }
9223 fn movx_rd(b: &[u8]) -> u32 {
9224 (u16::from_le_bytes([b[2], b[3]]) as u32 >> 8) & 0xF
9225 }
9226
9227 let seq = enc
9230 .encode_thumb32_add_imm(&Reg::R12, &Reg::R0, 70000)
9231 .unwrap();
9232 assert_eq!(seq.len(), 12, "MOVW + MOVT + ADD = 12 bytes");
9233 assert_eq!(u16::from_le_bytes([seq[0], seq[1]]) & 0xFBF0, 0xF240);
9235 assert_eq!(movx_rd(&seq[0..4]), 12);
9236 assert_eq!(movx_imm16(&seq[0..4]), 0x1170);
9237 assert_eq!(u16::from_le_bytes([seq[4], seq[5]]) & 0xFBF0, 0xF2C0);
9239 assert_eq!(movx_rd(&seq[4..8]), 12);
9240 assert_eq!(movx_imm16(&seq[4..8]), 0x0001);
9241 let add1 = u16::from_le_bytes([seq[8], seq[9]]) as u32;
9243 let add2 = u16::from_le_bytes([seq[10], seq[11]]) as u32;
9244 assert_eq!(add1 & 0xFFF0, 0xEB00);
9245 assert_eq!(add1 & 0xF, 0); assert_eq!((add2 >> 8) & 0xF, 12); assert_eq!(add2 & 0xF, 12); assert_eq!(
9250 (movx_imm16(&seq[4..8]) << 16) | movx_imm16(&seq[0..4]),
9251 70000
9252 );
9253
9254 let seq16 = enc
9256 .encode_thumb32_add_imm(&Reg::R3, &Reg::R0, 0xABCD)
9257 .unwrap();
9258 assert_eq!(seq16.len(), 8, "imm <= 0xFFFF skips MOVT");
9259 assert_eq!(movx_imm16(&seq16[0..4]), 0xABCD);
9260 assert_eq!(movx_rd(&seq16[0..4]), 3); let inplace = enc
9265 .encode_thumb32_add_imm(&Reg::R5, &Reg::R5, 0x12345)
9266 .unwrap();
9267 assert_eq!(inplace.len(), 12);
9268 assert_eq!(movx_rd(&inplace[0..4]), 12, "rd==rn must use R12 scratch");
9269 assert_eq!(
9270 (movx_imm16(&inplace[4..8]) << 16) | movx_imm16(&inplace[0..4]),
9271 0x12345
9272 );
9273 let ip_add2 = u16::from_le_bytes([inplace[10], inplace[11]]) as u32;
9275 assert_eq!(ip_add2 & 0xF, 12);
9276 assert_eq!((ip_add2 >> 8) & 0xF, 5);
9277 }
9278
9279 #[test]
9287 fn test_encode_add_imm_large_rd_rn_r12_errs_not_panics_350() {
9288 let enc = ArmEncoder::new_thumb2();
9289 let r = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 70000);
9291 assert!(
9292 r.is_err(),
9293 "rd==rn==R12 with out-of-range imm must Err (no free scratch), got {r:?}"
9294 );
9295 let small = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 0x10);
9299 assert!(small.is_ok(), "small imm needs no scratch, must stay Ok");
9300 }
9301
9302 #[test]
9311 fn test_encode_operand2_non_rotatable_imm_errs_not_masks_378() {
9312 let enc = ArmEncoder::new_arm32();
9313 let bad = enc.encode(&ArmOp::Add {
9314 rd: Reg::R0,
9315 rn: Reg::R1,
9316 op2: Operand2::Imm(0x1FF),
9317 });
9318 assert!(
9319 bad.is_err(),
9320 "non-rotatable ARM32 immediate 0x1FF must Err (was silently masked \
9321 to 0xFF), got {bad:?}"
9322 );
9323 let ok = enc.encode(&ArmOp::Add {
9325 rd: Reg::R0,
9326 rn: Reg::R1,
9327 op2: Operand2::Imm(0xFF),
9328 });
9329 assert!(
9330 ok.is_ok(),
9331 "0xFF is a valid rotated immediate, must stay Ok"
9332 );
9333 }
9334
9335 #[test]
9336 fn test_encode_ldr_arm32() {
9337 let encoder = ArmEncoder::new_arm32();
9338 let op = ArmOp::Ldr {
9339 rd: Reg::R0,
9340 addr: MemAddr::imm(Reg::R1, 4),
9341 };
9342
9343 let code = encoder.encode(&op).unwrap();
9344 assert_eq!(code.len(), 4);
9345
9346 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9347 assert_eq!(instr & 0x00100000, 0x00100000);
9349 }
9350
9351 #[test]
9352 fn test_encode_str_arm32() {
9353 let encoder = ArmEncoder::new_arm32();
9354 let op = ArmOp::Str {
9355 rd: Reg::R0,
9356 addr: MemAddr::imm(Reg::SP, 0),
9357 };
9358
9359 let code = encoder.encode(&op).unwrap();
9360 assert_eq!(code.len(), 4);
9361 }
9362
9363 #[test]
9364 fn test_encode_branch_arm32() {
9365 let encoder = ArmEncoder::new_arm32();
9366 let op = ArmOp::Bl {
9367 label: "main".to_string(),
9368 };
9369
9370 let code = encoder.encode(&op).unwrap();
9371 assert_eq!(code.len(), 4);
9372
9373 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9374 assert_eq!(instr & 0x0F000000, 0x0B000000);
9376 }
9377
9378 #[test]
9388 fn test_encode_thumb_bl_placeholder_addend_167_174() {
9389 let encoder = ArmEncoder::new_thumb2();
9390 let op = ArmOp::Bl {
9391 label: "callee".to_string(),
9392 };
9393
9394 let code = encoder.encode(&op).unwrap();
9395 assert_eq!(code.len(), 4, "Thumb-2 BL is 32-bit");
9396
9397 let hw1 = u16::from_le_bytes([code[0], code[1]]);
9398 let hw2 = u16::from_le_bytes([code[2], code[3]]);
9399 assert_eq!(hw1, 0xF7FF, "BL first halfword (matches gas `bl <extern>`)");
9400 assert_eq!(
9401 hw2, 0xFFFE,
9402 "BL second halfword must be 0xFFFE (-4 addend → nets to S), not 0xF800 (→ S+4, #174) or 0xD000 (#167)"
9403 );
9404 assert_ne!(hw2, 0xF800, "0xF800 (addend 0) lands at S+4 (#174)");
9405 assert_ne!(hw2, 0xD000, "0xD000 bakes in a ~+0x600000 addend (#167)");
9406 }
9407
9408 #[test]
9409 fn test_encode_sequence() {
9410 let encoder = ArmEncoder::new_arm32();
9411 let ops = vec![
9412 ArmOp::Mov {
9413 rd: Reg::R0,
9414 op2: Operand2::Imm(42),
9415 },
9416 ArmOp::Mov {
9417 rd: Reg::R1,
9418 op2: Operand2::Imm(10),
9419 },
9420 ArmOp::Add {
9421 rd: Reg::R2,
9422 rn: Reg::R0,
9423 op2: Operand2::Reg(Reg::R1),
9424 },
9425 ];
9426
9427 let code = encoder.encode_sequence(&ops).unwrap();
9428 assert_eq!(code.len(), 12); }
9430
9431 #[test]
9432 fn test_reg_to_bits() {
9433 assert_eq!(reg_to_bits(&Reg::R0), 0);
9434 assert_eq!(reg_to_bits(&Reg::R7), 7);
9435 assert_eq!(reg_to_bits(&Reg::SP), 13);
9436 assert_eq!(reg_to_bits(&Reg::LR), 14);
9437 assert_eq!(reg_to_bits(&Reg::PC), 15);
9438 }
9439
9440 #[test]
9441 fn test_encode_bitwise_operations() {
9442 let encoder = ArmEncoder::new_arm32();
9443
9444 let and_op = ArmOp::And {
9445 rd: Reg::R0,
9446 rn: Reg::R1,
9447 op2: Operand2::Reg(Reg::R2),
9448 };
9449 let and_code = encoder.encode(&and_op).unwrap();
9450 assert_eq!(and_code.len(), 4);
9451
9452 let orr_op = ArmOp::Orr {
9453 rd: Reg::R0,
9454 rn: Reg::R1,
9455 op2: Operand2::Reg(Reg::R2),
9456 };
9457 let orr_code = encoder.encode(&orr_op).unwrap();
9458 assert_eq!(orr_code.len(), 4);
9459
9460 let eor_op = ArmOp::Eor {
9461 rd: Reg::R0,
9462 rn: Reg::R1,
9463 op2: Operand2::Reg(Reg::R2),
9464 };
9465 let eor_code = encoder.encode(&eor_op).unwrap();
9466 assert_eq!(eor_code.len(), 4);
9467 }
9468
9469 #[test]
9472 fn test_encode_sdiv_thumb2() {
9473 let encoder = ArmEncoder::new_thumb2();
9474 let op = ArmOp::Sdiv {
9475 rd: Reg::R0,
9476 rn: Reg::R1,
9477 rm: Reg::R2,
9478 };
9479
9480 let code = encoder.encode(&op).unwrap();
9481 assert_eq!(code.len(), 4); assert_eq!(code[0], 0x91);
9488 assert_eq!(code[1], 0xFB);
9489 assert_eq!(code[2], 0xF2);
9490 assert_eq!(code[3], 0xF0);
9491 }
9492
9493 #[test]
9494 fn test_encode_udiv_thumb2() {
9495 let encoder = ArmEncoder::new_thumb2();
9496 let op = ArmOp::Udiv {
9497 rd: Reg::R0,
9498 rn: Reg::R1,
9499 rm: Reg::R2,
9500 };
9501
9502 let code = encoder.encode(&op).unwrap();
9503 assert_eq!(code.len(), 4); assert_eq!(code[0], 0xB1);
9508 assert_eq!(code[1], 0xFB);
9509 assert_eq!(code[2], 0xF2);
9510 assert_eq!(code[3], 0xF0);
9511 }
9512
9513 #[test]
9514 fn test_encode_mul_thumb2() {
9515 let encoder = ArmEncoder::new_thumb2();
9516 let op = ArmOp::Mul {
9517 rd: Reg::R0,
9518 rn: Reg::R1,
9519 rm: Reg::R2,
9520 };
9521
9522 let code = encoder.encode(&op).unwrap();
9523 assert_eq!(code.len(), 4); }
9525
9526 #[test]
9527 fn test_encode_and_thumb2() {
9528 let encoder = ArmEncoder::new_thumb2();
9529 let op = ArmOp::And {
9530 rd: Reg::R0,
9531 rn: Reg::R1,
9532 op2: Operand2::Reg(Reg::R2),
9533 };
9534
9535 let code = encoder.encode(&op).unwrap();
9536 assert_eq!(code.len(), 4); }
9538
9539 #[test]
9540 fn test_encode_lsl_thumb2_low_regs() {
9541 let encoder = ArmEncoder::new_thumb2();
9542 let op = ArmOp::Lsl {
9543 rd: Reg::R0,
9544 rn: Reg::R1,
9545 shift: 5,
9546 };
9547
9548 let code = encoder.encode(&op).unwrap();
9549 assert_eq!(code.len(), 2); }
9551
9552 #[test]
9553 fn test_encode_clz_thumb2() {
9554 let encoder = ArmEncoder::new_thumb2();
9555 let op = ArmOp::Clz {
9556 rd: Reg::R0,
9557 rm: Reg::R1,
9558 };
9559
9560 let code = encoder.encode(&op).unwrap();
9561 assert_eq!(code.len(), 4); }
9563
9564 #[test]
9565 fn test_encode_bx_thumb2() {
9566 let encoder = ArmEncoder::new_thumb2();
9567 let op = ArmOp::Bx { rm: Reg::LR };
9568
9569 let code = encoder.encode(&op).unwrap();
9570 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x70, 0x47]);
9574 }
9575
9576 #[test]
9581 fn test_encode_f32_abs_arm32() {
9582 let encoder = ArmEncoder::new_arm32();
9583 let op = ArmOp::F32Abs {
9584 sd: VfpReg::S0,
9585 sm: VfpReg::S2,
9586 };
9587 let code = encoder.encode(&op).unwrap();
9588 assert_eq!(code.len(), 4); }
9590
9591 #[test]
9592 fn test_encode_f32_neg_arm32() {
9593 let encoder = ArmEncoder::new_arm32();
9594 let op = ArmOp::F32Neg {
9595 sd: VfpReg::S0,
9596 sm: VfpReg::S2,
9597 };
9598 let code = encoder.encode(&op).unwrap();
9599 assert_eq!(code.len(), 4);
9600 }
9601
9602 #[test]
9603 fn test_encode_f32_sqrt_arm32() {
9604 let encoder = ArmEncoder::new_arm32();
9605 let op = ArmOp::F32Sqrt {
9606 sd: VfpReg::S0,
9607 sm: VfpReg::S2,
9608 };
9609 let code = encoder.encode(&op).unwrap();
9610 assert_eq!(code.len(), 4);
9611 }
9612
9613 #[test]
9614 fn test_encode_f32_ceil_arm32() {
9615 let encoder = ArmEncoder::new_arm32();
9616 let op = ArmOp::F32Ceil {
9617 sd: VfpReg::S0,
9618 sm: VfpReg::S2,
9619 };
9620 let code = encoder.encode(&op).unwrap();
9621 assert_eq!(code.len(), 36);
9623 }
9624
9625 #[test]
9626 fn test_encode_f32_floor_thumb2() {
9627 let encoder = ArmEncoder::new_thumb2();
9628 let op = ArmOp::F32Floor {
9629 sd: VfpReg::S0,
9630 sm: VfpReg::S2,
9631 };
9632 let code = encoder.encode(&op).unwrap();
9633 assert_eq!(code.len(), 36);
9635 }
9636
9637 #[test]
9638 fn test_encode_f32_min_arm32() {
9639 let encoder = ArmEncoder::new_arm32();
9640 let op = ArmOp::F32Min {
9641 sd: VfpReg::S0,
9642 sn: VfpReg::S2,
9643 sm: VfpReg::S4,
9644 };
9645 let code = encoder.encode(&op).unwrap();
9646 assert_eq!(code.len(), 16); }
9648
9649 #[test]
9650 fn test_encode_f32_max_thumb2() {
9651 let encoder = ArmEncoder::new_thumb2();
9652 let op = ArmOp::F32Max {
9653 sd: VfpReg::S0,
9654 sn: VfpReg::S2,
9655 sm: VfpReg::S4,
9656 };
9657 let code = encoder.encode(&op).unwrap();
9658 assert_eq!(code.len(), 18);
9660 }
9661
9662 #[test]
9663 fn test_encode_f32_copysign_arm32() {
9664 let encoder = ArmEncoder::new_arm32();
9665 let op = ArmOp::F32Copysign {
9666 sd: VfpReg::S0,
9667 sn: VfpReg::S2,
9668 sm: VfpReg::S4,
9669 };
9670 let code = encoder.encode(&op).unwrap();
9671 assert_eq!(code.len(), 24);
9673 }
9674
9675 #[test]
9680 fn test_encode_f64_add_arm32() {
9681 let encoder = ArmEncoder::new_arm32();
9682 let op = ArmOp::F64Add {
9683 dd: VfpReg::D0,
9684 dn: VfpReg::D1,
9685 dm: VfpReg::D2,
9686 };
9687 let code = encoder.encode(&op).unwrap();
9688 assert_eq!(code.len(), 4);
9689 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9691 assert_eq!((instr >> 8) & 0xF, 0xB); }
9693
9694 #[test]
9695 fn test_encode_f64_sub_thumb2() {
9696 let encoder = ArmEncoder::new_thumb2();
9697 let op = ArmOp::F64Sub {
9698 dd: VfpReg::D0,
9699 dn: VfpReg::D1,
9700 dm: VfpReg::D2,
9701 };
9702 let code = encoder.encode(&op).unwrap();
9703 assert_eq!(code.len(), 4); }
9705
9706 #[test]
9707 fn test_encode_f64_mul_arm32() {
9708 let encoder = ArmEncoder::new_arm32();
9709 let op = ArmOp::F64Mul {
9710 dd: VfpReg::D0,
9711 dn: VfpReg::D1,
9712 dm: VfpReg::D2,
9713 };
9714 let code = encoder.encode(&op).unwrap();
9715 assert_eq!(code.len(), 4);
9716 }
9717
9718 #[test]
9719 fn test_encode_f64_div_arm32() {
9720 let encoder = ArmEncoder::new_arm32();
9721 let op = ArmOp::F64Div {
9722 dd: VfpReg::D0,
9723 dn: VfpReg::D1,
9724 dm: VfpReg::D2,
9725 };
9726 let code = encoder.encode(&op).unwrap();
9727 assert_eq!(code.len(), 4);
9728 }
9729
9730 #[test]
9731 fn test_encode_f64_abs_arm32() {
9732 let encoder = ArmEncoder::new_arm32();
9733 let op = ArmOp::F64Abs {
9734 dd: VfpReg::D0,
9735 dm: VfpReg::D2,
9736 };
9737 let code = encoder.encode(&op).unwrap();
9738 assert_eq!(code.len(), 4);
9739 }
9740
9741 #[test]
9742 fn test_encode_f64_neg_arm32() {
9743 let encoder = ArmEncoder::new_arm32();
9744 let op = ArmOp::F64Neg {
9745 dd: VfpReg::D0,
9746 dm: VfpReg::D2,
9747 };
9748 let code = encoder.encode(&op).unwrap();
9749 assert_eq!(code.len(), 4);
9750 }
9751
9752 #[test]
9753 fn test_encode_f64_sqrt_arm32() {
9754 let encoder = ArmEncoder::new_arm32();
9755 let op = ArmOp::F64Sqrt {
9756 dd: VfpReg::D0,
9757 dm: VfpReg::D2,
9758 };
9759 let code = encoder.encode(&op).unwrap();
9760 assert_eq!(code.len(), 4);
9761 }
9762
9763 #[test]
9764 fn test_encode_f64_load_arm32() {
9765 let encoder = ArmEncoder::new_arm32();
9766 let op = ArmOp::F64Load {
9767 dd: VfpReg::D0,
9768 addr: MemAddr::imm(Reg::R0, 8),
9769 };
9770 let code = encoder.encode(&op).unwrap();
9771 assert_eq!(code.len(), 4);
9772 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9773 assert_eq!((instr >> 8) & 0xF, 0xB); assert_eq!(instr & 0xFF, 2); }
9776
9777 #[test]
9778 fn test_encode_f64_store_thumb2() {
9779 let encoder = ArmEncoder::new_thumb2();
9780 let op = ArmOp::F64Store {
9781 dd: VfpReg::D0,
9782 addr: MemAddr::imm(Reg::SP, 0),
9783 };
9784 let code = encoder.encode(&op).unwrap();
9785 assert_eq!(code.len(), 4);
9786 }
9787
9788 #[test]
9789 fn test_encode_f64_compare_arm32() {
9790 let encoder = ArmEncoder::new_arm32();
9791 let op = ArmOp::F64Eq {
9792 rd: Reg::R0,
9793 dn: VfpReg::D0,
9794 dm: VfpReg::D1,
9795 };
9796 let code = encoder.encode(&op).unwrap();
9797 assert_eq!(code.len(), 16); }
9799
9800 #[test]
9801 fn test_encode_f64_compare_thumb2() {
9802 let encoder = ArmEncoder::new_thumb2();
9803 let op = ArmOp::F64Lt {
9804 rd: Reg::R0,
9805 dn: VfpReg::D0,
9806 dm: VfpReg::D1,
9807 };
9808 let code = encoder.encode(&op).unwrap();
9809 assert_eq!(code.len(), 14);
9811 }
9812
9813 #[test]
9814 fn test_encode_f64_const_arm32() {
9815 let encoder = ArmEncoder::new_arm32();
9816 let op = ArmOp::F64Const {
9817 dd: VfpReg::D0,
9818 value: 3.125,
9819 };
9820 let code = encoder.encode(&op).unwrap();
9821 assert_eq!(code.len(), 20);
9823 }
9824
9825 #[test]
9826 fn test_encode_f64_const_thumb2() {
9827 let encoder = ArmEncoder::new_thumb2();
9828 let op = ArmOp::F64Const {
9829 dd: VfpReg::D0,
9830 value: 2.5,
9831 };
9832 let code = encoder.encode(&op).unwrap();
9833 assert_eq!(code.len(), 20);
9835 }
9836
9837 #[test]
9838 fn test_encode_f64_convert_i32s_arm32() {
9839 let encoder = ArmEncoder::new_arm32();
9840 let op = ArmOp::F64ConvertI32S {
9841 dd: VfpReg::D0,
9842 rm: Reg::R0,
9843 };
9844 let code = encoder.encode(&op).unwrap();
9845 assert_eq!(code.len(), 8);
9847 }
9848
9849 #[test]
9850 fn test_encode_f64_promote_f32_arm32() {
9851 let encoder = ArmEncoder::new_arm32();
9852 let op = ArmOp::F64PromoteF32 {
9853 dd: VfpReg::D0,
9854 sm: VfpReg::S0,
9855 };
9856 let code = encoder.encode(&op).unwrap();
9857 assert_eq!(code.len(), 4); }
9859
9860 #[test]
9861 fn test_encode_f64_promote_f32_thumb2() {
9862 let encoder = ArmEncoder::new_thumb2();
9863 let op = ArmOp::F64PromoteF32 {
9864 dd: VfpReg::D0,
9865 sm: VfpReg::S0,
9866 };
9867 let code = encoder.encode(&op).unwrap();
9868 assert_eq!(code.len(), 4);
9869 }
9870
9871 #[test]
9872 fn test_encode_i32_trunc_f64s_arm32() {
9873 let encoder = ArmEncoder::new_arm32();
9874 let op = ArmOp::I32TruncF64S {
9875 rd: Reg::R0,
9876 dm: VfpReg::D0,
9877 };
9878 let code = encoder.encode(&op).unwrap();
9879 assert_eq!(code.len(), 8);
9881 }
9882
9883 #[test]
9884 fn test_encode_f64_reinterpret_i64_arm32() {
9885 let encoder = ArmEncoder::new_arm32();
9886 let op = ArmOp::F64ReinterpretI64 {
9887 dd: VfpReg::D0,
9888 rmlo: Reg::R0,
9889 rmhi: Reg::R1,
9890 };
9891 let code = encoder.encode(&op).unwrap();
9892 assert_eq!(code.len(), 4); }
9894
9895 #[test]
9896 fn test_encode_i64_reinterpret_f64_thumb2() {
9897 let encoder = ArmEncoder::new_thumb2();
9898 let op = ArmOp::I64ReinterpretF64 {
9899 rdlo: Reg::R0,
9900 rdhi: Reg::R1,
9901 dm: VfpReg::D0,
9902 };
9903 let code = encoder.encode(&op).unwrap();
9904 assert_eq!(code.len(), 4);
9905 }
9906
9907 #[test]
9908 fn test_encode_f64_trunc_thumb2() {
9909 let encoder = ArmEncoder::new_thumb2();
9910 let op = ArmOp::F64Trunc {
9911 dd: VfpReg::D0,
9912 dm: VfpReg::D1,
9913 };
9914 let code = encoder.encode(&op).unwrap();
9915 assert_eq!(code.len(), 8);
9917 }
9918
9919 #[test]
9920 fn test_encode_f64_min_arm32() {
9921 let encoder = ArmEncoder::new_arm32();
9922 let op = ArmOp::F64Min {
9923 dd: VfpReg::D0,
9924 dn: VfpReg::D1,
9925 dm: VfpReg::D2,
9926 };
9927 let code = encoder.encode(&op).unwrap();
9928 assert_eq!(code.len(), 16);
9930 }
9931
9932 #[test]
9933 fn test_f64_cp11_encoding() {
9934 let encoder = ArmEncoder::new_arm32();
9936
9937 let code = encoder
9939 .encode(&ArmOp::F64Add {
9940 dd: VfpReg::D0,
9941 dn: VfpReg::D0,
9942 dm: VfpReg::D0,
9943 })
9944 .unwrap();
9945 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9946 assert_eq!((instr >> 8) & 0xF, 0xB, "F64 should use cp11");
9947
9948 let code = encoder
9950 .encode(&ArmOp::F32Add {
9951 sd: VfpReg::S0,
9952 sn: VfpReg::S0,
9953 sm: VfpReg::S0,
9954 })
9955 .unwrap();
9956 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9957 assert_eq!((instr >> 8) & 0xF, 0xA, "F32 should use cp10");
9958 }
9959
9960 #[test]
9961 fn test_dreg_encoding_higher_registers() {
9962 let encoder = ArmEncoder::new_arm32();
9963
9964 let op = ArmOp::F64Add {
9966 dd: VfpReg::D15,
9967 dn: VfpReg::D14,
9968 dm: VfpReg::D13,
9969 };
9970 let code = encoder.encode(&op).unwrap();
9971 assert_eq!(code.len(), 4);
9972
9973 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9975 assert_eq!((instr >> 8) & 0xF, 0xB); }
9977
9978 #[test]
9983 fn test_encode_label_emits_no_bytes() {
9984 let encoder = ArmEncoder::new_thumb2();
9985 let op = ArmOp::Label {
9986 name: ".Lblock_end_0".to_string(),
9987 };
9988 let code = encoder.encode(&op).unwrap();
9989 assert!(code.is_empty(), "Label should emit zero bytes");
9990
9991 let encoder32 = ArmEncoder::new_arm32();
9992 let code32 = encoder32.encode(&op).unwrap();
9993 assert!(
9994 code32.is_empty(),
9995 "Label should emit zero bytes in ARM32 too"
9996 );
9997 }
9998
9999 #[test]
10000 fn test_encode_bcc_eq_thumb2() {
10001 use synth_synthesis::Condition;
10002 let encoder = ArmEncoder::new_thumb2();
10003 let op = ArmOp::Bcc {
10004 cond: Condition::EQ,
10005 label: "target".to_string(),
10006 };
10007 let code = encoder.encode(&op).unwrap();
10008 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xD0]);
10012 }
10013
10014 #[test]
10015 fn test_encode_bcc_ne_thumb2() {
10016 use synth_synthesis::Condition;
10017 let encoder = ArmEncoder::new_thumb2();
10018 let op = ArmOp::Bcc {
10019 cond: Condition::NE,
10020 label: "target".to_string(),
10021 };
10022 let code = encoder.encode(&op).unwrap();
10023 assert_eq!(code.len(), 2);
10024
10025 assert_eq!(code, vec![0x00, 0xD1]);
10027 }
10028
10029 #[test]
10030 fn test_encode_bcc_arm32() {
10031 use synth_synthesis::Condition;
10032 let encoder = ArmEncoder::new_arm32();
10033 let op = ArmOp::Bcc {
10034 cond: Condition::EQ,
10035 label: "target".to_string(),
10036 };
10037 let code = encoder.encode(&op).unwrap();
10038 assert_eq!(code.len(), 4); let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10041 assert_eq!(instr & 0xF0000000, 0x00000000); assert_eq!(instr & 0x0F000000, 0x0A000000); }
10045
10046 #[test]
10047 fn test_encode_udf_thumb2() {
10048 let encoder = ArmEncoder::new_thumb2();
10049 let op = ArmOp::Udf { imm: 0 };
10050 let code = encoder.encode(&op).unwrap();
10051 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xDE]);
10055 }
10056
10057 #[test]
10063 fn test_610_i64_rot_expansion_ends_with_rd_movs_and_restore() {
10064 let encoder = ArmEncoder::new_thumb2();
10065 for op in [
10066 ArmOp::I64Rotl {
10067 rdlo: Reg::R4,
10068 rdhi: Reg::R5,
10069 rnlo: Reg::R0,
10070 rnhi: Reg::R1,
10071 shift: Reg::R2,
10072 },
10073 ArmOp::I64Rotr {
10074 rdlo: Reg::R4,
10075 rdhi: Reg::R5,
10076 rnlo: Reg::R0,
10077 rnhi: Reg::R1,
10078 shift: Reg::R2,
10079 },
10080 ] {
10081 let code = encoder.encode(&op).unwrap();
10082 assert_eq!(code.len(), 102, "register-independent size (estimator pin)");
10083 let tail: Vec<u16> = code[code.len() - 12..]
10086 .chunks(2)
10087 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10088 .collect();
10089 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
10090 }
10091 }
10092
10093 #[test]
10096 fn test_610_i64_div_rem_expansion_guard_and_rd() {
10097 let encoder = ArmEncoder::new_thumb2();
10098 let mk = |which: u8| {
10099 let (rdlo, rdhi, rnlo, rnhi, rmlo, rmhi) =
10100 (Reg::R4, Reg::R5, Reg::R0, Reg::R1, Reg::R2, Reg::R3);
10101 match which {
10102 0 => ArmOp::I64DivU {
10103 rdlo,
10104 rdhi,
10105 rnlo,
10106 rnhi,
10107 rmlo,
10108 rmhi,
10109 elide_zero_guard: false,
10110 },
10111 1 => ArmOp::I64RemU {
10112 rdlo,
10113 rdhi,
10114 rnlo,
10115 rnhi,
10116 rmlo,
10117 rmhi,
10118 elide_zero_guard: false,
10119 },
10120 2 => ArmOp::I64DivS {
10121 rdlo,
10122 rdhi,
10123 rnlo,
10124 rnhi,
10125 rmlo,
10126 rmhi,
10127 elide_zero_guard: false,
10128 elide_overflow_guard: false,
10129 },
10130 _ => ArmOp::I64RemS {
10131 rdlo,
10132 rdhi,
10133 rnlo,
10134 rnhi,
10135 rmlo,
10136 rmhi,
10137 elide_zero_guard: false,
10138 },
10139 }
10140 };
10141 for which in 0..4u8 {
10142 let code = encoder.encode(&mk(which)).unwrap();
10143 let guard: Vec<u16> = code[26..34]
10145 .chunks(2)
10146 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10147 .collect();
10148 assert_eq!(
10149 guard,
10150 vec![0xEA52, 0x0C03, 0xD100, 0xDE00],
10151 "ORRS R12,R2,R3; BNE +0; UDF #0"
10152 );
10153 let tail: Vec<u16> = code[code.len() - 12..]
10155 .chunks(2)
10156 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10157 .collect();
10158 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
10159 }
10160 }
10161
10162 #[test]
10165 fn test_610_i64_divu_rd_in_r0_r1_skips_restore() {
10166 let encoder = ArmEncoder::new_thumb2();
10167 let code = encoder
10168 .encode(&ArmOp::I64DivU {
10169 rdlo: Reg::R0,
10170 rdhi: Reg::R1,
10171 rnlo: Reg::R0,
10172 rnhi: Reg::R1,
10173 rmlo: Reg::R2,
10174 rmhi: Reg::R3,
10175 elide_zero_guard: false,
10176 })
10177 .unwrap();
10178 let tail: Vec<u16> = code[code.len() - 12..]
10179 .chunks(2)
10180 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10181 .collect();
10182 assert_eq!(tail, vec![0x4609, 0x4600, 0xB001, 0xB001, 0xBC04, 0xBC08]);
10185 }
10186
10187 #[test]
10191 fn test_610_i64_swapped_rd_pair_rejected() {
10192 let encoder = ArmEncoder::new_thumb2();
10193 let result = encoder.encode(&ArmOp::I64RemU {
10194 rdlo: Reg::R1,
10195 rdhi: Reg::R0,
10196 rnlo: Reg::R2,
10197 rnhi: Reg::R3,
10198 rmlo: Reg::R4,
10199 rmhi: Reg::R5,
10200 elide_zero_guard: false,
10201 });
10202 assert!(result.is_err(), "swapped rd pair must be rejected loudly");
10203 }
10204
10205 #[test]
10212 fn test_632_i64_popcnt_result_survives_scratch_restore() {
10213 let encoder = ArmEncoder::new_thumb2();
10214 for rd in [
10216 Reg::R0,
10217 Reg::R2,
10218 Reg::R3,
10219 Reg::R4,
10220 Reg::R5,
10221 Reg::R6,
10222 Reg::R8,
10223 ] {
10224 let code = encoder
10225 .encode(&ArmOp::I64Popcnt {
10226 rd,
10227 rnlo: Reg::R6,
10228 rnhi: Reg::R7,
10229 })
10230 .unwrap();
10231 assert_eq!(code.len(), 180, "register-independent size (estimator pin)");
10232 let hw: Vec<u16> = code
10233 .chunks(2)
10234 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10235 .collect();
10236 let pop = hw
10237 .iter()
10238 .position(|&h| h == 0xBC38)
10239 .expect("POP {R3,R4,R5} present");
10240 assert_eq!(
10243 &hw[pop - 2..pop],
10244 &[0xEB04, 0x0C05],
10245 "total must be carried in R12 across the restore"
10246 );
10247 let rd_bits = match rd {
10249 Reg::R8 => 8u16,
10250 Reg::R6 => 6,
10251 Reg::R5 => 5,
10252 Reg::R4 => 4,
10253 Reg::R3 => 3,
10254 Reg::R2 => 2,
10255 _ => 0,
10256 };
10257 let expect_mov = 0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7);
10258 assert_eq!(hw[pop + 1], expect_mov, "MOV rd, R12 after the restore");
10259 assert!(
10262 !hw[..pop].contains(&(0x1800 | (5 << 6) | (4 << 3) | rd_bits)),
10263 "no ADDS rd, R4, R5 before the restore pop"
10264 );
10265 }
10266 }
10267
10268 #[test]
10272 fn test_632_i64_popcnt_marshal_pair_at_r3_r4() {
10273 let encoder = ArmEncoder::new_thumb2();
10274 let code = encoder
10275 .encode(&ArmOp::I64Popcnt {
10276 rd: Reg::R0,
10277 rnlo: Reg::R3,
10278 rnhi: Reg::R4,
10279 })
10280 .unwrap();
10281 let hw: Vec<u16> = code
10282 .chunks(2)
10283 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10284 .collect();
10285 assert_eq!(hw[0], 0xB438);
10288 assert_eq!(hw[1], 0x4600 | (1 << 7) | (3 << 3) | 4, "MOV R12, rnlo");
10289 assert_eq!(hw[2], 0x4600 | (4 << 3) | 5, "MOV R5, rnhi");
10290 assert_eq!(hw[3], 0x4664, "MOV R4, R12");
10291 }
10292
10293 #[test]
10296 fn test_632_a32_i64_popcnt_result_survives_scratch_restore() {
10297 let encoder = ArmEncoder::new_arm32();
10298 for rd in [Reg::R0, Reg::R3, Reg::R4, Reg::R5, Reg::R8] {
10299 let code = encoder
10300 .encode(&ArmOp::I64Popcnt {
10301 rd,
10302 rnlo: Reg::R6,
10303 rnhi: Reg::R7,
10304 })
10305 .unwrap();
10306 let words: Vec<u32> = code
10307 .chunks(4)
10308 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
10309 .collect();
10310 let pop = words
10311 .iter()
10312 .position(|&w| w == 0xE8BD_0038)
10313 .expect("POP {R3,R4,R5} present");
10314 assert_eq!(words[pop - 1], 0xE084_C005, "ADD R12, R4, R5 before POP");
10315 let rd_bits = match rd {
10316 Reg::R8 => 8u32,
10317 Reg::R5 => 5,
10318 Reg::R4 => 4,
10319 Reg::R3 => 3,
10320 _ => 0,
10321 };
10322 assert_eq!(
10323 words[pop + 1],
10324 0xE1A0_0000 | (rd_bits << 12) | 12,
10325 "MOV rd, R12 after the restore"
10326 );
10327 }
10328 }
10329
10330 #[test]
10334 fn test_633_i64_divs_overflow_guard_emitted() {
10335 let encoder = ArmEncoder::new_thumb2();
10336 let code = encoder
10337 .encode(&ArmOp::I64DivS {
10338 rdlo: Reg::R4,
10339 rdhi: Reg::R5,
10340 rnlo: Reg::R0,
10341 rnhi: Reg::R1,
10342 rmlo: Reg::R2,
10343 rmhi: Reg::R3,
10344 elide_zero_guard: false,
10345 elide_overflow_guard: false,
10346 })
10347 .unwrap();
10348 let guard: Vec<u16> = code[34..56]
10350 .chunks(2)
10351 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10352 .collect();
10353 assert_eq!(
10354 guard,
10355 vec![
10356 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100, 0xDE00, ],
10365 "INT64_MIN/-1 overflow guard after the zero-divisor guard"
10366 );
10367 }
10368
10369 #[test]
10373 fn test_633_i64_rems_has_no_overflow_guard() {
10374 let encoder = ArmEncoder::new_thumb2();
10375 for (is_rem_s, op) in [
10376 (
10377 true,
10378 ArmOp::I64RemS {
10379 rdlo: Reg::R4,
10380 rdhi: Reg::R5,
10381 rnlo: Reg::R0,
10382 rnhi: Reg::R1,
10383 rmlo: Reg::R2,
10384 rmhi: Reg::R3,
10385 elide_zero_guard: false,
10386 },
10387 ),
10388 (
10389 false,
10390 ArmOp::I64DivS {
10391 rdlo: Reg::R4,
10392 rdhi: Reg::R5,
10393 rnlo: Reg::R0,
10394 rnhi: Reg::R1,
10395 rmlo: Reg::R2,
10396 rmhi: Reg::R3,
10397 elide_zero_guard: false,
10398 elide_overflow_guard: false,
10399 },
10400 ),
10401 ] {
10402 let code = encoder.encode(&op).unwrap();
10403 let udfs = code
10404 .chunks(2)
10405 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
10406 .count();
10407 let want = if is_rem_s { 1 } else { 2 };
10408 assert_eq!(
10409 udfs, want,
10410 "rem_s: zero-trap only; div_s: zero-trap + overflow trap"
10411 );
10412 }
10413 }
10414
10415 #[test]
10419 fn test_494_i64_zero_guard_elision_is_exact_splice() {
10420 let encoder = ArmEncoder::new_thumb2();
10421 let mk = |elide_zero_guard: bool| {
10422 encoder
10423 .encode(&ArmOp::I64DivU {
10424 rdlo: Reg::R4,
10425 rdhi: Reg::R5,
10426 rnlo: Reg::R0,
10427 rnhi: Reg::R1,
10428 rmlo: Reg::R2,
10429 rmhi: Reg::R3,
10430 elide_zero_guard,
10431 })
10432 .unwrap()
10433 };
10434 let full = mk(false);
10435 let elided = mk(true);
10436 assert_eq!(full.len(), elided.len() + 8, "zero guard is 8 bytes");
10437 assert_eq!(&full[..26], &elided[..26]);
10439 assert_eq!(
10440 &full[26..34],
10441 &[0x52, 0xEA, 0x03, 0x0C, 0x00, 0xD1, 0x00, 0xDE],
10442 "the spliced-out bytes are exactly ORRS.W; BNE; UDF #0"
10443 );
10444 assert_eq!(&full[34..], &elided[26..]);
10445 }
10446
10447 #[test]
10452 fn test_494_i64_divs_overflow_guard_retained_when_only_zero_elided() {
10453 let encoder = ArmEncoder::new_thumb2();
10454 let mk = |zero: bool, ovf: bool| {
10455 encoder
10456 .encode(&ArmOp::I64DivS {
10457 rdlo: Reg::R4,
10458 rdhi: Reg::R5,
10459 rnlo: Reg::R0,
10460 rnhi: Reg::R1,
10461 rmlo: Reg::R2,
10462 rmhi: Reg::R3,
10463 elide_zero_guard: zero,
10464 elide_overflow_guard: ovf,
10465 })
10466 .unwrap()
10467 };
10468 let udf_count = |code: &[u8]| {
10469 code.chunks(2)
10470 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
10471 .count()
10472 };
10473 let full = mk(false, false);
10474 let zero_only = mk(true, false);
10475 let both = mk(true, true);
10476 assert_eq!(udf_count(&full), 2, "baseline: zero trap + overflow trap");
10477 assert_eq!(
10478 udf_count(&zero_only),
10479 1,
10480 "divisor-nonzero elides the zero trap ONLY — the #633 overflow \
10481 guard must be retained"
10482 );
10483 let guard: Vec<u16> = zero_only[26..48]
10486 .chunks(2)
10487 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10488 .collect();
10489 assert_eq!(
10490 guard,
10491 vec![
10492 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100,
10493 0xDE00,
10494 ],
10495 "the surviving guard is the INT64_MIN/-1 overflow trap"
10496 );
10497 assert_eq!(full.len(), zero_only.len() + 8);
10498 assert_eq!(zero_only.len(), both.len() + 22);
10499 assert_eq!(udf_count(&both), 0, "both obligations discharged ⇒ no UDF");
10500 }
10501
10502 #[test]
10505 fn test_494_a32_i64_guard_elision() {
10506 let encoder = ArmEncoder::new_arm32();
10507 let mk = |zero: bool, ovf: bool| {
10508 encoder
10509 .encode(&ArmOp::I64DivS {
10510 rdlo: Reg::R4,
10511 rdhi: Reg::R5,
10512 rnlo: Reg::R0,
10513 rnhi: Reg::R1,
10514 rmlo: Reg::R2,
10515 rmhi: Reg::R3,
10516 elide_zero_guard: zero,
10517 elide_overflow_guard: ovf,
10518 })
10519 .unwrap()
10520 };
10521 let full = mk(false, false);
10522 let zero_only = mk(true, false);
10523 let both = mk(true, true);
10524 assert_eq!(full.len(), zero_only.len() + 12);
10526 assert_eq!(zero_only.len(), both.len() + 24);
10527 let udf_count = |code: &[u8]| {
10528 code.chunks(4)
10529 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
10530 .count()
10531 };
10532 assert_eq!(udf_count(&full), 2);
10533 assert_eq!(
10534 udf_count(&zero_only),
10535 1,
10536 "A32: overflow guard retained under zero-only elision"
10537 );
10538 assert_eq!(udf_count(&both), 0);
10539 }
10540
10541 #[test]
10544 fn test_633_a32_i64_divs_overflow_guard() {
10545 let encoder = ArmEncoder::new_arm32();
10546 let mk_divs = ArmOp::I64DivS {
10547 rdlo: Reg::R4,
10548 rdhi: Reg::R5,
10549 rnlo: Reg::R0,
10550 rnhi: Reg::R1,
10551 rmlo: Reg::R2,
10552 rmhi: Reg::R3,
10553 elide_zero_guard: false,
10554 elide_overflow_guard: false,
10555 };
10556 let code = encoder.encode(&mk_divs).unwrap();
10557 let words: Vec<u32> = code
10558 .chunks(4)
10559 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
10560 .collect();
10561 let guard = [
10562 0xE002_C003u32, 0xE37C_0001, 0x0350_0000, 0x0351_0102, 0x1A00_0000, 0xE7F0_00F0, ];
10569 assert!(
10570 words.windows(6).any(|w| w == guard),
10571 "A32 I64DivS carries the INT64_MIN/-1 overflow guard"
10572 );
10573 let rems = encoder
10574 .encode(&ArmOp::I64RemS {
10575 rdlo: Reg::R4,
10576 rdhi: Reg::R5,
10577 rnlo: Reg::R0,
10578 rnhi: Reg::R1,
10579 rmlo: Reg::R2,
10580 rmhi: Reg::R3,
10581 elide_zero_guard: false,
10582 })
10583 .unwrap();
10584 let rems_udfs = rems
10585 .chunks(4)
10586 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
10587 .count();
10588 assert_eq!(rems_udfs, 1, "A32 I64RemS keeps only the zero-divisor trap");
10589 }
10590
10591 #[test]
10592 fn test_encode_nop_thumb2() {
10593 let encoder = ArmEncoder::new_thumb2();
10594 let op = ArmOp::Nop;
10595 let code = encoder.encode(&op).unwrap();
10596 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]);
10600 }
10601
10602 #[test]
10607 fn test_encode_i64_add_thumb2() {
10608 let encoder = ArmEncoder::new_thumb2();
10609 let op = ArmOp::I64Add {
10610 rdlo: Reg::R0,
10611 rdhi: Reg::R1,
10612 rnlo: Reg::R0,
10613 rnhi: Reg::R1,
10614 rmlo: Reg::R2,
10615 rmhi: Reg::R3,
10616 };
10617 let code = encoder.encode(&op).unwrap();
10618 assert_eq!(code.len(), 6, "I64Add should be 6 bytes (ADDS + ADC.W)");
10620 }
10621
10622 #[test]
10623 fn test_encode_i64_sub_thumb2() {
10624 let encoder = ArmEncoder::new_thumb2();
10625 let op = ArmOp::I64Sub {
10626 rdlo: Reg::R0,
10627 rdhi: Reg::R1,
10628 rnlo: Reg::R0,
10629 rnhi: Reg::R1,
10630 rmlo: Reg::R2,
10631 rmhi: Reg::R3,
10632 };
10633 let code = encoder.encode(&op).unwrap();
10634 assert_eq!(code.len(), 6, "I64Sub should be 6 bytes (SUBS + SBC.W)");
10636 }
10637
10638 #[test]
10639 fn test_encode_i64_and_thumb2() {
10640 let encoder = ArmEncoder::new_thumb2();
10641 let op = ArmOp::I64And {
10642 rdlo: Reg::R0,
10643 rdhi: Reg::R1,
10644 rnlo: Reg::R0,
10645 rnhi: Reg::R1,
10646 rmlo: Reg::R2,
10647 rmhi: Reg::R3,
10648 };
10649 let code = encoder.encode(&op).unwrap();
10650 assert!(code.len() >= 4, "I64And should emit at least 4 bytes");
10652 }
10653
10654 #[test]
10655 fn test_encode_i64_or_thumb2() {
10656 let encoder = ArmEncoder::new_thumb2();
10657 let op = ArmOp::I64Or {
10658 rdlo: Reg::R0,
10659 rdhi: Reg::R1,
10660 rnlo: Reg::R0,
10661 rnhi: Reg::R1,
10662 rmlo: Reg::R2,
10663 rmhi: Reg::R3,
10664 };
10665 let code = encoder.encode(&op).unwrap();
10666 assert!(code.len() >= 4, "I64Or should emit at least 4 bytes");
10667 }
10668
10669 #[test]
10670 fn test_encode_i64_xor_thumb2() {
10671 let encoder = ArmEncoder::new_thumb2();
10672 let op = ArmOp::I64Xor {
10673 rdlo: Reg::R0,
10674 rdhi: Reg::R1,
10675 rnlo: Reg::R0,
10676 rnhi: Reg::R1,
10677 rmlo: Reg::R2,
10678 rmhi: Reg::R3,
10679 };
10680 let code = encoder.encode(&op).unwrap();
10681 assert!(code.len() >= 4, "I64Xor should emit at least 4 bytes");
10682 }
10683
10684 #[test]
10685 fn test_encode_i64_const_small_thumb2() {
10686 let encoder = ArmEncoder::new_thumb2();
10687 let op = ArmOp::I64Const {
10689 rdlo: Reg::R0,
10690 rdhi: Reg::R1,
10691 value: 42,
10692 };
10693 let code = encoder.encode(&op).unwrap();
10694 assert!(code.len() >= 8, "I64Const should emit at least 8 bytes");
10696 }
10697
10698 #[test]
10699 fn test_encode_i64_const_large_thumb2() {
10700 let encoder = ArmEncoder::new_thumb2();
10701 let op = ArmOp::I64Const {
10703 rdlo: Reg::R0,
10704 rdhi: Reg::R1,
10705 value: 0x1234_5678_9ABC_DEF0_u64 as i64,
10706 };
10707 let code = encoder.encode(&op).unwrap();
10708 assert_eq!(
10710 code.len(),
10711 16,
10712 "I64Const with large value should be 16 bytes"
10713 );
10714 }
10715
10716 #[test]
10717 fn test_encode_i64_extend_i32_s_thumb2() {
10718 let encoder = ArmEncoder::new_thumb2();
10719 let op = ArmOp::I64ExtendI32S {
10720 rdlo: Reg::R0,
10721 rdhi: Reg::R1,
10722 rn: Reg::R0,
10723 };
10724 let code = encoder.encode(&op).unwrap();
10725 assert_eq!(
10727 code.len(),
10728 4,
10729 "I64ExtendI32S (same reg) should be 4 bytes (ASR only)"
10730 );
10731 }
10732
10733 #[test]
10734 fn test_encode_i64_extend_i32_s_diff_reg_thumb2() {
10735 let encoder = ArmEncoder::new_thumb2();
10736 let op = ArmOp::I64ExtendI32S {
10737 rdlo: Reg::R0,
10738 rdhi: Reg::R1,
10739 rn: Reg::R2,
10740 };
10741 let code = encoder.encode(&op).unwrap();
10742 assert!(
10744 code.len() >= 6,
10745 "I64ExtendI32S (diff reg) should be at least 6 bytes"
10746 );
10747 }
10748
10749 #[test]
10750 fn test_encode_i64_extend_i32_u_thumb2() {
10751 let encoder = ArmEncoder::new_thumb2();
10752 let op = ArmOp::I64ExtendI32U {
10753 rdlo: Reg::R0,
10754 rdhi: Reg::R1,
10755 rn: Reg::R0,
10756 };
10757 let code = encoder.encode(&op).unwrap();
10758 assert_eq!(
10760 code.len(),
10761 2,
10762 "I64ExtendI32U (same reg) should be 2 bytes (MOV #0 only)"
10763 );
10764 }
10765
10766 #[test]
10767 fn test_encode_i32_wrap_i64_nop_thumb2() {
10768 let encoder = ArmEncoder::new_thumb2();
10769 let op = ArmOp::I32WrapI64 {
10771 rd: Reg::R0,
10772 rnlo: Reg::R0,
10773 };
10774 let code = encoder.encode(&op).unwrap();
10775 assert_eq!(code.len(), 2, "I32WrapI64 same reg should be NOP (2 bytes)");
10776 assert_eq!(code, vec![0x00, 0xBF]); }
10778
10779 #[test]
10780 fn test_encode_i32_wrap_i64_diff_reg_thumb2() {
10781 let encoder = ArmEncoder::new_thumb2();
10782 let op = ArmOp::I32WrapI64 {
10783 rd: Reg::R2,
10784 rnlo: Reg::R0,
10785 };
10786 let code = encoder.encode(&op).unwrap();
10787 assert!(
10789 code.len() >= 2,
10790 "I32WrapI64 diff reg should emit at least 2 bytes"
10791 );
10792 }
10793
10794 #[test]
10795 fn test_encode_i64_eqz_thumb2() {
10796 let encoder = ArmEncoder::new_thumb2();
10797 let op = ArmOp::I64Eqz {
10798 rd: Reg::R0,
10799 rnlo: Reg::R0,
10800 rnhi: Reg::R1,
10801 };
10802 let code = encoder.encode(&op).unwrap();
10803 assert!(
10805 code.len() >= 6,
10806 "I64Eqz should emit at least 6 bytes for ORR+ITE+MOV+MOV"
10807 );
10808 }
10809
10810 #[test]
10811 fn test_encode_i64_eq_thumb2() {
10812 let encoder = ArmEncoder::new_thumb2();
10813 let op = ArmOp::I64Eq {
10814 rd: Reg::R0,
10815 rnlo: Reg::R0,
10816 rnhi: Reg::R1,
10817 rmlo: Reg::R2,
10818 rmhi: Reg::R3,
10819 };
10820 let code = encoder.encode(&op).unwrap();
10821 assert!(code.len() >= 10, "I64Eq should emit at least 10 bytes");
10823 }
10824
10825 #[test]
10826 fn test_encode_i64_ldr_thumb2() {
10827 let encoder = ArmEncoder::new_thumb2();
10828 let op = ArmOp::I64Ldr {
10829 rdlo: Reg::R0,
10830 rdhi: Reg::R1,
10831 addr: MemAddr::imm(Reg::SP, 0),
10832 };
10833 let code = encoder.encode(&op).unwrap();
10834 assert!(code.len() >= 4, "I64Ldr should emit at least 4 bytes");
10836 }
10837
10838 #[test]
10839 fn test_372_i64_ldr_indexed_materializes_address() {
10840 let encoder = ArmEncoder::new_thumb2();
10845 let indexed = encoder
10846 .encode(&ArmOp::I64Ldr {
10847 rdlo: Reg::R0,
10848 rdhi: Reg::R1,
10849 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 0),
10850 })
10851 .unwrap();
10852 assert_eq!(
10854 &indexed[0..4],
10855 &[0x0b, 0xeb, 0x00, 0x0c],
10856 "indexed I64Ldr must start with ADD.W ip, base, index"
10857 );
10858 let frame = encoder
10859 .encode(&ArmOp::I64Ldr {
10860 rdlo: Reg::R0,
10861 rdhi: Reg::R1,
10862 addr: MemAddr::imm(Reg::SP, 8),
10863 })
10864 .unwrap();
10865 assert_ne!(
10867 &frame[0..2],
10868 &[0x0b, 0xeb],
10869 "frame (non-indexed) I64Ldr must NOT emit an ADD.W"
10870 );
10871 }
10872
10873 #[test]
10874 fn test_382_i64_ldst_large_offset_materializes_not_skips() {
10875 let encoder = ArmEncoder::new_thumb2();
10881 let ld = encoder
10884 .encode(&ArmOp::I64Ldr {
10885 rdlo: Reg::R0,
10886 rdhi: Reg::R1,
10887 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
10888 })
10889 .expect("large-offset i64.load must lower, not skip");
10890 assert_eq!(ld.len(), 20, "expected MOVW + 2×ADD + 2×LDR");
10892 assert_ne!(
10895 &ld[0..2],
10896 &[0x0b, 0xeb],
10897 "must materialize the large offset"
10898 );
10899 assert_eq!(
10901 &ld[4..20],
10902 &[
10903 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xdc, 0xf8, 0x00, 0x00, 0xdc, 0xf8, 0x04, 0x10, ],
10908 "large-offset i64.load must fold offset into ip and access [ip,#0]/[ip,#4]"
10909 );
10910
10911 let st = encoder
10913 .encode(&ArmOp::I64Str {
10914 rdlo: Reg::R2,
10915 rdhi: Reg::R3,
10916 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
10917 })
10918 .expect("large-offset i64.store must lower, not skip");
10919 assert_eq!(st.len(), 20);
10920 assert_eq!(
10921 &st[4..20],
10922 &[
10923 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xcc, 0xf8, 0x00, 0x20, 0xcc, 0xf8, 0x04, 0x30, ],
10928 "large-offset i64.store must fold offset into ip and access [ip,#0]/[ip,#4]"
10929 );
10930
10931 let small = encoder
10935 .encode(&ArmOp::I64Ldr {
10936 rdlo: Reg::R0,
10937 rdhi: Reg::R1,
10938 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 8),
10939 })
10940 .unwrap();
10941 assert_eq!(
10942 &small[0..4],
10943 &[0x0b, 0xeb, 0x00, 0x0c],
10944 "small-offset indexed i64 must keep the single ADD.W ip, fp, r0"
10945 );
10946 assert_eq!(small.len(), 12, "ADD.W + 2×LDR.W (offset folded in imm12)");
10947 }
10948
10949 #[test]
10950 fn test_encode_i64_str_thumb2() {
10951 let encoder = ArmEncoder::new_thumb2();
10952 let op = ArmOp::I64Str {
10953 rdlo: Reg::R0,
10954 rdhi: Reg::R1,
10955 addr: MemAddr::imm(Reg::SP, 0),
10956 };
10957 let code = encoder.encode(&op).unwrap();
10958 assert!(code.len() >= 4, "I64Str should emit at least 4 bytes");
10960 }
10961
10962 #[test]
10963 fn test_encode_i64_all_comparisons_thumb2() {
10964 let encoder = ArmEncoder::new_thumb2();
10965
10966 let ops = vec![
10967 ArmOp::I64Ne {
10968 rd: Reg::R0,
10969 rnlo: Reg::R0,
10970 rnhi: Reg::R1,
10971 rmlo: Reg::R2,
10972 rmhi: Reg::R3,
10973 },
10974 ArmOp::I64LtS {
10975 rd: Reg::R0,
10976 rnlo: Reg::R0,
10977 rnhi: Reg::R1,
10978 rmlo: Reg::R2,
10979 rmhi: Reg::R3,
10980 },
10981 ArmOp::I64LtU {
10982 rd: Reg::R0,
10983 rnlo: Reg::R0,
10984 rnhi: Reg::R1,
10985 rmlo: Reg::R2,
10986 rmhi: Reg::R3,
10987 },
10988 ArmOp::I64LeS {
10989 rd: Reg::R0,
10990 rnlo: Reg::R0,
10991 rnhi: Reg::R1,
10992 rmlo: Reg::R2,
10993 rmhi: Reg::R3,
10994 },
10995 ArmOp::I64LeU {
10996 rd: Reg::R0,
10997 rnlo: Reg::R0,
10998 rnhi: Reg::R1,
10999 rmlo: Reg::R2,
11000 rmhi: Reg::R3,
11001 },
11002 ArmOp::I64GtS {
11003 rd: Reg::R0,
11004 rnlo: Reg::R0,
11005 rnhi: Reg::R1,
11006 rmlo: Reg::R2,
11007 rmhi: Reg::R3,
11008 },
11009 ArmOp::I64GtU {
11010 rd: Reg::R0,
11011 rnlo: Reg::R0,
11012 rnhi: Reg::R1,
11013 rmlo: Reg::R2,
11014 rmhi: Reg::R3,
11015 },
11016 ArmOp::I64GeS {
11017 rd: Reg::R0,
11018 rnlo: Reg::R0,
11019 rnhi: Reg::R1,
11020 rmlo: Reg::R2,
11021 rmhi: Reg::R3,
11022 },
11023 ArmOp::I64GeU {
11024 rd: Reg::R0,
11025 rnlo: Reg::R0,
11026 rnhi: Reg::R1,
11027 rmlo: Reg::R2,
11028 rmhi: Reg::R3,
11029 },
11030 ];
11031
11032 for op in &ops {
11033 let code = encoder.encode(op).unwrap();
11034 assert!(
11035 code.len() >= 8,
11036 "i64 comparison {:?} should emit at least 8 bytes, got {}",
11037 op,
11038 code.len()
11039 );
11040 }
11041 }
11042
11043 #[test]
11044 fn test_encode_i64_const_zero_thumb2() {
11045 let encoder = ArmEncoder::new_thumb2();
11046 let op = ArmOp::I64Const {
11047 rdlo: Reg::R0,
11048 rdhi: Reg::R1,
11049 value: 0,
11050 };
11051 let code = encoder.encode(&op).unwrap();
11052 assert_eq!(code.len(), 8, "I64Const(0) should be 8 bytes");
11054 }
11055
11056 #[test]
11057 fn test_encode_i64_const_negative_one_thumb2() {
11058 let encoder = ArmEncoder::new_thumb2();
11059 let op = ArmOp::I64Const {
11060 rdlo: Reg::R0,
11061 rdhi: Reg::R1,
11062 value: -1, };
11064 let code = encoder.encode(&op).unwrap();
11065 assert_eq!(code.len(), 16, "I64Const(-1) should be 16 bytes");
11067 }
11068
11069 #[test]
11074 fn test_encode_ldrb_arm32() {
11075 let encoder = ArmEncoder::new_arm32();
11076 let op = ArmOp::Ldrb {
11077 rd: Reg::R0,
11078 addr: MemAddr::imm(Reg::R1, 4),
11079 };
11080 let code = encoder.encode(&op).unwrap();
11081 assert_eq!(code.len(), 4, "ARM32 LDRB should be 4 bytes");
11082 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11084 assert_eq!(encoded, 0xE5D10004, "Should encode LDRB R0, [R1, #4]");
11085 }
11086
11087 #[test]
11088 fn test_encode_strb_arm32() {
11089 let encoder = ArmEncoder::new_arm32();
11090 let op = ArmOp::Strb {
11091 rd: Reg::R0,
11092 addr: MemAddr::imm(Reg::R1, 0),
11093 };
11094 let code = encoder.encode(&op).unwrap();
11095 assert_eq!(code.len(), 4, "ARM32 STRB should be 4 bytes");
11096 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11098 assert_eq!(encoded, 0xE5C10000, "Should encode STRB R0, [R1, #0]");
11099 }
11100
11101 #[test]
11102 fn test_encode_ldrh_arm32() {
11103 let encoder = ArmEncoder::new_arm32();
11104 let op = ArmOp::Ldrh {
11105 rd: Reg::R0,
11106 addr: MemAddr::imm(Reg::R1, 2),
11107 };
11108 let code = encoder.encode(&op).unwrap();
11109 assert_eq!(code.len(), 4, "ARM32 LDRH should be 4 bytes");
11110 }
11111
11112 #[test]
11113 fn test_encode_strh_arm32() {
11114 let encoder = ArmEncoder::new_arm32();
11115 let op = ArmOp::Strh {
11116 rd: Reg::R0,
11117 addr: MemAddr::imm(Reg::R1, 0),
11118 };
11119 let code = encoder.encode(&op).unwrap();
11120 assert_eq!(code.len(), 4, "ARM32 STRH should be 4 bytes");
11121 }
11122
11123 #[test]
11124 fn test_encode_ldrsb_arm32() {
11125 let encoder = ArmEncoder::new_arm32();
11126 let op = ArmOp::Ldrsb {
11127 rd: Reg::R0,
11128 addr: MemAddr::imm(Reg::R1, 0),
11129 };
11130 let code = encoder.encode(&op).unwrap();
11131 assert_eq!(code.len(), 4, "ARM32 LDRSB should be 4 bytes");
11132 }
11133
11134 #[test]
11135 fn test_encode_ldrsh_arm32() {
11136 let encoder = ArmEncoder::new_arm32();
11137 let op = ArmOp::Ldrsh {
11138 rd: Reg::R0,
11139 addr: MemAddr::imm(Reg::R1, 0),
11140 };
11141 let code = encoder.encode(&op).unwrap();
11142 assert_eq!(code.len(), 4, "ARM32 LDRSH should be 4 bytes");
11143 }
11144
11145 #[test]
11146 fn test_encode_ldrb_thumb2_16bit() {
11147 let encoder = ArmEncoder::new_thumb2();
11148 let op = ArmOp::Ldrb {
11149 rd: Reg::R0,
11150 addr: MemAddr::imm(Reg::R1, 4),
11151 };
11152 let code = encoder.encode(&op).unwrap();
11153 assert_eq!(
11155 code.len(),
11156 2,
11157 "Thumb-2 LDRB with small offset should be 16-bit"
11158 );
11159 }
11160
11161 #[test]
11162 fn test_encode_ldrb_thumb2_32bit() {
11163 let encoder = ArmEncoder::new_thumb2();
11164 let op = ArmOp::Ldrb {
11165 rd: Reg::R0,
11166 addr: MemAddr::imm(Reg::R1, 100), };
11168 let code = encoder.encode(&op).unwrap();
11169 assert_eq!(
11170 code.len(),
11171 4,
11172 "Thumb-2 LDRB with large offset should be 32-bit"
11173 );
11174 }
11175
11176 #[test]
11177 fn test_encode_strb_thumb2_16bit() {
11178 let encoder = ArmEncoder::new_thumb2();
11179 let op = ArmOp::Strb {
11180 rd: Reg::R0,
11181 addr: MemAddr::imm(Reg::R1, 10),
11182 };
11183 let code = encoder.encode(&op).unwrap();
11184 assert_eq!(
11185 code.len(),
11186 2,
11187 "Thumb-2 STRB with small offset should be 16-bit"
11188 );
11189 }
11190
11191 #[test]
11192 fn test_encode_ldrh_thumb2_16bit() {
11193 let encoder = ArmEncoder::new_thumb2();
11194 let op = ArmOp::Ldrh {
11195 rd: Reg::R0,
11196 addr: MemAddr::imm(Reg::R1, 4), };
11198 let code = encoder.encode(&op).unwrap();
11199 assert_eq!(
11200 code.len(),
11201 2,
11202 "Thumb-2 LDRH with small aligned offset should be 16-bit"
11203 );
11204 }
11205
11206 #[test]
11207 fn test_encode_strh_thumb2_16bit() {
11208 let encoder = ArmEncoder::new_thumb2();
11209 let op = ArmOp::Strh {
11210 rd: Reg::R0,
11211 addr: MemAddr::imm(Reg::R1, 4),
11212 };
11213 let code = encoder.encode(&op).unwrap();
11214 assert_eq!(
11215 code.len(),
11216 2,
11217 "Thumb-2 STRH with small aligned offset should be 16-bit"
11218 );
11219 }
11220
11221 #[test]
11222 fn test_encode_ldrsb_thumb2() {
11223 let encoder = ArmEncoder::new_thumb2();
11224 let op = ArmOp::Ldrsb {
11225 rd: Reg::R0,
11226 addr: MemAddr::imm(Reg::R1, 0),
11227 };
11228 let code = encoder.encode(&op).unwrap();
11229 assert_eq!(code.len(), 4, "Thumb-2 LDRSB should be 32-bit");
11231 }
11232
11233 #[test]
11234 fn test_encode_ldrsh_thumb2() {
11235 let encoder = ArmEncoder::new_thumb2();
11236 let op = ArmOp::Ldrsh {
11237 rd: Reg::R0,
11238 addr: MemAddr::imm(Reg::R1, 0),
11239 };
11240 let code = encoder.encode(&op).unwrap();
11241 assert_eq!(code.len(), 4, "Thumb-2 LDRSH should be 32-bit");
11242 }
11243
11244 #[test]
11245 fn test_encode_memory_size_thumb2() {
11246 let encoder = ArmEncoder::new_thumb2();
11247 let op = ArmOp::MemorySize { rd: Reg::R0 };
11248 let code = encoder.encode(&op).unwrap();
11249 assert!(!code.is_empty(), "MemorySize should produce code");
11251 }
11252
11253 #[test]
11254 fn test_encode_memory_grow_thumb2() {
11255 let encoder = ArmEncoder::new_thumb2();
11256 let op = ArmOp::MemoryGrow {
11257 rd: Reg::R0,
11258 rn: Reg::R0,
11259 };
11260 let code = encoder.encode(&op).unwrap();
11261 assert_eq!(code.len(), 4, "MemoryGrow (MVN) should be 32-bit Thumb-2");
11262 }
11263
11264 #[test]
11265 fn test_encode_subword_reg_offset_thumb2() {
11266 let encoder = ArmEncoder::new_thumb2();
11267
11268 let op = ArmOp::Ldrb {
11270 rd: Reg::R0,
11271 addr: MemAddr::reg(Reg::R1, Reg::R2),
11272 };
11273 let code = encoder.encode(&op).unwrap();
11274 assert_eq!(
11275 code.len(),
11276 4,
11277 "Thumb-2 LDRB with reg offset should be 32-bit"
11278 );
11279
11280 let op = ArmOp::Strb {
11282 rd: Reg::R0,
11283 addr: MemAddr::reg(Reg::R1, Reg::R2),
11284 };
11285 let code = encoder.encode(&op).unwrap();
11286 assert_eq!(
11287 code.len(),
11288 4,
11289 "Thumb-2 STRB with reg offset should be 32-bit"
11290 );
11291
11292 let op = ArmOp::Ldrh {
11294 rd: Reg::R0,
11295 addr: MemAddr::reg(Reg::R1, Reg::R2),
11296 };
11297 let code = encoder.encode(&op).unwrap();
11298 assert_eq!(
11299 code.len(),
11300 4,
11301 "Thumb-2 LDRH with reg offset should be 32-bit"
11302 );
11303
11304 let op = ArmOp::Strh {
11306 rd: Reg::R0,
11307 addr: MemAddr::reg(Reg::R1, Reg::R2),
11308 };
11309 let code = encoder.encode(&op).unwrap();
11310 assert_eq!(
11311 code.len(),
11312 4,
11313 "Thumb-2 STRH with reg offset should be 32-bit"
11314 );
11315 }
11316
11317 #[test]
11318 fn test_encode_subword_reg_imm_offset_thumb2() {
11319 let encoder = ArmEncoder::new_thumb2();
11320
11321 let op = ArmOp::Ldrb {
11323 rd: Reg::R0,
11324 addr: MemAddr::reg_imm(Reg::R1, Reg::R2, 4),
11325 };
11326 let code = encoder.encode(&op).unwrap();
11327 assert_eq!(
11329 code.len(),
11330 8,
11331 "Thumb-2 LDRB with reg+imm offset should be 8 bytes"
11332 );
11333 }
11334
11335 #[test]
11340 fn test_encode_mve_addi32_thumb2() {
11341 let encoder = ArmEncoder::new_thumb2();
11342 let op = ArmOp::MveAddI {
11343 qd: QReg::Q0,
11344 qn: QReg::Q1,
11345 qm: QReg::Q2,
11346 size: MveSize::S32,
11347 };
11348 let code = encoder.encode(&op).unwrap();
11349 assert_eq!(
11350 code.len(),
11351 4,
11352 "MVE VADD.I32 should be 4 bytes (Thumb-2 32-bit)"
11353 );
11354 }
11355
11356 #[test]
11357 fn test_encode_mve_subi16_thumb2() {
11358 let encoder = ArmEncoder::new_thumb2();
11359 let op = ArmOp::MveSubI {
11360 qd: QReg::Q0,
11361 qn: QReg::Q1,
11362 qm: QReg::Q2,
11363 size: MveSize::S16,
11364 };
11365 let code = encoder.encode(&op).unwrap();
11366 assert_eq!(code.len(), 4, "MVE VSUB.I16 should be 4 bytes");
11367 }
11368
11369 #[test]
11370 fn test_encode_mve_muli8_thumb2() {
11371 let encoder = ArmEncoder::new_thumb2();
11372 let op = ArmOp::MveMulI {
11373 qd: QReg::Q0,
11374 qn: QReg::Q1,
11375 qm: QReg::Q2,
11376 size: MveSize::S8,
11377 };
11378 let code = encoder.encode(&op).unwrap();
11379 assert_eq!(code.len(), 4, "MVE VMUL.I8 should be 4 bytes");
11380 }
11381
11382 #[test]
11383 fn test_encode_mve_bitwise_thumb2() {
11384 let encoder = ArmEncoder::new_thumb2();
11385
11386 let ops = vec![
11387 ArmOp::MveAnd {
11388 qd: QReg::Q0,
11389 qn: QReg::Q1,
11390 qm: QReg::Q2,
11391 },
11392 ArmOp::MveOrr {
11393 qd: QReg::Q0,
11394 qn: QReg::Q1,
11395 qm: QReg::Q2,
11396 },
11397 ArmOp::MveEor {
11398 qd: QReg::Q0,
11399 qn: QReg::Q1,
11400 qm: QReg::Q2,
11401 },
11402 ArmOp::MveBic {
11403 qd: QReg::Q0,
11404 qn: QReg::Q1,
11405 qm: QReg::Q2,
11406 },
11407 ];
11408 for op in ops {
11409 let code = encoder.encode(&op).unwrap();
11410 assert_eq!(code.len(), 4, "MVE bitwise op should be 4 bytes");
11411 }
11412 }
11413
11414 #[test]
11415 fn test_encode_mve_mvn_thumb2() {
11416 let encoder = ArmEncoder::new_thumb2();
11417 let op = ArmOp::MveMvn {
11418 qd: QReg::Q0,
11419 qm: QReg::Q1,
11420 };
11421 let code = encoder.encode(&op).unwrap();
11422 assert_eq!(code.len(), 4, "MVE VMVN should be 4 bytes");
11423 }
11424
11425 #[test]
11426 fn test_encode_mve_load_store_thumb2() {
11427 let encoder = ArmEncoder::new_thumb2();
11428
11429 let load = ArmOp::MveLoad {
11430 qd: QReg::Q0,
11431 addr: MemAddr::imm(Reg::R0, 16),
11432 };
11433 let code = encoder.encode(&load).unwrap();
11434 assert_eq!(code.len(), 4, "MVE VLDRW.32 should be 4 bytes");
11435
11436 let store = ArmOp::MveStore {
11437 qd: QReg::Q1,
11438 addr: MemAddr::imm(Reg::R1, 0),
11439 };
11440 let code = encoder.encode(&store).unwrap();
11441 assert_eq!(code.len(), 4, "MVE VSTRW.32 should be 4 bytes");
11442 }
11443
11444 #[test]
11445 fn test_encode_mve_const_thumb2() {
11446 let encoder = ArmEncoder::new_thumb2();
11447 let op = ArmOp::MveConst {
11448 qd: QReg::Q0,
11449 bytes: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0],
11450 };
11451 let code = encoder.encode(&op).unwrap();
11452 assert!(
11455 code.len() >= 24,
11456 "MVE const should produce multiple instructions"
11457 );
11458 }
11459
11460 #[test]
11461 fn test_encode_mve_dup_thumb2() {
11462 let encoder = ArmEncoder::new_thumb2();
11463 let op = ArmOp::MveDup {
11464 qd: QReg::Q0,
11465 rn: Reg::R0,
11466 size: MveSize::S32,
11467 };
11468 let code = encoder.encode(&op).unwrap();
11469 assert_eq!(code.len(), 4, "MVE VDUP.32 should be 4 bytes");
11470 }
11471
11472 #[test]
11473 fn test_encode_mve_extract_lane_thumb2() {
11474 let encoder = ArmEncoder::new_thumb2();
11475 let op = ArmOp::MveExtractLane {
11476 rd: Reg::R0,
11477 qn: QReg::Q1,
11478 lane: 2,
11479 size: MveSize::S32,
11480 };
11481 let code = encoder.encode(&op).unwrap();
11482 assert_eq!(code.len(), 4, "MVE extract lane should be 4 bytes");
11483 }
11484
11485 #[test]
11486 fn test_encode_mve_insert_lane_thumb2() {
11487 let encoder = ArmEncoder::new_thumb2();
11488 let op = ArmOp::MveInsertLane {
11489 qd: QReg::Q0,
11490 rn: Reg::R1,
11491 lane: 3,
11492 size: MveSize::S32,
11493 };
11494 let code = encoder.encode(&op).unwrap();
11495 assert_eq!(code.len(), 4, "MVE insert lane should be 4 bytes");
11496 }
11497
11498 #[test]
11499 fn test_encode_mve_addf32_thumb2() {
11500 let encoder = ArmEncoder::new_thumb2();
11501 let op = ArmOp::MveAddF32 {
11502 qd: QReg::Q0,
11503 qn: QReg::Q1,
11504 qm: QReg::Q2,
11505 };
11506 let code = encoder.encode(&op).unwrap();
11507 assert_eq!(code.len(), 4, "MVE VADD.F32 should be 4 bytes");
11508 }
11509
11510 #[test]
11511 fn test_encode_mve_divf32_thumb2() {
11512 let encoder = ArmEncoder::new_thumb2();
11513 let op = ArmOp::MveDivF32 {
11514 qd: QReg::Q0,
11515 qn: QReg::Q1,
11516 qm: QReg::Q2,
11517 };
11518 let code = encoder.encode(&op).unwrap();
11519 assert_eq!(
11521 code.len(),
11522 16,
11523 "MVE VDIV.F32 (lane-wise) should be 16 bytes"
11524 );
11525 }
11526
11527 #[test]
11528 fn test_encode_mve_sqrtf32_thumb2() {
11529 let encoder = ArmEncoder::new_thumb2();
11530 let op = ArmOp::MveSqrtF32 {
11531 qd: QReg::Q0,
11532 qm: QReg::Q1,
11533 };
11534 let code = encoder.encode(&op).unwrap();
11535 assert_eq!(
11537 code.len(),
11538 16,
11539 "MVE VSQRT.F32 (lane-wise) should be 16 bytes"
11540 );
11541 }
11542
11543 #[test]
11544 fn test_encode_mve_negf32_thumb2() {
11545 let encoder = ArmEncoder::new_thumb2();
11546 let op = ArmOp::MveNegF32 {
11547 qd: QReg::Q0,
11548 qm: QReg::Q1,
11549 };
11550 let code = encoder.encode(&op).unwrap();
11551 assert_eq!(code.len(), 4, "MVE VNEG.F32 should be 4 bytes");
11552 }
11553
11554 #[test]
11555 fn test_encode_mve_absf32_thumb2() {
11556 let encoder = ArmEncoder::new_thumb2();
11557 let op = ArmOp::MveAbsF32 {
11558 qd: QReg::Q0,
11559 qm: QReg::Q1,
11560 };
11561 let code = encoder.encode(&op).unwrap();
11562 assert_eq!(code.len(), 4, "MVE VABS.F32 should be 4 bytes");
11563 }
11564
11565 #[test]
11580 fn and_immediate_encodes_correctly_in_byte_range_documents_fold_bound() {
11581 let encoder = ArmEncoder::new_thumb2();
11582 let op = ArmOp::And {
11583 rd: Reg::R2,
11584 rn: Reg::R0,
11585 op2: Operand2::Imm(0x7e),
11586 };
11587 let code = encoder.encode(&op).unwrap();
11588 assert_eq!(
11589 code,
11590 vec![0x00, 0xf0, 0x7e, 0x02],
11591 "and r2, r0, #0x7e must encode to the canonical AND.W T1 (imm8=0x7e)"
11592 );
11593 }
11594
11595 #[test]
11602 fn try_thumb_expand_imm_encodes_modified_immediates() {
11603 assert_eq!(try_thumb_expand_imm(0x7e), Some(0x07e)); assert_eq!(try_thumb_expand_imm(0xff), Some(0x0ff));
11605 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);
11613 assert_eq!(try_thumb_expand_imm(0x12345), None);
11614 }
11615
11616 #[test]
11621 fn cmp_adds_subs_immediate_error_on_non_modified_imm() {
11622 let encoder = ArmEncoder::new_thumb2();
11623 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 0xff).is_ok());
11625 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 1000).is_ok());
11626 assert!(
11628 encoder.encode_thumb32_cmp_imm(&Reg::R0, 0x101).is_err(),
11629 "cmp #0x101 must error, not compare the wrong constant"
11630 );
11631 assert!(
11632 encoder
11633 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x101)
11634 .is_err()
11635 );
11636 assert!(
11637 encoder
11638 .encode_thumb32_subs(&Reg::R0, &Reg::R0, 0x101)
11639 .is_err()
11640 );
11641 assert!(
11643 encoder
11644 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x80)
11645 .is_ok()
11646 );
11647 }
11648
11649 #[test]
11652 fn mla_thumb2_encodes_correctly() {
11653 let encoder = ArmEncoder::new_thumb2();
11654 let code = encoder
11655 .encode(&ArmOp::Mla {
11656 rd: Reg::R2,
11657 rn: Reg::R3,
11658 rm: Reg::R4,
11659 ra: Reg::R8,
11660 })
11661 .unwrap();
11662 assert_eq!(code, vec![0x03, 0xfb, 0x04, 0x82]);
11664 }
11665
11666 #[test]
11671 fn ldst_imm12_offset_errors_when_out_of_range() {
11672 let encoder = ArmEncoder::new_thumb2();
11673 assert!(
11675 encoder
11676 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0xFFF)
11677 .is_ok()
11678 );
11679 assert!(
11681 encoder
11682 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0x1000)
11683 .is_err(),
11684 "ldr offset 4096 must error, not wrap to 0"
11685 );
11686 assert!(
11687 encoder
11688 .encode_thumb32_str(&Reg::R0, &Reg::R1, 0x1000)
11689 .is_err()
11690 );
11691 assert!(
11692 encoder
11693 .encode_thumb32_ldrb_imm(&Reg::R0, &Reg::R1, 5000)
11694 .is_err()
11695 );
11696 assert!(
11697 encoder
11698 .encode_thumb32_strh_imm(&Reg::R0, &Reg::R1, 5000)
11699 .is_err()
11700 );
11701 }
11702
11703 #[test]
11710 fn add_sub_large_immediate_use_addw_subw_not_misencoded() {
11711 let encoder = ArmEncoder::new_thumb2();
11712 assert_eq!(
11714 encoder
11715 .encode(&ArmOp::Add {
11716 rd: Reg::SP,
11717 rn: Reg::SP,
11718 op2: Operand2::Imm(256),
11719 })
11720 .unwrap(),
11721 vec![0x0d, 0xf2, 0x00, 0x1d],
11722 "add sp,sp,#256 must be ADDW (plain imm12), not a mis-encoded ADD.W"
11723 );
11724 assert_eq!(
11726 encoder
11727 .encode(&ArmOp::Sub {
11728 rd: Reg::SP,
11729 rn: Reg::SP,
11730 op2: Operand2::Imm(256),
11731 })
11732 .unwrap(),
11733 vec![0xad, 0xf2, 0x00, 0x1d],
11734 );
11735 assert!(
11737 encoder
11738 .encode(&ArmOp::Add {
11739 rd: Reg::SP,
11740 rn: Reg::SP,
11741 op2: Operand2::Imm(5000),
11742 })
11743 .is_err(),
11744 "add #5000 must error (no single ADDW), not mis-encode"
11745 );
11746 }
11747
11748 #[test]
11753 fn and_cmn_immediate_thumb_expand_else_error() {
11754 let encoder = ArmEncoder::new_thumb2();
11755 assert_eq!(
11757 encoder
11758 .encode(&ArmOp::And {
11759 rd: Reg::R2,
11760 rn: Reg::R0,
11761 op2: Operand2::Imm(0x7e),
11762 })
11763 .unwrap(),
11764 vec![0x00, 0xf0, 0x7e, 0x02],
11765 );
11766 assert!(
11768 encoder
11769 .encode(&ArmOp::And {
11770 rd: Reg::R2,
11771 rn: Reg::R0,
11772 op2: Operand2::Imm(0xff00ff00u32 as i32),
11773 })
11774 .is_ok()
11775 );
11776 assert!(
11778 encoder
11779 .encode(&ArmOp::And {
11780 rd: Reg::R2,
11781 rn: Reg::R0,
11782 op2: Operand2::Imm(0x101),
11783 })
11784 .is_err()
11785 );
11786 assert!(
11787 encoder
11788 .encode(&ArmOp::Cmn {
11789 rn: Reg::R0,
11790 op2: Operand2::Imm(0x101),
11791 })
11792 .is_err(),
11793 "CMN #0x101 must error, not emit a NOP"
11794 );
11795 }
11796
11797 #[test]
11801 fn orr_eor_immediate_encode_in_byte_range_else_error() {
11802 let encoder = ArmEncoder::new_thumb2();
11803 assert_eq!(
11805 encoder
11806 .encode(&ArmOp::Orr {
11807 rd: Reg::R2,
11808 rn: Reg::R0,
11809 op2: Operand2::Imm(0x7e),
11810 })
11811 .unwrap(),
11812 vec![0x40, 0xf0, 0x7e, 0x02],
11813 );
11814 assert_eq!(
11816 encoder
11817 .encode(&ArmOp::Eor {
11818 rd: Reg::R2,
11819 rn: Reg::R0,
11820 op2: Operand2::Imm(0x7e),
11821 })
11822 .unwrap(),
11823 vec![0x80, 0xf0, 0x7e, 0x02],
11824 );
11825 assert!(
11827 encoder
11828 .encode(&ArmOp::Orr {
11829 rd: Reg::R2,
11830 rn: Reg::R0,
11831 op2: Operand2::Imm(0x140),
11832 })
11833 .is_err(),
11834 "ORR #0x140 must error, not emit a NOP"
11835 );
11836 }
11837
11838 #[test]
11839 fn test_encode_mve_different_qregs() {
11840 let encoder = ArmEncoder::new_thumb2();
11841
11842 let op1 = ArmOp::MveAddI {
11844 qd: QReg::Q0,
11845 qn: QReg::Q0,
11846 qm: QReg::Q0,
11847 size: MveSize::S32,
11848 };
11849 let op2 = ArmOp::MveAddI {
11850 qd: QReg::Q3,
11851 qn: QReg::Q5,
11852 qm: QReg::Q7,
11853 size: MveSize::S32,
11854 };
11855 let code1 = encoder.encode(&op1).unwrap();
11856 let code2 = encoder.encode(&op2).unwrap();
11857 assert_ne!(
11858 code1, code2,
11859 "Different Q-registers should produce different encodings"
11860 );
11861 }
11862
11863 #[test]
11864 fn test_encode_mve_arm32_loud_err() {
11865 let encoder = ArmEncoder::new_arm32();
11869 let op = ArmOp::MveAddI {
11870 qd: QReg::Q0,
11871 qn: QReg::Q1,
11872 qm: QReg::Q2,
11873 size: MveSize::S32,
11874 };
11875 let err = encoder
11876 .encode(&op)
11877 .expect_err("ARM32 MVE must be a loud Err, not a silent NOP (#615)");
11878 assert!(
11879 err.to_string().contains("Thumb-2 only"),
11880 "unexpected error message: {err}"
11881 );
11882 }
11883}