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) -> Vec<u8> {
138 let idx = reg_to_bits(table_index_reg);
139 let mut bytes = Vec::with_capacity(12);
140 let mov: u32 = 0xE1A0C000 | (2 << 7) | idx;
143 bytes.extend_from_slice(&mov.to_le_bytes());
144 let ldr: u32 = 0xE79BC00C;
146 bytes.extend_from_slice(&ldr.to_le_bytes());
147 let blx: u32 = 0xE12FFF3C;
149 bytes.extend_from_slice(&blx.to_le_bytes());
150 bytes
151 }
152
153 fn encode_arm_expanded(&self, op: &ArmOp) -> Result<Option<Vec<u8>>> {
162 use synth_synthesis::Condition;
163
164 fn cond_bits(cond: &Condition) -> u32 {
166 match cond {
167 Condition::EQ => 0x0,
168 Condition::NE => 0x1,
169 Condition::HS => 0x2, Condition::LO => 0x3, Condition::HI => 0x8, Condition::LS => 0x9, Condition::GE => 0xA,
174 Condition::LT => 0xB,
175 Condition::GT => 0xC,
176 Condition::LE => 0xD,
177 }
178 }
179 fn w(b: &mut Vec<u8>, word: u32) {
180 b.extend_from_slice(&word.to_le_bytes());
181 }
182 fn mov_cond_imm(b: &mut Vec<u8>, cond: u32, rd: u32, imm: u32) {
184 w(b, (cond << 28) | 0x03A0_0000 | (rd << 12) | imm);
185 }
186 fn set_cond(b: &mut Vec<u8>, cond: &Condition, rd: u32) {
188 mov_cond_imm(b, cond_bits(cond), rd, 1);
189 mov_cond_imm(b, cond_bits(&cond.invert()), rd, 0);
190 }
191 fn cmp_reg(b: &mut Vec<u8>, rn: u32, rm: u32) {
193 w(b, 0xE150_0000 | (rn << 16) | rm);
194 }
195 fn sbcs(b: &mut Vec<u8>, rd: u32, rn: u32, rm: u32) {
197 w(b, 0xE0D0_0000 | (rn << 16) | (rd << 12) | rm);
198 }
199 fn movw(b: &mut Vec<u8>, rd: u32, v: u32) {
201 w(
202 b,
203 0xE300_0000 | (((v >> 12) & 0xF) << 16) | (rd << 12) | (v & 0xFFF),
204 );
205 }
206 fn movt(b: &mut Vec<u8>, rd: u32, v: u32) {
208 w(
209 b,
210 0xE340_0000 | (((v >> 12) & 0xF) << 16) | (rd << 12) | (v & 0xFFF),
211 );
212 }
213 fn shift_reg(b: &mut Vec<u8>, ty: u32, rd: u32, rn: u32, rs: u32) {
218 w(b, 0xE1A0_0010 | (rd << 12) | (rs << 8) | (ty << 5) | rn);
219 }
220 const LSL: u32 = 0;
221 const LSR: u32 = 1;
222 const ASR: u32 = 2;
223 fn shift_imm(b: &mut Vec<u8>, ty: u32, rd: u32, rn: u32, imm: u32) {
225 w(
226 b,
227 0xE1A0_0000 | (rd << 12) | ((imm & 0x1F) << 7) | (ty << 5) | rn,
228 );
229 }
230 fn dp_reg(b: &mut Vec<u8>, base: u32, rd: u32, rn: u32, rm: u32) {
233 w(b, base | (rn << 16) | (rd << 12) | rm);
234 }
235 fn orr_lsr31(b: &mut Vec<u8>, rd: u32, rm: u32) {
238 w(
239 b,
240 0xE180_0000 | (rd << 16) | (rd << 12) | (31 << 7) | (1 << 5) | rm,
241 );
242 }
243 fn negate64(b: &mut Vec<u8>, lo: u32, hi: u32) {
245 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)); }
250 fn skip_negate_if_positive(b: &mut Vec<u8>, x: u32) {
253 w(b, 0xE110_0000 | (x << 16) | x); w(b, 0x5A00_0003); }
256 fn div_loop(b: &mut Vec<u8>, counter: u32) {
260 w(b, 0xE3A0_0040 | (counter << 12)); let loop_start = b.len();
262 shift_imm(b, LSL, 5, 5, 1);
264 orr_lsr31(b, 5, 4);
265 shift_imm(b, LSL, 4, 4, 1);
266 shift_imm(b, LSL, 7, 7, 1);
268 orr_lsr31(b, 7, 6);
269 shift_imm(b, LSL, 6, 6, 1);
270 orr_lsr31(b, 6, 1);
271 shift_imm(b, LSL, 1, 1, 1);
273 orr_lsr31(b, 1, 0);
274 shift_imm(b, LSL, 0, 0, 1);
275 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);
287 w(b, 0x1A00_0000 | (((diff / 4) as u32) & 0x00FF_FFFF)); }
289 fn popcnt_word(b: &mut Vec<u8>, x: u32, c: u32) {
293 shift_imm(b, LSR, 12, x, 1);
295 movw(b, c, 0x5555);
296 movt(b, c, 0x5555);
297 dp_reg(b, 0xE000_0000, 12, 12, c); dp_reg(b, 0xE040_0000, x, x, 12); movw(b, c, 0x3333);
301 movt(b, c, 0x3333);
302 dp_reg(b, 0xE000_0000, 12, x, c); shift_imm(b, LSR, x, x, 2);
304 dp_reg(b, 0xE000_0000, x, x, c); dp_reg(b, 0xE080_0000, x, x, 12); shift_imm(b, LSR, 12, x, 4);
308 dp_reg(b, 0xE080_0000, x, x, 12); movw(b, c, 0x0F0F);
310 movt(b, c, 0x0F0F);
311 dp_reg(b, 0xE000_0000, x, x, c); movw(b, c, 0x0101);
314 movt(b, c, 0x0101);
315 w(b, 0xE000_0090 | (x << 16) | (c << 8) | x); shift_imm(b, LSR, x, x, 24);
317 }
318
319 let mut b: Vec<u8> = Vec::new();
320 match op {
321 ArmOp::SetCond { rd, cond } => {
324 set_cond(&mut b, cond, reg_to_bits(rd));
325 }
326
327 ArmOp::SelectMove { rd, rm, cond } => {
329 w(
330 &mut b,
331 (cond_bits(cond) << 28)
332 | 0x01A0_0000
333 | (reg_to_bits(rd) << 12)
334 | reg_to_bits(rm),
335 );
336 }
337
338 ArmOp::I64SetCond {
343 rd,
344 rn_lo,
345 rn_hi,
346 rm_lo,
347 rm_hi,
348 cond,
349 } => {
350 let rd_b = reg_to_bits(rd);
351 let (n_lo, n_hi, m_lo, m_hi) = (
352 reg_to_bits(rn_lo),
353 reg_to_bits(rn_hi),
354 reg_to_bits(rm_lo),
355 reg_to_bits(rm_hi),
356 );
357 match cond {
358 Condition::EQ | Condition::NE => {
359 cmp_reg(&mut b, n_lo, m_lo);
360 w(&mut b, 0x0150_0000 | (n_hi << 16) | m_hi);
362 set_cond(&mut b, cond, rd_b);
363 }
364 Condition::LT => {
367 cmp_reg(&mut b, n_lo, m_lo);
368 sbcs(&mut b, rd_b, n_hi, m_hi);
369 set_cond(&mut b, &Condition::LT, rd_b);
370 }
371 Condition::GE => {
372 cmp_reg(&mut b, n_lo, m_lo);
373 sbcs(&mut b, rd_b, n_hi, m_hi);
374 set_cond(&mut b, &Condition::GE, rd_b);
375 }
376 Condition::GT => {
377 cmp_reg(&mut b, m_lo, n_lo);
378 sbcs(&mut b, rd_b, m_hi, n_hi);
379 set_cond(&mut b, &Condition::LT, rd_b);
380 }
381 Condition::LE => {
382 cmp_reg(&mut b, m_lo, n_lo);
383 sbcs(&mut b, rd_b, m_hi, n_hi);
384 set_cond(&mut b, &Condition::GE, rd_b);
385 }
386 Condition::LO => {
387 cmp_reg(&mut b, n_lo, m_lo);
388 sbcs(&mut b, rd_b, n_hi, m_hi);
389 set_cond(&mut b, &Condition::LO, rd_b);
390 }
391 Condition::HS => {
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::HS, rd_b);
395 }
396 Condition::HI => {
397 cmp_reg(&mut b, m_lo, n_lo);
398 sbcs(&mut b, rd_b, m_hi, n_hi);
399 set_cond(&mut b, &Condition::LO, rd_b);
400 }
401 Condition::LS => {
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::HS, rd_b);
405 }
406 }
407 }
408
409 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
411 let rd_b = reg_to_bits(rd);
412 w(
413 &mut b,
414 0xE190_0000 | (reg_to_bits(rn_lo) << 16) | (rd_b << 12) | reg_to_bits(rn_hi),
415 );
416 set_cond(&mut b, &Condition::EQ, rd_b);
417 }
418
419 ArmOp::I64Eqz { rd, rnlo, rnhi } => {
422 return self
423 .encode_arm(&ArmOp::I64SetCondZ {
424 rd: *rd,
425 rn_lo: *rnlo,
426 rn_hi: *rnhi,
427 })
428 .map(Some);
429 }
430 ArmOp::I64Eq {
431 rd,
432 rnlo,
433 rnhi,
434 rmlo,
435 rmhi,
436 }
437 | ArmOp::I64Ne {
438 rd,
439 rnlo,
440 rnhi,
441 rmlo,
442 rmhi,
443 }
444 | ArmOp::I64LtS {
445 rd,
446 rnlo,
447 rnhi,
448 rmlo,
449 rmhi,
450 }
451 | ArmOp::I64LtU {
452 rd,
453 rnlo,
454 rnhi,
455 rmlo,
456 rmhi,
457 }
458 | ArmOp::I64LeS {
459 rd,
460 rnlo,
461 rnhi,
462 rmlo,
463 rmhi,
464 }
465 | ArmOp::I64LeU {
466 rd,
467 rnlo,
468 rnhi,
469 rmlo,
470 rmhi,
471 }
472 | ArmOp::I64GtS {
473 rd,
474 rnlo,
475 rnhi,
476 rmlo,
477 rmhi,
478 }
479 | ArmOp::I64GtU {
480 rd,
481 rnlo,
482 rnhi,
483 rmlo,
484 rmhi,
485 }
486 | ArmOp::I64GeS {
487 rd,
488 rnlo,
489 rnhi,
490 rmlo,
491 rmhi,
492 }
493 | ArmOp::I64GeU {
494 rd,
495 rnlo,
496 rnhi,
497 rmlo,
498 rmhi,
499 } => {
500 let cond = match op {
501 ArmOp::I64Eq { .. } => Condition::EQ,
502 ArmOp::I64Ne { .. } => Condition::NE,
503 ArmOp::I64LtS { .. } => Condition::LT,
504 ArmOp::I64LtU { .. } => Condition::LO,
505 ArmOp::I64LeS { .. } => Condition::LE,
506 ArmOp::I64LeU { .. } => Condition::LS,
507 ArmOp::I64GtS { .. } => Condition::GT,
508 ArmOp::I64GtU { .. } => Condition::HI,
509 ArmOp::I64GeS { .. } => Condition::GE,
510 _ => Condition::HS,
511 };
512 return self
513 .encode_arm(&ArmOp::I64SetCond {
514 rd: *rd,
515 rn_lo: *rnlo,
516 rn_hi: *rnhi,
517 rm_lo: *rmlo,
518 rm_hi: *rmhi,
519 cond,
520 })
521 .map(Some);
522 }
523
524 ArmOp::I64Mul {
527 rd_lo,
528 rd_hi,
529 rn_lo,
530 rn_hi,
531 rm_lo,
532 rm_hi,
533 } => {
534 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
535 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
536 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
537 w(&mut b, 0xE000_0090 | (12 << 16) | (mh << 8) | nl);
539 w(
541 &mut b,
542 0xE020_0090 | (12 << 16) | (12 << 12) | (ml << 8) | nh,
543 );
544 w(
546 &mut b,
547 0xE080_0090 | (dh << 16) | (dl << 12) | (ml << 8) | nl,
548 );
549 w(&mut b, 0xE080_0000 | (dh << 16) | (dh << 12) | 12);
551 }
552
553 ArmOp::I64Shl {
558 rd_lo,
559 rd_hi,
560 rn_lo,
561 rn_hi,
562 rm_lo,
563 rm_hi,
564 } => {
565 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
566 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
567 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
568 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)); }
580 ArmOp::I64ShrU {
581 rd_lo,
582 rd_hi,
583 rn_lo,
584 rn_hi,
585 rm_lo,
586 rm_hi,
587 } => {
588 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
589 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
590 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
591 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)); }
603 ArmOp::I64ShrS {
604 rd_lo,
605 rd_hi,
606 rn_lo,
607 rn_hi,
608 rm_lo,
609 rm_hi,
610 } => {
611 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
612 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
613 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
614 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); }
626
627 ArmOp::I64Rotl {
631 rdlo,
632 rdhi,
633 rnlo,
634 rnhi,
635 shift,
636 } => {
637 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, shift]);
638 for word in [
639 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, ] {
661 w(&mut b, word);
662 }
663 emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
664 }
665 ArmOp::I64Rotr {
666 rdlo,
667 rdhi,
668 rnlo,
669 rnhi,
670 shift,
671 } => {
672 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, shift]);
673 for word in [
674 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, ] {
696 w(&mut b, word);
697 }
698 emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
699 }
700
701 ArmOp::I64Clz { rd, rnlo, rnhi } => {
705 let (rd_b, lo, hi) = (reg_to_bits(rd), reg_to_bits(rnlo), reg_to_bits(rnhi));
706 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)); }
712
713 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
717 let (rd_b, lo, hi) = (reg_to_bits(rd), reg_to_bits(rnlo), reg_to_bits(rnhi));
718 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)); }
725
726 ArmOp::I64Const { rdlo, rdhi, value } => {
729 let lo32 = *value as u32;
730 let hi32 = (*value >> 32) as u32;
731 movw(&mut b, reg_to_bits(rdlo), lo32 & 0xFFFF);
732 if lo32 > 0xFFFF {
733 movt(&mut b, reg_to_bits(rdlo), lo32 >> 16);
734 }
735 movw(&mut b, reg_to_bits(rdhi), hi32 & 0xFFFF);
736 if hi32 > 0xFFFF {
737 movt(&mut b, reg_to_bits(rdhi), hi32 >> 16);
738 }
739 }
740
741 ArmOp::I64Ldr { rdlo, rdhi, addr } | ArmOp::I64Str { rdlo, rdhi, addr } => {
745 let base = if let Some(rm) = addr.offset_reg {
746 w(
748 &mut b,
749 0xE080_0000
750 | (reg_to_bits(&addr.base) << 16)
751 | (12 << 12)
752 | reg_to_bits(&rm),
753 );
754 12
755 } else {
756 reg_to_bits(&addr.base)
757 };
758 if addr.offset < 0 || addr.offset > 0xFFB {
759 return Err(synth_core::Error::synthesis(format!(
760 "i64 load/store offset {} out of the A32 imm12 range (0..=4091) — materialize the offset into a register",
761 addr.offset
762 )));
763 }
764 let off = addr.offset as u32;
765 let opc: u32 = if matches!(op, ArmOp::I64Ldr { .. }) {
766 0xE590_0000 } else {
768 0xE580_0000 };
770 w(&mut b, opc | (base << 16) | (reg_to_bits(rdlo) << 12) | off);
771 w(
772 &mut b,
773 opc | (base << 16) | (reg_to_bits(rdhi) << 12) | (off + 4),
774 );
775 }
776
777 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
779 if rdlo != rn {
780 w(
781 &mut b,
782 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rn),
783 );
784 }
785 w(
786 &mut b,
787 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
788 );
789 }
790
791 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
793 if rdlo != rn {
794 w(
795 &mut b,
796 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rn),
797 );
798 }
799 w(&mut b, 0xE3A0_0000 | (reg_to_bits(rdhi) << 12));
800 }
801
802 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
804 w(
805 &mut b,
806 0xE6AF_0070 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
807 );
808 w(
809 &mut b,
810 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
811 );
812 }
813 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
814 w(
815 &mut b,
816 0xE6BF_0070 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
817 );
818 w(
819 &mut b,
820 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
821 );
822 }
823 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
824 if rdlo != rnlo {
825 w(
826 &mut b,
827 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
828 );
829 }
830 w(
831 &mut b,
832 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rnlo),
833 );
834 }
835
836 ArmOp::I32WrapI64 { rd, rnlo } => {
839 w(
840 &mut b,
841 0xE1A0_0000 | (reg_to_bits(rd) << 12) | reg_to_bits(rnlo),
842 );
843 }
844
845 ArmOp::I64Add {
849 rdlo,
850 rdhi,
851 rnlo,
852 rnhi,
853 rmlo,
854 rmhi,
855 } => {
856 dp_reg(
857 &mut b,
858 0xE090_0000, reg_to_bits(rdlo),
860 reg_to_bits(rnlo),
861 reg_to_bits(rmlo),
862 );
863 dp_reg(
864 &mut b,
865 0xE0A0_0000, reg_to_bits(rdhi),
867 reg_to_bits(rnhi),
868 reg_to_bits(rmhi),
869 );
870 }
871 ArmOp::I64Sub {
872 rdlo,
873 rdhi,
874 rnlo,
875 rnhi,
876 rmlo,
877 rmhi,
878 } => {
879 dp_reg(
880 &mut b,
881 0xE050_0000, reg_to_bits(rdlo),
883 reg_to_bits(rnlo),
884 reg_to_bits(rmlo),
885 );
886 dp_reg(
887 &mut b,
888 0xE0C0_0000, reg_to_bits(rdhi),
890 reg_to_bits(rnhi),
891 reg_to_bits(rmhi),
892 );
893 }
894
895 ArmOp::I64And {
897 rdlo,
898 rdhi,
899 rnlo,
900 rnhi,
901 rmlo,
902 rmhi,
903 }
904 | ArmOp::I64Or {
905 rdlo,
906 rdhi,
907 rnlo,
908 rnhi,
909 rmlo,
910 rmhi,
911 }
912 | ArmOp::I64Xor {
913 rdlo,
914 rdhi,
915 rnlo,
916 rnhi,
917 rmlo,
918 rmhi,
919 } => {
920 let base = match op {
921 ArmOp::I64And { .. } => 0xE000_0000, ArmOp::I64Or { .. } => 0xE180_0000, _ => 0xE020_0000, };
925 dp_reg(
926 &mut b,
927 base,
928 reg_to_bits(rdlo),
929 reg_to_bits(rnlo),
930 reg_to_bits(rmlo),
931 );
932 dp_reg(
933 &mut b,
934 base,
935 reg_to_bits(rdhi),
936 reg_to_bits(rnhi),
937 reg_to_bits(rmhi),
938 );
939 }
940
941 ArmOp::I64DivU {
945 rdlo,
946 rdhi,
947 rnlo,
948 rnhi,
949 rmlo,
950 rmhi,
951 } => {
952 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
953 emit_a32_i64_divisor_zero_trap(&mut b);
954 w(&mut b, 0xE92D_00F0); for r in 4..8u32 {
956 w(&mut b, 0xE3A0_0000 | (r << 12)); }
958 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)?;
963 }
964
965 ArmOp::I64DivS {
968 rdlo,
969 rdhi,
970 rnlo,
971 rnhi,
972 rmlo,
973 rmhi,
974 } => {
975 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
976 emit_a32_i64_divisor_zero_trap(&mut b);
977 emit_a32_i64_divs_overflow_trap(&mut b);
980 w(&mut b, 0xE92D_0FF0); w(&mut b, 0xE021_9003); skip_negate_if_positive(&mut b, 1);
983 negate64(&mut b, 0, 1);
984 skip_negate_if_positive(&mut b, 3);
985 negate64(&mut b, 2, 3);
986 for r in 4..8u32 {
987 w(&mut b, 0xE3A0_0000 | (r << 12)); }
989 div_loop(&mut b, 8); w(&mut b, 0xE1A0_0004); w(&mut b, 0xE1A0_1005); skip_negate_if_positive(&mut b, 9);
993 negate64(&mut b, 0, 1);
994 w(&mut b, 0xE8BD_0FF0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
996 }
997
998 ArmOp::I64RemU {
1000 rdlo,
1001 rdhi,
1002 rnlo,
1003 rnhi,
1004 rmlo,
1005 rmhi,
1006 } => {
1007 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1008 emit_a32_i64_divisor_zero_trap(&mut b);
1009 w(&mut b, 0xE92D_01F0); for r in 4..8u32 {
1011 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1013 div_loop(&mut b, 8);
1014 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)?;
1018 }
1019
1020 ArmOp::I64RemS {
1022 rdlo,
1023 rdhi,
1024 rnlo,
1025 rnhi,
1026 rmlo,
1027 rmhi,
1028 } => {
1029 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1030 emit_a32_i64_divisor_zero_trap(&mut b);
1031 w(&mut b, 0xE92D_0FF0); w(&mut b, 0xE1A0_9001); skip_negate_if_positive(&mut b, 1);
1034 negate64(&mut b, 0, 1);
1035 skip_negate_if_positive(&mut b, 3);
1036 negate64(&mut b, 2, 3);
1037 for r in 4..8u32 {
1038 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1040 div_loop(&mut b, 8);
1041 w(&mut b, 0xE1A0_0006); w(&mut b, 0xE1A0_1007); skip_negate_if_positive(&mut b, 9);
1044 negate64(&mut b, 0, 1);
1045 w(&mut b, 0xE8BD_0FF0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
1047 }
1048
1049 ArmOp::Popcnt { rd, rm } => {
1053 let rd_b = reg_to_bits(rd);
1054 if rd != rm {
1055 w(&mut b, 0xE1A0_0000 | (rd_b << 12) | reg_to_bits(rm)); }
1057 movw(&mut b, 12, 0x5555);
1059 movt(&mut b, 12, 0x5555);
1060 shift_imm(&mut b, LSR, 11, rd_b, 1);
1061 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);
1065 movt(&mut b, 12, 0x3333);
1066 dp_reg(&mut b, 0xE000_0000, 11, rd_b, 12); shift_imm(&mut b, LSR, rd_b, rd_b, 2);
1068 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);
1072 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11); movw(&mut b, 12, 0x0F0F);
1074 movt(&mut b, 12, 0x0F0F);
1075 dp_reg(&mut b, 0xE000_0000, rd_b, rd_b, 12); shift_imm(&mut b, LSR, 11, rd_b, 8);
1078 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11);
1079 shift_imm(&mut b, LSR, 11, rd_b, 16);
1080 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11);
1081 w(&mut b, 0xE200_003F | (rd_b << 16) | (rd_b << 12)); }
1083
1084 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
1088 let hi = reg_to_bits(rnhi);
1089 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);
1097 popcnt_word(&mut b, 5, 3);
1098 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)); }
1107
1108 _ => return Ok(None),
1109 }
1110 Ok(Some(b))
1111 }
1112
1113 fn encode_arm(&self, op: &ArmOp) -> Result<Vec<u8>> {
1114 if let Some(bytes) = self.encode_arm_expanded(op)? {
1121 return Ok(bytes);
1122 }
1123 if let Some(bytes) = self.encode_arm_reg_offset_mem(op)? {
1130 return Ok(bytes);
1131 }
1132 if let ArmOp::CallIndirect {
1138 table_index_reg, ..
1139 } = op
1140 {
1141 return Ok(Self::encode_arm_call_indirect(table_index_reg));
1142 }
1143 let instr: u32 = match op {
1144 ArmOp::Add { rd, rn, op2 } => {
1146 let rd_bits = reg_to_bits(rd);
1147 let rn_bits = reg_to_bits(rn);
1148 let (op2_bits, i_flag) = encode_operand2(op2)?;
1149
1150 0xE0800000 | (i_flag << 25)
1153 | (rn_bits << 16)
1154 | (rd_bits << 12)
1155 | op2_bits
1156 }
1157
1158 ArmOp::Sub { rd, rn, op2 } => {
1159 let rd_bits = reg_to_bits(rd);
1160 let rn_bits = reg_to_bits(rn);
1161 let (op2_bits, i_flag) = encode_operand2(op2)?;
1162
1163 0xE0400000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1165 }
1166
1167 ArmOp::Adds { rd, rn, op2 } => {
1169 let rd_bits = reg_to_bits(rd);
1170 let rn_bits = reg_to_bits(rn);
1171 let (op2_bits, i_flag) = encode_operand2(op2)?;
1172
1173 0xE0900000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1175 }
1176
1177 ArmOp::Adc { rd, rn, op2 } => {
1178 let rd_bits = reg_to_bits(rd);
1179 let rn_bits = reg_to_bits(rn);
1180 let (op2_bits, i_flag) = encode_operand2(op2)?;
1181
1182 0xE0A00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1184 }
1185
1186 ArmOp::Subs { rd, rn, op2 } => {
1187 let rd_bits = reg_to_bits(rd);
1188 let rn_bits = reg_to_bits(rn);
1189 let (op2_bits, i_flag) = encode_operand2(op2)?;
1190
1191 0xE0500000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1193 }
1194
1195 ArmOp::Sbc { rd, rn, op2 } => {
1196 let rd_bits = reg_to_bits(rd);
1197 let rn_bits = reg_to_bits(rn);
1198 let (op2_bits, i_flag) = encode_operand2(op2)?;
1199
1200 0xE0C00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1202 }
1203
1204 ArmOp::Mul { rd, rn, rm } => {
1205 let rd_bits = reg_to_bits(rd);
1206 let rn_bits = reg_to_bits(rn);
1207 let rm_bits = reg_to_bits(rm);
1208
1209 0xE0000090 | (rd_bits << 16) | (rn_bits << 8) | rm_bits
1211 }
1212
1213 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
1214 let rdlo_bits = reg_to_bits(rdlo);
1215 let rdhi_bits = reg_to_bits(rdhi);
1216 let rn_bits = reg_to_bits(rn);
1217 let rm_bits = reg_to_bits(rm);
1218
1219 0xE0800090 | (rdhi_bits << 16) | (rdlo_bits << 12) | (rm_bits << 8) | rn_bits
1221 }
1222
1223 ArmOp::Sdiv { rd, rn, rm } => {
1224 let rd_bits = reg_to_bits(rd);
1225 let rn_bits = reg_to_bits(rn);
1226 let rm_bits = reg_to_bits(rm);
1227
1228 0xE710F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
1231 }
1232
1233 ArmOp::Udiv { rd, rn, rm } => {
1234 let rd_bits = reg_to_bits(rd);
1235 let rn_bits = reg_to_bits(rn);
1236 let rm_bits = reg_to_bits(rm);
1237
1238 0xE730F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
1241 }
1242
1243 ArmOp::Mls { rd, rn, rm, ra } => {
1244 let rd_bits = reg_to_bits(rd);
1245 let rn_bits = reg_to_bits(rn);
1246 let rm_bits = reg_to_bits(rm);
1247 let ra_bits = reg_to_bits(ra);
1248
1249 0xE0600090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
1252 }
1253
1254 ArmOp::Mla { rd, rn, rm, ra } => {
1255 let rd_bits = reg_to_bits(rd);
1256 let rn_bits = reg_to_bits(rn);
1257 let rm_bits = reg_to_bits(rm);
1258 let ra_bits = reg_to_bits(ra);
1259
1260 0xE0200090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
1263 }
1264
1265 ArmOp::And { rd, rn, op2 } => {
1266 let rd_bits = reg_to_bits(rd);
1267 let rn_bits = reg_to_bits(rn);
1268 let (op2_bits, i_flag) = encode_operand2(op2)?;
1269
1270 0xE0000000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1272 }
1273
1274 ArmOp::Orr { rd, rn, op2 } => {
1275 let rd_bits = reg_to_bits(rd);
1276 let rn_bits = reg_to_bits(rn);
1277 let (op2_bits, i_flag) = encode_operand2(op2)?;
1278
1279 0xE1800000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1281 }
1282
1283 ArmOp::Eor { rd, rn, op2 } => {
1284 let rd_bits = reg_to_bits(rd);
1285 let rn_bits = reg_to_bits(rn);
1286 let (op2_bits, i_flag) = encode_operand2(op2)?;
1287
1288 0xE0200000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1290 }
1291
1292 ArmOp::Lsl { rd, rn, shift } => {
1294 let rd_bits = reg_to_bits(rd);
1295 let rn_bits = reg_to_bits(rn);
1296 let shift_bits = *shift & 0x1F;
1297
1298 0xE1A00000 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1300 }
1301
1302 ArmOp::Lsr { rd, rn, shift } => {
1303 let rd_bits = reg_to_bits(rd);
1304 let rn_bits = reg_to_bits(rn);
1305 let shift_bits = *shift & 0x1F;
1306
1307 0xE1A00020 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1309 }
1310
1311 ArmOp::Asr { rd, rn, shift } => {
1312 let rd_bits = reg_to_bits(rd);
1313 let rn_bits = reg_to_bits(rn);
1314 let shift_bits = *shift & 0x1F;
1315
1316 0xE1A00040 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1318 }
1319
1320 ArmOp::Ror { rd, rn, shift } => {
1321 let rd_bits = reg_to_bits(rd);
1322 let rn_bits = reg_to_bits(rn);
1323 let shift_bits = *shift & 0x1F;
1324
1325 0xE1A00060 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1327 }
1328
1329 ArmOp::LslReg { rd, rn, rm } => {
1332 let rd_bits = reg_to_bits(rd);
1333 let rn_bits = reg_to_bits(rn);
1334 let rm_bits = reg_to_bits(rm);
1335 0xE1A00010 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1336 }
1337 ArmOp::LsrReg { rd, rn, rm } => {
1338 let rd_bits = reg_to_bits(rd);
1339 let rn_bits = reg_to_bits(rn);
1340 let rm_bits = reg_to_bits(rm);
1341 0xE1A00030 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1342 }
1343 ArmOp::AsrReg { rd, rn, rm } => {
1344 let rd_bits = reg_to_bits(rd);
1345 let rn_bits = reg_to_bits(rn);
1346 let rm_bits = reg_to_bits(rm);
1347 0xE1A00050 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1348 }
1349 ArmOp::RorReg { rd, rn, rm } => {
1350 let rd_bits = reg_to_bits(rd);
1351 let rn_bits = reg_to_bits(rn);
1352 let rm_bits = reg_to_bits(rm);
1353 0xE1A00070 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1354 }
1355
1356 ArmOp::Rsb { rd, rn, imm } => {
1358 let rd_bits = reg_to_bits(rd);
1359 let rn_bits = reg_to_bits(rn);
1360 0xE2600000 | (rn_bits << 16) | (rd_bits << 12) | (*imm & 0xFF)
1363 }
1364
1365 ArmOp::Clz { rd, rm } => {
1367 let rd_bits = reg_to_bits(rd);
1368 let rm_bits = reg_to_bits(rm);
1369
1370 0xE16F0F10 | (rd_bits << 12) | rm_bits
1373 }
1374
1375 ArmOp::Rbit { rd, rm } => {
1376 let rd_bits = reg_to_bits(rd);
1377 let rm_bits = reg_to_bits(rm);
1378
1379 0xE6FF0F30 | (rd_bits << 12) | rm_bits
1382 }
1383
1384 ArmOp::Sxtb { rd, rm } => {
1385 let rd_bits = reg_to_bits(rd);
1386 let rm_bits = reg_to_bits(rm);
1387
1388 0xE6AF0070 | (rd_bits << 12) | rm_bits
1391 }
1392
1393 ArmOp::Sxth { rd, rm } => {
1394 let rd_bits = reg_to_bits(rd);
1395 let rm_bits = reg_to_bits(rm);
1396
1397 0xE6BF0070 | (rd_bits << 12) | rm_bits
1400 }
1401
1402 ArmOp::Uxtb { rd, rm } => {
1403 let rd_bits = reg_to_bits(rd);
1404 let rm_bits = reg_to_bits(rm);
1405 0xE6EF0070 | (rd_bits << 12) | rm_bits
1407 }
1408
1409 ArmOp::Uxth { rd, rm } => {
1410 let rd_bits = reg_to_bits(rd);
1411 let rm_bits = reg_to_bits(rm);
1412 0xE6FF0070 | (rd_bits << 12) | rm_bits
1414 }
1415
1416 ArmOp::Mov { rd, op2 } => {
1418 let rd_bits = reg_to_bits(rd);
1419 let (op2_bits, i_flag) = encode_operand2(op2)?;
1420
1421 0xE1A00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
1423 }
1424
1425 ArmOp::Mvn { rd, op2 } => {
1426 let rd_bits = reg_to_bits(rd);
1427 let (op2_bits, i_flag) = encode_operand2(op2)?;
1428
1429 0xE1E00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
1431 }
1432
1433 ArmOp::Movw { rd, imm16 } => {
1436 let rd_bits = reg_to_bits(rd);
1437 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
1438 let imm12 = (*imm16 as u32) & 0xFFF;
1439 0xE3000000 | (imm4 << 16) | (rd_bits << 12) | imm12
1440 }
1441
1442 ArmOp::Movt { rd, imm16 } => {
1445 let rd_bits = reg_to_bits(rd);
1446 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
1447 let imm12 = (*imm16 as u32) & 0xFFF;
1448 0xE3400000 | (imm4 << 16) | (rd_bits << 12) | imm12
1449 }
1450
1451 ArmOp::MovwSym { rd, addend, .. } => {
1454 let rd_bits = reg_to_bits(rd);
1455 let v = (*addend as u32) & 0xffff;
1456 0xE3000000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
1457 }
1458 ArmOp::MovtSym { rd, addend, .. } => {
1459 let rd_bits = reg_to_bits(rd);
1460 let v = ((*addend as u32) >> 16) & 0xffff;
1461 0xE3400000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
1462 }
1463
1464 ArmOp::LdrSym { .. } => {
1468 return Err(synth_core::Error::synthesis(
1469 "LdrSym (literal-pool address load) is Thumb-2-only",
1470 ));
1471 }
1472
1473 ArmOp::Cmp { rn, op2 } => {
1475 let rn_bits = reg_to_bits(rn);
1476 let (op2_bits, i_flag) = encode_operand2(op2)?;
1477
1478 0xE1500000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
1480 }
1481
1482 ArmOp::Cmn { rn, op2 } => {
1484 let rn_bits = reg_to_bits(rn);
1485 let (op2_bits, i_flag) = encode_operand2(op2)?;
1486
1487 0xE1700000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
1489 }
1490
1491 ArmOp::Ldr { rd, addr } => {
1493 let rd_bits = reg_to_bits(rd);
1494 let (base_bits, offset_bits) = encode_mem_addr(addr);
1495
1496 0xE5900000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1499 }
1500
1501 ArmOp::Str { rd, addr } => {
1502 let rd_bits = reg_to_bits(rd);
1503 let (base_bits, offset_bits) = encode_mem_addr(addr);
1504
1505 0xE5800000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1507 }
1508
1509 ArmOp::Ldrb { rd, addr } => {
1511 let rd_bits = reg_to_bits(rd);
1512 let (base_bits, offset_bits) = encode_mem_addr(addr);
1513 0xE5D00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1515 }
1516
1517 ArmOp::Ldrsb { rd, addr } => {
1518 let rd_bits = reg_to_bits(rd);
1519 let (base_bits, offset_bits) = encode_mem_addr(addr);
1520 let offset_val = offset_bits & 0xFF;
1523 let imm4h = (offset_val >> 4) & 0xF;
1524 let imm4l = offset_val & 0xF;
1525 0xE1D000D0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1526 }
1527
1528 ArmOp::Ldrh { rd, addr } => {
1529 let rd_bits = reg_to_bits(rd);
1530 let (base_bits, offset_bits) = encode_mem_addr(addr);
1531 let offset_val = offset_bits & 0xFF;
1533 let imm4h = (offset_val >> 4) & 0xF;
1534 let imm4l = offset_val & 0xF;
1535 0xE1D000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1536 }
1537
1538 ArmOp::Ldrsh { rd, addr } => {
1539 let rd_bits = reg_to_bits(rd);
1540 let (base_bits, offset_bits) = encode_mem_addr(addr);
1541 let offset_val = offset_bits & 0xFF;
1543 let imm4h = (offset_val >> 4) & 0xF;
1544 let imm4l = offset_val & 0xF;
1545 0xE1D000F0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1546 }
1547
1548 ArmOp::Strb { rd, addr } => {
1550 let rd_bits = reg_to_bits(rd);
1551 let (base_bits, offset_bits) = encode_mem_addr(addr);
1552 0xE5C00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1554 }
1555
1556 ArmOp::Strh { rd, addr } => {
1557 let rd_bits = reg_to_bits(rd);
1558 let (base_bits, offset_bits) = encode_mem_addr(addr);
1559 let offset_val = offset_bits & 0xFF;
1561 let imm4h = (offset_val >> 4) & 0xF;
1562 let imm4l = offset_val & 0xF;
1563 0xE1C000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1564 }
1565
1566 ArmOp::MemorySize { rd } => {
1568 let rd_bits = reg_to_bits(rd);
1569 0xE1A00820 | (rd_bits << 12) | 0x0A }
1574
1575 ArmOp::MemoryGrow { rd, .. } => {
1576 let rd_bits = reg_to_bits(rd);
1577 0xE3E00000 | (rd_bits << 12) }
1580
1581 ArmOp::Label { .. } => {
1583 return Ok(Vec::new());
1584 }
1585
1586 ArmOp::B { label: _ } => {
1588 0xEA000000
1591 }
1592
1593 ArmOp::Bcc { cond, label: _ } => {
1595 use synth_synthesis::Condition;
1596 let cond_bits: u32 = match cond {
1597 Condition::EQ => 0x0,
1598 Condition::NE => 0x1,
1599 Condition::HS => 0x2,
1600 Condition::LO => 0x3,
1601 Condition::HI => 0x8,
1602 Condition::LS => 0x9,
1603 Condition::GE => 0xA,
1604 Condition::LT => 0xB,
1605 Condition::GT => 0xC,
1606 Condition::LE => 0xD,
1607 };
1608 (cond_bits << 28) | 0x0A000000
1610 }
1611
1612 ArmOp::Bhs { label: _ } => {
1614 0x2A000000 }
1617
1618 ArmOp::Blo { label: _ } => {
1620 0x3A000000 }
1623
1624 ArmOp::BOffset { offset } => {
1628 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
1638 0xEA000000 | offset_bits
1639 }
1640
1641 ArmOp::BCondOffset { cond, offset } => {
1643 use synth_synthesis::Condition;
1644 let cond_bits: u32 = match cond {
1645 Condition::EQ => 0x0,
1646 Condition::NE => 0x1,
1647 Condition::HS => 0x2,
1648 Condition::LO => 0x3,
1649 Condition::HI => 0x8,
1650 Condition::LS => 0x9,
1651 Condition::GE => 0xA,
1652 Condition::LT => 0xB,
1653 Condition::GT => 0xC,
1654 Condition::LE => 0xD,
1655 };
1656 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
1660 (cond_bits << 28) | 0x0A000000 | offset_bits
1661 }
1662
1663 ArmOp::Bl { label: _ } => {
1664 0xEB000000
1666 }
1667
1668 ArmOp::Bx { rm } => {
1669 let rm_bits = reg_to_bits(rm);
1670
1671 0xE12FFF10 | rm_bits
1673 }
1674
1675 ArmOp::Blx { rm } => {
1676 let rm_bits = reg_to_bits(rm);
1677
1678 0xE12FFF30 | rm_bits
1680 }
1681
1682 ArmOp::Push { regs } => {
1683 let mut reg_list: u32 = 0;
1685 for r in regs {
1686 reg_list |= 1 << reg_to_bits(r);
1687 }
1688 0xE92D0000 | reg_list
1689 }
1690
1691 ArmOp::Pop { regs } => {
1692 let mut reg_list: u32 = 0;
1694 for r in regs {
1695 reg_list |= 1 << reg_to_bits(r);
1696 }
1697 0xE8BD0000 | reg_list
1698 }
1699
1700 ArmOp::Nop => {
1701 0xE1A00000
1703 }
1704
1705 ArmOp::Udf { imm } => {
1706 let imm8 = *imm as u32;
1709 0xE7F000F0 | ((imm8 & 0xF0) << 4) | (imm8 & 0x0F)
1710 }
1711
1712 ArmOp::Popcnt { .. } | ArmOp::SetCond { .. } | ArmOp::SelectMove { .. } => {
1716 unreachable!("handled by encode_arm_expanded (#615)")
1717 }
1718
1719 ArmOp::Select { .. }
1727 | ArmOp::LocalGet { .. }
1728 | ArmOp::LocalSet { .. }
1729 | ArmOp::LocalTee { .. }
1730 | ArmOp::GlobalGet { .. }
1731 | ArmOp::GlobalSet { .. }
1732 | ArmOp::BrTable { .. }
1733 | ArmOp::Call { .. } => {
1734 return Err(synth_core::Error::synthesis(format!(
1735 "verification-only pseudo-op {op:?} reached the A32 encoder — \
1736 codegen lowers it before encoding; refusing to emit a silent NOP (#615)"
1737 )));
1738 }
1739
1740 ArmOp::CallIndirect { .. } => {
1744 unreachable!("CallIndirect handled by encode_arm_call_indirect (#594)")
1745 }
1746
1747 ArmOp::I64Add { .. }
1752 | ArmOp::I64Sub { .. }
1753 | ArmOp::I64DivS { .. }
1754 | ArmOp::I64DivU { .. }
1755 | ArmOp::I64RemS { .. }
1756 | ArmOp::I64RemU { .. }
1757 | ArmOp::I64Clz { .. }
1758 | ArmOp::I64Ctz { .. }
1759 | ArmOp::I64Popcnt { .. }
1760 | ArmOp::I64And { .. }
1761 | ArmOp::I64Or { .. }
1762 | ArmOp::I64Xor { .. }
1763 | ArmOp::I64Eqz { .. }
1764 | ArmOp::I64Eq { .. }
1765 | ArmOp::I64Ne { .. }
1766 | ArmOp::I64LtS { .. }
1767 | ArmOp::I64LtU { .. }
1768 | ArmOp::I64LeS { .. }
1769 | ArmOp::I64LeU { .. }
1770 | ArmOp::I64GtS { .. }
1771 | ArmOp::I64GtU { .. }
1772 | ArmOp::I64GeS { .. }
1773 | ArmOp::I64GeU { .. }
1774 | ArmOp::I64Const { .. }
1775 | ArmOp::I64Ldr { .. }
1776 | ArmOp::I64Str { .. }
1777 | ArmOp::I64ExtendI32S { .. }
1778 | ArmOp::I64ExtendI32U { .. }
1779 | ArmOp::I64Extend8S { .. }
1780 | ArmOp::I64Extend16S { .. }
1781 | ArmOp::I64Extend32S { .. }
1782 | ArmOp::I32WrapI64 { .. } => {
1783 unreachable!("handled by encode_arm_expanded (#615)")
1784 }
1785
1786 ArmOp::F32Add { sd, sn, sm } => encode_vfp_3reg(0xEE300A00, sd, sn, sm)?,
1788 ArmOp::F32Sub { sd, sn, sm } => encode_vfp_3reg(0xEE300A40, sd, sn, sm)?,
1789 ArmOp::F32Mul { sd, sn, sm } => encode_vfp_3reg(0xEE200A00, sd, sn, sm)?,
1790 ArmOp::F32Div { sd, sn, sm } => encode_vfp_3reg(0xEE800A00, sd, sn, sm)?,
1791 ArmOp::F32Abs { sd, sm } => encode_vfp_2reg(0xEEB00AC0, sd, sm)?,
1792 ArmOp::F32Neg { sd, sm } => encode_vfp_2reg(0xEEB10A40, sd, sm)?,
1793 ArmOp::F32Sqrt { sd, sm } => encode_vfp_2reg(0xEEB10AC0, sd, sm)?,
1794
1795 ArmOp::F32Ceil { sd, sm } => {
1798 return self.encode_arm_f32_rounding(sd, sm, 0b01); }
1800 ArmOp::F32Floor { sd, sm } => {
1801 return self.encode_arm_f32_rounding(sd, sm, 0b10); }
1803 ArmOp::F32Trunc { sd, sm } => {
1804 return self.encode_arm_f32_rounding(sd, sm, 0b11); }
1806 ArmOp::F32Nearest { sd, sm } => {
1807 return self.encode_arm_f32_rounding(sd, sm, 0b00); }
1809 ArmOp::F32Min { sd, sn, sm } => {
1810 return self.encode_arm_f32_minmax(sd, sn, sm, true);
1811 }
1812 ArmOp::F32Max { sd, sn, sm } => {
1813 return self.encode_arm_f32_minmax(sd, sn, sm, false);
1814 }
1815 ArmOp::F32Copysign { sd, sn, sm } => {
1816 return self.encode_arm_f32_copysign(sd, sn, sm);
1817 }
1818
1819 ArmOp::F32Eq { rd, sn, sm } => {
1821 return self.encode_arm_f32_compare(rd, sn, sm, 0x0); }
1823 ArmOp::F32Ne { rd, sn, sm } => {
1824 return self.encode_arm_f32_compare(rd, sn, sm, 0x1); }
1826 ArmOp::F32Lt { rd, sn, sm } => {
1827 return self.encode_arm_f32_compare(rd, sn, sm, 0x4); }
1829 ArmOp::F32Le { rd, sn, sm } => {
1830 return self.encode_arm_f32_compare(rd, sn, sm, 0x9); }
1832 ArmOp::F32Gt { rd, sn, sm } => {
1833 return self.encode_arm_f32_compare(rd, sn, sm, 0xC); }
1835 ArmOp::F32Ge { rd, sn, sm } => {
1836 return self.encode_arm_f32_compare(rd, sn, sm, 0xA); }
1838
1839 ArmOp::F32Const { sd, value } => {
1841 return self.encode_arm_f32_const(sd, *value);
1842 }
1843
1844 ArmOp::F32Load { sd, addr } => encode_vfp_ldst(0xED900A00, sd, addr)?,
1845 ArmOp::F32Store { sd, addr } => encode_vfp_ldst(0xED800A00, sd, addr)?,
1846
1847 ArmOp::F32ConvertI32S { sd, rm } => {
1849 return self.encode_arm_f32_convert_i32(sd, rm, true);
1850 }
1851 ArmOp::F32ConvertI32U { sd, rm } => {
1852 return self.encode_arm_f32_convert_i32(sd, rm, false);
1853 }
1854 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
1855 return Err(synth_core::Error::synthesis(
1856 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
1857 ));
1858 }
1859 ArmOp::F32ReinterpretI32 { sd, rm } => encode_vmov_core_sreg(true, sd, rm)?,
1860 ArmOp::I32ReinterpretF32 { rd, sm } => encode_vmov_core_sreg(false, sm, rd)?,
1861 ArmOp::I32TruncF32S { rd, sm } => {
1862 return self.encode_arm_i32_trunc_f32(rd, sm, true);
1863 }
1864 ArmOp::I32TruncF32U { rd, sm } => {
1865 return self.encode_arm_i32_trunc_f32(rd, sm, false);
1866 }
1867
1868 ArmOp::F64Add { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B00, dd, dn, dm)?,
1871 ArmOp::F64Sub { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B40, dd, dn, dm)?,
1872 ArmOp::F64Mul { dd, dn, dm } => encode_vfp_3reg_f64(0xEE200B00, dd, dn, dm)?,
1873 ArmOp::F64Div { dd, dn, dm } => encode_vfp_3reg_f64(0xEE800B00, dd, dn, dm)?,
1874 ArmOp::F64Abs { dd, dm } => encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?,
1875 ArmOp::F64Neg { dd, dm } => encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?,
1876 ArmOp::F64Sqrt { dd, dm } => encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?,
1877
1878 ArmOp::F64Ceil { dd, dm } => {
1881 return self.encode_arm_f64_rounding(dd, dm, 0b01);
1882 }
1883 ArmOp::F64Floor { dd, dm } => {
1884 return self.encode_arm_f64_rounding(dd, dm, 0b10);
1885 }
1886 ArmOp::F64Trunc { dd, dm } => {
1887 return self.encode_arm_f64_rounding(dd, dm, 0b11);
1888 }
1889 ArmOp::F64Nearest { dd, dm } => {
1890 return self.encode_arm_f64_rounding(dd, dm, 0b00);
1891 }
1892 ArmOp::F64Min { dd, dn, dm } => {
1893 return self.encode_arm_f64_minmax(dd, dn, dm, true);
1894 }
1895 ArmOp::F64Max { dd, dn, dm } => {
1896 return self.encode_arm_f64_minmax(dd, dn, dm, false);
1897 }
1898 ArmOp::F64Copysign { dd, dn, dm } => {
1899 return self.encode_arm_f64_copysign(dd, dn, dm);
1900 }
1901
1902 ArmOp::F64Eq { rd, dn, dm } => {
1904 return self.encode_arm_f64_compare(rd, dn, dm, 0x0);
1905 }
1906 ArmOp::F64Ne { rd, dn, dm } => {
1907 return self.encode_arm_f64_compare(rd, dn, dm, 0x1);
1908 }
1909 ArmOp::F64Lt { rd, dn, dm } => {
1910 return self.encode_arm_f64_compare(rd, dn, dm, 0x4);
1911 }
1912 ArmOp::F64Le { rd, dn, dm } => {
1913 return self.encode_arm_f64_compare(rd, dn, dm, 0x9);
1914 }
1915 ArmOp::F64Gt { rd, dn, dm } => {
1916 return self.encode_arm_f64_compare(rd, dn, dm, 0xC);
1917 }
1918 ArmOp::F64Ge { rd, dn, dm } => {
1919 return self.encode_arm_f64_compare(rd, dn, dm, 0xA);
1920 }
1921
1922 ArmOp::F64Const { dd, value } => {
1923 return self.encode_arm_f64_const(dd, *value);
1924 }
1925
1926 ArmOp::F64Load { dd, addr } => encode_vfp_ldst_f64(0xED900B00, dd, addr)?,
1927 ArmOp::F64Store { dd, addr } => encode_vfp_ldst_f64(0xED800B00, dd, addr)?,
1928
1929 ArmOp::F64ConvertI32S { dd, rm } => {
1930 return self.encode_arm_f64_convert_i32(dd, rm, true);
1931 }
1932 ArmOp::F64ConvertI32U { dd, rm } => {
1933 return self.encode_arm_f64_convert_i32(dd, rm, false);
1934 }
1935 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
1936 return Err(synth_core::Error::synthesis(
1937 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
1938 ));
1939 }
1940 ArmOp::F64PromoteF32 { dd, sm } => {
1941 return self.encode_arm_f64_promote_f32(dd, sm);
1942 }
1943 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => {
1944 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?
1945 }
1946 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => {
1947 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?
1948 }
1949 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
1950 return Err(synth_core::Error::synthesis(
1951 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
1952 ));
1953 }
1954 ArmOp::I32TruncF64S { rd, dm } => {
1955 return self.encode_arm_i32_trunc_f64(rd, dm, true);
1956 }
1957 ArmOp::I32TruncF64U { rd, dm } => {
1958 return self.encode_arm_i32_trunc_f64(rd, dm, false);
1959 }
1960 ArmOp::I64SetCond { .. }
1963 | ArmOp::I64SetCondZ { .. }
1964 | ArmOp::I64Mul { .. }
1965 | ArmOp::I64Shl { .. }
1966 | ArmOp::I64ShrS { .. }
1967 | ArmOp::I64ShrU { .. }
1968 | ArmOp::I64Rotl { .. }
1969 | ArmOp::I64Rotr { .. } => {
1970 unreachable!("handled by encode_arm_expanded (#615)")
1971 }
1972
1973 ArmOp::MveLoad { .. }
1975 | ArmOp::MveStore { .. }
1976 | ArmOp::MveConst { .. }
1977 | ArmOp::MveAnd { .. }
1978 | ArmOp::MveOrr { .. }
1979 | ArmOp::MveEor { .. }
1980 | ArmOp::MveMvn { .. }
1981 | ArmOp::MveBic { .. }
1982 | ArmOp::MveAddI { .. }
1983 | ArmOp::MveSubI { .. }
1984 | ArmOp::MveMulI { .. }
1985 | ArmOp::MveNegI { .. }
1986 | ArmOp::MveCmpEqI { .. }
1987 | ArmOp::MveCmpNeI { .. }
1988 | ArmOp::MveCmpLtS { .. }
1989 | ArmOp::MveCmpLtU { .. }
1990 | ArmOp::MveCmpGtS { .. }
1991 | ArmOp::MveCmpGtU { .. }
1992 | ArmOp::MveCmpLeS { .. }
1993 | ArmOp::MveCmpLeU { .. }
1994 | ArmOp::MveCmpGeS { .. }
1995 | ArmOp::MveCmpGeU { .. }
1996 | ArmOp::MveDup { .. }
1997 | ArmOp::MveExtractLane { .. }
1998 | ArmOp::MveInsertLane { .. }
1999 | ArmOp::MveAddF32 { .. }
2000 | ArmOp::MveSubF32 { .. }
2001 | ArmOp::MveMulF32 { .. }
2002 | ArmOp::MveNegF32 { .. }
2003 | ArmOp::MveAbsF32 { .. }
2004 | ArmOp::MveCmpEqF32 { .. }
2005 | ArmOp::MveCmpNeF32 { .. }
2006 | ArmOp::MveCmpLtF32 { .. }
2007 | ArmOp::MveCmpLeF32 { .. }
2008 | ArmOp::MveCmpGtF32 { .. }
2009 | ArmOp::MveCmpGeF32 { .. }
2010 | ArmOp::MveDupF32 { .. }
2011 | ArmOp::MveExtractLaneF32 { .. }
2012 | ArmOp::MveReplaceLaneF32 { .. }
2013 | ArmOp::MveDivF32 { .. }
2014 | ArmOp::MveSqrtF32 { .. } => {
2015 return Err(synth_core::Error::synthesis(format!(
2021 "MVE op {op:?} has no A32 (ARM-mode) encoding — MVE is Thumb-2 only (#615)"
2022 )));
2023 }
2024 };
2025
2026 Ok(instr.to_le_bytes().to_vec())
2028 }
2029
2030 fn encode_arm_f32_compare(
2034 &self,
2035 rd: &Reg,
2036 sn: &VfpReg,
2037 sm: &VfpReg,
2038 cond_code: u32,
2039 ) -> Result<Vec<u8>> {
2040 let mut bytes = Vec::new();
2041
2042 let sn_num = vfp_sreg_to_num(sn)?;
2044 let sm_num = vfp_sreg_to_num(sm)?;
2045 let (vd, d) = encode_sreg(sn_num);
2046 let (vm, m) = encode_sreg(sm_num);
2047 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2048 bytes.extend_from_slice(&vcmp.to_le_bytes());
2049
2050 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2052
2053 let rd_bits = reg_to_bits(rd);
2055 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2056 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2057
2058 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2060 bytes.extend_from_slice(&mov_one.to_le_bytes());
2061
2062 Ok(bytes)
2063 }
2064
2065 fn encode_arm_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
2067 let mut bytes = Vec::new();
2068 let bits = value.to_bits();
2069
2070 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
2075 let movw = 0xE3000000 | (rt << 12) | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2076 bytes.extend_from_slice(&movw.to_le_bytes());
2077
2078 let hi16 = (bits >> 16) & 0xFFFF;
2080 let movt = 0xE3400000 | (rt << 12) | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2081 bytes.extend_from_slice(&movt.to_le_bytes());
2082
2083 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
2085 bytes.extend_from_slice(&vmov.to_le_bytes());
2086
2087 Ok(bytes)
2088 }
2089
2090 fn encode_arm_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2092 let mut bytes = Vec::new();
2093
2094 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
2096 bytes.extend_from_slice(&vmov.to_le_bytes());
2097
2098 let sd_num = vfp_sreg_to_num(sd)?;
2101 let (vd, d) = encode_sreg(sd_num);
2102 let (vm, m) = encode_sreg(sd_num); let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
2104 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2105 bytes.extend_from_slice(&vcvt.to_le_bytes());
2106
2107 Ok(bytes)
2108 }
2109
2110 fn encode_arm_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2122 let mut bytes = Vec::new();
2123 let sm_num = vfp_sreg_to_num(sm)?;
2124 let sd_num = vfp_sreg_to_num(sd)?;
2125 let (vd_s, d_s) = encode_sreg(sd_num);
2126 let (vm_s, m_s) = encode_sreg(sm_num);
2127
2128 if mode == 0b11 {
2129 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2132 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2133 } else {
2134 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
2139 bytes.extend_from_slice(&vmrs.to_le_bytes());
2140
2141 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2144 bytes.extend_from_slice(&bic.to_le_bytes());
2145
2146 if mode != 0 {
2148 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2150 bytes.extend_from_slice(&orr.to_le_bytes());
2151 }
2152
2153 let vmsr = 0xEEE10A10 | (rt << 12);
2155 bytes.extend_from_slice(&vmsr.to_le_bytes());
2156
2157 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2159 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2160
2161 bytes.extend_from_slice(&vmrs.to_le_bytes());
2163 bytes.extend_from_slice(&bic.to_le_bytes());
2164 bytes.extend_from_slice(&vmsr.to_le_bytes());
2165 }
2166
2167 let (vd2, d2) = encode_sreg(sd_num);
2169 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
2170 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2171
2172 Ok(bytes)
2173 }
2174
2175 fn encode_arm_f32_minmax(
2177 &self,
2178 sd: &VfpReg,
2179 sn: &VfpReg,
2180 sm: &VfpReg,
2181 is_min: bool,
2182 ) -> Result<Vec<u8>> {
2183 let mut bytes = Vec::new();
2184 let sn_num = vfp_sreg_to_num(sn)?;
2185 let sm_num = vfp_sreg_to_num(sm)?;
2186 let sd_num = vfp_sreg_to_num(sd)?;
2187
2188 let (vd, d) = encode_sreg(sd_num);
2190 let (vn, n) = encode_sreg(sn_num);
2191 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2192 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2193
2194 let (vm, m) = encode_sreg(sm_num);
2196 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2197 bytes.extend_from_slice(&vcmp.to_le_bytes());
2198
2199 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2201
2202 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2205
2206 let vmov_cond = (cond << 28) | 0x0EB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2208 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2209
2210 Ok(bytes)
2211 }
2212
2213 fn encode_arm_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2215 let mut bytes = Vec::new();
2216
2217 let vmov_sm = encode_vmov_core_sreg(false, sm, &Reg::R12)?;
2219 bytes.extend_from_slice(&vmov_sm.to_le_bytes());
2220
2221 let vmov_sn = encode_vmov_core_sreg(false, sn, &Reg::R0)?;
2223 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2224
2225 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2229 bytes.extend_from_slice(&and_sign.to_le_bytes());
2230
2231 let bic_sign = 0xE3C00000u32 | (1 << 8) | 0x02;
2234 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2235
2236 let orr = 0xE1800000u32 | 12;
2239 bytes.extend_from_slice(&orr.to_le_bytes());
2240
2241 let vmov_result = encode_vmov_core_sreg(true, sd, &Reg::R0)?;
2243 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2244
2245 Ok(bytes)
2246 }
2247
2248 fn encode_arm_f64_compare(
2250 &self,
2251 rd: &Reg,
2252 dn: &VfpReg,
2253 dm: &VfpReg,
2254 cond_code: u32,
2255 ) -> Result<Vec<u8>> {
2256 let mut bytes = Vec::new();
2257
2258 let dn_num = vfp_dreg_to_num(dn)?;
2260 let dm_num = vfp_dreg_to_num(dm)?;
2261 let (vd, d) = encode_dreg(dn_num);
2262 let (vm, m) = encode_dreg(dm_num);
2263 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2264 bytes.extend_from_slice(&vcmp.to_le_bytes());
2265
2266 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2268
2269 let rd_bits = reg_to_bits(rd);
2271 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2272 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2273
2274 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2276 bytes.extend_from_slice(&mov_one.to_le_bytes());
2277
2278 Ok(bytes)
2279 }
2280
2281 fn encode_arm_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
2283 let mut bytes = Vec::new();
2284 let bits = value.to_bits();
2285 let lo32 = bits as u32;
2286 let hi32 = (bits >> 32) as u32;
2287
2288 let lo16 = lo32 & 0xFFFF;
2290 let movw_r0 = 0xE3000000 | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2291 bytes.extend_from_slice(&movw_r0.to_le_bytes());
2292 let hi16 = (lo32 >> 16) & 0xFFFF;
2293 let movt_r0 = 0xE3400000 | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2294 bytes.extend_from_slice(&movt_r0.to_le_bytes());
2295
2296 let lo16 = hi32 & 0xFFFF;
2298 let movw_r12 = 0xE3000000 | ((lo16 >> 12) << 16) | (12 << 12) | (lo16 & 0xFFF);
2299 bytes.extend_from_slice(&movw_r12.to_le_bytes());
2300 let hi16 = (hi32 >> 16) & 0xFFFF;
2301 let movt_r12 = 0xE3400000 | ((hi16 >> 12) << 16) | (12 << 12) | (hi16 & 0xFFF);
2302 bytes.extend_from_slice(&movt_r12.to_le_bytes());
2303
2304 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
2306 bytes.extend_from_slice(&vmov.to_le_bytes());
2307
2308 Ok(bytes)
2309 }
2310
2311 fn encode_arm_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2313 let mut bytes = Vec::new();
2314
2315 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
2317 bytes.extend_from_slice(&vmov.to_le_bytes());
2318
2319 let dd_num = vfp_dreg_to_num(dd)?;
2322 let (vd, d) = encode_dreg(dd_num);
2323 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
2324 let vcvt = base | (d << 22) | (vd << 12);
2326 bytes.extend_from_slice(&vcvt.to_le_bytes());
2327
2328 Ok(bytes)
2329 }
2330
2331 fn encode_arm_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2333 let dd_num = vfp_dreg_to_num(dd)?;
2334 let sm_num = vfp_sreg_to_num(sm)?;
2335 let (vd, d) = encode_dreg(dd_num);
2336 let (vm, m) = encode_sreg(sm_num);
2337
2338 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
2340 Ok(vcvt.to_le_bytes().to_vec())
2341 }
2342
2343 fn encode_arm_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2345 let mut bytes = Vec::new();
2346 let dm_num = vfp_dreg_to_num(dm)?;
2347 let (vm, m) = encode_dreg(dm_num);
2348
2349 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
2352 let vcvt = base | (m << 5) | vm;
2353 bytes.extend_from_slice(&vcvt.to_le_bytes());
2354
2355 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
2357 bytes.extend_from_slice(&vmov.to_le_bytes());
2358
2359 Ok(bytes)
2360 }
2361
2362 fn encode_arm_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2370 let mut bytes = Vec::new();
2371 let dm_num = vfp_dreg_to_num(dm)?;
2372 let dd_num = vfp_dreg_to_num(dd)?;
2373 let (vm, m) = encode_dreg(dm_num);
2374 let (vd, d) = encode_dreg(dd_num);
2375
2376 if mode == 0b11 {
2377 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
2379 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2380 } else {
2381 let rt: u32 = 12;
2383
2384 let vmrs = 0xEEF10A10 | (rt << 12);
2386 bytes.extend_from_slice(&vmrs.to_le_bytes());
2387
2388 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2390 bytes.extend_from_slice(&bic.to_le_bytes());
2391
2392 if mode != 0 {
2394 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2395 bytes.extend_from_slice(&orr.to_le_bytes());
2396 }
2397
2398 let vmsr = 0xEEE10A10 | (rt << 12);
2400 bytes.extend_from_slice(&vmsr.to_le_bytes());
2401
2402 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
2404 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2405
2406 bytes.extend_from_slice(&vmrs.to_le_bytes());
2408 bytes.extend_from_slice(&bic.to_le_bytes());
2409 bytes.extend_from_slice(&vmsr.to_le_bytes());
2410 }
2411
2412 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
2414 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2415
2416 Ok(bytes)
2417 }
2418
2419 fn encode_arm_f64_minmax(
2421 &self,
2422 dd: &VfpReg,
2423 dn: &VfpReg,
2424 dm: &VfpReg,
2425 is_min: bool,
2426 ) -> Result<Vec<u8>> {
2427 let mut bytes = Vec::new();
2428 let dn_num = vfp_dreg_to_num(dn)?;
2429 let dm_num = vfp_dreg_to_num(dm)?;
2430 let dd_num = vfp_dreg_to_num(dd)?;
2431
2432 let (vd, d) = encode_dreg(dd_num);
2434 let (vn, n) = encode_dreg(dn_num);
2435 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2436 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2437
2438 let (vm, m) = encode_dreg(dm_num);
2440 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2441 bytes.extend_from_slice(&vcmp.to_le_bytes());
2442
2443 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2445
2446 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2447 let vmov_cond = (cond << 28) | 0x0EB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2448 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2449
2450 Ok(bytes)
2451 }
2452
2453 fn encode_arm_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
2455 let mut bytes = Vec::new();
2456
2457 let vmov_dm = encode_vmov_core_dreg(false, dm, &Reg::R0, &Reg::R12)?;
2459 bytes.extend_from_slice(&vmov_dm.to_le_bytes());
2460
2461 let vmov_dn = encode_vmov_core_dreg(false, dn, &Reg::R1, &Reg::R2)?;
2464 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2465
2466 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2468 bytes.extend_from_slice(&and_sign.to_le_bytes());
2469
2470 let bic_sign = 0xE3C00000u32 | (2 << 16) | (2 << 12) | (1 << 8) | 0x02;
2472 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2473
2474 let orr = 0xE1800000u32 | (2 << 16) | (2 << 12) | 12;
2476 bytes.extend_from_slice(&orr.to_le_bytes());
2477
2478 let vmov_result = encode_vmov_core_dreg(true, dd, &Reg::R1, &Reg::R2)?;
2480 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2481
2482 Ok(bytes)
2483 }
2484
2485 fn encode_arm_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2487 let mut bytes = Vec::new();
2488
2489 let sm_num = vfp_sreg_to_num(sm)?;
2492 let (vd, d) = encode_sreg(sm_num);
2493 let (vm, m) = encode_sreg(sm_num);
2494 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
2495 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2496 bytes.extend_from_slice(&vcvt.to_le_bytes());
2497
2498 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
2500 bytes.extend_from_slice(&vmov.to_le_bytes());
2501
2502 Ok(bytes)
2503 }
2504
2505 fn encode_thumb(&self, op: &ArmOp) -> Result<Vec<u8>> {
2507 match op {
2510 ArmOp::Add { rd, rn, op2 } => {
2512 let rd_bits = reg_to_bits(rd) as u16;
2513 let rn_bits = reg_to_bits(rn) as u16;
2514
2515 if let Operand2::Reg(rm) = op2 {
2516 let rm_bits = reg_to_bits(rm) as u16;
2517 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2525 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2527 Ok(instr.to_le_bytes().to_vec())
2528 } else {
2529 self.encode_thumb32_add_reg_raw(
2531 rd_bits as u32,
2532 rn_bits as u32,
2533 rm_bits as u32,
2534 )
2535 }
2536 } else if let Operand2::Imm(imm) = op2 {
2537 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2538 let instr: u16 = 0x1C00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2540 Ok(instr.to_le_bytes().to_vec())
2541 } else {
2542 self.encode_thumb32_add(rd, rn, *imm as u32)
2544 }
2545 } else {
2546 self.encode_thumb32_add(rd, rn, 0)
2548 }
2549 }
2550
2551 ArmOp::Sub { rd, rn, op2 } => {
2552 let rd_bits = reg_to_bits(rd) as u16;
2553 let rn_bits = reg_to_bits(rn) as u16;
2554
2555 if let Operand2::Reg(rm) = op2 {
2556 let rm_bits = reg_to_bits(rm) as u16;
2557 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2559 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2561 Ok(instr.to_le_bytes().to_vec())
2562 } else {
2563 self.encode_thumb32_sub_reg_raw(
2565 rd_bits as u32,
2566 rn_bits as u32,
2567 rm_bits as u32,
2568 )
2569 }
2570 } else if let Operand2::Imm(imm) = op2 {
2571 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2572 let instr: u16 = 0x1E00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2574 Ok(instr.to_le_bytes().to_vec())
2575 } else {
2576 self.encode_thumb32_sub(rd, rn, *imm as u32)
2577 }
2578 } else {
2579 self.encode_thumb32_sub(rd, rn, 0)
2580 }
2581 }
2582
2583 ArmOp::Mov { rd, op2 } => {
2584 let rd_bits = reg_to_bits(rd) as u16;
2585
2586 if let Operand2::Imm(imm) = op2 {
2587 if *imm <= 255 && rd_bits < 8 {
2588 let imm_bits = (*imm as u16) & 0xFF;
2590 let instr: u16 = 0x2000 | (rd_bits << 8) | imm_bits;
2591 Ok(instr.to_le_bytes().to_vec())
2592 } else {
2593 self.encode_thumb32_movw(rd, *imm as u32)
2595 }
2596 } else if let Operand2::Reg(rm) = op2 {
2597 let rm_bits = reg_to_bits(rm) as u16;
2598 let d_bit = (rd_bits >> 3) & 1;
2601 let instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
2602 Ok(instr.to_le_bytes().to_vec())
2603 } else {
2604 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2606 }
2607 }
2608
2609 ArmOp::Push { regs } => {
2610 let mut reg_list: u16 = 0;
2614 let mut need_32bit = false;
2615 for r in regs {
2616 let bit = reg_to_bits(r);
2617 if bit >= 8 && *r != Reg::LR {
2618 need_32bit = true;
2619 }
2620 reg_list |= 1 << bit;
2621 }
2622 if !need_32bit {
2623 let m_bit = if reg_list & (1 << 14) != 0 {
2625 1u16
2626 } else {
2627 0u16
2628 };
2629 let low_regs = reg_list & 0xFF;
2630 let instr: u16 = 0xB400 | (m_bit << 8) | low_regs;
2631 Ok(instr.to_le_bytes().to_vec())
2632 } else {
2633 let hw1: u16 = 0xE92D;
2635 let hw2: u16 = reg_list;
2636 let mut bytes = hw1.to_le_bytes().to_vec();
2637 bytes.extend_from_slice(&hw2.to_le_bytes());
2638 Ok(bytes)
2639 }
2640 }
2641
2642 ArmOp::Pop { regs } => {
2643 let mut reg_list: u16 = 0;
2647 let mut need_32bit = false;
2648 for r in regs {
2649 let bit = reg_to_bits(r);
2650 if bit >= 8 && *r != Reg::PC {
2651 need_32bit = true;
2652 }
2653 reg_list |= 1 << bit;
2654 }
2655 if !need_32bit {
2656 let p_bit = if reg_list & (1 << 15) != 0 {
2658 1u16
2659 } else {
2660 0u16
2661 };
2662 let low_regs = reg_list & 0xFF;
2663 let instr: u16 = 0xBC00 | (p_bit << 8) | low_regs;
2664 Ok(instr.to_le_bytes().to_vec())
2665 } else {
2666 let hw1: u16 = 0xE8BD;
2668 let hw2: u16 = reg_list;
2669 let mut bytes = hw1.to_le_bytes().to_vec();
2670 bytes.extend_from_slice(&hw2.to_le_bytes());
2671 Ok(bytes)
2672 }
2673 }
2674
2675 ArmOp::Nop => {
2676 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2678 }
2679
2680 ArmOp::Udf { imm } => {
2681 let instr: u16 = 0xDE00 | (*imm as u16);
2684 let bytes = instr.to_le_bytes().to_vec();
2685 encoding_contracts::verify_thumb16(&bytes);
2686 Ok(bytes)
2687 }
2688
2689 ArmOp::Adds { rd, rn, op2 } => {
2692 let rd_bits = reg_to_bits(rd) as u16;
2693 let rn_bits = reg_to_bits(rn) as u16;
2694
2695 if let Operand2::Reg(rm) = op2 {
2696 let rm_bits = reg_to_bits(rm) as u16;
2697 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2702 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2704 Ok(instr.to_le_bytes().to_vec())
2705 } else {
2706 self.encode_thumb32_adds_reg_raw(
2707 rd_bits as u32,
2708 rn_bits as u32,
2709 rm_bits as u32,
2710 )
2711 }
2712 } else {
2713 self.encode_thumb32_adds(rd, rn, 0)
2715 }
2716 }
2717
2718 ArmOp::Adc { rd, rn, op2 } => {
2721 let rd_bits = reg_to_bits(rd);
2722 let rn_bits = reg_to_bits(rn);
2723
2724 if let Operand2::Reg(rm) = op2 {
2725 let rm_bits = reg_to_bits(rm);
2726 let hw1: u16 = (0xEB40 | rn_bits) as u16;
2728 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2729
2730 let mut bytes = hw1.to_le_bytes().to_vec();
2731 bytes.extend_from_slice(&hw2.to_le_bytes());
2732 Ok(bytes)
2733 } else {
2734 let hw1: u16 = (0xF140 | rn_bits) as u16;
2736 let hw2: u16 = (rd_bits << 8) as u16;
2737 let mut bytes = hw1.to_le_bytes().to_vec();
2738 bytes.extend_from_slice(&hw2.to_le_bytes());
2739 Ok(bytes)
2740 }
2741 }
2742
2743 ArmOp::Subs { rd, rn, op2 } => {
2745 let rd_bits = reg_to_bits(rd) as u16;
2746 let rn_bits = reg_to_bits(rn) as u16;
2747
2748 if let Operand2::Reg(rm) = op2 {
2749 let rm_bits = reg_to_bits(rm) as u16;
2750 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2754 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2756 Ok(instr.to_le_bytes().to_vec())
2757 } else {
2758 self.encode_thumb32_subs_reg_raw(
2759 rd_bits as u32,
2760 rn_bits as u32,
2761 rm_bits as u32,
2762 )
2763 }
2764 } else {
2765 self.encode_thumb32_subs(rd, rn, 0)
2767 }
2768 }
2769
2770 ArmOp::Sbc { rd, rn, op2 } => {
2773 let rd_bits = reg_to_bits(rd);
2774 let rn_bits = reg_to_bits(rn);
2775
2776 if let Operand2::Reg(rm) = op2 {
2777 let rm_bits = reg_to_bits(rm);
2778 let hw1: u16 = (0xEB60 | rn_bits) as u16;
2780 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2781
2782 let mut bytes = hw1.to_le_bytes().to_vec();
2783 bytes.extend_from_slice(&hw2.to_le_bytes());
2784 Ok(bytes)
2785 } else {
2786 let hw1: u16 = (0xF160 | rn_bits) as u16;
2788 let hw2: u16 = (rd_bits << 8) as u16;
2789 let mut bytes = hw1.to_le_bytes().to_vec();
2790 bytes.extend_from_slice(&hw2.to_le_bytes());
2791 Ok(bytes)
2792 }
2793 }
2794
2795 ArmOp::Sdiv { rd, rn, rm } => {
2799 let rd_bits = reg_to_bits(rd);
2800 let rn_bits = reg_to_bits(rn);
2801 let rm_bits = reg_to_bits(rm);
2802 reg_bits_checked(rd_bits)?;
2803 reg_bits_checked(rn_bits)?;
2804 reg_bits_checked(rm_bits)?;
2805
2806 let hw1: u16 = (0xFB90 | rn_bits) as u16;
2810 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2811
2812 let mut bytes = hw1.to_le_bytes().to_vec();
2814 bytes.extend_from_slice(&hw2.to_le_bytes());
2815 encoding_contracts::verify_thumb32(&bytes);
2816 Ok(bytes)
2817 }
2818
2819 ArmOp::Udiv { rd, rn, rm } => {
2821 let rd_bits = reg_to_bits(rd);
2822 let rn_bits = reg_to_bits(rn);
2823 let rm_bits = reg_to_bits(rm);
2824 reg_bits_checked(rd_bits)?;
2825 reg_bits_checked(rn_bits)?;
2826 reg_bits_checked(rm_bits)?;
2827
2828 let hw1: u16 = (0xFBB0 | rn_bits) as u16;
2830 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2831
2832 let mut bytes = hw1.to_le_bytes().to_vec();
2833 bytes.extend_from_slice(&hw2.to_le_bytes());
2834 encoding_contracts::verify_thumb32(&bytes);
2835 Ok(bytes)
2836 }
2837
2838 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
2839 let rdlo_bits = reg_to_bits(rdlo);
2840 let rdhi_bits = reg_to_bits(rdhi);
2841 let rn_bits = reg_to_bits(rn);
2842 let rm_bits = reg_to_bits(rm);
2843 reg_bits_checked(rdlo_bits)?;
2844 reg_bits_checked(rdhi_bits)?;
2845 reg_bits_checked(rn_bits)?;
2846 reg_bits_checked(rm_bits)?;
2847
2848 let hw1: u16 = (0xFBA0 | rn_bits) as u16;
2850 let hw2: u16 = ((rdlo_bits << 12) | (rdhi_bits << 8) | rm_bits) as u16;
2851
2852 let mut bytes = hw1.to_le_bytes().to_vec();
2853 bytes.extend_from_slice(&hw2.to_le_bytes());
2854 encoding_contracts::verify_thumb32(&bytes);
2855 Ok(bytes)
2856 }
2857
2858 ArmOp::Mul { rd, rn, rm } => {
2860 let rd_bits = reg_to_bits(rd);
2861 let rn_bits = reg_to_bits(rn);
2862 let rm_bits = reg_to_bits(rm);
2863
2864 let hw1: u16 = (0xFB00 | rn_bits) as u16;
2867 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
2868
2869 let mut bytes = hw1.to_le_bytes().to_vec();
2870 bytes.extend_from_slice(&hw2.to_le_bytes());
2871 Ok(bytes)
2872 }
2873
2874 ArmOp::Mls { rd, rn, rm, ra } => {
2876 let rd_bits = reg_to_bits(rd);
2877 let rn_bits = reg_to_bits(rn);
2878 let rm_bits = reg_to_bits(rm);
2879 let ra_bits = reg_to_bits(ra);
2880
2881 let hw1: u16 = (0xFB00 | rn_bits) as u16;
2884 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | 0x10 | rm_bits) as u16;
2885
2886 let mut bytes = hw1.to_le_bytes().to_vec();
2887 bytes.extend_from_slice(&hw2.to_le_bytes());
2888 Ok(bytes)
2889 }
2890
2891 ArmOp::Mla { rd, rn, rm, ra } => {
2892 let rd_bits = reg_to_bits(rd);
2893 let rn_bits = reg_to_bits(rn);
2894 let rm_bits = reg_to_bits(rm);
2895 let ra_bits = reg_to_bits(ra);
2896
2897 let hw1: u16 = (0xFB00 | rn_bits) as u16;
2900 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | rm_bits) as u16;
2901
2902 let mut bytes = hw1.to_le_bytes().to_vec();
2903 bytes.extend_from_slice(&hw2.to_le_bytes());
2904 Ok(bytes)
2905 }
2906
2907 ArmOp::And { rd, rn, op2 } => {
2909 if let Operand2::Reg(rm) = op2 {
2910 let rd_bits = reg_to_bits(rd);
2911 let rn_bits = reg_to_bits(rn);
2912 let rm_bits = reg_to_bits(rm);
2913
2914 let hw1: u16 = (0xEA00 | rn_bits) as u16;
2916 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2917
2918 let mut bytes = hw1.to_le_bytes().to_vec();
2919 bytes.extend_from_slice(&hw2.to_le_bytes());
2920 Ok(bytes)
2921 } else if let Operand2::Imm(imm) = op2 {
2922 let rd_bits = reg_to_bits(rd);
2923 let rn_bits = reg_to_bits(rn);
2924
2925 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
2932 synth_core::Error::synthesis(
2933 "AND immediate is not a valid ThumbExpandImm — materialize into a register",
2934 )
2935 })?;
2936 let i_bit = (field >> 11) & 1;
2937 let imm3 = (field >> 8) & 0x7;
2938 let imm8 = field & 0xFF;
2939
2940 let hw1: u16 = (0xF000 | (i_bit << 10) | rn_bits) as u16;
2941 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
2942
2943 let mut bytes = hw1.to_le_bytes().to_vec();
2944 bytes.extend_from_slice(&hw2.to_le_bytes());
2945 Ok(bytes)
2946 } else {
2947 let instr: u16 = 0xBF00;
2949 Ok(instr.to_le_bytes().to_vec())
2950 }
2951 }
2952
2953 ArmOp::Orr { rd, rn, op2 } => {
2955 if let Operand2::Reg(rm) = op2 {
2956 let rd_bits = reg_to_bits(rd);
2957 let rn_bits = reg_to_bits(rn);
2958 let rm_bits = reg_to_bits(rm);
2959
2960 let hw1: u16 = (0xEA40 | rn_bits) as u16;
2962 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2963
2964 let mut bytes = hw1.to_le_bytes().to_vec();
2965 bytes.extend_from_slice(&hw2.to_le_bytes());
2966 Ok(bytes)
2967 } else if let Operand2::Imm(imm) = op2 {
2968 let imm_val = *imm as u32;
2973 if imm_val > 0xFF {
2974 return Err(synth_core::Error::synthesis(
2975 "ORR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
2976 ));
2977 }
2978 let rd_bits = reg_to_bits(rd);
2979 let rn_bits = reg_to_bits(rn);
2980 let hw1: u16 = (0xF040 | rn_bits) as u16;
2981 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
2982 let mut bytes = hw1.to_le_bytes().to_vec();
2983 bytes.extend_from_slice(&hw2.to_le_bytes());
2984 Ok(bytes)
2985 } else {
2986 let instr: u16 = 0xBF00;
2987 Ok(instr.to_le_bytes().to_vec())
2988 }
2989 }
2990
2991 ArmOp::Eor { rd, rn, op2 } => {
2993 if let Operand2::Reg(rm) = op2 {
2994 let rd_bits = reg_to_bits(rd);
2995 let rn_bits = reg_to_bits(rn);
2996 let rm_bits = reg_to_bits(rm);
2997
2998 let hw1: u16 = (0xEA80 | rn_bits) as u16;
3000 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3001
3002 let mut bytes = hw1.to_le_bytes().to_vec();
3003 bytes.extend_from_slice(&hw2.to_le_bytes());
3004 Ok(bytes)
3005 } else if let Operand2::Imm(imm) = op2 {
3006 let imm_val = *imm as u32;
3010 if imm_val > 0xFF {
3011 return Err(synth_core::Error::synthesis(
3012 "EOR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
3013 ));
3014 }
3015 let rd_bits = reg_to_bits(rd);
3016 let rn_bits = reg_to_bits(rn);
3017 let hw1: u16 = (0xF080 | rn_bits) as u16;
3018 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
3019 let mut bytes = hw1.to_le_bytes().to_vec();
3020 bytes.extend_from_slice(&hw2.to_le_bytes());
3021 Ok(bytes)
3022 } else {
3023 let instr: u16 = 0xBF00;
3024 Ok(instr.to_le_bytes().to_vec())
3025 }
3026 }
3027
3028 ArmOp::Lsl { rd, rn, shift } => {
3030 let rd_bits = reg_to_bits(rd) as u16;
3031 let rn_bits = reg_to_bits(rn) as u16;
3032 let shift_bits = (*shift as u16) & 0x1F;
3033
3034 if rd_bits < 8 && rn_bits < 8 {
3035 let instr: u16 = (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3037 Ok(instr.to_le_bytes().to_vec())
3038 } else {
3039 self.encode_thumb32_shift(rd, rn, *shift, 0b00) }
3042 }
3043
3044 ArmOp::Lsr { rd, rn, shift } => {
3045 let rd_bits = reg_to_bits(rd) as u16;
3046 let rn_bits = reg_to_bits(rn) as u16;
3047 let shift_bits = (*shift as u16) & 0x1F;
3048
3049 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3050 let instr: u16 = 0x0800 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3052 Ok(instr.to_le_bytes().to_vec())
3053 } else {
3054 self.encode_thumb32_shift(rd, rn, *shift, 0b01) }
3056 }
3057
3058 ArmOp::Asr { rd, rn, shift } => {
3059 let rd_bits = reg_to_bits(rd) as u16;
3060 let rn_bits = reg_to_bits(rn) as u16;
3061 let shift_bits = (*shift as u16) & 0x1F;
3062
3063 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3064 let instr: u16 = 0x1000 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3066 Ok(instr.to_le_bytes().to_vec())
3067 } else {
3068 self.encode_thumb32_shift(rd, rn, *shift, 0b10) }
3070 }
3071
3072 ArmOp::Ror { rd, rn, shift } => {
3073 self.encode_thumb32_shift(rd, rn, *shift, 0b11) }
3076
3077 ArmOp::LslReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b00),
3081 ArmOp::LsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b01),
3082 ArmOp::AsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b10),
3083 ArmOp::RorReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b11),
3084
3085 ArmOp::Rsb { rd, rn, imm } => {
3088 let rd_bits = reg_to_bits(rd);
3089 let rn_bits = reg_to_bits(rn);
3090 let imm_val = *imm;
3091
3092 let i_bit = (imm_val >> 11) & 1;
3093 let imm3 = (imm_val >> 8) & 0x7;
3094 let imm8 = imm_val & 0xFF;
3095
3096 let hw1: u16 = (0xF1C0 | (i_bit << 10) | rn_bits) as u16;
3098 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
3100
3101 let mut bytes = hw1.to_le_bytes().to_vec();
3102 bytes.extend_from_slice(&hw2.to_le_bytes());
3103 Ok(bytes)
3104 }
3105
3106 ArmOp::Clz { rd, rm } => {
3108 let rd_bits = reg_to_bits(rd);
3109 let rm_bits = reg_to_bits(rm);
3110
3111 let hw1: u16 = (0xFAB0 | rm_bits) as u16;
3114 let hw2: u16 = (0xF080 | (rd_bits << 8) | rm_bits) as u16;
3115
3116 let mut bytes = hw1.to_le_bytes().to_vec();
3117 bytes.extend_from_slice(&hw2.to_le_bytes());
3118 Ok(bytes)
3119 }
3120
3121 ArmOp::Rbit { rd, rm } => {
3123 let rd_bits = reg_to_bits(rd);
3124 let rm_bits = reg_to_bits(rm);
3125
3126 let hw1: u16 = (0xFA90 | rm_bits) as u16;
3129 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rm_bits) as u16;
3130
3131 let mut bytes = hw1.to_le_bytes().to_vec();
3132 bytes.extend_from_slice(&hw2.to_le_bytes());
3133 Ok(bytes)
3134 }
3135
3136 ArmOp::Sxtb { rd, rm } => {
3138 let rd_bits = reg_to_bits(rd) as u16;
3139 let rm_bits = reg_to_bits(rm) as u16;
3140
3141 if rd_bits < 8 && rm_bits < 8 {
3142 let instr: u16 = 0xB240 | (rm_bits << 3) | rd_bits;
3144 Ok(instr.to_le_bytes().to_vec())
3145 } else {
3146 let rd_bits32 = rd_bits as u32;
3149 let rm_bits32 = rm_bits as u32;
3150 let hw1: u16 = 0xFA4F;
3151 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3152 let mut bytes = hw1.to_le_bytes().to_vec();
3153 bytes.extend_from_slice(&hw2.to_le_bytes());
3154 Ok(bytes)
3155 }
3156 }
3157
3158 ArmOp::Sxth { rd, rm } => {
3160 let rd_bits = reg_to_bits(rd) as u16;
3161 let rm_bits = reg_to_bits(rm) as u16;
3162
3163 if rd_bits < 8 && rm_bits < 8 {
3164 let instr: u16 = 0xB200 | (rm_bits << 3) | rd_bits;
3166 Ok(instr.to_le_bytes().to_vec())
3167 } else {
3168 let rd_bits32 = rd_bits as u32;
3171 let rm_bits32 = rm_bits as u32;
3172 let hw1: u16 = 0xFA0F;
3173 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3174 let mut bytes = hw1.to_le_bytes().to_vec();
3175 bytes.extend_from_slice(&hw2.to_le_bytes());
3176 Ok(bytes)
3177 }
3178 }
3179
3180 ArmOp::Uxtb { rd, rm } => {
3182 let rd_bits = reg_to_bits(rd) as u16;
3183 let rm_bits = reg_to_bits(rm) as u16;
3184 if rd_bits < 8 && rm_bits < 8 {
3185 let instr: u16 = 0xB2C0 | (rm_bits << 3) | rd_bits;
3187 Ok(instr.to_le_bytes().to_vec())
3188 } else {
3189 let hw1: u16 = 0xFA5F;
3191 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3192 let mut bytes = hw1.to_le_bytes().to_vec();
3193 bytes.extend_from_slice(&hw2.to_le_bytes());
3194 Ok(bytes)
3195 }
3196 }
3197
3198 ArmOp::Uxth { rd, rm } => {
3200 let rd_bits = reg_to_bits(rd) as u16;
3201 let rm_bits = reg_to_bits(rm) as u16;
3202 if rd_bits < 8 && rm_bits < 8 {
3203 let instr: u16 = 0xB280 | (rm_bits << 3) | rd_bits;
3205 Ok(instr.to_le_bytes().to_vec())
3206 } else {
3207 let hw1: u16 = 0xFA1F;
3209 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3210 let mut bytes = hw1.to_le_bytes().to_vec();
3211 bytes.extend_from_slice(&hw2.to_le_bytes());
3212 Ok(bytes)
3213 }
3214 }
3215
3216 ArmOp::Cmp { rn, op2 } => {
3218 let rn_bits = reg_to_bits(rn) as u16;
3219
3220 if let Operand2::Imm(imm) = op2 {
3221 if *imm >= 0 && *imm <= 255 && rn_bits < 8 {
3224 let instr: u16 = 0x2800 | (rn_bits << 8) | (*imm as u16 & 0xFF);
3226 Ok(instr.to_le_bytes().to_vec())
3227 } else {
3228 self.encode_thumb32_cmp_imm(rn, *imm as u32)
3229 }
3230 } else if let Operand2::Reg(rm) = op2 {
3231 let rm_bits = reg_to_bits(rm) as u16;
3232 if rn_bits < 8 && rm_bits < 8 {
3233 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
3235 Ok(instr.to_le_bytes().to_vec())
3236 } else {
3237 let n_bit = (rn_bits >> 3) & 1;
3239 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
3240 Ok(instr.to_le_bytes().to_vec())
3241 }
3242 } else {
3243 let instr: u16 = 0xBF00;
3244 Ok(instr.to_le_bytes().to_vec())
3245 }
3246 }
3247
3248 ArmOp::Cmn { rn, op2 } => {
3251 let rn_bits = reg_to_bits(rn) as u16;
3252
3253 if let Operand2::Imm(imm) = op2 {
3254 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
3260 synth_core::Error::synthesis(
3261 "CMN immediate is not a valid ThumbExpandImm — materialize into a register",
3262 )
3263 })?;
3264 let i_bit = (field >> 11) & 1;
3265 let imm3 = (field >> 8) & 0x7;
3266 let imm8 = field & 0xFF;
3267 let hw1: u16 = (0xF110 | (i_bit << 10) as u16) | rn_bits;
3268 let hw2: u16 = (imm3 << 12) as u16 | 0x0F00 | imm8 as u16;
3269 let mut bytes = hw1.to_le_bytes().to_vec();
3270 bytes.extend_from_slice(&hw2.to_le_bytes());
3271 Ok(bytes)
3272 } else if let Operand2::Reg(rm) = op2 {
3273 let rm_bits = reg_to_bits(rm) as u16;
3274 if rn_bits < 8 && rm_bits < 8 {
3280 let instr: u16 = 0x42C0 | (rm_bits << 3) | rn_bits;
3282 Ok(instr.to_le_bytes().to_vec())
3283 } else {
3284 let hw1: u16 = 0xEB10 | rn_bits;
3285 let hw2: u16 = 0x0F00 | rm_bits;
3286 let mut bytes = hw1.to_le_bytes().to_vec();
3287 bytes.extend_from_slice(&hw2.to_le_bytes());
3288 Ok(bytes)
3289 }
3290 } else {
3291 Ok(vec![0xBF, 0x00])
3292 }
3293 }
3294
3295 ArmOp::Ldr { rd, addr } => {
3297 let rd_bits = reg_to_bits(rd);
3298 let base_bits = reg_to_bits(&addr.base);
3299
3300 if let Some(offset_reg) = &addr.offset_reg {
3302 let rm_bits = reg_to_bits(offset_reg);
3303
3304 if addr.offset != 0 {
3306 let scratch = Reg::R12;
3309 let mut bytes =
3310 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3311 bytes.extend(self.encode_thumb32_ldr_reg(rd, &addr.base, &scratch)?);
3312 return Ok(bytes);
3313 }
3314
3315 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3318 let instr: u16 = 0x5800
3320 | ((rm_bits as u16) << 6)
3321 | ((base_bits as u16) << 3)
3322 | (rd_bits as u16);
3323 return Ok(instr.to_le_bytes().to_vec());
3324 }
3325
3326 return self.encode_thumb32_ldr_reg(rd, &addr.base, offset_reg);
3328 }
3329
3330 let offset = addr.offset as u32;
3332
3333 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3334 let imm5 = (offset >> 2) as u16;
3336 let instr: u16 =
3337 0x6800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3338 Ok(instr.to_le_bytes().to_vec())
3339 } else {
3340 self.encode_thumb32_ldr(rd, &addr.base, offset)
3341 }
3342 }
3343
3344 ArmOp::Str { rd, addr } => {
3346 let rd_bits = reg_to_bits(rd);
3347 let base_bits = reg_to_bits(&addr.base);
3348
3349 if let Some(offset_reg) = &addr.offset_reg {
3351 let rm_bits = reg_to_bits(offset_reg);
3352
3353 if addr.offset != 0 {
3355 let scratch = Reg::R12;
3358 let mut bytes =
3359 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3360 bytes.extend(self.encode_thumb32_str_reg(rd, &addr.base, &scratch)?);
3361 return Ok(bytes);
3362 }
3363
3364 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3367 let instr: u16 = 0x5000
3369 | ((rm_bits as u16) << 6)
3370 | ((base_bits as u16) << 3)
3371 | (rd_bits as u16);
3372 return Ok(instr.to_le_bytes().to_vec());
3373 }
3374
3375 return self.encode_thumb32_str_reg(rd, &addr.base, offset_reg);
3377 }
3378
3379 let offset = addr.offset as u32;
3381
3382 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3383 let imm5 = (offset >> 2) as u16;
3385 let instr: u16 =
3386 0x6000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3387 Ok(instr.to_le_bytes().to_vec())
3388 } else {
3389 self.encode_thumb32_str(rd, &addr.base, offset)
3390 }
3391 }
3392
3393 ArmOp::Ldrb { rd, addr } => {
3395 let rd_bits = reg_to_bits(rd);
3396 let base_bits = reg_to_bits(&addr.base);
3397
3398 if let Some(offset_reg) = &addr.offset_reg {
3399 if addr.offset != 0 {
3400 let scratch = Reg::R12;
3401 let mut bytes =
3402 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3403 bytes.extend(self.encode_thumb32_ldrb_reg(rd, &addr.base, &scratch)?);
3404 return Ok(bytes);
3405 }
3406 return self.encode_thumb32_ldrb_reg(rd, &addr.base, offset_reg);
3407 }
3408
3409 let offset = addr.offset as u32;
3410 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3411 let instr: u16 = 0x7800
3413 | ((offset as u16) << 6)
3414 | ((base_bits as u16) << 3)
3415 | (rd_bits as u16);
3416 Ok(instr.to_le_bytes().to_vec())
3417 } else {
3418 self.encode_thumb32_ldrb_imm(rd, &addr.base, offset)
3419 }
3420 }
3421
3422 ArmOp::Ldrsb { rd, addr } => {
3424 let rd_bits = reg_to_bits(rd);
3425 let base_bits = reg_to_bits(&addr.base);
3426
3427 if let Some(offset_reg) = &addr.offset_reg {
3428 if addr.offset != 0 {
3429 let scratch = Reg::R12;
3430 let mut bytes =
3431 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3432 bytes.extend(self.encode_thumb32_ldrsb_reg(rd, &addr.base, &scratch)?);
3433 return Ok(bytes);
3434 }
3435 return self.encode_thumb32_ldrsb_reg(rd, &addr.base, offset_reg);
3436 }
3437
3438 let offset = addr.offset as u32;
3439 if rd_bits < 8 && base_bits < 8 && offset == 0 {
3442 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3444 } else {
3445 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3446 }
3447 }
3448
3449 ArmOp::Ldrh { rd, addr } => {
3451 let rd_bits = reg_to_bits(rd);
3452 let base_bits = reg_to_bits(&addr.base);
3453
3454 if let Some(offset_reg) = &addr.offset_reg {
3455 if addr.offset != 0 {
3456 let scratch = Reg::R12;
3457 let mut bytes =
3458 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3459 bytes.extend(self.encode_thumb32_ldrh_reg(rd, &addr.base, &scratch)?);
3460 return Ok(bytes);
3461 }
3462 return self.encode_thumb32_ldrh_reg(rd, &addr.base, offset_reg);
3463 }
3464
3465 let offset = addr.offset as u32;
3466 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3467 let imm5 = (offset >> 1) as u16;
3469 let instr: u16 =
3470 0x8800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3471 Ok(instr.to_le_bytes().to_vec())
3472 } else {
3473 self.encode_thumb32_ldrh_imm(rd, &addr.base, offset)
3474 }
3475 }
3476
3477 ArmOp::Ldrsh { rd, addr } => {
3479 if let Some(offset_reg) = &addr.offset_reg {
3480 if addr.offset != 0 {
3481 let scratch = Reg::R12;
3482 let mut bytes =
3483 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3484 bytes.extend(self.encode_thumb32_ldrsh_reg(rd, &addr.base, &scratch)?);
3485 return Ok(bytes);
3486 }
3487 return self.encode_thumb32_ldrsh_reg(rd, &addr.base, offset_reg);
3488 }
3489
3490 let offset = addr.offset as u32;
3491 self.encode_thumb32_ldrsh_imm(rd, &addr.base, offset)
3492 }
3493
3494 ArmOp::Strb { rd, addr } => {
3496 let rd_bits = reg_to_bits(rd);
3497 let base_bits = reg_to_bits(&addr.base);
3498
3499 if let Some(offset_reg) = &addr.offset_reg {
3500 if addr.offset != 0 {
3501 let scratch = Reg::R12;
3502 let mut bytes =
3503 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3504 bytes.extend(self.encode_thumb32_strb_reg(rd, &addr.base, &scratch)?);
3505 return Ok(bytes);
3506 }
3507 return self.encode_thumb32_strb_reg(rd, &addr.base, offset_reg);
3508 }
3509
3510 let offset = addr.offset as u32;
3511 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3512 let instr: u16 = 0x7000
3514 | ((offset as u16) << 6)
3515 | ((base_bits as u16) << 3)
3516 | (rd_bits as u16);
3517 Ok(instr.to_le_bytes().to_vec())
3518 } else {
3519 self.encode_thumb32_strb_imm(rd, &addr.base, offset)
3520 }
3521 }
3522
3523 ArmOp::Strh { rd, addr } => {
3525 let rd_bits = reg_to_bits(rd);
3526 let base_bits = reg_to_bits(&addr.base);
3527
3528 if let Some(offset_reg) = &addr.offset_reg {
3529 if addr.offset != 0 {
3530 let scratch = Reg::R12;
3531 let mut bytes =
3532 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3533 bytes.extend(self.encode_thumb32_strh_reg(rd, &addr.base, &scratch)?);
3534 return Ok(bytes);
3535 }
3536 return self.encode_thumb32_strh_reg(rd, &addr.base, offset_reg);
3537 }
3538
3539 let offset = addr.offset as u32;
3540 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3541 let imm5 = (offset >> 1) as u16;
3543 let instr: u16 =
3544 0x8000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3545 Ok(instr.to_le_bytes().to_vec())
3546 } else {
3547 self.encode_thumb32_strh_imm(rd, &addr.base, offset)
3548 }
3549 }
3550
3551 ArmOp::MemorySize { rd } => {
3553 let rd_bits = reg_to_bits(rd);
3556 let r10_bits = reg_to_bits(&Reg::R10);
3557 if rd_bits < 8 && r10_bits < 8 {
3558 let instr: u16 =
3559 0x0800 | (16u16 << 6) | ((r10_bits as u16) << 3) | (rd_bits as u16);
3560 Ok(instr.to_le_bytes().to_vec())
3561 } else {
3562 let imm5: u32 = 16;
3564 let imm3 = (imm5 >> 2) & 0x7;
3565 let imm2 = imm5 & 0x3;
3566 let hw1: u16 = 0xEA4F;
3567 let hw2: u16 =
3568 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | 0x10 | r10_bits) as u16;
3569 let mut bytes = hw1.to_le_bytes().to_vec();
3570 bytes.extend_from_slice(&hw2.to_le_bytes());
3571 Ok(bytes)
3572 }
3573 }
3574
3575 ArmOp::MemoryGrow { rd, .. } => {
3577 let rd_bits = reg_to_bits(rd);
3581 let hw1: u16 = 0xF06F; let hw2: u16 = (rd_bits << 8) as u16; let mut bytes = hw1.to_le_bytes().to_vec();
3584 bytes.extend_from_slice(&hw2.to_le_bytes());
3585 Ok(bytes)
3586 }
3587
3588 ArmOp::Bx { rm } => {
3590 let rm_bits = reg_to_bits(rm) as u16;
3591 let instr: u16 = 0x4700 | (rm_bits << 3);
3593 Ok(instr.to_le_bytes().to_vec())
3594 }
3595
3596 ArmOp::Blx { rm } => {
3599 let rm_bits = reg_to_bits(rm) as u16;
3600 let instr: u16 = 0x4780 | (rm_bits << 3);
3601 Ok(instr.to_le_bytes().to_vec())
3602 }
3603
3604 ArmOp::CallIndirect {
3608 rd: _,
3609 type_idx: _,
3610 table_index_reg,
3611 } => {
3612 let idx_reg = reg_to_bits(table_index_reg);
3613 let mut bytes = Vec::new();
3614
3615 let hw1: u16 = 0xEA4F_u16; let hw2: u16 = ((0x0C00 | (0b10 << 6)) | idx_reg) as u16;
3635 bytes.extend_from_slice(&hw1.to_le_bytes());
3636 bytes.extend_from_slice(&hw2.to_le_bytes());
3637
3638 let ldr_hw1: u16 = 0xF85B; let ldr_hw2: u16 = 0xC00C; bytes.extend_from_slice(&ldr_hw1.to_le_bytes());
3644 bytes.extend_from_slice(&ldr_hw2.to_le_bytes());
3645
3646 let blx: u16 = 0x47E0; bytes.extend_from_slice(&blx.to_le_bytes());
3650
3651 Ok(bytes)
3652 }
3653
3654 ArmOp::Label { .. } => Ok(Vec::new()),
3656
3657 ArmOp::Bcc { cond, label: _ } => {
3659 use synth_synthesis::Condition;
3660 let cond_bits: u16 = match cond {
3661 Condition::EQ => 0x0,
3662 Condition::NE => 0x1,
3663 Condition::HS => 0x2,
3664 Condition::LO => 0x3,
3665 Condition::HI => 0x8,
3666 Condition::LS => 0x9,
3667 Condition::GE => 0xA,
3668 Condition::LT => 0xB,
3669 Condition::GT => 0xC,
3670 Condition::LE => 0xD,
3671 };
3672 let instr: u16 = 0xD000 | (cond_bits << 8);
3674 Ok(instr.to_le_bytes().to_vec())
3675 }
3676
3677 ArmOp::B { label: _ } => {
3679 let instr: u16 = 0xE000; Ok(instr.to_le_bytes().to_vec())
3683 }
3684
3685 ArmOp::Bhs { label: _ } => {
3688 let instr: u16 = 0xD200; Ok(instr.to_le_bytes().to_vec())
3692 }
3693
3694 ArmOp::Blo { label: _ } => {
3697 let instr: u16 = 0xD300; Ok(instr.to_le_bytes().to_vec())
3701 }
3702
3703 ArmOp::BOffset { offset } => {
3706 let halfword_offset = *offset;
3709
3710 if (-1024..=1022).contains(&halfword_offset) {
3713 let imm11 = (halfword_offset as u16) & 0x7FF;
3715 let instr: u16 = 0xE000 | imm11;
3716 Ok(instr.to_le_bytes().to_vec())
3717 } else {
3718 let signed_offset = halfword_offset << 1; let s = if signed_offset < 0 { 1u32 } else { 0u32 };
3734 let uoffset = signed_offset as u32;
3735 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;
3743 let hw2: u16 = (0x9000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
3744
3745 let mut bytes = hw1.to_le_bytes().to_vec();
3746 bytes.extend_from_slice(&hw2.to_le_bytes());
3747 Ok(bytes)
3748 }
3749 }
3750
3751 ArmOp::BCondOffset { cond, offset } => {
3753 use synth_synthesis::Condition;
3754 let cond_bits: u16 = match cond {
3755 Condition::EQ => 0x0,
3756 Condition::NE => 0x1,
3757 Condition::HS => 0x2,
3758 Condition::LO => 0x3,
3759 Condition::HI => 0x8,
3760 Condition::LS => 0x9,
3761 Condition::GE => 0xA,
3762 Condition::LT => 0xB,
3763 Condition::GT => 0xC,
3764 Condition::LE => 0xD,
3765 };
3766
3767 let halfword_offset = *offset;
3770
3771 if (-128..=127).contains(&halfword_offset) {
3774 let imm8 = (halfword_offset as u16) & 0xFF;
3775 let instr: u16 = 0xD000 | (cond_bits << 8) | imm8;
3776 Ok(instr.to_le_bytes().to_vec())
3777 } else {
3778 let offset = halfword_offset >> 1;
3782 let s = if offset < 0 { 1u32 } else { 0u32 };
3783 let imm6 = ((offset >> 11) as u32) & 0x3F;
3784 let imm11 = (offset as u32) & 0x7FF;
3785 let j1 = if s == 1 { 1 } else { 0 };
3786 let j2 = if s == 1 { 1 } else { 0 };
3787
3788 let hw1: u16 = (0xF000 | (s << 10) | ((cond_bits as u32) << 6) | imm6) as u16;
3789 let hw2: u16 = (0x8000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
3790
3791 let mut bytes = hw1.to_le_bytes().to_vec();
3792 bytes.extend_from_slice(&hw2.to_le_bytes());
3793 Ok(bytes)
3794 }
3795 }
3796
3797 ArmOp::Bl { label: _ } => {
3798 let hw1: u16 = 0xF7FF;
3813 let hw2: u16 = 0xFFFE;
3814 let mut bytes = hw1.to_le_bytes().to_vec();
3815 bytes.extend_from_slice(&hw2.to_le_bytes());
3816 Ok(bytes)
3817 }
3818
3819 ArmOp::Mvn { rd, op2 } => {
3821 if let Operand2::Reg(rm) = op2 {
3822 let rd_bits = reg_to_bits(rd) as u16;
3823 let rm_bits = reg_to_bits(rm) as u16;
3824
3825 if rd_bits < 8 && rm_bits < 8 {
3826 let instr: u16 = 0x43C0 | (rm_bits << 3) | rd_bits;
3828 Ok(instr.to_le_bytes().to_vec())
3829 } else {
3830 let hw1: u16 = 0xEA6F_u16;
3832 let hw2: u16 = ((reg_to_bits(rd) << 8) | reg_to_bits(rm)) as u16;
3833 let mut bytes = hw1.to_le_bytes().to_vec();
3834 bytes.extend_from_slice(&hw2.to_le_bytes());
3835 Ok(bytes)
3836 }
3837 } else {
3838 let instr: u16 = 0xBF00;
3839 Ok(instr.to_le_bytes().to_vec())
3840 }
3841 }
3842
3843 ArmOp::Movw { rd, imm16 } => {
3845 self.encode_thumb32_movw_raw(reg_to_bits(rd), *imm16 as u32)
3846 }
3847
3848 ArmOp::Movt { rd, imm16 } => {
3850 self.encode_thumb32_movt_raw(reg_to_bits(rd), *imm16 as u32)
3851 }
3852
3853 ArmOp::MovwSym { rd, addend, .. } => {
3858 self.encode_thumb32_movw_raw(reg_to_bits(rd), (*addend as u32) & 0xffff)
3859 }
3860 ArmOp::MovtSym { rd, addend, .. } => {
3861 self.encode_thumb32_movt_raw(reg_to_bits(rd), ((*addend as u32) >> 16) & 0xffff)
3862 }
3863
3864 ArmOp::LdrSym { rd, .. } => {
3872 let rt = reg_to_bits(rd) as u16;
3873 let hw1: u16 = 0xF8DF; let hw2: u16 = rt << 12; let mut bytes = Vec::with_capacity(4);
3876 bytes.extend_from_slice(&hw1.to_le_bytes());
3877 bytes.extend_from_slice(&hw2.to_le_bytes());
3878 Ok(bytes)
3879 }
3880
3881 ArmOp::SetCond { rd, cond } => {
3887 let rd_bits = reg_to_bits(rd) as u16;
3888
3889 use synth_synthesis::Condition;
3891 let cond_bits: u16 = match cond {
3892 Condition::EQ => 0x0,
3893 Condition::NE => 0x1,
3894 Condition::LT => 0xB,
3895 Condition::LE => 0xD,
3896 Condition::GT => 0xC,
3897 Condition::GE => 0xA,
3898 Condition::LO => 0x3, Condition::LS => 0x9, Condition::HI => 0x8, Condition::HS => 0x2, };
3903
3904 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
3909 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
3910
3911 let mut bytes = ite_instr.to_le_bytes().to_vec();
3922 let push_mov = |bytes: &mut Vec<u8>, imm: u16| {
3923 if rd_bits <= 7 {
3924 let m: u16 = 0x2000 | (rd_bits << 8) | imm; bytes.extend_from_slice(&m.to_le_bytes());
3926 } else {
3927 let hw1: u16 = 0xF04F;
3929 let hw2: u16 = (rd_bits << 8) | imm;
3930 bytes.extend_from_slice(&hw1.to_le_bytes());
3931 bytes.extend_from_slice(&hw2.to_le_bytes());
3932 }
3933 };
3934 push_mov(&mut bytes, 1); push_mov(&mut bytes, 0); Ok(bytes)
3937 }
3938
3939 ArmOp::I64SetCond {
3944 rd,
3945 rn_lo,
3946 rn_hi,
3947 rm_lo,
3948 rm_hi,
3949 cond,
3950 } => {
3951 use synth_synthesis::Condition;
3952 let rd_bits = reg_to_bits(rd) as u16;
3953 let mut bytes = Vec::new();
3954
3955 let encode_cmp_reg = |rn: &synth_synthesis::Reg,
3957 rm: &synth_synthesis::Reg|
3958 -> Vec<u8> {
3959 let rn_bits = reg_to_bits(rn) as u16;
3960 let rm_bits = reg_to_bits(rm) as u16;
3961 if rn_bits < 8 && rm_bits < 8 {
3962 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
3963 instr.to_le_bytes().to_vec()
3964 } else {
3965 let n_bit = (rn_bits >> 3) & 1;
3966 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
3967 instr.to_le_bytes().to_vec()
3968 }
3969 };
3970
3971 let encode_ite = |cond_bits: u16| -> Vec<u8> {
3973 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
3974 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
3975 ite_instr.to_le_bytes().to_vec()
3976 };
3977
3978 let encode_setcond = |cond_bits: u16, rd_bits: u16| -> Vec<u8> {
3980 let mut b = encode_ite(cond_bits);
3981 if rd_bits < 8 {
3982 let mov_one: u16 = 0x2001 | (rd_bits << 8);
3983 let mov_zero: u16 = 0x2000 | (rd_bits << 8);
3984 b.extend_from_slice(&mov_one.to_le_bytes());
3985 b.extend_from_slice(&mov_zero.to_le_bytes());
3986 } else {
3987 for imm in [1u16, 0u16] {
3995 let hw1: u16 = 0xF04F;
3996 let hw2: u16 = (rd_bits << 8) | imm;
3997 b.extend_from_slice(&hw1.to_le_bytes());
3998 b.extend_from_slice(&hw2.to_le_bytes());
3999 }
4000 }
4001 b
4002 };
4003
4004 match cond {
4005 Condition::EQ | Condition::NE => {
4006 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4008
4009 let it_eq: u16 = 0xBF08; bytes.extend_from_slice(&it_eq.to_le_bytes());
4012
4013 bytes.extend_from_slice(&encode_cmp_reg(rn_hi, rm_hi));
4015
4016 let cond_bits: u16 = match cond {
4018 Condition::EQ => 0x0,
4019 Condition::NE => 0x1,
4020 _ => unreachable!(),
4021 };
4022 bytes.extend_from_slice(&encode_setcond(cond_bits, rd_bits));
4023 }
4024
4025 Condition::LT => {
4026 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4028
4029 let rn_hi_bits = reg_to_bits(rn_hi);
4032 let rm_hi_bits = reg_to_bits(rm_hi);
4033 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4034 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4035 bytes.extend_from_slice(&hw1.to_le_bytes());
4036 bytes.extend_from_slice(&hw2.to_le_bytes());
4037
4038 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4041
4042 Condition::GT => {
4043 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4046
4047 let rm_hi_bits = reg_to_bits(rm_hi);
4049 let rn_hi_bits = reg_to_bits(rn_hi);
4050 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4051 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4052 bytes.extend_from_slice(&hw1.to_le_bytes());
4053 bytes.extend_from_slice(&hw2.to_le_bytes());
4054
4055 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4058
4059 Condition::LE => {
4060 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4064
4065 let rm_hi_bits = reg_to_bits(rm_hi);
4067 let rn_hi_bits = reg_to_bits(rn_hi);
4068 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4069 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4070 bytes.extend_from_slice(&hw1.to_le_bytes());
4071 bytes.extend_from_slice(&hw2.to_le_bytes());
4072
4073 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4076
4077 Condition::GE => {
4078 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4081
4082 let rn_hi_bits = reg_to_bits(rn_hi);
4084 let rm_hi_bits = reg_to_bits(rm_hi);
4085 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4086 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4087 bytes.extend_from_slice(&hw1.to_le_bytes());
4088 bytes.extend_from_slice(&hw2.to_le_bytes());
4089
4090 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4093
4094 Condition::LO => {
4096 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4098 let rn_hi_bits = reg_to_bits(rn_hi);
4099 let rm_hi_bits = reg_to_bits(rm_hi);
4100 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4101 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4102 bytes.extend_from_slice(&hw1.to_le_bytes());
4103 bytes.extend_from_slice(&hw2.to_le_bytes());
4104 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4106
4107 Condition::HI => {
4108 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4110 let rm_hi_bits = reg_to_bits(rm_hi);
4111 let rn_hi_bits = reg_to_bits(rn_hi);
4112 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4113 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4114 bytes.extend_from_slice(&hw1.to_le_bytes());
4115 bytes.extend_from_slice(&hw2.to_le_bytes());
4116 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4118
4119 Condition::LS => {
4120 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4122 let rm_hi_bits = reg_to_bits(rm_hi);
4123 let rn_hi_bits = reg_to_bits(rn_hi);
4124 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4125 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4126 bytes.extend_from_slice(&hw1.to_le_bytes());
4127 bytes.extend_from_slice(&hw2.to_le_bytes());
4128 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
4130
4131 Condition::HS => {
4132 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4134 let rn_hi_bits = reg_to_bits(rn_hi);
4135 let rm_hi_bits = reg_to_bits(rm_hi);
4136 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4137 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4138 bytes.extend_from_slice(&hw1.to_le_bytes());
4139 bytes.extend_from_slice(&hw2.to_le_bytes());
4140 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
4142 }
4143
4144 Ok(bytes)
4145 }
4146
4147 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
4150 let rd_bits = reg_to_bits(rd);
4151 let rn_lo_bits = reg_to_bits(rn_lo);
4152 let rn_hi_bits = reg_to_bits(rn_hi);
4153 let mut bytes = Vec::new();
4154
4155 let hw1: u16 = (0xEA40 | rn_lo_bits) as u16;
4157 let hw2: u16 = ((rd_bits << 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 if rd_bits < 8 {
4166 let cmp_instr: u16 = 0x2800 | ((rd_bits as u16) << 8);
4167 bytes.extend_from_slice(&cmp_instr.to_le_bytes());
4168 } else {
4169 let hw1: u16 = 0xF1B0 | (rd_bits as u16);
4170 let hw2: u16 = 0x0F00;
4171 bytes.extend_from_slice(&hw1.to_le_bytes());
4172 bytes.extend_from_slice(&hw2.to_le_bytes());
4173 }
4174
4175 let mask = 0xC_u16; let ite_instr: u16 = 0xBF00 | mask;
4179 bytes.extend_from_slice(&ite_instr.to_le_bytes());
4180 if rd_bits < 8 {
4181 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
4182 let mov_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
4183 bytes.extend_from_slice(&mov_one.to_le_bytes());
4184 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4185 } else {
4186 for imm in [1u16, 0u16] {
4187 let hw1: u16 = 0xF04F;
4188 let hw2: u16 = ((rd_bits as u16) << 8) | imm;
4189 bytes.extend_from_slice(&hw1.to_le_bytes());
4190 bytes.extend_from_slice(&hw2.to_le_bytes());
4191 }
4192 }
4193
4194 Ok(bytes)
4195 }
4196
4197 ArmOp::I64Mul {
4201 rd_lo,
4202 rd_hi,
4203 rn_lo,
4204 rn_hi,
4205 rm_lo,
4206 rm_hi,
4207 } => {
4208 let rd_lo_bits = reg_to_bits(rd_lo);
4209 let rd_hi_bits = reg_to_bits(rd_hi);
4210 let rn_lo_bits = reg_to_bits(rn_lo);
4211 let rn_hi_bits = reg_to_bits(rn_hi);
4212 let rm_lo_bits = reg_to_bits(rm_lo);
4213 let rm_hi_bits = reg_to_bits(rm_hi);
4214 let r12: u32 = 12; let mut bytes = Vec::new();
4216
4217 let hw1: u16 = (0xFB00 | rn_lo_bits) as u16;
4220 let hw2: u16 = (0xF000 | (r12 << 8) | rm_hi_bits) as u16;
4221 bytes.extend_from_slice(&hw1.to_le_bytes());
4222 bytes.extend_from_slice(&hw2.to_le_bytes());
4223
4224 let hw1: u16 = (0xFB00 | rn_hi_bits) as u16;
4227 let hw2: u16 = ((r12 << 12) | (r12 << 8) | rm_lo_bits) as u16;
4228 bytes.extend_from_slice(&hw1.to_le_bytes());
4229 bytes.extend_from_slice(&hw2.to_le_bytes());
4230
4231 let hw1: u16 = (0xFBA0 | rn_lo_bits) as u16;
4234 let hw2: u16 = ((rd_lo_bits << 12) | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4235 bytes.extend_from_slice(&hw1.to_le_bytes());
4236 bytes.extend_from_slice(&hw2.to_le_bytes());
4237
4238 let d_bit = (rd_hi_bits >> 3) & 1;
4241 let add_instr: u16 =
4242 (0x4400 | (d_bit << 7) | (r12 << 3) | (rd_hi_bits & 0x7)) as u16;
4243 bytes.extend_from_slice(&add_instr.to_le_bytes());
4244
4245 Ok(bytes)
4246 }
4247
4248 ArmOp::I64Shl {
4251 rd_lo,
4252 rd_hi,
4253 rn_lo,
4254 rn_hi,
4255 rm_lo,
4256 rm_hi,
4257 } => {
4258 let rd_lo_bits = reg_to_bits(rd_lo);
4259 let rd_hi_bits = reg_to_bits(rd_hi);
4260 let rn_lo_bits = reg_to_bits(rn_lo);
4261 let rn_hi_bits = reg_to_bits(rn_hi);
4262 let rm_lo_bits = reg_to_bits(rm_lo);
4263 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4265
4266 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4268 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4269 bytes.extend_from_slice(&hw1.to_le_bytes());
4270 bytes.extend_from_slice(&hw2.to_le_bytes());
4271
4272 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4274 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4275 bytes.extend_from_slice(&hw1.to_le_bytes());
4276 bytes.extend_from_slice(&hw2.to_le_bytes());
4277
4278 let bpl: u16 = 0xD50A;
4280 bytes.extend_from_slice(&bpl.to_le_bytes());
4281
4282 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4285 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4286 bytes.extend_from_slice(&hw1.to_le_bytes());
4287 bytes.extend_from_slice(&hw2.to_le_bytes());
4288
4289 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4291 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4292 bytes.extend_from_slice(&hw1.to_le_bytes());
4293 bytes.extend_from_slice(&hw2.to_le_bytes());
4294
4295 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4297 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4298 bytes.extend_from_slice(&hw1.to_le_bytes());
4299 bytes.extend_from_slice(&hw2.to_le_bytes());
4300
4301 let hw1: u16 = (0xEA40 | rd_hi_bits) as u16;
4303 let hw2: u16 = ((rd_hi_bits << 8) | rm_hi_bits) as u16;
4304 bytes.extend_from_slice(&hw1.to_le_bytes());
4305 bytes.extend_from_slice(&hw2.to_le_bytes());
4306
4307 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4309 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4310 bytes.extend_from_slice(&hw1.to_le_bytes());
4311 bytes.extend_from_slice(&hw2.to_le_bytes());
4312
4313 let b_done: u16 = 0xE002;
4315 bytes.extend_from_slice(&b_done.to_le_bytes());
4316
4317 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4320 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_hi_bits) as u16;
4321 bytes.extend_from_slice(&hw1.to_le_bytes());
4322 bytes.extend_from_slice(&hw2.to_le_bytes());
4323
4324 let mov_zero: u16 = 0x2000 | ((rd_lo_bits as u16) << 8);
4326 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4327
4328 Ok(bytes) }
4330
4331 ArmOp::I64ShrU {
4333 rd_lo,
4334 rd_hi,
4335 rn_lo,
4336 rn_hi,
4337 rm_lo,
4338 rm_hi,
4339 } => {
4340 let rd_lo_bits = reg_to_bits(rd_lo);
4341 let rd_hi_bits = reg_to_bits(rd_hi);
4342 let rn_lo_bits = reg_to_bits(rn_lo);
4343 let rn_hi_bits = reg_to_bits(rn_hi);
4344 let rm_lo_bits = reg_to_bits(rm_lo);
4345 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4347
4348 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4350 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4351 bytes.extend_from_slice(&hw1.to_le_bytes());
4352 bytes.extend_from_slice(&hw2.to_le_bytes());
4353
4354 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4356 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4357 bytes.extend_from_slice(&hw1.to_le_bytes());
4358 bytes.extend_from_slice(&hw2.to_le_bytes());
4359
4360 let bpl: u16 = 0xD50A;
4362 bytes.extend_from_slice(&bpl.to_le_bytes());
4363
4364 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4367 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4368 bytes.extend_from_slice(&hw1.to_le_bytes());
4369 bytes.extend_from_slice(&hw2.to_le_bytes());
4370
4371 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4373 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4374 bytes.extend_from_slice(&hw1.to_le_bytes());
4375 bytes.extend_from_slice(&hw2.to_le_bytes());
4376
4377 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4379 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4380 bytes.extend_from_slice(&hw1.to_le_bytes());
4381 bytes.extend_from_slice(&hw2.to_le_bytes());
4382
4383 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4385 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4386 bytes.extend_from_slice(&hw1.to_le_bytes());
4387 bytes.extend_from_slice(&hw2.to_le_bytes());
4388
4389 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4391 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4392 bytes.extend_from_slice(&hw1.to_le_bytes());
4393 bytes.extend_from_slice(&hw2.to_le_bytes());
4394
4395 let b_done: u16 = 0xE002;
4397 bytes.extend_from_slice(&b_done.to_le_bytes());
4398
4399 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4402 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4403 bytes.extend_from_slice(&hw1.to_le_bytes());
4404 bytes.extend_from_slice(&hw2.to_le_bytes());
4405
4406 let mov_zero: u16 = 0x2000 | ((rd_hi_bits as u16) << 8);
4408 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4409
4410 Ok(bytes) }
4412
4413 ArmOp::I64ShrS {
4415 rd_lo,
4416 rd_hi,
4417 rn_lo,
4418 rn_hi,
4419 rm_lo,
4420 rm_hi,
4421 } => {
4422 let rd_lo_bits = reg_to_bits(rd_lo);
4423 let rd_hi_bits = reg_to_bits(rd_hi);
4424 let rn_lo_bits = reg_to_bits(rn_lo);
4425 let rn_hi_bits = reg_to_bits(rn_hi);
4426 let rm_lo_bits = reg_to_bits(rm_lo);
4427 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4429
4430 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4432 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4433 bytes.extend_from_slice(&hw1.to_le_bytes());
4434 bytes.extend_from_slice(&hw2.to_le_bytes());
4435
4436 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4438 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4439 bytes.extend_from_slice(&hw1.to_le_bytes());
4440 bytes.extend_from_slice(&hw2.to_le_bytes());
4441
4442 let bpl: u16 = 0xD50A;
4444 bytes.extend_from_slice(&bpl.to_le_bytes());
4445
4446 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4449 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4450 bytes.extend_from_slice(&hw1.to_le_bytes());
4451 bytes.extend_from_slice(&hw2.to_le_bytes());
4452
4453 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4455 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4456 bytes.extend_from_slice(&hw1.to_le_bytes());
4457 bytes.extend_from_slice(&hw2.to_le_bytes());
4458
4459 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4461 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4462 bytes.extend_from_slice(&hw1.to_le_bytes());
4463 bytes.extend_from_slice(&hw2.to_le_bytes());
4464
4465 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4467 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4468 bytes.extend_from_slice(&hw1.to_le_bytes());
4469 bytes.extend_from_slice(&hw2.to_le_bytes());
4470
4471 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4473 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4474 bytes.extend_from_slice(&hw1.to_le_bytes());
4475 bytes.extend_from_slice(&hw2.to_le_bytes());
4476
4477 let b_done: u16 = 0xE003;
4479 bytes.extend_from_slice(&b_done.to_le_bytes());
4480
4481 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4484 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4485 bytes.extend_from_slice(&hw1.to_le_bytes());
4486 bytes.extend_from_slice(&hw2.to_le_bytes());
4487
4488 let hw1: u16 = 0xEA4F;
4492 let hw2: u16 = (0x7000 | (rd_hi_bits << 8) | 0x00E0 | rn_hi_bits) as u16;
4493 bytes.extend_from_slice(&hw1.to_le_bytes());
4494 bytes.extend_from_slice(&hw2.to_le_bytes());
4495
4496 Ok(bytes) }
4498
4499 ArmOp::I64Rotl {
4510 rdlo,
4511 rdhi,
4512 rnlo,
4513 rnhi,
4514 shift,
4515 } => {
4516 let mut bytes = Vec::new();
4517 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4518
4519 let core: [u16; 35] = [
4520 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, ];
4543 for hw in core {
4544 bytes.extend_from_slice(&hw.to_le_bytes());
4545 }
4546
4547 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4548 Ok(bytes) }
4550
4551 ArmOp::I64Rotr {
4558 rdlo,
4559 rdhi,
4560 rnlo,
4561 rnhi,
4562 shift,
4563 } => {
4564 let mut bytes = Vec::new();
4565 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4566
4567 let core: [u16; 35] = [
4568 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, ];
4591 for hw in core {
4592 bytes.extend_from_slice(&hw.to_le_bytes());
4593 }
4594
4595 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4596 Ok(bytes) }
4598
4599 ArmOp::I64Clz { rd, rnlo, rnhi } => {
4613 let rd_bits = reg_to_bits(rd);
4614 let rn_lo_bits = reg_to_bits(rnlo);
4615 let rn_hi_bits = reg_to_bits(rnhi);
4616 let mut bytes = Vec::new();
4617
4618 let hw1: u16 = (0xF1B0 | rn_hi_bits) as u16;
4620 let hw2: u16 = 0x0F00;
4621 bytes.extend_from_slice(&hw1.to_le_bytes());
4622 bytes.extend_from_slice(&hw2.to_le_bytes());
4623
4624 let beq: u16 = 0xD003;
4627 bytes.extend_from_slice(&beq.to_le_bytes());
4628
4629 let hw1: u16 = (0xFAB0 | rn_hi_bits) as u16;
4632 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_hi_bits) as u16;
4633 bytes.extend_from_slice(&hw1.to_le_bytes());
4634 bytes.extend_from_slice(&hw2.to_le_bytes());
4635
4636 let b_done: u16 = 0xE004;
4639 bytes.extend_from_slice(&b_done.to_le_bytes());
4640
4641 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
4643
4644 let hw1: u16 = (0xFAB0 | rn_lo_bits) as u16;
4648 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_lo_bits) as u16;
4649 bytes.extend_from_slice(&hw1.to_le_bytes());
4650 bytes.extend_from_slice(&hw2.to_le_bytes());
4651
4652 let hw1: u16 = (0xF100 | rd_bits) as u16;
4654 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
4655 bytes.extend_from_slice(&hw1.to_le_bytes());
4656 bytes.extend_from_slice(&hw2.to_le_bytes());
4657
4658 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4662 bytes.extend_from_slice(&mov0.to_le_bytes());
4663
4664 Ok(bytes)
4665 }
4666
4667 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
4683 let rd_bits = reg_to_bits(rd);
4684 let rn_lo_bits = reg_to_bits(rnlo);
4685 let rn_hi_bits = reg_to_bits(rnhi);
4686 let mut bytes = Vec::new();
4687
4688 let hw1: u16 = (0xF1B0 | rn_lo_bits) as u16;
4690 let hw2: u16 = 0x0F00;
4691 bytes.extend_from_slice(&hw1.to_le_bytes());
4692 bytes.extend_from_slice(&hw2.to_le_bytes());
4693
4694 let beq: u16 = 0xD005;
4697 bytes.extend_from_slice(&beq.to_le_bytes());
4698
4699 let hw1: u16 = (0xFA90 | rn_lo_bits) as u16;
4702 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_lo_bits) as u16;
4703 bytes.extend_from_slice(&hw1.to_le_bytes());
4704 bytes.extend_from_slice(&hw2.to_le_bytes());
4705
4706 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
4709 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
4710 bytes.extend_from_slice(&hw1.to_le_bytes());
4711 bytes.extend_from_slice(&hw2.to_le_bytes());
4712
4713 let b_done: u16 = 0xE006;
4716 bytes.extend_from_slice(&b_done.to_le_bytes());
4717
4718 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
4720
4721 let hw1: u16 = (0xFA90 | rn_hi_bits) as u16;
4725 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_hi_bits) as u16;
4726 bytes.extend_from_slice(&hw1.to_le_bytes());
4727 bytes.extend_from_slice(&hw2.to_le_bytes());
4728
4729 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
4732 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
4733 bytes.extend_from_slice(&hw1.to_le_bytes());
4734 bytes.extend_from_slice(&hw2.to_le_bytes());
4735
4736 let hw1: u16 = (0xF100 | rd_bits) as u16;
4738 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
4739 bytes.extend_from_slice(&hw1.to_le_bytes());
4740 bytes.extend_from_slice(&hw2.to_le_bytes());
4741
4742 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4745 bytes.extend_from_slice(&mov0.to_le_bytes());
4746
4747 Ok(bytes)
4748 }
4749
4750 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
4754 let rd_bits = reg_to_bits(rd);
4755 let rn_lo_bits = reg_to_bits(rnlo);
4756 let rn_hi_bits = reg_to_bits(rnhi);
4757 let r12: u32 = 12; let r3: u32 = 3; let mut bytes = Vec::new();
4760
4761 bytes.extend_from_slice(&0xB438u16.to_le_bytes());
4763
4764 let mov: u16 = (0x4600 | (1 << 7) | (rn_lo_bits << 3) | 4) as u16;
4777 bytes.extend_from_slice(&mov.to_le_bytes());
4778 let mov: u16 = (0x4600 | (rn_hi_bits << 3) | 5) as u16;
4780 bytes.extend_from_slice(&mov.to_le_bytes());
4781 bytes.extend_from_slice(&0x4664u16.to_le_bytes());
4783
4784 let hw1: u16 = 0xEA4F;
4788 let hw2: u16 = ((r12 << 8) | 0x50 | 4) as u16;
4789 bytes.extend_from_slice(&hw1.to_le_bytes());
4790 bytes.extend_from_slice(&hw2.to_le_bytes());
4791
4792 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
4795 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4796 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
4798 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4799
4800 let hw1: u16 = (0xEA00 | r12) as u16;
4802 let hw2: u16 = ((r12 << 8) | r3) as u16;
4803 bytes.extend_from_slice(&hw1.to_le_bytes());
4804 bytes.extend_from_slice(&hw2.to_le_bytes());
4805
4806 let hw1: u16 = (0xEBA0 | 4) as u16;
4808 let hw2: u16 = ((4 << 8) | r12) as u16;
4809 bytes.extend_from_slice(&hw1.to_le_bytes());
4810 bytes.extend_from_slice(&hw2.to_le_bytes());
4811
4812 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
4816 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4817 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
4819 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4820
4821 let hw1: u16 = (0xEA00 | 4) as u16;
4823 let hw2: u16 = ((r12 << 8) | r3) as u16;
4824 bytes.extend_from_slice(&hw1.to_le_bytes());
4825 bytes.extend_from_slice(&hw2.to_le_bytes());
4826
4827 let hw1: u16 = 0xEA4F;
4829 let hw2: u16 = ((4 << 8) | 0x90 | 4) as u16;
4830 bytes.extend_from_slice(&hw1.to_le_bytes());
4831 bytes.extend_from_slice(&hw2.to_le_bytes());
4832
4833 let hw1: u16 = (0xEA00 | 4) as u16;
4835 let hw2: u16 = ((4 << 8) | r3) as u16;
4836 bytes.extend_from_slice(&hw1.to_le_bytes());
4837 bytes.extend_from_slice(&hw2.to_le_bytes());
4838
4839 let hw1: u16 = (0xEB00 | 4) as u16;
4841 let hw2: u16 = ((4 << 8) | r12) as u16;
4842 bytes.extend_from_slice(&hw1.to_le_bytes());
4843 bytes.extend_from_slice(&hw2.to_le_bytes());
4844
4845 let hw1: u16 = 0xEA4F;
4850 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 4) as u16;
4851 bytes.extend_from_slice(&hw1.to_le_bytes());
4852 bytes.extend_from_slice(&hw2.to_le_bytes());
4853
4854 let hw1: u16 = (0xEB00 | 4) as u16;
4856 let hw2: u16 = ((4 << 8) | r12) as u16;
4857 bytes.extend_from_slice(&hw1.to_le_bytes());
4858 bytes.extend_from_slice(&hw2.to_le_bytes());
4859
4860 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
4865 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4866 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
4868 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4869
4870 let hw1: u16 = (0xEA00 | 4) as u16;
4872 let hw2: u16 = ((4 << 8) | r3) as u16;
4873 bytes.extend_from_slice(&hw1.to_le_bytes());
4874 bytes.extend_from_slice(&hw2.to_le_bytes());
4875
4876 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
4880 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4881 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
4883 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4884
4885 let hw1: u16 = (0xFB00 | 4) as u16;
4888 let hw2: u16 = (0xF000 | (4 << 8) | r3) as u16;
4889 bytes.extend_from_slice(&hw1.to_le_bytes());
4890 bytes.extend_from_slice(&hw2.to_le_bytes());
4891
4892 let hw1: u16 = 0xEA4F;
4895 let hw2: u16 = (0x6000 | (4 << 8) | 0x10 | 4) as u16;
4896 bytes.extend_from_slice(&hw1.to_le_bytes());
4897 bytes.extend_from_slice(&hw2.to_le_bytes());
4898
4899 let hw1: u16 = 0xEA4F;
4902 let hw2: u16 = ((r12 << 8) | 0x50 | 5) as u16;
4903 bytes.extend_from_slice(&hw1.to_le_bytes());
4904 bytes.extend_from_slice(&hw2.to_le_bytes());
4905
4906 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
4908 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4909 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
4910 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4911
4912 let hw1: u16 = (0xEA00 | r12) as u16;
4913 let hw2: u16 = ((r12 << 8) | r3) as u16;
4914 bytes.extend_from_slice(&hw1.to_le_bytes());
4915 bytes.extend_from_slice(&hw2.to_le_bytes());
4916
4917 let hw1: u16 = (0xEBA0 | 5) as u16;
4918 let hw2: u16 = ((5 << 8) | r12) as u16;
4919 bytes.extend_from_slice(&hw1.to_le_bytes());
4920 bytes.extend_from_slice(&hw2.to_le_bytes());
4921
4922 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
4924 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4925 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
4926 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4927
4928 let hw1: u16 = (0xEA00 | 5) 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;
4934 let hw2: u16 = ((5 << 8) | 0x90 | 5) as u16;
4935 bytes.extend_from_slice(&hw1.to_le_bytes());
4936 bytes.extend_from_slice(&hw2.to_le_bytes());
4937
4938 let hw1: u16 = (0xEA00 | 5) as u16;
4939 let hw2: u16 = ((5 << 8) | r3) as u16;
4940 bytes.extend_from_slice(&hw1.to_le_bytes());
4941 bytes.extend_from_slice(&hw2.to_le_bytes());
4942
4943 let hw1: u16 = (0xEB00 | 5) as u16;
4944 let hw2: u16 = ((5 << 8) | r12) as u16;
4945 bytes.extend_from_slice(&hw1.to_le_bytes());
4946 bytes.extend_from_slice(&hw2.to_le_bytes());
4947
4948 let hw1: u16 = 0xEA4F;
4951 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 5) as u16;
4952 bytes.extend_from_slice(&hw1.to_le_bytes());
4953 bytes.extend_from_slice(&hw2.to_le_bytes());
4954
4955 let hw1: u16 = (0xEB00 | 5) as u16;
4956 let hw2: u16 = ((5 << 8) | r12) as u16;
4957 bytes.extend_from_slice(&hw1.to_le_bytes());
4958 bytes.extend_from_slice(&hw2.to_le_bytes());
4959
4960 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
4962 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4963 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
4964 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4965
4966 let hw1: u16 = (0xEA00 | 5) as u16;
4967 let hw2: u16 = ((5 << 8) | r3) as u16;
4968 bytes.extend_from_slice(&hw1.to_le_bytes());
4969 bytes.extend_from_slice(&hw2.to_le_bytes());
4970
4971 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
4973 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4974 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
4975 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4976
4977 let hw1: u16 = (0xFB00 | 5) as u16;
4980 let hw2: u16 = (0xF000 | (5 << 8) | r3) as u16;
4981 bytes.extend_from_slice(&hw1.to_le_bytes());
4982 bytes.extend_from_slice(&hw2.to_le_bytes());
4983
4984 let hw1: u16 = 0xEA4F;
4987 let hw2: u16 = (0x6000 | (5 << 8) | 0x10 | 5) as u16;
4988 bytes.extend_from_slice(&hw1.to_le_bytes());
4989 bytes.extend_from_slice(&hw2.to_le_bytes());
4990
4991 bytes.extend_from_slice(&0xEB04u16.to_le_bytes());
5000 bytes.extend_from_slice(&0x0C05u16.to_le_bytes());
5001
5002 bytes.extend_from_slice(&0xBC38u16.to_le_bytes());
5004
5005 let mov: u16 =
5009 (0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7)) as u16;
5010 bytes.extend_from_slice(&mov.to_le_bytes());
5011
5012 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5016 bytes.extend_from_slice(&(((rn_hi_bits & 0xF) << 8) as u16).to_le_bytes());
5017
5018 Ok(bytes)
5019 }
5020
5021 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
5024 let rdlo_bits = reg_to_bits(rdlo);
5025 let rdhi_bits = reg_to_bits(rdhi);
5026 let rnlo_bits = reg_to_bits(rnlo);
5027 let mut bytes = Vec::new();
5028
5029 let hw1: u16 = 0xFA4F_u16;
5032 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5033 bytes.extend_from_slice(&hw1.to_le_bytes());
5034 bytes.extend_from_slice(&hw2.to_le_bytes());
5035
5036 let hw1: u16 = 0xEA4F;
5041 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5042 bytes.extend_from_slice(&hw1.to_le_bytes());
5043 bytes.extend_from_slice(&hw2.to_le_bytes());
5044
5045 Ok(bytes)
5046 }
5047
5048 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
5051 let rdlo_bits = reg_to_bits(rdlo);
5052 let rdhi_bits = reg_to_bits(rdhi);
5053 let rnlo_bits = reg_to_bits(rnlo);
5054 let mut bytes = Vec::new();
5055
5056 let hw1: u16 = 0xFA0F_u16;
5059 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5060 bytes.extend_from_slice(&hw1.to_le_bytes());
5061 bytes.extend_from_slice(&hw2.to_le_bytes());
5062
5063 let hw1: u16 = 0xEA4F;
5065 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5066 bytes.extend_from_slice(&hw1.to_le_bytes());
5067 bytes.extend_from_slice(&hw2.to_le_bytes());
5068
5069 Ok(bytes)
5070 }
5071
5072 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
5075 let rdlo_bits = reg_to_bits(rdlo);
5076 let rdhi_bits = reg_to_bits(rdhi);
5077 let rnlo_bits = reg_to_bits(rnlo);
5078 let mut bytes = Vec::new();
5079
5080 if rdlo_bits != rnlo_bits {
5082 let d_bit = ((rdlo_bits >> 3) & 1) as u16;
5084 let mov: u16 = 0x4600
5085 | (d_bit << 7)
5086 | ((rnlo_bits as u16) << 3)
5087 | ((rdlo_bits & 0x7) as u16);
5088 bytes.extend_from_slice(&mov.to_le_bytes());
5089 }
5090
5091 let hw1: u16 = 0xEA4F;
5093 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rnlo_bits) as u16;
5094 bytes.extend_from_slice(&hw1.to_le_bytes());
5095 bytes.extend_from_slice(&hw2.to_le_bytes());
5096
5097 Ok(bytes)
5098 }
5099
5100 ArmOp::SelectMove { rd, rm, cond } => {
5103 let rd_bits = reg_to_bits(rd) as u16;
5104 let rm_bits = reg_to_bits(rm) as u16;
5105
5106 use synth_synthesis::Condition;
5108 let cond_bits: u16 = match cond {
5109 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, };
5120
5121 let it_instr: u16 = 0xBF00 | (cond_bits << 4) | 0x8;
5124
5125 let d_bit = (rd_bits >> 3) & 1;
5128 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5129
5130 let mut bytes = it_instr.to_le_bytes().to_vec();
5132 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5133 Ok(bytes)
5134 }
5135
5136 ArmOp::Popcnt { rd, rm } => {
5147 let mut bytes = Vec::new();
5148
5149 if rd != rm {
5151 let rd_bits = reg_to_bits(rd) as u16;
5152 let rm_bits = reg_to_bits(rm) as u16;
5153 let d_bit = (rd_bits >> 3) & 1;
5155 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5156 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5157 }
5158
5159 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x5555)?);
5162 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x5555)?);
5163
5164 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 1)?);
5167
5168 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(11, 11, 12)?);
5170
5171 bytes.extend_from_slice(&self.encode_thumb32_sub_reg_raw(
5173 reg_to_bits(rd),
5174 reg_to_bits(rd),
5175 11,
5176 )?);
5177
5178 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x3333)?);
5181 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x3333)?);
5182
5183 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5185 11,
5186 reg_to_bits(rd),
5187 12,
5188 )?);
5189
5190 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(
5192 reg_to_bits(rd),
5193 reg_to_bits(rd),
5194 2,
5195 )?);
5196
5197 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5199 reg_to_bits(rd),
5200 reg_to_bits(rd),
5201 12,
5202 )?);
5203
5204 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5206 reg_to_bits(rd),
5207 reg_to_bits(rd),
5208 11,
5209 )?);
5210
5211 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 4)?);
5214
5215 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5217 reg_to_bits(rd),
5218 reg_to_bits(rd),
5219 11,
5220 )?);
5221
5222 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x0F0F)?);
5224 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x0F0F)?);
5225
5226 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5228 reg_to_bits(rd),
5229 reg_to_bits(rd),
5230 12,
5231 )?);
5232
5233 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 8)?);
5236
5237 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5239 reg_to_bits(rd),
5240 reg_to_bits(rd),
5241 11,
5242 )?);
5243
5244 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 16)?);
5247
5248 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5250 reg_to_bits(rd),
5251 reg_to_bits(rd),
5252 11,
5253 )?);
5254
5255 bytes.extend_from_slice(&self.encode_thumb32_and_imm_raw(
5258 reg_to_bits(rd),
5259 reg_to_bits(rd),
5260 0x3F,
5261 )?);
5262
5263 Ok(bytes)
5264 }
5265
5266 ArmOp::I64DivU {
5277 rdlo,
5278 rdhi,
5279 rnlo,
5280 rnhi,
5281 rmlo,
5282 rmhi,
5283 } => {
5284 let mut bytes = Vec::new();
5285 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5286 emit_i64_divisor_zero_trap(&mut bytes);
5287
5288 bytes.extend_from_slice(&0xB4F0u16.to_le_bytes());
5292
5293 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());
5304 bytes.extend_from_slice(&0x0C40u16.to_le_bytes());
5305
5306 let loop_start = bytes.len();
5308
5309 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes());
5320 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());
5329 bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
5330 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes());
5334 bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5335
5336 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes());
5341 bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5342 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());
5373 bytes.extend_from_slice(&0x0703u16.to_le_bytes());
5374 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5377
5378 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
5382 bytes.extend_from_slice(&0x0C01u16.to_le_bytes());
5383
5384 let branch_offset_bytes = bytes.len() - loop_start + 4; let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5387 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5388 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5389
5390 bytes.extend_from_slice(&0x4620u16.to_le_bytes()); bytes.extend_from_slice(&0x4629u16.to_le_bytes()); bytes.extend_from_slice(&0xBCF0u16.to_le_bytes());
5398
5399 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5400 Ok(bytes)
5401 }
5402
5403 ArmOp::I64DivS {
5409 rdlo,
5410 rdhi,
5411 rnlo,
5412 rnhi,
5413 rmlo,
5414 rmhi,
5415 } => {
5416 let mut bytes = Vec::new();
5417 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5418 emit_i64_divisor_zero_trap(&mut bytes);
5419 emit_i64_divs_overflow_trap(&mut bytes);
5422
5423 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5425 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5426
5427 bytes.extend_from_slice(&0xEA81u16.to_le_bytes());
5430 bytes.extend_from_slice(&0x0903u16.to_le_bytes());
5431
5432 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());
5445
5446 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());
5456
5457 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5460 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5461 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5463 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5464 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5466 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5467
5468 let loop_start = bytes.len();
5469
5470 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5474 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());
5480 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5483
5484 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5488 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());
5501 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5503
5504 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5507
5508 let branch_offset_bytes = bytes.len() - loop_start + 4;
5509 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5510 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5511 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5512
5513 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());
5520 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());
5528
5529 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5531 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5532
5533 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5534 Ok(bytes)
5535 }
5536
5537 ArmOp::I64RemU {
5542 rdlo,
5543 rdhi,
5544 rnlo,
5545 rnhi,
5546 rmlo,
5547 rmhi,
5548 } => {
5549 let mut bytes = Vec::new();
5550 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5551 emit_i64_divisor_zero_trap(&mut bytes);
5552
5553 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5555 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5556
5557 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5559 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5560 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5562 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5563 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5565 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5566
5567 let loop_start = bytes.len();
5568
5569 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5573 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());
5579 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5582
5583 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5587 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());
5600 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5602
5603 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5606
5607 let branch_offset_bytes = bytes.len() - loop_start + 4;
5608 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5609 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5610 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5611
5612 bytes.extend_from_slice(&0x4630u16.to_le_bytes()); bytes.extend_from_slice(&0x4639u16.to_le_bytes()); bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5618 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5619
5620 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5621 Ok(bytes)
5622 }
5623
5624 ArmOp::I64RemS {
5630 rdlo,
5631 rdhi,
5632 rnlo,
5633 rnhi,
5634 rmlo,
5635 rmhi,
5636 } => {
5637 let mut bytes = Vec::new();
5638 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5639 emit_i64_divisor_zero_trap(&mut bytes);
5640
5641 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5643 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5644
5645 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());
5659
5660 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());
5670
5671 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5674 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5675 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5677 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5678 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5680 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5681
5682 let loop_start = bytes.len();
5683
5684 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5688 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());
5694 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5697
5698 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5702 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());
5715 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5717
5718 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5721
5722 let branch_offset_bytes = bytes.len() - loop_start + 4;
5723 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5724 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5725 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5726
5727 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());
5734 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());
5742
5743 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5745 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5746
5747 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5748 Ok(bytes)
5749 }
5750
5751 ArmOp::F32Add { sd, sn, sm } => {
5754 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A00, sd, sn, sm)?))
5755 }
5756 ArmOp::F32Sub { sd, sn, sm } => {
5757 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A40, sd, sn, sm)?))
5758 }
5759 ArmOp::F32Mul { sd, sn, sm } => {
5760 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE200A00, sd, sn, sm)?))
5761 }
5762 ArmOp::F32Div { sd, sn, sm } => {
5763 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE800A00, sd, sn, sm)?))
5764 }
5765 ArmOp::F32Abs { sd, sm } => {
5766 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB00AC0, sd, sm)?))
5767 }
5768 ArmOp::F32Neg { sd, sm } => {
5769 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10A40, sd, sm)?))
5770 }
5771 ArmOp::F32Sqrt { sd, sm } => {
5772 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10AC0, sd, sm)?))
5773 }
5774
5775 ArmOp::F32Ceil { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b01),
5778 ArmOp::F32Floor { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b10),
5779 ArmOp::F32Trunc { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b11),
5780 ArmOp::F32Nearest { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b00),
5781 ArmOp::F32Min { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, true),
5782 ArmOp::F32Max { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, false),
5783 ArmOp::F32Copysign { sd, sn, sm } => self.encode_thumb_f32_copysign(sd, sn, sm),
5784
5785 ArmOp::F32Eq { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x0),
5787 ArmOp::F32Ne { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x1),
5788 ArmOp::F32Lt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x4),
5789 ArmOp::F32Le { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x9),
5790 ArmOp::F32Gt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xC),
5791 ArmOp::F32Ge { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xA),
5792
5793 ArmOp::F32Const { sd, value } => self.encode_thumb_f32_const(sd, *value),
5794
5795 ArmOp::F32Load { sd, addr } => {
5796 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED900A00, sd, addr)?))
5797 }
5798 ArmOp::F32Store { sd, addr } => {
5799 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED800A00, sd, addr)?))
5800 }
5801
5802 ArmOp::F32ConvertI32S { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, true),
5803 ArmOp::F32ConvertI32U { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, false),
5804 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
5805 Err(synth_core::Error::synthesis(
5806 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
5807 ))
5808 }
5809 ArmOp::F32ReinterpretI32 { sd, rm } => {
5810 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(true, sd, rm)?))
5811 }
5812 ArmOp::I32ReinterpretF32 { rd, sm } => {
5813 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(false, sm, rd)?))
5814 }
5815 ArmOp::I32TruncF32S { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, true),
5816 ArmOp::I32TruncF32U { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, false),
5817
5818 ArmOp::F64Add { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5821 0xEE300B00, dd, dn, dm,
5822 )?)),
5823 ArmOp::F64Sub { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5824 0xEE300B40, dd, dn, dm,
5825 )?)),
5826 ArmOp::F64Mul { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5827 0xEE200B00, dd, dn, dm,
5828 )?)),
5829 ArmOp::F64Div { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5830 0xEE800B00, dd, dn, dm,
5831 )?)),
5832 ArmOp::F64Abs { dd, dm } => {
5833 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?))
5834 }
5835 ArmOp::F64Neg { dd, dm } => {
5836 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?))
5837 }
5838 ArmOp::F64Sqrt { dd, dm } => {
5839 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?))
5840 }
5841
5842 ArmOp::F64Ceil { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b01),
5845 ArmOp::F64Floor { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b10),
5846 ArmOp::F64Trunc { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b11),
5847 ArmOp::F64Nearest { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b00),
5848 ArmOp::F64Min { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, true),
5849 ArmOp::F64Max { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, false),
5850 ArmOp::F64Copysign { dd, dn, dm } => self.encode_thumb_f64_copysign(dd, dn, dm),
5851
5852 ArmOp::F64Eq { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x0),
5854 ArmOp::F64Ne { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x1),
5855 ArmOp::F64Lt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x4),
5856 ArmOp::F64Le { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x9),
5857 ArmOp::F64Gt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xC),
5858 ArmOp::F64Ge { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xA),
5859
5860 ArmOp::F64Const { dd, value } => self.encode_thumb_f64_const(dd, *value),
5861
5862 ArmOp::F64Load { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
5863 0xED900B00, dd, addr,
5864 )?)),
5865 ArmOp::F64Store { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
5866 0xED800B00, dd, addr,
5867 )?)),
5868
5869 ArmOp::F64ConvertI32S { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, true),
5870 ArmOp::F64ConvertI32U { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, false),
5871 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
5872 Err(synth_core::Error::synthesis(
5873 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
5874 ))
5875 }
5876 ArmOp::F64PromoteF32 { dd, sm } => self.encode_thumb_f64_promote_f32(dd, sm),
5877 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => Ok(vfp_to_thumb_bytes(
5878 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?,
5879 )),
5880 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => Ok(vfp_to_thumb_bytes(
5881 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?,
5882 )),
5883 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
5884 Err(synth_core::Error::synthesis(
5885 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
5886 ))
5887 }
5888 ArmOp::I32TruncF64S { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, true),
5889 ArmOp::I32TruncF64U { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, false),
5890
5891 ArmOp::I64Add {
5895 rdlo,
5896 rdhi,
5897 rnlo,
5898 rnhi,
5899 rmlo,
5900 rmhi,
5901 } => {
5902 let mut bytes = Vec::new();
5903 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adds {
5905 rd: *rdlo,
5906 rn: *rnlo,
5907 op2: Operand2::Reg(*rmlo),
5908 })?);
5909 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adc {
5911 rd: *rdhi,
5912 rn: *rnhi,
5913 op2: Operand2::Reg(*rmhi),
5914 })?);
5915 Ok(bytes)
5916 }
5917
5918 ArmOp::I64Sub {
5920 rdlo,
5921 rdhi,
5922 rnlo,
5923 rnhi,
5924 rmlo,
5925 rmhi,
5926 } => {
5927 let mut bytes = Vec::new();
5928 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Subs {
5930 rd: *rdlo,
5931 rn: *rnlo,
5932 op2: Operand2::Reg(*rmlo),
5933 })?);
5934 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Sbc {
5936 rd: *rdhi,
5937 rn: *rnhi,
5938 op2: Operand2::Reg(*rmhi),
5939 })?);
5940 Ok(bytes)
5941 }
5942
5943 ArmOp::I64And {
5945 rdlo,
5946 rdhi,
5947 rnlo,
5948 rnhi,
5949 rmlo,
5950 rmhi,
5951 } => {
5952 let mut bytes = Vec::new();
5953 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
5954 rd: *rdlo,
5955 rn: *rnlo,
5956 op2: Operand2::Reg(*rmlo),
5957 })?);
5958 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
5959 rd: *rdhi,
5960 rn: *rnhi,
5961 op2: Operand2::Reg(*rmhi),
5962 })?);
5963 Ok(bytes)
5964 }
5965
5966 ArmOp::I64Or {
5968 rdlo,
5969 rdhi,
5970 rnlo,
5971 rnhi,
5972 rmlo,
5973 rmhi,
5974 } => {
5975 let mut bytes = Vec::new();
5976 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
5977 rd: *rdlo,
5978 rn: *rnlo,
5979 op2: Operand2::Reg(*rmlo),
5980 })?);
5981 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
5982 rd: *rdhi,
5983 rn: *rnhi,
5984 op2: Operand2::Reg(*rmhi),
5985 })?);
5986 Ok(bytes)
5987 }
5988
5989 ArmOp::I64Xor {
5991 rdlo,
5992 rdhi,
5993 rnlo,
5994 rnhi,
5995 rmlo,
5996 rmhi,
5997 } => {
5998 let mut bytes = Vec::new();
5999 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6000 rd: *rdlo,
6001 rn: *rnlo,
6002 op2: Operand2::Reg(*rmlo),
6003 })?);
6004 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6005 rd: *rdhi,
6006 rn: *rnhi,
6007 op2: Operand2::Reg(*rmhi),
6008 })?);
6009 Ok(bytes)
6010 }
6011
6012 ArmOp::I64Eqz { rd, rnlo, rnhi } => self.encode_thumb(&ArmOp::I64SetCondZ {
6014 rd: *rd,
6015 rn_lo: *rnlo,
6016 rn_hi: *rnhi,
6017 }),
6018
6019 ArmOp::I64Eq {
6021 rd,
6022 rnlo,
6023 rnhi,
6024 rmlo,
6025 rmhi,
6026 } => self.encode_thumb(&ArmOp::I64SetCond {
6027 rd: *rd,
6028 rn_lo: *rnlo,
6029 rn_hi: *rnhi,
6030 rm_lo: *rmlo,
6031 rm_hi: *rmhi,
6032 cond: synth_synthesis::Condition::EQ,
6033 }),
6034
6035 ArmOp::I64Ne {
6036 rd,
6037 rnlo,
6038 rnhi,
6039 rmlo,
6040 rmhi,
6041 } => self.encode_thumb(&ArmOp::I64SetCond {
6042 rd: *rd,
6043 rn_lo: *rnlo,
6044 rn_hi: *rnhi,
6045 rm_lo: *rmlo,
6046 rm_hi: *rmhi,
6047 cond: synth_synthesis::Condition::NE,
6048 }),
6049
6050 ArmOp::I64LtS {
6051 rd,
6052 rnlo,
6053 rnhi,
6054 rmlo,
6055 rmhi,
6056 } => self.encode_thumb(&ArmOp::I64SetCond {
6057 rd: *rd,
6058 rn_lo: *rnlo,
6059 rn_hi: *rnhi,
6060 rm_lo: *rmlo,
6061 rm_hi: *rmhi,
6062 cond: synth_synthesis::Condition::LT,
6063 }),
6064
6065 ArmOp::I64LtU {
6066 rd,
6067 rnlo,
6068 rnhi,
6069 rmlo,
6070 rmhi,
6071 } => self.encode_thumb(&ArmOp::I64SetCond {
6072 rd: *rd,
6073 rn_lo: *rnlo,
6074 rn_hi: *rnhi,
6075 rm_lo: *rmlo,
6076 rm_hi: *rmhi,
6077 cond: synth_synthesis::Condition::LO,
6078 }),
6079
6080 ArmOp::I64LeS {
6081 rd,
6082 rnlo,
6083 rnhi,
6084 rmlo,
6085 rmhi,
6086 } => self.encode_thumb(&ArmOp::I64SetCond {
6087 rd: *rd,
6088 rn_lo: *rnlo,
6089 rn_hi: *rnhi,
6090 rm_lo: *rmlo,
6091 rm_hi: *rmhi,
6092 cond: synth_synthesis::Condition::LE,
6093 }),
6094
6095 ArmOp::I64LeU {
6096 rd,
6097 rnlo,
6098 rnhi,
6099 rmlo,
6100 rmhi,
6101 } => self.encode_thumb(&ArmOp::I64SetCond {
6102 rd: *rd,
6103 rn_lo: *rnlo,
6104 rn_hi: *rnhi,
6105 rm_lo: *rmlo,
6106 rm_hi: *rmhi,
6107 cond: synth_synthesis::Condition::LS,
6108 }),
6109
6110 ArmOp::I64GtS {
6111 rd,
6112 rnlo,
6113 rnhi,
6114 rmlo,
6115 rmhi,
6116 } => self.encode_thumb(&ArmOp::I64SetCond {
6117 rd: *rd,
6118 rn_lo: *rnlo,
6119 rn_hi: *rnhi,
6120 rm_lo: *rmlo,
6121 rm_hi: *rmhi,
6122 cond: synth_synthesis::Condition::GT,
6123 }),
6124
6125 ArmOp::I64GtU {
6126 rd,
6127 rnlo,
6128 rnhi,
6129 rmlo,
6130 rmhi,
6131 } => self.encode_thumb(&ArmOp::I64SetCond {
6132 rd: *rd,
6133 rn_lo: *rnlo,
6134 rn_hi: *rnhi,
6135 rm_lo: *rmlo,
6136 rm_hi: *rmhi,
6137 cond: synth_synthesis::Condition::HI,
6138 }),
6139
6140 ArmOp::I64GeS {
6141 rd,
6142 rnlo,
6143 rnhi,
6144 rmlo,
6145 rmhi,
6146 } => self.encode_thumb(&ArmOp::I64SetCond {
6147 rd: *rd,
6148 rn_lo: *rnlo,
6149 rn_hi: *rnhi,
6150 rm_lo: *rmlo,
6151 rm_hi: *rmhi,
6152 cond: synth_synthesis::Condition::GE,
6153 }),
6154
6155 ArmOp::I64GeU {
6156 rd,
6157 rnlo,
6158 rnhi,
6159 rmlo,
6160 rmhi,
6161 } => self.encode_thumb(&ArmOp::I64SetCond {
6162 rd: *rd,
6163 rn_lo: *rnlo,
6164 rn_hi: *rnhi,
6165 rm_lo: *rmlo,
6166 rm_hi: *rmhi,
6167 cond: synth_synthesis::Condition::HS,
6168 }),
6169
6170 ArmOp::I64Const { rdlo, rdhi, value } => {
6172 let lo32 = *value as u32;
6173 let hi32 = (*value >> 32) as u32;
6174 let mut bytes = Vec::new();
6175 bytes.extend_from_slice(
6177 &self.encode_thumb32_movw_raw(reg_to_bits(rdlo), lo32 & 0xFFFF)?,
6178 );
6179 if lo32 > 0xFFFF {
6180 bytes.extend_from_slice(
6181 &self.encode_thumb32_movt_raw(reg_to_bits(rdlo), lo32 >> 16)?,
6182 );
6183 }
6184 bytes.extend_from_slice(
6186 &self.encode_thumb32_movw_raw(reg_to_bits(rdhi), hi32 & 0xFFFF)?,
6187 );
6188 if hi32 > 0xFFFF {
6189 bytes.extend_from_slice(
6190 &self.encode_thumb32_movt_raw(reg_to_bits(rdhi), hi32 >> 16)?,
6191 );
6192 }
6193 Ok(bytes)
6194 }
6195
6196 ArmOp::I64Ldr { rdlo, rdhi, addr } => {
6198 let mut bytes = Vec::new();
6199 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6210 bytes.extend_from_slice(&self.encode_thumb32_ldr(rdlo, &base, offset)?);
6211 bytes.extend_from_slice(&self.encode_thumb32_ldr(
6212 rdhi,
6213 &base,
6214 offset.wrapping_add(4),
6215 )?);
6216 Ok(bytes)
6217 }
6218
6219 ArmOp::I64Str { rdlo, rdhi, addr } => {
6221 let mut bytes = Vec::new();
6222 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6225 bytes.extend_from_slice(&self.encode_thumb32_str(rdlo, &base, offset)?);
6226 bytes.extend_from_slice(&self.encode_thumb32_str(
6227 rdhi,
6228 &base,
6229 offset.wrapping_add(4),
6230 )?);
6231 Ok(bytes)
6232 }
6233
6234 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
6236 let mut bytes = Vec::new();
6237 if rdlo != rn {
6238 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6240 rd: *rdlo,
6241 op2: Operand2::Reg(*rn),
6242 })?);
6243 }
6244 bytes.extend_from_slice(
6246 &self.encode_thumb32_shift(rdhi, rdlo, 31, 0b10)?, );
6248 Ok(bytes)
6249 }
6250
6251 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
6253 let mut bytes = Vec::new();
6254 if rdlo != rn {
6255 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6257 rd: *rdlo,
6258 op2: Operand2::Reg(*rn),
6259 })?);
6260 }
6261 let rdhi_bits = reg_to_bits(rdhi) as u16;
6263 let instr: u16 = 0x2000 | (rdhi_bits << 8);
6264 bytes.extend_from_slice(&instr.to_le_bytes());
6265 Ok(bytes)
6266 }
6267
6268 ArmOp::I32WrapI64 { rd, rnlo } => {
6270 if rd == rnlo {
6271 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6274 } else {
6275 self.encode_thumb(&ArmOp::Mov {
6277 rd: *rd,
6278 op2: Operand2::Reg(*rnlo),
6279 })
6280 }
6281 }
6282
6283 ArmOp::MveLoad { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vldrw(qd, addr))),
6285 ArmOp::MveStore { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vstrw(qd, addr))),
6286 ArmOp::MveConst { qd, bytes } => self.encode_thumb_mve_const(qd, bytes),
6287 ArmOp::MveAnd { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6288 0xEF000150, qd, qn, qm,
6289 ))),
6290 ArmOp::MveOrr { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6291 0xEF200150, qd, qn, qm,
6292 ))),
6293 ArmOp::MveEor { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6294 0xFF000150, qd, qn, qm,
6295 ))),
6296 ArmOp::MveMvn { qd, qm } => {
6297 let qd_enc = qreg_to_num(qd);
6299 let qm_enc = qreg_to_num(qm);
6300 let instr: u32 = 0xFFB005C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6301 Ok(vfp_to_thumb_bytes(instr))
6302 }
6303 ArmOp::MveBic { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6304 0xEF100150, qd, qn, qm,
6305 ))),
6306 ArmOp::MveAddI { qd, qn, qm, size } => {
6307 let sz = mve_size_bits(size);
6308 let base: u32 = 0xEF000840 | (sz << 20);
6309 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6310 }
6311 ArmOp::MveSubI { qd, qn, qm, size } => {
6312 let sz = mve_size_bits(size);
6313 let base: u32 = 0xFF000840 | (sz << 20);
6314 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6315 }
6316 ArmOp::MveMulI { qd, qn, qm, size } => {
6317 let sz = mve_size_bits(size);
6318 let base: u32 = 0xEF000950 | (sz << 20);
6319 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6320 }
6321 ArmOp::MveNegI { qd, qm, size } => {
6322 let sz = mve_size_bits(size);
6323 let qd_enc = qreg_to_num(qd);
6325 let qm_enc = qreg_to_num(qm);
6326 let base: u32 = 0xFFB103C0 | (sz << 18);
6327 let instr = base | ((qd_enc * 2) << 12) | (qm_enc * 2);
6328 Ok(vfp_to_thumb_bytes(instr))
6329 }
6330 ArmOp::MveDup { qd, rn, size } => {
6331 let sz = mve_size_bits(size);
6332 let qd_enc = qreg_to_num(qd);
6333 let rn_bits = reg_to_bits(rn);
6334 let be = match sz {
6337 0 => 0b00u32, 1 => 0b01, _ => 0b00, };
6341 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12) | (be << 5);
6342 Ok(vfp_to_thumb_bytes(instr))
6343 }
6344 ArmOp::MveExtractLane { rd, qn, lane, size } => {
6345 let qn_enc = qreg_to_num(qn);
6346 let rd_bits = reg_to_bits(rd);
6347 let d_reg = qn_enc * 2 + ((*lane as u32) >> 1);
6350 let lane_in_d = (*lane as u32) & 1;
6351 let _sz = mve_size_bits(size);
6352 let instr: u32 = 0xEE100B10 | (d_reg << 16) | (rd_bits << 12) | (lane_in_d << 21);
6354 Ok(vfp_to_thumb_bytes(instr))
6355 }
6356 ArmOp::MveInsertLane { qd, rn, lane, size } => {
6357 let qd_enc = qreg_to_num(qd);
6358 let rn_bits = reg_to_bits(rn);
6359 let d_reg = qd_enc * 2 + ((*lane as u32) >> 1);
6360 let lane_in_d = (*lane as u32) & 1;
6361 let _sz = mve_size_bits(size);
6362 let instr: u32 = 0xEE000B10 | (d_reg << 16) | (rn_bits << 12) | (lane_in_d << 21);
6364 Ok(vfp_to_thumb_bytes(instr))
6365 }
6366
6367 ArmOp::MveCmpEqI { qd, qn, qm, size }
6369 | ArmOp::MveCmpNeI { qd, qn, qm, size }
6370 | ArmOp::MveCmpLtS { qd, qn, qm, size }
6371 | ArmOp::MveCmpLtU { qd, qn, qm, size }
6372 | ArmOp::MveCmpGtS { qd, qn, qm, size }
6373 | ArmOp::MveCmpGtU { qd, qn, qm, size }
6374 | ArmOp::MveCmpLeS { qd, qn, qm, size }
6375 | ArmOp::MveCmpLeU { qd, qn, qm, size }
6376 | ArmOp::MveCmpGeS { qd, qn, qm, size }
6377 | ArmOp::MveCmpGeU { qd, qn, qm, size } => {
6378 let sz = mve_size_bits(size);
6381 let base: u32 = 0xEF000840 | (sz << 20);
6382 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6383 }
6384
6385 ArmOp::MveAddF32 { qd, qn, qm } => {
6387 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6389 }
6390 ArmOp::MveSubF32 { qd, qn, qm } => {
6391 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF200D40, qd, qn, qm)))
6393 }
6394 ArmOp::MveMulF32 { qd, qn, qm } => {
6395 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xFF000D50, qd, qn, qm)))
6397 }
6398 ArmOp::MveNegF32 { qd, qm } => {
6399 let qd_enc = qreg_to_num(qd);
6400 let qm_enc = qreg_to_num(qm);
6401 let instr: u32 = 0xFFB907C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6403 Ok(vfp_to_thumb_bytes(instr))
6404 }
6405 ArmOp::MveAbsF32 { qd, qm } => {
6406 let qd_enc = qreg_to_num(qd);
6407 let qm_enc = qreg_to_num(qm);
6408 let instr: u32 = 0xFFB90740 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6410 Ok(vfp_to_thumb_bytes(instr))
6411 }
6412 ArmOp::MveCmpEqF32 { qd, qn, qm }
6413 | ArmOp::MveCmpNeF32 { qd, qn, qm }
6414 | ArmOp::MveCmpLtF32 { qd, qn, qm }
6415 | ArmOp::MveCmpLeF32 { qd, qn, qm }
6416 | ArmOp::MveCmpGtF32 { qd, qn, qm }
6417 | ArmOp::MveCmpGeF32 { qd, qn, qm } => {
6418 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6420 }
6421 ArmOp::MveDupF32 { qd, rn } => {
6422 let qd_enc = qreg_to_num(qd);
6423 let rn_bits = reg_to_bits(rn);
6424 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12);
6426 Ok(vfp_to_thumb_bytes(instr))
6427 }
6428 ArmOp::MveExtractLaneF32 { rd, qn, lane } => {
6429 let qn_enc = qreg_to_num(qn);
6430 let rd_bits = reg_to_bits(rd);
6431 let s_num = qn_enc * 4 + (*lane as u32);
6433 let (vn, n) = encode_sreg(s_num);
6434 let instr: u32 = 0xEE100A10 | (vn << 16) | (rd_bits << 12) | (n << 7);
6435 Ok(vfp_to_thumb_bytes(instr))
6436 }
6437 ArmOp::MveReplaceLaneF32 { qd, rn, lane } => {
6438 let qd_enc = qreg_to_num(qd);
6439 let rn_bits = reg_to_bits(rn);
6440 let s_num = qd_enc * 4 + (*lane as u32);
6442 let (vn, n) = encode_sreg(s_num);
6443 let instr: u32 = 0xEE000A10 | (vn << 16) | (rn_bits << 12) | (n << 7);
6444 Ok(vfp_to_thumb_bytes(instr))
6445 }
6446 ArmOp::MveDivF32 { qd, qn, qm } => {
6447 self.encode_thumb_mve_lane_wise_f32_binop(qd, qn, qm, 0xEE800A00)
6449 }
6450 ArmOp::MveSqrtF32 { qd, qm } => {
6451 self.encode_thumb_mve_lane_wise_f32_sqrt(qd, qm)
6453 }
6454
6455 _ => {
6457 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6459 }
6460 }
6461 }
6462
6463 fn encode_thumb_f32_compare(
6467 &self,
6468 rd: &Reg,
6469 sn: &VfpReg,
6470 sm: &VfpReg,
6471 cond_code: u32,
6472 ) -> Result<Vec<u8>> {
6473 let mut bytes = Vec::new();
6474 let rd_bits = reg_to_bits(rd);
6475
6476 let sn_num = vfp_sreg_to_num(sn)?;
6478 let sm_num = vfp_sreg_to_num(sm)?;
6479 let (vd, d) = encode_sreg(sn_num);
6480 let (vm, m) = encode_sreg(sm_num);
6481 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6482 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6483
6484 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6486
6487 if rd_bits < 8 {
6489 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
6490 bytes.extend_from_slice(&movs_zero.to_le_bytes());
6491 } else {
6492 let hw1: u16 = 0xF04F;
6494 let hw2: u16 = (rd_bits as u16) << 8;
6495 bytes.extend_from_slice(&hw1.to_le_bytes());
6496 bytes.extend_from_slice(&hw2.to_le_bytes());
6497 }
6498
6499 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
6503 bytes.extend_from_slice(&it.to_le_bytes());
6504
6505 if rd_bits < 8 {
6507 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
6508 bytes.extend_from_slice(&mov_one.to_le_bytes());
6509 } else {
6510 let hw1: u16 = 0xF04F;
6512 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
6513 bytes.extend_from_slice(&hw1.to_le_bytes());
6514 bytes.extend_from_slice(&hw2.to_le_bytes());
6515 }
6516
6517 Ok(bytes)
6518 }
6519
6520 fn encode_thumb_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
6522 let mut bytes = Vec::new();
6523 let bits = value.to_bits();
6524 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
6529 let imm4 = (lo16 >> 12) & 0xF;
6530 let i_bit = (lo16 >> 11) & 1;
6531 let imm3 = (lo16 >> 8) & 0x7;
6532 let imm8 = lo16 & 0xFF;
6533 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
6534 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6535 bytes.extend_from_slice(&hw1.to_le_bytes());
6536 bytes.extend_from_slice(&hw2.to_le_bytes());
6537
6538 let hi16 = (bits >> 16) & 0xFFFF;
6540 let imm4 = (hi16 >> 12) & 0xF;
6541 let i_bit = (hi16 >> 11) & 1;
6542 let imm3 = (hi16 >> 8) & 0x7;
6543 let imm8 = hi16 & 0xFF;
6544 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
6545 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6546 bytes.extend_from_slice(&hw1.to_le_bytes());
6547 bytes.extend_from_slice(&hw2.to_le_bytes());
6548
6549 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
6551 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6552
6553 Ok(bytes)
6554 }
6555
6556 fn encode_thumb_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
6558 let mut bytes = Vec::new();
6559
6560 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
6562 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6563
6564 let sd_num = vfp_sreg_to_num(sd)?;
6566 let (vd, d) = encode_sreg(sd_num);
6567 let (vm, m) = encode_sreg(sd_num);
6568 let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
6569 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
6570 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6571
6572 Ok(bytes)
6573 }
6574
6575 fn encode_thumb_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
6583 let mut bytes = Vec::new();
6584 let sm_num = vfp_sreg_to_num(sm)?;
6585 let sd_num = vfp_sreg_to_num(sd)?;
6586 let (vd_s, d_s) = encode_sreg(sd_num);
6587 let (vm_s, m_s) = encode_sreg(sm_num);
6588
6589 if mode == 0b11 {
6590 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6592 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6593 } else {
6594 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
6599 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6600
6601 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF); let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
6607 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6608 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6609
6610 if mode != 0 {
6612 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF); let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
6614 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
6615 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
6616 }
6617
6618 let vmsr = 0xEEE10A10 | (rt << 12);
6620 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6621
6622 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6624 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6625
6626 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6628 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6629 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6630 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6631 }
6632
6633 let (vd2, d2) = encode_sreg(sd_num);
6635 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
6636 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
6637
6638 Ok(bytes)
6639 }
6640
6641 fn encode_thumb_f32_minmax(
6643 &self,
6644 sd: &VfpReg,
6645 sn: &VfpReg,
6646 sm: &VfpReg,
6647 is_min: bool,
6648 ) -> Result<Vec<u8>> {
6649 let mut bytes = Vec::new();
6650 let sn_num = vfp_sreg_to_num(sn)?;
6651 let sm_num = vfp_sreg_to_num(sm)?;
6652 let sd_num = vfp_sreg_to_num(sd)?;
6653
6654 let (vd, d) = encode_sreg(sd_num);
6656 let (vn, n) = encode_sreg(sn_num);
6657 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
6658 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sn));
6659
6660 let (vm, m) = encode_sreg(sm_num);
6662 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
6663 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6664
6665 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6667
6668 let cond: u16 = if is_min { 0xC } else { 0x4 };
6670 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
6671 bytes.extend_from_slice(&it.to_le_bytes());
6672
6673 let vmov_sm = 0xEEB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6675 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sm));
6676
6677 Ok(bytes)
6678 }
6679
6680 fn encode_thumb_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
6682 let mut bytes = Vec::new();
6683
6684 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
6686 false,
6687 sm,
6688 &Reg::R12,
6689 )?));
6690
6691 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
6693 false,
6694 sn,
6695 &Reg::R0,
6696 )?));
6697
6698 let hw1: u16 = 0xF000 | 12; let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
6710 bytes.extend_from_slice(&hw2.to_le_bytes());
6711
6712 let hw1: u16 = 0xF020; let hw2: u16 = (0x1 << 12) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
6716 bytes.extend_from_slice(&hw2.to_le_bytes());
6717
6718 let hw1: u16 = 0xEA40; let hw2: u16 = 12; bytes.extend_from_slice(&hw1.to_le_bytes());
6722 bytes.extend_from_slice(&hw2.to_le_bytes());
6723
6724 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
6726 true,
6727 sd,
6728 &Reg::R0,
6729 )?));
6730
6731 Ok(bytes)
6732 }
6733
6734 fn encode_thumb_f64_compare(
6736 &self,
6737 rd: &Reg,
6738 dn: &VfpReg,
6739 dm: &VfpReg,
6740 cond_code: u32,
6741 ) -> Result<Vec<u8>> {
6742 let mut bytes = Vec::new();
6743 let rd_bits = reg_to_bits(rd);
6744
6745 let dn_num = vfp_dreg_to_num(dn)?;
6747 let dm_num = vfp_dreg_to_num(dm)?;
6748 let (vd, d) = encode_dreg(dn_num);
6749 let (vm, m) = encode_dreg(dm_num);
6750 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6751 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6752
6753 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6755
6756 if rd_bits < 8 {
6758 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
6759 bytes.extend_from_slice(&movs_zero.to_le_bytes());
6760 } else {
6761 let hw1: u16 = 0xF04F;
6762 let hw2: u16 = (rd_bits as u16) << 8;
6763 bytes.extend_from_slice(&hw1.to_le_bytes());
6764 bytes.extend_from_slice(&hw2.to_le_bytes());
6765 }
6766
6767 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
6769 bytes.extend_from_slice(&it.to_le_bytes());
6770
6771 if rd_bits < 8 {
6773 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
6774 bytes.extend_from_slice(&mov_one.to_le_bytes());
6775 } else {
6776 let hw1: u16 = 0xF04F;
6777 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
6778 bytes.extend_from_slice(&hw1.to_le_bytes());
6779 bytes.extend_from_slice(&hw2.to_le_bytes());
6780 }
6781
6782 Ok(bytes)
6783 }
6784
6785 fn encode_thumb_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
6787 let mut bytes = Vec::new();
6788 let bits = value.to_bits();
6789 let lo32 = bits as u32;
6790 let hi32 = (bits >> 32) as u32;
6791
6792 let lo16 = lo32 & 0xFFFF;
6794 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(0, lo16)?);
6795
6796 let hi16 = (lo32 >> 16) & 0xFFFF;
6798 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(0, hi16)?);
6799
6800 let lo16 = hi32 & 0xFFFF;
6802 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
6803
6804 let hi16 = (hi32 >> 16) & 0xFFFF;
6806 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
6807
6808 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
6810 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6811
6812 Ok(bytes)
6813 }
6814
6815 fn encode_thumb_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
6817 let mut bytes = Vec::new();
6818
6819 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
6821 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6822
6823 let dd_num = vfp_dreg_to_num(dd)?;
6825 let (vd, d) = encode_dreg(dd_num);
6826 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
6827 let vcvt = base | (d << 22) | (vd << 12);
6828 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6829
6830 Ok(bytes)
6831 }
6832
6833 fn encode_thumb_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
6835 let dd_num = vfp_dreg_to_num(dd)?;
6836 let sm_num = vfp_sreg_to_num(sm)?;
6837 let (vd, d) = encode_dreg(dd_num);
6838 let (vm, m) = encode_sreg(sm_num);
6839
6840 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
6841 Ok(vfp_to_thumb_bytes(vcvt))
6842 }
6843
6844 fn encode_thumb_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
6846 let mut bytes = Vec::new();
6847 let dm_num = vfp_dreg_to_num(dm)?;
6848 let (vm, m) = encode_dreg(dm_num);
6849
6850 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
6852 let vcvt = base | (m << 5) | vm;
6853 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6854
6855 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
6857 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6858
6859 Ok(bytes)
6860 }
6861
6862 fn encode_thumb_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
6866 let mut bytes = Vec::new();
6867 let dm_num = vfp_dreg_to_num(dm)?;
6868 let dd_num = vfp_dreg_to_num(dd)?;
6869 let (vm, m) = encode_dreg(dm_num);
6870 let (vd, d) = encode_dreg(dd_num);
6871
6872 if mode == 0b11 {
6873 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
6875 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6876 } else {
6877 let rt: u32 = 12;
6878
6879 let vmrs = 0xEEF10A10 | (rt << 12);
6881 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6882
6883 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF);
6885 let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
6886 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6887 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6888
6889 if mode != 0 {
6891 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF);
6892 let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
6893 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
6894 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
6895 }
6896
6897 let vmsr = 0xEEE10A10 | (rt << 12);
6899 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6900
6901 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
6903 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6904
6905 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6907 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6908 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6909 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6910 }
6911
6912 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
6914 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
6915
6916 Ok(bytes)
6917 }
6918
6919 fn encode_thumb_f64_minmax(
6921 &self,
6922 dd: &VfpReg,
6923 dn: &VfpReg,
6924 dm: &VfpReg,
6925 is_min: bool,
6926 ) -> Result<Vec<u8>> {
6927 let mut bytes = Vec::new();
6928 let dn_num = vfp_dreg_to_num(dn)?;
6929 let dm_num = vfp_dreg_to_num(dm)?;
6930 let dd_num = vfp_dreg_to_num(dd)?;
6931
6932 let (vd, d) = encode_dreg(dd_num);
6934 let (vn, n) = encode_dreg(dn_num);
6935 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
6936 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dn));
6937
6938 let (vm, m) = encode_dreg(dm_num);
6940 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
6941 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6942
6943 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6945
6946 let cond: u16 = if is_min { 0xC } else { 0x4 };
6948 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
6949 bytes.extend_from_slice(&it.to_le_bytes());
6950
6951 let vmov_dm = 0xEEB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6953 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dm));
6954
6955 Ok(bytes)
6956 }
6957
6958 fn encode_thumb_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
6960 let mut bytes = Vec::new();
6961
6962 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
6964 false,
6965 dm,
6966 &Reg::R0,
6967 &Reg::R12,
6968 )?));
6969
6970 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
6972 false,
6973 dn,
6974 &Reg::R1,
6975 &Reg::R2,
6976 )?));
6977
6978 let hw1: u16 = 0xF000 | 12;
6980 let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02;
6981 bytes.extend_from_slice(&hw1.to_le_bytes());
6982 bytes.extend_from_slice(&hw2.to_le_bytes());
6983
6984 let hw1: u16 = 0xF020 | 2;
6986 let hw2: u16 = (0x1 << 12) | (2 << 8) | 0x02;
6987 bytes.extend_from_slice(&hw1.to_le_bytes());
6988 bytes.extend_from_slice(&hw2.to_le_bytes());
6989
6990 let hw1: u16 = 0xEA40 | 2;
6992 let hw2: u16 = (2 << 8) | 12;
6993 bytes.extend_from_slice(&hw1.to_le_bytes());
6994 bytes.extend_from_slice(&hw2.to_le_bytes());
6995
6996 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
6998 true,
6999 dd,
7000 &Reg::R1,
7001 &Reg::R2,
7002 )?));
7003
7004 Ok(bytes)
7005 }
7006
7007 fn encode_thumb_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7009 let mut bytes = Vec::new();
7010
7011 let sm_num = vfp_sreg_to_num(sm)?;
7012 let (vd, d) = encode_sreg(sm_num);
7013 let (vm, m) = encode_sreg(sm_num);
7014 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
7015 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
7016 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7017
7018 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
7020 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7021
7022 Ok(bytes)
7023 }
7024
7025 fn encode_thumb32_add(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7029 let rd_bits = reg_to_bits(rd);
7030 let rn_bits = reg_to_bits(rn);
7031
7032 let i_bit = (imm >> 11) & 1;
7034 let imm3 = (imm >> 8) & 0x7;
7035 let imm8 = imm & 0xFF;
7036
7037 let hw1_base = if imm <= 0xFF {
7038 0xF100
7042 } else if imm <= 0xFFF {
7043 0xF200
7047 } else {
7048 return Err(synth_core::Error::synthesis(
7049 "ADD immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7050 ));
7051 };
7052
7053 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7054 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7055
7056 let mut bytes = hw1.to_le_bytes().to_vec();
7057 bytes.extend_from_slice(&hw2.to_le_bytes());
7058 Ok(bytes)
7059 }
7060
7061 fn encode_thumb32_sub(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7063 let rd_bits = reg_to_bits(rd);
7064 let rn_bits = reg_to_bits(rn);
7065
7066 let i_bit = (imm >> 11) & 1;
7067 let imm3 = (imm >> 8) & 0x7;
7068 let imm8 = imm & 0xFF;
7069
7070 let hw1_base = if imm <= 0xFF {
7071 0xF1A0
7074 } else if imm <= 0xFFF {
7075 0xF2A0
7078 } else {
7079 return Err(synth_core::Error::synthesis(
7080 "SUB immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7081 ));
7082 };
7083
7084 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7085 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7086
7087 let mut bytes = hw1.to_le_bytes().to_vec();
7088 bytes.extend_from_slice(&hw2.to_le_bytes());
7089 Ok(bytes)
7090 }
7091
7092 fn encode_thumb32_adds(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7094 let rd_bits = reg_to_bits(rd);
7095 let rn_bits = reg_to_bits(rn);
7096
7097 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7100 synth_core::Error::synthesis(
7101 "ADDS immediate is not a valid ThumbExpandImm — materialize into a register",
7102 )
7103 })?;
7104 let i_bit = (field >> 11) & 1;
7105 let imm3 = (field >> 8) & 0x7;
7106 let imm8 = field & 0xFF;
7107
7108 let hw1: u16 = (0xF110 | (i_bit << 10) | rn_bits) as u16;
7111 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7112
7113 let mut bytes = hw1.to_le_bytes().to_vec();
7114 bytes.extend_from_slice(&hw2.to_le_bytes());
7115 Ok(bytes)
7116 }
7117
7118 fn encode_thumb32_subs(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7120 let rd_bits = reg_to_bits(rd);
7121 let rn_bits = reg_to_bits(rn);
7122
7123 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7126 synth_core::Error::synthesis(
7127 "SUBS immediate is not a valid ThumbExpandImm — materialize into a register",
7128 )
7129 })?;
7130 let i_bit = (field >> 11) & 1;
7131 let imm3 = (field >> 8) & 0x7;
7132 let imm8 = field & 0xFF;
7133
7134 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7137 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7138
7139 let mut bytes = hw1.to_le_bytes().to_vec();
7140 bytes.extend_from_slice(&hw2.to_le_bytes());
7141 Ok(bytes)
7142 }
7143
7144 fn encode_thumb32_movw(&self, rd: &Reg, imm: u32) -> Result<Vec<u8>> {
7153 let rd_bits = reg_to_bits(rd);
7154 reg_bits_checked(rd_bits)?;
7155 let imm16 = imm & 0xFFFF;
7156
7157 let imm4 = (imm16 >> 12) & 0xF;
7160 let i_bit = (imm16 >> 11) & 1;
7161 let imm3 = (imm16 >> 8) & 0x7;
7162 let imm8 = imm16 & 0xFF;
7163
7164 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7165 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7166
7167 let mut bytes = hw1.to_le_bytes().to_vec();
7168 bytes.extend_from_slice(&hw2.to_le_bytes());
7169 encoding_contracts::verify_thumb32(&bytes);
7170 Ok(bytes)
7171 }
7172
7173 fn encode_thumb32_shift(
7181 &self,
7182 rd: &Reg,
7183 rm: &Reg,
7184 shift: u32,
7185 shift_type: u8,
7186 ) -> Result<Vec<u8>> {
7187 let rd_bits = reg_to_bits(rd);
7188 let rm_bits = reg_to_bits(rm);
7189 reg_bits_checked(rd_bits)?;
7190 reg_bits_checked(rm_bits)?;
7191 let imm5 = shift & 0x1F;
7192 let imm2 = imm5 & 0x3;
7193 let imm3 = (imm5 >> 2) & 0x7;
7194
7195 let hw1: u16 = 0xEA4F;
7198 let hw2: u16 =
7199 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | ((shift_type as u32) << 4) | rm_bits)
7200 as u16;
7201
7202 let mut bytes = hw1.to_le_bytes().to_vec();
7203 bytes.extend_from_slice(&hw2.to_le_bytes());
7204 Ok(bytes)
7205 }
7206
7207 fn encode_thumb32_shift_reg(
7211 &self,
7212 rd: &Reg,
7213 rn: &Reg,
7214 rm: &Reg,
7215 shift_type: u8,
7216 ) -> Result<Vec<u8>> {
7217 let rd_bits = reg_to_bits(rd);
7218 let rn_bits = reg_to_bits(rn);
7219 let rm_bits = reg_to_bits(rm);
7220
7221 let hw1: u16 = (0xFA00 | ((shift_type as u32) << 5) | rn_bits) as u16;
7223 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
7225
7226 let mut bytes = hw1.to_le_bytes().to_vec();
7227 bytes.extend_from_slice(&hw2.to_le_bytes());
7228 Ok(bytes)
7229 }
7230
7231 fn encode_thumb32_cmp_imm(&self, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7233 let rn_bits = reg_to_bits(rn);
7234
7235 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7239 synth_core::Error::synthesis(
7240 "CMP immediate is not a valid ThumbExpandImm — materialize into a register",
7241 )
7242 })?;
7243 let i_bit = (field >> 11) & 1;
7244 let imm3 = (field >> 8) & 0x7;
7245 let imm8 = field & 0xFF;
7246
7247 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7249 let hw2: u16 = ((imm3 << 12) | 0x0F00 | imm8) as u16;
7250
7251 let mut bytes = hw1.to_le_bytes().to_vec();
7252 bytes.extend_from_slice(&hw2.to_le_bytes());
7253 Ok(bytes)
7254 }
7255
7256 fn i64_effective_base(&self, bytes: &mut Vec<u8>, addr: &MemAddr) -> Result<(Reg, u32)> {
7278 let offset = if addr.offset < 0 {
7279 0u32
7280 } else {
7281 addr.offset as u32
7282 };
7283 match addr.offset_reg {
7284 Some(idx) => {
7285 let ip = Reg::R12;
7286 if offset.wrapping_add(4) > 0xFFF {
7287 bytes.extend_from_slice(&self.encode_thumb32_add_imm(&ip, &idx, offset)?);
7291 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
7293 reg_to_bits(&ip),
7294 reg_to_bits(&ip),
7295 reg_to_bits(&addr.base),
7296 )?);
7297 Ok((ip, 0))
7298 } else {
7299 let hw1: u16 = 0xEB00 | reg_to_bits(&addr.base) as u16;
7301 let hw2: u16 = 0x0C00 | reg_to_bits(&idx) as u16;
7302 bytes.extend_from_slice(&hw1.to_le_bytes());
7303 bytes.extend_from_slice(&hw2.to_le_bytes());
7304 Ok((ip, offset))
7305 }
7306 }
7307 None => Ok((addr.base, offset)),
7308 }
7309 }
7310
7311 fn encode_thumb32_ldr(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7313 let rd_bits = reg_to_bits(rd);
7314 let base_bits = reg_to_bits(base);
7315
7316 check_ldst_imm12(offset)?;
7318 let hw1: u16 = (0xF8D0 | base_bits) as u16;
7319 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7320
7321 let mut bytes = hw1.to_le_bytes().to_vec();
7322 bytes.extend_from_slice(&hw2.to_le_bytes());
7323 Ok(bytes)
7324 }
7325
7326 fn encode_thumb32_str(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7328 let rd_bits = reg_to_bits(rd);
7329 let base_bits = reg_to_bits(base);
7330
7331 check_ldst_imm12(offset)?;
7333 let hw1: u16 = (0xF8C0 | base_bits) as u16;
7334 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7335
7336 let mut bytes = hw1.to_le_bytes().to_vec();
7337 bytes.extend_from_slice(&hw2.to_le_bytes());
7338 Ok(bytes)
7339 }
7340
7341 fn encode_thumb32_ldr_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7343 let rd_bits = reg_to_bits(rd);
7344 let base_bits = reg_to_bits(base);
7345 let rm_bits = reg_to_bits(offset_reg);
7346
7347 let hw1: u16 = (0xF850 | base_bits) as u16;
7351 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7352
7353 let mut bytes = hw1.to_le_bytes().to_vec();
7354 bytes.extend_from_slice(&hw2.to_le_bytes());
7355 Ok(bytes)
7356 }
7357
7358 fn encode_thumb32_str_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7360 let rd_bits = reg_to_bits(rd);
7361 let base_bits = reg_to_bits(base);
7362 let rm_bits = reg_to_bits(offset_reg);
7363
7364 let hw1: u16 = (0xF840 | base_bits) as u16;
7368 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7369
7370 let mut bytes = hw1.to_le_bytes().to_vec();
7371 bytes.extend_from_slice(&hw2.to_le_bytes());
7372 Ok(bytes)
7373 }
7374
7375 fn encode_thumb32_ldrb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7379 let rd_bits = reg_to_bits(rd);
7380 let base_bits = reg_to_bits(base);
7381 check_ldst_imm12(offset)?;
7383 let hw1: u16 = (0xF890 | base_bits) as u16;
7384 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7385 let mut bytes = hw1.to_le_bytes().to_vec();
7386 bytes.extend_from_slice(&hw2.to_le_bytes());
7387 Ok(bytes)
7388 }
7389
7390 fn encode_thumb32_ldrb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7392 let rd_bits = reg_to_bits(rd);
7393 let base_bits = reg_to_bits(base);
7394 let rm_bits = reg_to_bits(offset_reg);
7395 let hw1: u16 = (0xF810 | base_bits) as u16;
7397 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7398 let mut bytes = hw1.to_le_bytes().to_vec();
7399 bytes.extend_from_slice(&hw2.to_le_bytes());
7400 Ok(bytes)
7401 }
7402
7403 fn encode_thumb32_ldrsb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7405 let rd_bits = reg_to_bits(rd);
7406 let base_bits = reg_to_bits(base);
7407 check_ldst_imm12(offset)?;
7409 let hw1: u16 = (0xF990 | base_bits) as u16;
7410 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7411 let mut bytes = hw1.to_le_bytes().to_vec();
7412 bytes.extend_from_slice(&hw2.to_le_bytes());
7413 Ok(bytes)
7414 }
7415
7416 fn encode_thumb32_ldrsb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7418 let rd_bits = reg_to_bits(rd);
7419 let base_bits = reg_to_bits(base);
7420 let rm_bits = reg_to_bits(offset_reg);
7421 let hw1: u16 = (0xF910 | base_bits) as u16;
7423 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7424 let mut bytes = hw1.to_le_bytes().to_vec();
7425 bytes.extend_from_slice(&hw2.to_le_bytes());
7426 Ok(bytes)
7427 }
7428
7429 fn encode_thumb32_ldrh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7431 let rd_bits = reg_to_bits(rd);
7432 let base_bits = reg_to_bits(base);
7433 check_ldst_imm12(offset)?;
7435 let hw1: u16 = (0xF8B0 | base_bits) as u16;
7436 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7437 let mut bytes = hw1.to_le_bytes().to_vec();
7438 bytes.extend_from_slice(&hw2.to_le_bytes());
7439 Ok(bytes)
7440 }
7441
7442 fn encode_thumb32_ldrh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7444 let rd_bits = reg_to_bits(rd);
7445 let base_bits = reg_to_bits(base);
7446 let rm_bits = reg_to_bits(offset_reg);
7447 let hw1: u16 = (0xF830 | base_bits) as u16;
7449 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7450 let mut bytes = hw1.to_le_bytes().to_vec();
7451 bytes.extend_from_slice(&hw2.to_le_bytes());
7452 Ok(bytes)
7453 }
7454
7455 fn encode_thumb32_ldrsh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7457 let rd_bits = reg_to_bits(rd);
7458 let base_bits = reg_to_bits(base);
7459 check_ldst_imm12(offset)?;
7461 let hw1: u16 = (0xF9B0 | base_bits) as u16;
7462 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7463 let mut bytes = hw1.to_le_bytes().to_vec();
7464 bytes.extend_from_slice(&hw2.to_le_bytes());
7465 Ok(bytes)
7466 }
7467
7468 fn encode_thumb32_ldrsh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7470 let rd_bits = reg_to_bits(rd);
7471 let base_bits = reg_to_bits(base);
7472 let rm_bits = reg_to_bits(offset_reg);
7473 let hw1: u16 = (0xF930 | base_bits) as u16;
7475 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7476 let mut bytes = hw1.to_le_bytes().to_vec();
7477 bytes.extend_from_slice(&hw2.to_le_bytes());
7478 Ok(bytes)
7479 }
7480
7481 fn encode_thumb32_strb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7483 let rd_bits = reg_to_bits(rd);
7484 let base_bits = reg_to_bits(base);
7485 check_ldst_imm12(offset)?;
7487 let hw1: u16 = (0xF880 | base_bits) as u16;
7488 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7489 let mut bytes = hw1.to_le_bytes().to_vec();
7490 bytes.extend_from_slice(&hw2.to_le_bytes());
7491 Ok(bytes)
7492 }
7493
7494 fn encode_thumb32_strb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7496 let rd_bits = reg_to_bits(rd);
7497 let base_bits = reg_to_bits(base);
7498 let rm_bits = reg_to_bits(offset_reg);
7499 let hw1: u16 = (0xF800 | base_bits) as u16;
7501 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7502 let mut bytes = hw1.to_le_bytes().to_vec();
7503 bytes.extend_from_slice(&hw2.to_le_bytes());
7504 Ok(bytes)
7505 }
7506
7507 fn encode_thumb32_strh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7509 let rd_bits = reg_to_bits(rd);
7510 let base_bits = reg_to_bits(base);
7511 check_ldst_imm12(offset)?;
7513 let hw1: u16 = (0xF8A0 | base_bits) as u16;
7514 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7515 let mut bytes = hw1.to_le_bytes().to_vec();
7516 bytes.extend_from_slice(&hw2.to_le_bytes());
7517 Ok(bytes)
7518 }
7519
7520 fn encode_thumb32_strh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7522 let rd_bits = reg_to_bits(rd);
7523 let base_bits = reg_to_bits(base);
7524 let rm_bits = reg_to_bits(offset_reg);
7525 let hw1: u16 = (0xF820 | base_bits) as u16;
7527 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7528 let mut bytes = hw1.to_le_bytes().to_vec();
7529 bytes.extend_from_slice(&hw2.to_le_bytes());
7530 Ok(bytes)
7531 }
7532
7533 fn encode_thumb32_add_imm(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7535 let rd_bits = reg_to_bits(rd);
7536 let rn_bits = reg_to_bits(rn);
7537
7538 if imm <= 0xFFF {
7544 let i_bit = (imm >> 11) & 1;
7545 let imm3 = (imm >> 8) & 0x7;
7546 let imm8 = imm & 0xFF;
7547
7548 let hw1: u16 = (0xF100 | (i_bit << 10) | rn_bits) as u16;
7549 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7550
7551 let mut bytes = hw1.to_le_bytes().to_vec();
7552 bytes.extend_from_slice(&hw2.to_le_bytes());
7553 Ok(bytes)
7554 } else {
7555 let scratch: u32 = if rd_bits == rn_bits {
7569 12 } else {
7571 rd_bits };
7573 if scratch == rn_bits {
7581 return Err(synth_core::Error::synthesis(format!(
7582 "ADD #imm: cannot lower #{imm:#x} for Rd==Rn==R12 — no free scratch \
7583 register (R12 is the reserved encoder scratch and aliases Rn here)"
7584 )));
7585 }
7586
7587 let lo16 = imm & 0xFFFF;
7588 let hi16 = (imm >> 16) & 0xFFFF;
7589
7590 let mut bytes = self.encode_thumb32_movw_raw(scratch, lo16)?;
7591 if hi16 != 0 {
7592 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(scratch, hi16)?);
7593 }
7594 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(rd_bits, rn_bits, scratch)?);
7595 Ok(bytes)
7596 }
7597 }
7598
7599 fn encode_thumb32_movw_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7609 reg_bits_checked(rd)?;
7610 encoding_contracts::verify_imm16(imm16);
7611 let imm16 = imm16 & 0xFFFF;
7614 let imm4 = (imm16 >> 12) & 0xF;
7615 let i_bit = (imm16 >> 11) & 1;
7616 let imm3 = (imm16 >> 8) & 0x7;
7617 let imm8 = imm16 & 0xFF;
7618
7619 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7620 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7621
7622 let mut bytes = hw1.to_le_bytes().to_vec();
7623 bytes.extend_from_slice(&hw2.to_le_bytes());
7624 encoding_contracts::verify_thumb32(&bytes);
7625 Ok(bytes)
7626 }
7627
7628 fn encode_thumb32_movt_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7636 reg_bits_checked(rd)?;
7637 encoding_contracts::verify_imm16(imm16);
7638 let imm16 = imm16 & 0xFFFF;
7641 let imm4 = (imm16 >> 12) & 0xF;
7642 let i_bit = (imm16 >> 11) & 1;
7643 let imm3 = (imm16 >> 8) & 0x7;
7644 let imm8 = imm16 & 0xFF;
7645
7646 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
7647 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7648
7649 let mut bytes = hw1.to_le_bytes().to_vec();
7650 bytes.extend_from_slice(&hw2.to_le_bytes());
7651 encoding_contracts::verify_thumb32(&bytes);
7652 Ok(bytes)
7653 }
7654
7655 fn encode_thumb32_lsr_raw(&self, rd: u32, rm: u32, shift: u32) -> Result<Vec<u8>> {
7657 let imm5 = shift & 0x1F;
7660 let imm2 = imm5 & 0x3;
7661 let imm3 = (imm5 >> 2) & 0x7;
7662
7663 let hw1: u16 = 0xEA4F;
7664 let hw2: u16 = ((imm3 << 12) | (rd << 8) | (imm2 << 6) | (0b01 << 4) | rm) as u16;
7665
7666 let mut bytes = hw1.to_le_bytes().to_vec();
7667 bytes.extend_from_slice(&hw2.to_le_bytes());
7668 Ok(bytes)
7669 }
7670
7671 fn encode_thumb32_and_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7673 let hw1: u16 = (0xEA00 | rn) as u16;
7676 let hw2: u16 = ((rd << 8) | rm) as u16;
7677
7678 let mut bytes = hw1.to_le_bytes().to_vec();
7679 bytes.extend_from_slice(&hw2.to_le_bytes());
7680 Ok(bytes)
7681 }
7682
7683 fn encode_thumb32_and_imm_raw(&self, rd: u32, rn: u32, imm: u32) -> Result<Vec<u8>> {
7685 let i_bit = (imm >> 11) & 1;
7689 let imm3 = (imm >> 8) & 0x7;
7690 let imm8 = imm & 0xFF;
7691
7692 let hw1: u16 = (0xF000 | (i_bit << 10) | rn) as u16;
7693 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7694
7695 let mut bytes = hw1.to_le_bytes().to_vec();
7696 bytes.extend_from_slice(&hw2.to_le_bytes());
7697 Ok(bytes)
7698 }
7699
7700 fn encode_thumb32_sub_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7702 let hw1: u16 = (0xEBA0 | rn) as u16;
7705 let hw2: u16 = ((rd << 8) | rm) as u16;
7706
7707 let mut bytes = hw1.to_le_bytes().to_vec();
7708 bytes.extend_from_slice(&hw2.to_le_bytes());
7709 Ok(bytes)
7710 }
7711
7712 fn encode_thumb32_add_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7714 let hw1: u16 = (0xEB00 | rn) as u16;
7717 let hw2: u16 = ((rd << 8) | rm) as u16;
7718
7719 let mut bytes = hw1.to_le_bytes().to_vec();
7720 bytes.extend_from_slice(&hw2.to_le_bytes());
7721 Ok(bytes)
7722 }
7723
7724 fn encode_thumb32_adds_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7728 let hw1: u16 = (0xEB10 | rn) as u16;
7730 let hw2: u16 = ((rd << 8) | rm) as u16;
7731 let mut bytes = hw1.to_le_bytes().to_vec();
7732 bytes.extend_from_slice(&hw2.to_le_bytes());
7733 Ok(bytes)
7734 }
7735
7736 fn encode_thumb32_subs_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7739 let hw1: u16 = (0xEBB0 | rn) as u16;
7741 let hw2: u16 = ((rd << 8) | rm) as u16;
7742 let mut bytes = hw1.to_le_bytes().to_vec();
7743 bytes.extend_from_slice(&hw2.to_le_bytes());
7744 Ok(bytes)
7745 }
7746
7747 pub fn encode_sequence(&self, ops: &[ArmOp]) -> Result<Vec<u8>> {
7749 let mut code = Vec::new();
7750
7751 for op in ops {
7752 let encoded = self.encode(op)?;
7753 code.extend_from_slice(&encoded);
7754 }
7755
7756 Ok(code)
7757 }
7758}
7759
7760fn try_thumb_expand_imm(value: u32) -> Option<u32> {
7768 if value <= 0xFF {
7770 return Some(value);
7771 }
7772 let b0 = value & 0xFF; let b1 = (value >> 8) & 0xFF; if value == (b0 << 16) | b0 {
7776 return Some(0x100 | b0);
7777 }
7778 if value == (b1 << 24) | (b1 << 8) {
7780 return Some(0x200 | b1);
7781 }
7782 if value == (b0 << 24) | (b0 << 16) | (b0 << 8) | b0 {
7784 return Some(0x300 | b0);
7785 }
7786 for rot in 8..=31u32 {
7790 let unrot = value.rotate_left(rot);
7791 if (0x80..=0xFF).contains(&unrot) {
7792 return Some((rot << 7) | (unrot & 0x7F));
7793 }
7794 }
7795 None
7796}
7797
7798fn check_ldst_imm12(offset: u32) -> Result<()> {
7804 if offset > 0xFFF {
7805 Err(synth_core::Error::synthesis(
7806 "load/store immediate offset > 0xFFF (4095) — materialize the offset into a register",
7807 ))
7808 } else {
7809 Ok(())
7810 }
7811}
7812
7813fn reg_to_bits(reg: &Reg) -> u32 {
7814 match reg {
7815 Reg::R0 => 0,
7816 Reg::R1 => 1,
7817 Reg::R2 => 2,
7818 Reg::R3 => 3,
7819 Reg::R4 => 4,
7820 Reg::R5 => 5,
7821 Reg::R6 => 6,
7822 Reg::R7 => 7,
7823 Reg::R8 => 8,
7824 Reg::R9 => 9,
7825 Reg::R10 => 10,
7826 Reg::R11 => 11,
7827 Reg::R12 => 12,
7828 Reg::SP => 13,
7829 Reg::LR => 14,
7830 Reg::PC => 15,
7831 }
7832}
7833
7834fn emit_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
7865 debug_assert!(srcs.len() <= 4);
7866 bytes.extend_from_slice(&0xB40Fu16.to_le_bytes());
7868 for src in srcs.iter().rev() {
7870 let rt = reg_to_bits(src) as u16;
7871 bytes.extend_from_slice(&0xF84Du16.to_le_bytes());
7872 bytes.extend_from_slice(&((rt << 12) | 0x0D04).to_le_bytes());
7873 }
7874 for i in 0..srcs.len() as u16 {
7876 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes());
7877 }
7878}
7879
7880fn emit_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
7884 let lo = reg_to_bits(rdlo);
7885 let hi = reg_to_bits(rdhi);
7886 if lo == 1 && hi == 0 {
7887 return Err(synth_core::Error::synthesis(
7890 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
7891 ));
7892 }
7893 let mov16 = |bytes: &mut Vec<u8>, rd: u32, rm: u32| {
7894 let d = ((rd >> 3) & 1) as u16;
7895 bytes.extend_from_slice(
7896 &(0x4600u16 | (d << 7) | ((rm as u16) << 3) | ((rd & 7) as u16)).to_le_bytes(),
7897 );
7898 };
7899 if hi == 0 {
7900 mov16(bytes, lo, 0);
7902 mov16(bytes, hi, 1);
7903 } else {
7904 mov16(bytes, hi, 1);
7906 mov16(bytes, lo, 0);
7907 }
7908 for i in 0..4u32 {
7909 if i == lo || i == hi {
7910 bytes.extend_from_slice(&0xB001u16.to_le_bytes()); } else {
7913 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes()); }
7915 }
7916 Ok(())
7917}
7918
7919fn emit_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
7923 bytes.extend_from_slice(&0xEA52u16.to_le_bytes()); bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
7925 bytes.extend_from_slice(&0xD100u16.to_le_bytes()); bytes.extend_from_slice(&0xDE00u16.to_le_bytes()); }
7928
7929fn emit_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
7939 bytes.extend_from_slice(&0xEA02u16.to_le_bytes());
7941 bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
7942 bytes.extend_from_slice(&0xF11Cu16.to_le_bytes());
7944 bytes.extend_from_slice(&0x0F01u16.to_le_bytes());
7945 bytes.extend_from_slice(&0xD105u16.to_le_bytes());
7947 bytes.extend_from_slice(&0x2800u16.to_le_bytes());
7949 bytes.extend_from_slice(&0xD103u16.to_le_bytes());
7951 bytes.extend_from_slice(&0xF1B1u16.to_le_bytes());
7953 bytes.extend_from_slice(&0x4F00u16.to_le_bytes());
7954 bytes.extend_from_slice(&0xD100u16.to_le_bytes());
7956 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
7958 }
7960
7961fn emit_a32_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
7975 debug_assert!(srcs.len() <= 4);
7976 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
7977 w(bytes, 0xE92D_000F);
7979 for src in srcs.iter().rev() {
7981 w(bytes, 0xE52D_0004 | (reg_to_bits(src) << 12));
7982 }
7983 for i in 0..srcs.len() as u32 {
7985 w(bytes, 0xE49D_0004 | (i << 12));
7986 }
7987}
7988
7989fn emit_a32_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
7993 let lo = reg_to_bits(rdlo);
7994 let hi = reg_to_bits(rdhi);
7995 if lo == 1 && hi == 0 {
7996 return Err(synth_core::Error::synthesis(
7999 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8000 ));
8001 }
8002 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8003 let mov = |bytes: &mut Vec<u8>, rd: u32, rm: u32| w(bytes, 0xE1A0_0000 | (rd << 12) | rm);
8004 if hi == 0 {
8005 mov(bytes, lo, 0);
8007 mov(bytes, hi, 1);
8008 } else {
8009 mov(bytes, hi, 1);
8011 mov(bytes, lo, 0);
8012 }
8013 for i in 0..4u32 {
8014 if i == lo || i == hi {
8015 w(bytes, 0xE28D_D004); } else {
8018 w(bytes, 0xE49D_0004 | (i << 12)); }
8020 }
8021 Ok(())
8022}
8023
8024fn emit_a32_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8028 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8029 w(bytes, 0xE192_C003); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8033
8034fn emit_a32_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8039 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8040 w(bytes, 0xE002_C003); w(bytes, 0xE37C_0001); w(bytes, 0x0350_0000); w(bytes, 0x0351_0102); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8047
8048fn reg_bits_checked(bits: u32) -> Result<()> {
8056 if bits > 14 {
8057 return Err(synth_core::Error::synthesis(format!(
8058 "register bits {bits} (PC/R15) is not a valid operand for this Thumb-2 encoding"
8059 )));
8060 }
8061 Ok(())
8062}
8063
8064fn try_encode_rotated_imm(val: u32) -> Option<(u32, u32)> {
8067 if val == 0 {
8068 return Some((0, 1));
8069 }
8070 for rot in 0..16u32 {
8071 let shift = rot * 2;
8072 let unrotated = val.rotate_left(shift);
8074 if unrotated <= 0xFF {
8075 return Some(((rot << 8) | unrotated, 1));
8077 }
8078 }
8079 None
8080}
8081
8082fn encode_operand2(op2: &Operand2) -> Result<(u32, u32)> {
8087 match op2 {
8088 Operand2::Imm(val) => {
8089 let uval = *val as u32;
8090 if let Some(encoded) = try_encode_rotated_imm(uval) {
8092 Ok(encoded)
8093 } else {
8094 Err(synth_core::Error::synthesis(format!(
8103 "encode_operand2: immediate {uval:#x} ({val}) is not an ARM32 \
8104 rotated immediate — the selector must materialize large \
8105 constants via MOVW/MOVT"
8106 )))
8107 }
8108 }
8109
8110 Operand2::Reg(reg) => {
8111 let reg_bits = reg_to_bits(reg);
8112 Ok((reg_bits, 0)) }
8114
8115 Operand2::RegShift {
8116 rm,
8117 shift: _,
8118 amount,
8119 } => {
8120 let rm_bits = reg_to_bits(rm);
8122 let shift_bits = (*amount & 0x1F) << 7;
8123 Ok((shift_bits | rm_bits, 0))
8124 }
8125 }
8126}
8127
8128fn encode_mem_addr(addr: &MemAddr) -> (u32, u32) {
8130 let base_bits = reg_to_bits(&addr.base);
8131 let offset_bits = (addr.offset as u32) & 0xFFF; (base_bits, offset_bits)
8133}
8134
8135fn vfp_sreg_to_num(reg: &VfpReg) -> Result<u32> {
8137 match reg {
8138 VfpReg::S0 => Ok(0),
8139 VfpReg::S1 => Ok(1),
8140 VfpReg::S2 => Ok(2),
8141 VfpReg::S3 => Ok(3),
8142 VfpReg::S4 => Ok(4),
8143 VfpReg::S5 => Ok(5),
8144 VfpReg::S6 => Ok(6),
8145 VfpReg::S7 => Ok(7),
8146 VfpReg::S8 => Ok(8),
8147 VfpReg::S9 => Ok(9),
8148 VfpReg::S10 => Ok(10),
8149 VfpReg::S11 => Ok(11),
8150 VfpReg::S12 => Ok(12),
8151 VfpReg::S13 => Ok(13),
8152 VfpReg::S14 => Ok(14),
8153 VfpReg::S15 => Ok(15),
8154 VfpReg::S16 => Ok(16),
8155 VfpReg::S17 => Ok(17),
8156 VfpReg::S18 => Ok(18),
8157 VfpReg::S19 => Ok(19),
8158 VfpReg::S20 => Ok(20),
8159 VfpReg::S21 => Ok(21),
8160 VfpReg::S22 => Ok(22),
8161 VfpReg::S23 => Ok(23),
8162 VfpReg::S24 => Ok(24),
8163 VfpReg::S25 => Ok(25),
8164 VfpReg::S26 => Ok(26),
8165 VfpReg::S27 => Ok(27),
8166 VfpReg::S28 => Ok(28),
8167 VfpReg::S29 => Ok(29),
8168 VfpReg::S30 => Ok(30),
8169 VfpReg::S31 => Ok(31),
8170 _ => Err(synth_core::Error::SynthesisError(
8172 "D-register not supported in single-precision VFP encoding".to_string(),
8173 )),
8174 }
8175}
8176
8177fn vfp_dreg_to_num(reg: &VfpReg) -> Result<u32> {
8179 match reg {
8180 VfpReg::D0 => Ok(0),
8181 VfpReg::D1 => Ok(1),
8182 VfpReg::D2 => Ok(2),
8183 VfpReg::D3 => Ok(3),
8184 VfpReg::D4 => Ok(4),
8185 VfpReg::D5 => Ok(5),
8186 VfpReg::D6 => Ok(6),
8187 VfpReg::D7 => Ok(7),
8188 VfpReg::D8 => Ok(8),
8189 VfpReg::D9 => Ok(9),
8190 VfpReg::D10 => Ok(10),
8191 VfpReg::D11 => Ok(11),
8192 VfpReg::D12 => Ok(12),
8193 VfpReg::D13 => Ok(13),
8194 VfpReg::D14 => Ok(14),
8195 VfpReg::D15 => Ok(15),
8196 _ => Err(synth_core::Error::SynthesisError(
8198 "S-register not supported in double-precision VFP encoding".to_string(),
8199 )),
8200 }
8201}
8202
8203fn encode_sreg(s: u32) -> (u32, u32) {
8207 (s >> 1, s & 1)
8208}
8209
8210fn encode_dreg(d: u32) -> (u32, u32) {
8214 (d & 0xF, (d >> 4) & 1)
8215}
8216
8217fn encode_vfp_3reg(base: u32, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<u32> {
8223 let sd_num = vfp_sreg_to_num(sd)?;
8224 let sn_num = vfp_sreg_to_num(sn)?;
8225 let sm_num = vfp_sreg_to_num(sm)?;
8226 let (vd, d) = encode_sreg(sd_num);
8227 let (vn, n) = encode_sreg(sn_num);
8228 let (vm, m) = encode_sreg(sm_num);
8229
8230 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8231}
8232
8233fn encode_vfp_2reg(base: u32, sd: &VfpReg, sm: &VfpReg) -> Result<u32> {
8236 let sd_num = vfp_sreg_to_num(sd)?;
8237 let sm_num = vfp_sreg_to_num(sm)?;
8238 let (vd, d) = encode_sreg(sd_num);
8239 let (vm, m) = encode_sreg(sm_num);
8240
8241 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8242}
8243
8244fn encode_vfp_ldst(base: u32, sd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8248 let sd_num = vfp_sreg_to_num(sd)?;
8249 let (vd, d) = encode_sreg(sd_num);
8250 let rn = reg_to_bits(&addr.base);
8251
8252 let offset = addr.offset;
8253 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8254 let abs_offset = offset.unsigned_abs();
8255 let imm8 = (abs_offset / 4) & 0xFF;
8256
8257 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8258}
8259
8260fn encode_vmov_core_sreg(to_sreg: bool, sreg: &VfpReg, core: &Reg) -> Result<u32> {
8264 let s_num = vfp_sreg_to_num(sreg)?;
8265 let (vn, n) = encode_sreg(s_num);
8266 let rt = reg_to_bits(core);
8267
8268 let base = if to_sreg { 0xEE000A10 } else { 0xEE100A10 };
8269 Ok(base | (vn << 16) | (rt << 12) | (n << 7))
8270}
8271
8272fn encode_vfp_3reg_f64(base: u32, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<u32> {
8276 let dd_num = vfp_dreg_to_num(dd)?;
8277 let dn_num = vfp_dreg_to_num(dn)?;
8278 let dm_num = vfp_dreg_to_num(dm)?;
8279 let (vd, d) = encode_dreg(dd_num);
8280 let (vn, n) = encode_dreg(dn_num);
8281 let (vm, m) = encode_dreg(dm_num);
8282
8283 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8284}
8285
8286fn encode_vfp_2reg_f64(base: u32, dd: &VfpReg, dm: &VfpReg) -> Result<u32> {
8288 let dd_num = vfp_dreg_to_num(dd)?;
8289 let dm_num = vfp_dreg_to_num(dm)?;
8290 let (vd, d) = encode_dreg(dd_num);
8291 let (vm, m) = encode_dreg(dm_num);
8292
8293 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8294}
8295
8296fn encode_vfp_ldst_f64(base: u32, dd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8299 let dd_num = vfp_dreg_to_num(dd)?;
8300 let (vd, d) = encode_dreg(dd_num);
8301 let rn = reg_to_bits(&addr.base);
8302
8303 let offset = addr.offset;
8304 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8305 let abs_offset = offset.unsigned_abs();
8306 let imm8 = (abs_offset / 4) & 0xFF;
8307
8308 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8309}
8310
8311fn encode_vmov_core_dreg(
8315 to_dreg: bool,
8316 dreg: &VfpReg,
8317 core_lo: &Reg,
8318 core_hi: &Reg,
8319) -> Result<u32> {
8320 let d_num = vfp_dreg_to_num(dreg)?;
8321 let (vm, m) = encode_dreg(d_num);
8322 let rt = reg_to_bits(core_lo);
8323 let rt2 = reg_to_bits(core_hi);
8324
8325 let base = if to_dreg { 0xEC400B10 } else { 0xEC500B10 };
8326 Ok(base | (rt2 << 16) | (rt << 12) | (m << 5) | vm)
8327}
8328
8329fn vfp_to_thumb_bytes(instr: u32) -> Vec<u8> {
8331 let hw1 = ((instr >> 16) & 0xFFFF) as u16;
8332 let hw2 = (instr & 0xFFFF) as u16;
8333 let mut bytes = hw1.to_le_bytes().to_vec();
8334 bytes.extend_from_slice(&hw2.to_le_bytes());
8335 bytes
8336}
8337
8338fn qreg_to_num(reg: &QReg) -> u32 {
8344 match reg {
8345 QReg::Q0 => 0,
8346 QReg::Q1 => 1,
8347 QReg::Q2 => 2,
8348 QReg::Q3 => 3,
8349 QReg::Q4 => 4,
8350 QReg::Q5 => 5,
8351 QReg::Q6 => 6,
8352 QReg::Q7 => 7,
8353 }
8354}
8355
8356fn mve_size_bits(size: &MveSize) -> u32 {
8358 match size {
8359 MveSize::S8 => 0b00,
8360 MveSize::S16 => 0b01,
8361 MveSize::S32 => 0b10,
8362 }
8363}
8364
8365fn encode_mve_3reg(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8369 let d = qreg_to_num(qd) * 2;
8370 let n = qreg_to_num(qn) * 2;
8371 let m = qreg_to_num(qm) * 2;
8372
8373 let vd = d & 0xF;
8378 let d_bit = (d >> 4) & 1;
8379 let vn = n & 0xF;
8380 let n_bit = (n >> 4) & 1;
8381 let vm = m & 0xF;
8382 let m_bit = (m >> 4) & 1;
8383
8384 base | (d_bit << 22) | (vn << 16) | (vd << 12) | (n_bit << 7) | (m_bit << 5) | vm
8385}
8386
8387fn encode_mve_3reg_bitwise(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8389 encode_mve_3reg(base, qd, qn, qm)
8390}
8391
8392fn encode_mve_vldrw(qd: &QReg, addr: &MemAddr) -> u32 {
8395 let qd_enc = qreg_to_num(qd) * 2;
8396 let rn = reg_to_bits(&addr.base);
8397 let offset = addr.offset;
8398 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8399 let abs_offset = offset.unsigned_abs();
8400 let imm7 = (abs_offset / 4) & 0x7F; 0xED100E80
8404 | (u_bit << 23)
8405 | ((qd_enc >> 4) << 22)
8406 | (rn << 16)
8407 | ((qd_enc & 0xF) << 12)
8408 | (imm7 & 0x7F)
8409}
8410
8411fn encode_mve_vstrw(qd: &QReg, addr: &MemAddr) -> u32 {
8413 let qd_enc = qreg_to_num(qd) * 2;
8414 let rn = reg_to_bits(&addr.base);
8415 let offset = addr.offset;
8416 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8417 let abs_offset = offset.unsigned_abs();
8418 let imm7 = (abs_offset / 4) & 0x7F;
8419
8420 0xED000E80
8421 | (u_bit << 23)
8422 | ((qd_enc >> 4) << 22)
8423 | (rn << 16)
8424 | ((qd_enc & 0xF) << 12)
8425 | (imm7 & 0x7F)
8426}
8427
8428impl ArmEncoder {
8429 fn encode_thumb_mve_const(&self, qd: &QReg, bytes: &[u8; 16]) -> Result<Vec<u8>> {
8431 let mut result = Vec::new();
8432 let qd_num = qreg_to_num(qd);
8433
8434 for i in 0..4 {
8436 let word = u32::from_le_bytes([
8437 bytes[i * 4],
8438 bytes[i * 4 + 1],
8439 bytes[i * 4 + 2],
8440 bytes[i * 4 + 3],
8441 ]);
8442 let lo16 = word & 0xFFFF;
8443 let hi16 = (word >> 16) & 0xFFFF;
8444
8445 result.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
8447 if hi16 != 0 {
8449 result.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
8450 }
8451
8452 let s_num = qd_num * 4 + i as u32;
8454 let (vn, n) = encode_sreg(s_num);
8455 let vmov: u32 = 0xEE000A10 | (vn << 16) | (12 << 12) | (n << 7);
8456 result.extend_from_slice(&vfp_to_thumb_bytes(vmov));
8457 }
8458
8459 Ok(result)
8460 }
8461
8462 fn encode_thumb_mve_lane_wise_f32_binop(
8464 &self,
8465 qd: &QReg,
8466 qn: &QReg,
8467 qm: &QReg,
8468 vfp_base: u32,
8469 ) -> Result<Vec<u8>> {
8470 let mut result = Vec::new();
8471 let qd_num = qreg_to_num(qd);
8472 let qn_num = qreg_to_num(qn);
8473 let qm_num = qreg_to_num(qm);
8474
8475 for i in 0..4u32 {
8477 let sd = qd_num * 4 + i;
8478 let sn = qn_num * 4 + i;
8479 let sm = qm_num * 4 + i;
8480
8481 let (vd, d) = encode_sreg(sd);
8482 let (vn, n) = encode_sreg(sn);
8483 let (vm, m) = encode_sreg(sm);
8484
8485 let instr = vfp_base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
8486 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8487 }
8488
8489 Ok(result)
8490 }
8491
8492 fn encode_thumb_mve_lane_wise_f32_sqrt(&self, qd: &QReg, qm: &QReg) -> Result<Vec<u8>> {
8494 let mut result = Vec::new();
8495 let qd_num = qreg_to_num(qd);
8496 let qm_num = qreg_to_num(qm);
8497
8498 for i in 0..4u32 {
8500 let sd = qd_num * 4 + i;
8501 let sm = qm_num * 4 + i;
8502
8503 let (vd, d) = encode_sreg(sd);
8504 let (vm, m) = encode_sreg(sm);
8505
8506 let instr: u32 = 0xEEB10AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
8507 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8508 }
8509
8510 Ok(result)
8511 }
8512}
8513
8514#[cfg(test)]
8515mod tests {
8516 use super::*;
8517
8518 #[test]
8519 fn test_encoder_creation() {
8520 let encoder_arm = ArmEncoder::new_arm32();
8521 assert!(!encoder_arm.thumb_mode);
8522
8523 let encoder_thumb = ArmEncoder::new_thumb2();
8524 assert!(encoder_thumb.thumb_mode);
8525 }
8526
8527 #[test]
8539 fn test_encode_i64setcond_high_reg_uses_mov_w_311() {
8540 use synth_synthesis::{ArmOp, Condition, Reg};
8541 let enc = ArmEncoder::new_thumb2();
8542 let bytes = enc
8543 .encode(&ArmOp::I64SetCond {
8544 rd: Reg::R8,
8545 rn_lo: Reg::R2,
8546 rn_hi: Reg::R3,
8547 rm_lo: Reg::R6,
8548 rm_hi: Reg::R7,
8549 cond: Condition::EQ,
8550 })
8551 .unwrap();
8552 let halfwords: Vec<u16> = bytes
8555 .chunks(2)
8556 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8557 .collect();
8558 assert!(
8559 halfwords.iter().filter(|&&h| h == 0xF04F).count() == 2,
8560 "high rd must use two MOV.W (T2) encodings, got {halfwords:04x?}"
8561 );
8562 assert!(
8563 !halfwords.contains(&0x2801) && !halfwords.contains(&0x2800),
8564 "no transmuted 16-bit CMP imm: {halfwords:04x?}"
8565 );
8566
8567 let bytes_z = enc
8568 .encode(&ArmOp::I64SetCondZ {
8569 rd: Reg::R8,
8570 rn_lo: Reg::R2,
8571 rn_hi: Reg::R3,
8572 })
8573 .unwrap();
8574 let hw_z: Vec<u16> = bytes_z
8575 .chunks(2)
8576 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8577 .collect();
8578 assert!(
8579 hw_z.iter().filter(|&&h| h == 0xF04F).count() == 2,
8580 "SetCondZ high rd MOV.W: {hw_z:04x?}"
8581 );
8582 assert!(
8584 hw_z.contains(&(0xF1B0 | 8)),
8585 "SetCondZ high rd must use CMP.W: {hw_z:04x?}"
8586 );
8587 }
8588
8589 #[test]
8590 fn test_encode_setcond_high_reg_uses_mov_w_204() {
8591 use synth_synthesis::{ArmOp, Condition, Reg};
8592 let enc = ArmEncoder::new_thumb2();
8593 let hi = enc
8595 .encode(&ArmOp::SetCond {
8596 rd: Reg::R12,
8597 cond: Condition::NE,
8598 })
8599 .unwrap();
8600 assert_eq!(hi.len(), 10, "ITE(2) + MOV.W(4) + MOV.W(4): {hi:02x?}");
8601 assert_eq!(&hi[2..4], &[0x4F, 0xF0], "then = MOV.W: {hi:02x?}");
8603 assert_eq!(&hi[6..8], &[0x4F, 0xF0], "else = MOV.W: {hi:02x?}");
8604 assert_eq!(hi[4] & 0x0F, 0x01, "then imm = #1");
8605 assert_eq!(hi[8] & 0x0F, 0x00, "else imm = #0");
8606 let lo = enc
8608 .encode(&ArmOp::SetCond {
8609 rd: Reg::R0,
8610 cond: Condition::NE,
8611 })
8612 .unwrap();
8613 assert_eq!(lo.len(), 6, "ITE(2) + MOVS(2) + MOVS(2): {lo:02x?}");
8614 assert_eq!(lo[2..4], [0x01, 0x20], "then = MOVS R0,#1");
8615 assert_eq!(lo[4..6], [0x00, 0x20], "else = MOVS R0,#0");
8616 }
8617
8618 #[test]
8622 fn test_encode_umull_209b() {
8623 use synth_synthesis::{ArmOp, Reg};
8624 let op = ArmOp::Umull {
8625 rdlo: Reg::R4,
8626 rdhi: Reg::R5,
8627 rn: Reg::R0,
8628 rm: Reg::R3,
8629 };
8630 let t = ArmEncoder::new_thumb2().encode(&op).unwrap();
8632 assert_eq!(
8633 t,
8634 vec![0xA0, 0xFB, 0x03, 0x45],
8635 "umull r4,r5,r0,r3 (T2): {t:02x?}"
8636 );
8637 let a = ArmEncoder::new_arm32().encode(&op).unwrap();
8639 assert_eq!(
8640 a,
8641 0xE085_4390u32.to_le_bytes().to_vec(),
8642 "umull (A32): {a:02x?}"
8643 );
8644 }
8645
8646 #[test]
8653 fn test_encode_arm32_indexed_load_keeps_index_206() {
8654 use synth_synthesis::{ArmOp, MemAddr, Reg};
8655 let enc = ArmEncoder::new_arm32();
8656 let bytes = enc
8658 .encode(&ArmOp::Ldr {
8659 rd: Reg::R0,
8660 addr: MemAddr::reg_imm(Reg::R11, Reg::R1, 8),
8661 })
8662 .unwrap();
8663 assert_eq!(
8664 bytes.len(),
8665 8,
8666 "expected ADD ip + LDR (2 words): {bytes:02x?}"
8667 );
8668 let add = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
8669 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
8670 assert_eq!(add, 0xE08B_C001, "ADD ip,r11,r1: {add:#010x}");
8672 assert_eq!(ldr, 0xE59C_0008, "LDR r0,[ip,#8]: {ldr:#010x}");
8674 assert_ne!(ldr, 0xE59B_0008, "index must not be dropped");
8676 }
8677
8678 #[test]
8684 fn test_encode_arm32_call_indirect_is_real_call_594() {
8685 use synth_synthesis::{ArmOp, Reg};
8686 let enc = ArmEncoder::new_arm32();
8687 let bytes = enc
8688 .encode(&ArmOp::CallIndirect {
8689 rd: Reg::R0,
8690 type_idx: 0,
8691 table_index_reg: Reg::R0,
8692 })
8693 .unwrap();
8694 assert_eq!(
8695 bytes.len(),
8696 12,
8697 "expected MOV + LDR + BLX (3 words): {bytes:02x?}"
8698 );
8699 let mov = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
8700 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
8701 let blx = u32::from_le_bytes(bytes[8..12].try_into().unwrap());
8702 assert_eq!(mov, 0xE1A0_C100, "MOV r12,r0,LSL#2: {mov:#010x}");
8704 assert_eq!(ldr, 0xE79B_C00C, "LDR r12,[r11,r12]: {ldr:#010x}");
8706 assert_eq!(blx, 0xE12F_FF3C, "BLX r12: {blx:#010x}");
8708 assert!(
8710 !bytes
8711 .chunks_exact(4)
8712 .any(|w| w == 0xE1A0_0000u32.to_le_bytes()),
8713 "call_indirect must not contain a NOP (#594): {bytes:02x?}"
8714 );
8715
8716 let bytes = enc
8718 .encode(&ArmOp::CallIndirect {
8719 rd: Reg::R0,
8720 type_idx: 0,
8721 table_index_reg: Reg::R4,
8722 })
8723 .unwrap();
8724 let mov = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
8725 assert_eq!(mov, 0xE1A0_C104, "MOV r12,r4,LSL#2: {mov:#010x}");
8726 }
8727
8728 #[test]
8744 fn test_encode_thumb_call_indirect_lsl2_597() {
8745 use synth_synthesis::{ArmOp, Reg};
8746 let enc = ArmEncoder::new_thumb2();
8747 let bytes = enc
8748 .encode(&ArmOp::CallIndirect {
8749 rd: Reg::R0,
8750 type_idx: 0,
8751 table_index_reg: Reg::R0,
8752 })
8753 .unwrap();
8754 assert_eq!(
8755 bytes,
8756 vec![0x4F, 0xEA, 0x80, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47],
8757 "Thumb-2 CallIndirect: mov.w ip,r0,LSL#2; ldr.w ip,[r11,ip]; blx ip: {bytes:02x?}"
8758 );
8759 assert_ne!(
8761 &bytes[0..4],
8762 &[0x4F, 0xEA, 0x20, 0x0C],
8763 "mov.w ip, rm, ASR #32 — the #597 type-field bug"
8764 );
8765
8766 let bytes = enc
8768 .encode(&ArmOp::CallIndirect {
8769 rd: Reg::R0,
8770 type_idx: 0,
8771 table_index_reg: Reg::R4,
8772 })
8773 .unwrap();
8774 assert_eq!(
8775 &bytes[0..4],
8776 &[0x4F, 0xEA, 0x84, 0x0C],
8777 "mov.w ip, r4, LSL #2: {bytes:02x?}"
8778 );
8779 }
8780
8781 #[test]
8788 fn test_encode_thumb_add_high_reg_uses_add_w_178_180() {
8789 let encoder = ArmEncoder::new_thumb2();
8790
8791 let code = encoder
8793 .encode(&ArmOp::Add {
8794 rd: Reg::R12,
8795 rn: Reg::R12,
8796 op2: Operand2::Reg(Reg::R0),
8797 })
8798 .unwrap();
8799 assert_eq!(
8801 code,
8802 vec![0x0C, 0xEB, 0x00, 0x0C],
8803 "high-reg Thumb ADD must be 32-bit ADD.W (EB0C 0C00), not corrupt 16-bit; got {code:02X?}"
8804 );
8805 assert_ne!(code, vec![0x6C, 0x18], "regressed to corrupt 16-bit ADDS");
8807
8808 let lo = encoder
8810 .encode(&ArmOp::Add {
8811 rd: Reg::R1,
8812 rn: Reg::R2,
8813 op2: Operand2::Reg(Reg::R3),
8814 })
8815 .unwrap();
8816 assert_eq!(
8817 lo.len(),
8818 2,
8819 "low-reg ADD should remain 16-bit, got {lo:02X?}"
8820 );
8821 }
8822
8823 #[test]
8826 fn test_encode_thumb_adds_subs_high_reg_use_32bit_178_180() {
8827 let encoder = ArmEncoder::new_thumb2();
8828
8829 let adds = encoder
8831 .encode(&ArmOp::Adds {
8832 rd: Reg::R10,
8833 rn: Reg::R10,
8834 op2: Operand2::Reg(Reg::R8),
8835 })
8836 .unwrap();
8837 assert_eq!(
8838 adds,
8839 vec![0x1A, 0xEB, 0x08, 0x0A],
8840 "high-reg ADDS must be 32-bit ADDS.W (EB1A 0A08); got {adds:02X?}"
8841 );
8842
8843 let subs = encoder
8845 .encode(&ArmOp::Subs {
8846 rd: Reg::R10,
8847 rn: Reg::R10,
8848 op2: Operand2::Reg(Reg::R8),
8849 })
8850 .unwrap();
8851 assert_eq!(
8852 subs,
8853 vec![0xBA, 0xEB, 0x08, 0x0A],
8854 "high-reg SUBS must be 32-bit SUBS.W (EBBA 0A08); got {subs:02X?}"
8855 );
8856 }
8857
8858 #[test]
8861 fn test_encode_thumb_cmn_high_reg_uses_cmn_w_184() {
8862 let encoder = ArmEncoder::new_thumb2();
8863
8864 let cmn = encoder
8866 .encode(&ArmOp::Cmn {
8867 rn: Reg::R10,
8868 op2: Operand2::Reg(Reg::R8),
8869 })
8870 .unwrap();
8871 assert_eq!(
8872 cmn,
8873 vec![0x1A, 0xEB, 0x08, 0x0F],
8874 "high-reg CMN must be 32-bit CMN.W (EB1A 0F08); got {cmn:02X?}"
8875 );
8876
8877 let lo = encoder
8879 .encode(&ArmOp::Cmn {
8880 rn: Reg::R1,
8881 op2: Operand2::Reg(Reg::R2),
8882 })
8883 .unwrap();
8884 assert_eq!(
8885 lo.len(),
8886 2,
8887 "low-reg CMN should remain 16-bit, got {lo:02X?}"
8888 );
8889 assert_eq!(lo, vec![0xD1, 0x42], "low-reg CMN bytes wrong: {lo:02X?}");
8890 }
8891
8892 #[test]
8896 fn test_encode_pc_operand_returns_err_not_panic_185() {
8897 let encoder = ArmEncoder::new_thumb2();
8898 for op in [
8899 ArmOp::Sdiv {
8900 rd: Reg::PC,
8901 rn: Reg::R0,
8902 rm: Reg::R1,
8903 },
8904 ArmOp::Udiv {
8905 rd: Reg::R0,
8906 rn: Reg::PC,
8907 rm: Reg::R1,
8908 },
8909 ArmOp::Sdiv {
8910 rd: Reg::R0,
8911 rn: Reg::R1,
8912 rm: Reg::PC,
8913 },
8914 ] {
8915 let r = encoder.encode(&op);
8916 assert!(
8917 r.is_err(),
8918 "encode({op:?}) must return Err for a PC operand, got {r:?}"
8919 );
8920 }
8921 assert!(
8923 encoder
8924 .encode(&ArmOp::Sdiv {
8925 rd: Reg::R0,
8926 rn: Reg::R1,
8927 rm: Reg::R2
8928 })
8929 .is_ok()
8930 );
8931 }
8932
8933 #[test]
8934 fn test_encode_nop_arm32() {
8935 let encoder = ArmEncoder::new_arm32();
8936 let code = encoder.encode(&ArmOp::Nop).unwrap();
8937
8938 assert_eq!(code.len(), 4); assert_eq!(code, vec![0x00, 0x00, 0xA0, 0xE1]); }
8941
8942 #[test]
8943 fn test_encode_nop_thumb() {
8944 let encoder = ArmEncoder::new_thumb2();
8945 let code = encoder.encode(&ArmOp::Nop).unwrap();
8946
8947 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]); }
8950
8951 #[test]
8952 fn test_encode_mov_immediate_arm32() {
8953 let encoder = ArmEncoder::new_arm32();
8954 let op = ArmOp::Mov {
8955 rd: Reg::R0,
8956 op2: Operand2::Imm(42),
8957 };
8958
8959 let code = encoder.encode(&op).unwrap();
8960 assert_eq!(code.len(), 4);
8961
8962 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8964 assert_eq!(instr & 0x0E000000, 0x02000000); }
8966
8967 #[test]
8968 fn test_encode_add_registers_arm32() {
8969 let encoder = ArmEncoder::new_arm32();
8970 let op = ArmOp::Add {
8971 rd: Reg::R0,
8972 rn: Reg::R1,
8973 op2: Operand2::Reg(Reg::R2),
8974 };
8975
8976 let code = encoder.encode(&op).unwrap();
8977 assert_eq!(code.len(), 4);
8978
8979 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8980 assert_eq!(instr & 0x0FE00000, 0x00800000);
8982 }
8983
8984 #[test]
8988 fn test_encode_add_imm_large_350() {
8989 let enc = ArmEncoder::new_thumb2();
8990
8991 let small = enc
8993 .encode_thumb32_add_imm(&Reg::R0, &Reg::R1, 0x123)
8994 .unwrap();
8995 assert_eq!(small.len(), 4, "small imm must stay a single instruction");
8996
8997 fn movx_imm16(b: &[u8]) -> u32 {
8999 let hw1 = u16::from_le_bytes([b[0], b[1]]) as u32;
9000 let hw2 = u16::from_le_bytes([b[2], b[3]]) as u32;
9001 let imm4 = hw1 & 0xF;
9002 let i = (hw1 >> 10) & 1;
9003 let imm3 = (hw2 >> 12) & 0x7;
9004 let imm8 = hw2 & 0xFF;
9005 (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8
9006 }
9007 fn movx_rd(b: &[u8]) -> u32 {
9008 (u16::from_le_bytes([b[2], b[3]]) as u32 >> 8) & 0xF
9009 }
9010
9011 let seq = enc
9014 .encode_thumb32_add_imm(&Reg::R12, &Reg::R0, 70000)
9015 .unwrap();
9016 assert_eq!(seq.len(), 12, "MOVW + MOVT + ADD = 12 bytes");
9017 assert_eq!(u16::from_le_bytes([seq[0], seq[1]]) & 0xFBF0, 0xF240);
9019 assert_eq!(movx_rd(&seq[0..4]), 12);
9020 assert_eq!(movx_imm16(&seq[0..4]), 0x1170);
9021 assert_eq!(u16::from_le_bytes([seq[4], seq[5]]) & 0xFBF0, 0xF2C0);
9023 assert_eq!(movx_rd(&seq[4..8]), 12);
9024 assert_eq!(movx_imm16(&seq[4..8]), 0x0001);
9025 let add1 = u16::from_le_bytes([seq[8], seq[9]]) as u32;
9027 let add2 = u16::from_le_bytes([seq[10], seq[11]]) as u32;
9028 assert_eq!(add1 & 0xFFF0, 0xEB00);
9029 assert_eq!(add1 & 0xF, 0); assert_eq!((add2 >> 8) & 0xF, 12); assert_eq!(add2 & 0xF, 12); assert_eq!(
9034 (movx_imm16(&seq[4..8]) << 16) | movx_imm16(&seq[0..4]),
9035 70000
9036 );
9037
9038 let seq16 = enc
9040 .encode_thumb32_add_imm(&Reg::R3, &Reg::R0, 0xABCD)
9041 .unwrap();
9042 assert_eq!(seq16.len(), 8, "imm <= 0xFFFF skips MOVT");
9043 assert_eq!(movx_imm16(&seq16[0..4]), 0xABCD);
9044 assert_eq!(movx_rd(&seq16[0..4]), 3); let inplace = enc
9049 .encode_thumb32_add_imm(&Reg::R5, &Reg::R5, 0x12345)
9050 .unwrap();
9051 assert_eq!(inplace.len(), 12);
9052 assert_eq!(movx_rd(&inplace[0..4]), 12, "rd==rn must use R12 scratch");
9053 assert_eq!(
9054 (movx_imm16(&inplace[4..8]) << 16) | movx_imm16(&inplace[0..4]),
9055 0x12345
9056 );
9057 let ip_add2 = u16::from_le_bytes([inplace[10], inplace[11]]) as u32;
9059 assert_eq!(ip_add2 & 0xF, 12);
9060 assert_eq!((ip_add2 >> 8) & 0xF, 5);
9061 }
9062
9063 #[test]
9071 fn test_encode_add_imm_large_rd_rn_r12_errs_not_panics_350() {
9072 let enc = ArmEncoder::new_thumb2();
9073 let r = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 70000);
9075 assert!(
9076 r.is_err(),
9077 "rd==rn==R12 with out-of-range imm must Err (no free scratch), got {r:?}"
9078 );
9079 let small = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 0x10);
9083 assert!(small.is_ok(), "small imm needs no scratch, must stay Ok");
9084 }
9085
9086 #[test]
9095 fn test_encode_operand2_non_rotatable_imm_errs_not_masks_378() {
9096 let enc = ArmEncoder::new_arm32();
9097 let bad = enc.encode(&ArmOp::Add {
9098 rd: Reg::R0,
9099 rn: Reg::R1,
9100 op2: Operand2::Imm(0x1FF),
9101 });
9102 assert!(
9103 bad.is_err(),
9104 "non-rotatable ARM32 immediate 0x1FF must Err (was silently masked \
9105 to 0xFF), got {bad:?}"
9106 );
9107 let ok = enc.encode(&ArmOp::Add {
9109 rd: Reg::R0,
9110 rn: Reg::R1,
9111 op2: Operand2::Imm(0xFF),
9112 });
9113 assert!(
9114 ok.is_ok(),
9115 "0xFF is a valid rotated immediate, must stay Ok"
9116 );
9117 }
9118
9119 #[test]
9120 fn test_encode_ldr_arm32() {
9121 let encoder = ArmEncoder::new_arm32();
9122 let op = ArmOp::Ldr {
9123 rd: Reg::R0,
9124 addr: MemAddr::imm(Reg::R1, 4),
9125 };
9126
9127 let code = encoder.encode(&op).unwrap();
9128 assert_eq!(code.len(), 4);
9129
9130 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9131 assert_eq!(instr & 0x00100000, 0x00100000);
9133 }
9134
9135 #[test]
9136 fn test_encode_str_arm32() {
9137 let encoder = ArmEncoder::new_arm32();
9138 let op = ArmOp::Str {
9139 rd: Reg::R0,
9140 addr: MemAddr::imm(Reg::SP, 0),
9141 };
9142
9143 let code = encoder.encode(&op).unwrap();
9144 assert_eq!(code.len(), 4);
9145 }
9146
9147 #[test]
9148 fn test_encode_branch_arm32() {
9149 let encoder = ArmEncoder::new_arm32();
9150 let op = ArmOp::Bl {
9151 label: "main".to_string(),
9152 };
9153
9154 let code = encoder.encode(&op).unwrap();
9155 assert_eq!(code.len(), 4);
9156
9157 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9158 assert_eq!(instr & 0x0F000000, 0x0B000000);
9160 }
9161
9162 #[test]
9172 fn test_encode_thumb_bl_placeholder_addend_167_174() {
9173 let encoder = ArmEncoder::new_thumb2();
9174 let op = ArmOp::Bl {
9175 label: "callee".to_string(),
9176 };
9177
9178 let code = encoder.encode(&op).unwrap();
9179 assert_eq!(code.len(), 4, "Thumb-2 BL is 32-bit");
9180
9181 let hw1 = u16::from_le_bytes([code[0], code[1]]);
9182 let hw2 = u16::from_le_bytes([code[2], code[3]]);
9183 assert_eq!(hw1, 0xF7FF, "BL first halfword (matches gas `bl <extern>`)");
9184 assert_eq!(
9185 hw2, 0xFFFE,
9186 "BL second halfword must be 0xFFFE (-4 addend → nets to S), not 0xF800 (→ S+4, #174) or 0xD000 (#167)"
9187 );
9188 assert_ne!(hw2, 0xF800, "0xF800 (addend 0) lands at S+4 (#174)");
9189 assert_ne!(hw2, 0xD000, "0xD000 bakes in a ~+0x600000 addend (#167)");
9190 }
9191
9192 #[test]
9193 fn test_encode_sequence() {
9194 let encoder = ArmEncoder::new_arm32();
9195 let ops = vec![
9196 ArmOp::Mov {
9197 rd: Reg::R0,
9198 op2: Operand2::Imm(42),
9199 },
9200 ArmOp::Mov {
9201 rd: Reg::R1,
9202 op2: Operand2::Imm(10),
9203 },
9204 ArmOp::Add {
9205 rd: Reg::R2,
9206 rn: Reg::R0,
9207 op2: Operand2::Reg(Reg::R1),
9208 },
9209 ];
9210
9211 let code = encoder.encode_sequence(&ops).unwrap();
9212 assert_eq!(code.len(), 12); }
9214
9215 #[test]
9216 fn test_reg_to_bits() {
9217 assert_eq!(reg_to_bits(&Reg::R0), 0);
9218 assert_eq!(reg_to_bits(&Reg::R7), 7);
9219 assert_eq!(reg_to_bits(&Reg::SP), 13);
9220 assert_eq!(reg_to_bits(&Reg::LR), 14);
9221 assert_eq!(reg_to_bits(&Reg::PC), 15);
9222 }
9223
9224 #[test]
9225 fn test_encode_bitwise_operations() {
9226 let encoder = ArmEncoder::new_arm32();
9227
9228 let and_op = ArmOp::And {
9229 rd: Reg::R0,
9230 rn: Reg::R1,
9231 op2: Operand2::Reg(Reg::R2),
9232 };
9233 let and_code = encoder.encode(&and_op).unwrap();
9234 assert_eq!(and_code.len(), 4);
9235
9236 let orr_op = ArmOp::Orr {
9237 rd: Reg::R0,
9238 rn: Reg::R1,
9239 op2: Operand2::Reg(Reg::R2),
9240 };
9241 let orr_code = encoder.encode(&orr_op).unwrap();
9242 assert_eq!(orr_code.len(), 4);
9243
9244 let eor_op = ArmOp::Eor {
9245 rd: Reg::R0,
9246 rn: Reg::R1,
9247 op2: Operand2::Reg(Reg::R2),
9248 };
9249 let eor_code = encoder.encode(&eor_op).unwrap();
9250 assert_eq!(eor_code.len(), 4);
9251 }
9252
9253 #[test]
9256 fn test_encode_sdiv_thumb2() {
9257 let encoder = ArmEncoder::new_thumb2();
9258 let op = ArmOp::Sdiv {
9259 rd: Reg::R0,
9260 rn: Reg::R1,
9261 rm: Reg::R2,
9262 };
9263
9264 let code = encoder.encode(&op).unwrap();
9265 assert_eq!(code.len(), 4); assert_eq!(code[0], 0x91);
9272 assert_eq!(code[1], 0xFB);
9273 assert_eq!(code[2], 0xF2);
9274 assert_eq!(code[3], 0xF0);
9275 }
9276
9277 #[test]
9278 fn test_encode_udiv_thumb2() {
9279 let encoder = ArmEncoder::new_thumb2();
9280 let op = ArmOp::Udiv {
9281 rd: Reg::R0,
9282 rn: Reg::R1,
9283 rm: Reg::R2,
9284 };
9285
9286 let code = encoder.encode(&op).unwrap();
9287 assert_eq!(code.len(), 4); assert_eq!(code[0], 0xB1);
9292 assert_eq!(code[1], 0xFB);
9293 assert_eq!(code[2], 0xF2);
9294 assert_eq!(code[3], 0xF0);
9295 }
9296
9297 #[test]
9298 fn test_encode_mul_thumb2() {
9299 let encoder = ArmEncoder::new_thumb2();
9300 let op = ArmOp::Mul {
9301 rd: Reg::R0,
9302 rn: Reg::R1,
9303 rm: Reg::R2,
9304 };
9305
9306 let code = encoder.encode(&op).unwrap();
9307 assert_eq!(code.len(), 4); }
9309
9310 #[test]
9311 fn test_encode_and_thumb2() {
9312 let encoder = ArmEncoder::new_thumb2();
9313 let op = ArmOp::And {
9314 rd: Reg::R0,
9315 rn: Reg::R1,
9316 op2: Operand2::Reg(Reg::R2),
9317 };
9318
9319 let code = encoder.encode(&op).unwrap();
9320 assert_eq!(code.len(), 4); }
9322
9323 #[test]
9324 fn test_encode_lsl_thumb2_low_regs() {
9325 let encoder = ArmEncoder::new_thumb2();
9326 let op = ArmOp::Lsl {
9327 rd: Reg::R0,
9328 rn: Reg::R1,
9329 shift: 5,
9330 };
9331
9332 let code = encoder.encode(&op).unwrap();
9333 assert_eq!(code.len(), 2); }
9335
9336 #[test]
9337 fn test_encode_clz_thumb2() {
9338 let encoder = ArmEncoder::new_thumb2();
9339 let op = ArmOp::Clz {
9340 rd: Reg::R0,
9341 rm: Reg::R1,
9342 };
9343
9344 let code = encoder.encode(&op).unwrap();
9345 assert_eq!(code.len(), 4); }
9347
9348 #[test]
9349 fn test_encode_bx_thumb2() {
9350 let encoder = ArmEncoder::new_thumb2();
9351 let op = ArmOp::Bx { rm: Reg::LR };
9352
9353 let code = encoder.encode(&op).unwrap();
9354 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x70, 0x47]);
9358 }
9359
9360 #[test]
9365 fn test_encode_f32_abs_arm32() {
9366 let encoder = ArmEncoder::new_arm32();
9367 let op = ArmOp::F32Abs {
9368 sd: VfpReg::S0,
9369 sm: VfpReg::S2,
9370 };
9371 let code = encoder.encode(&op).unwrap();
9372 assert_eq!(code.len(), 4); }
9374
9375 #[test]
9376 fn test_encode_f32_neg_arm32() {
9377 let encoder = ArmEncoder::new_arm32();
9378 let op = ArmOp::F32Neg {
9379 sd: VfpReg::S0,
9380 sm: VfpReg::S2,
9381 };
9382 let code = encoder.encode(&op).unwrap();
9383 assert_eq!(code.len(), 4);
9384 }
9385
9386 #[test]
9387 fn test_encode_f32_sqrt_arm32() {
9388 let encoder = ArmEncoder::new_arm32();
9389 let op = ArmOp::F32Sqrt {
9390 sd: VfpReg::S0,
9391 sm: VfpReg::S2,
9392 };
9393 let code = encoder.encode(&op).unwrap();
9394 assert_eq!(code.len(), 4);
9395 }
9396
9397 #[test]
9398 fn test_encode_f32_ceil_arm32() {
9399 let encoder = ArmEncoder::new_arm32();
9400 let op = ArmOp::F32Ceil {
9401 sd: VfpReg::S0,
9402 sm: VfpReg::S2,
9403 };
9404 let code = encoder.encode(&op).unwrap();
9405 assert_eq!(code.len(), 36);
9407 }
9408
9409 #[test]
9410 fn test_encode_f32_floor_thumb2() {
9411 let encoder = ArmEncoder::new_thumb2();
9412 let op = ArmOp::F32Floor {
9413 sd: VfpReg::S0,
9414 sm: VfpReg::S2,
9415 };
9416 let code = encoder.encode(&op).unwrap();
9417 assert_eq!(code.len(), 36);
9419 }
9420
9421 #[test]
9422 fn test_encode_f32_min_arm32() {
9423 let encoder = ArmEncoder::new_arm32();
9424 let op = ArmOp::F32Min {
9425 sd: VfpReg::S0,
9426 sn: VfpReg::S2,
9427 sm: VfpReg::S4,
9428 };
9429 let code = encoder.encode(&op).unwrap();
9430 assert_eq!(code.len(), 16); }
9432
9433 #[test]
9434 fn test_encode_f32_max_thumb2() {
9435 let encoder = ArmEncoder::new_thumb2();
9436 let op = ArmOp::F32Max {
9437 sd: VfpReg::S0,
9438 sn: VfpReg::S2,
9439 sm: VfpReg::S4,
9440 };
9441 let code = encoder.encode(&op).unwrap();
9442 assert_eq!(code.len(), 18);
9444 }
9445
9446 #[test]
9447 fn test_encode_f32_copysign_arm32() {
9448 let encoder = ArmEncoder::new_arm32();
9449 let op = ArmOp::F32Copysign {
9450 sd: VfpReg::S0,
9451 sn: VfpReg::S2,
9452 sm: VfpReg::S4,
9453 };
9454 let code = encoder.encode(&op).unwrap();
9455 assert_eq!(code.len(), 24);
9457 }
9458
9459 #[test]
9464 fn test_encode_f64_add_arm32() {
9465 let encoder = ArmEncoder::new_arm32();
9466 let op = ArmOp::F64Add {
9467 dd: VfpReg::D0,
9468 dn: VfpReg::D1,
9469 dm: VfpReg::D2,
9470 };
9471 let code = encoder.encode(&op).unwrap();
9472 assert_eq!(code.len(), 4);
9473 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9475 assert_eq!((instr >> 8) & 0xF, 0xB); }
9477
9478 #[test]
9479 fn test_encode_f64_sub_thumb2() {
9480 let encoder = ArmEncoder::new_thumb2();
9481 let op = ArmOp::F64Sub {
9482 dd: VfpReg::D0,
9483 dn: VfpReg::D1,
9484 dm: VfpReg::D2,
9485 };
9486 let code = encoder.encode(&op).unwrap();
9487 assert_eq!(code.len(), 4); }
9489
9490 #[test]
9491 fn test_encode_f64_mul_arm32() {
9492 let encoder = ArmEncoder::new_arm32();
9493 let op = ArmOp::F64Mul {
9494 dd: VfpReg::D0,
9495 dn: VfpReg::D1,
9496 dm: VfpReg::D2,
9497 };
9498 let code = encoder.encode(&op).unwrap();
9499 assert_eq!(code.len(), 4);
9500 }
9501
9502 #[test]
9503 fn test_encode_f64_div_arm32() {
9504 let encoder = ArmEncoder::new_arm32();
9505 let op = ArmOp::F64Div {
9506 dd: VfpReg::D0,
9507 dn: VfpReg::D1,
9508 dm: VfpReg::D2,
9509 };
9510 let code = encoder.encode(&op).unwrap();
9511 assert_eq!(code.len(), 4);
9512 }
9513
9514 #[test]
9515 fn test_encode_f64_abs_arm32() {
9516 let encoder = ArmEncoder::new_arm32();
9517 let op = ArmOp::F64Abs {
9518 dd: VfpReg::D0,
9519 dm: VfpReg::D2,
9520 };
9521 let code = encoder.encode(&op).unwrap();
9522 assert_eq!(code.len(), 4);
9523 }
9524
9525 #[test]
9526 fn test_encode_f64_neg_arm32() {
9527 let encoder = ArmEncoder::new_arm32();
9528 let op = ArmOp::F64Neg {
9529 dd: VfpReg::D0,
9530 dm: VfpReg::D2,
9531 };
9532 let code = encoder.encode(&op).unwrap();
9533 assert_eq!(code.len(), 4);
9534 }
9535
9536 #[test]
9537 fn test_encode_f64_sqrt_arm32() {
9538 let encoder = ArmEncoder::new_arm32();
9539 let op = ArmOp::F64Sqrt {
9540 dd: VfpReg::D0,
9541 dm: VfpReg::D2,
9542 };
9543 let code = encoder.encode(&op).unwrap();
9544 assert_eq!(code.len(), 4);
9545 }
9546
9547 #[test]
9548 fn test_encode_f64_load_arm32() {
9549 let encoder = ArmEncoder::new_arm32();
9550 let op = ArmOp::F64Load {
9551 dd: VfpReg::D0,
9552 addr: MemAddr::imm(Reg::R0, 8),
9553 };
9554 let code = encoder.encode(&op).unwrap();
9555 assert_eq!(code.len(), 4);
9556 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9557 assert_eq!((instr >> 8) & 0xF, 0xB); assert_eq!(instr & 0xFF, 2); }
9560
9561 #[test]
9562 fn test_encode_f64_store_thumb2() {
9563 let encoder = ArmEncoder::new_thumb2();
9564 let op = ArmOp::F64Store {
9565 dd: VfpReg::D0,
9566 addr: MemAddr::imm(Reg::SP, 0),
9567 };
9568 let code = encoder.encode(&op).unwrap();
9569 assert_eq!(code.len(), 4);
9570 }
9571
9572 #[test]
9573 fn test_encode_f64_compare_arm32() {
9574 let encoder = ArmEncoder::new_arm32();
9575 let op = ArmOp::F64Eq {
9576 rd: Reg::R0,
9577 dn: VfpReg::D0,
9578 dm: VfpReg::D1,
9579 };
9580 let code = encoder.encode(&op).unwrap();
9581 assert_eq!(code.len(), 16); }
9583
9584 #[test]
9585 fn test_encode_f64_compare_thumb2() {
9586 let encoder = ArmEncoder::new_thumb2();
9587 let op = ArmOp::F64Lt {
9588 rd: Reg::R0,
9589 dn: VfpReg::D0,
9590 dm: VfpReg::D1,
9591 };
9592 let code = encoder.encode(&op).unwrap();
9593 assert_eq!(code.len(), 14);
9595 }
9596
9597 #[test]
9598 fn test_encode_f64_const_arm32() {
9599 let encoder = ArmEncoder::new_arm32();
9600 let op = ArmOp::F64Const {
9601 dd: VfpReg::D0,
9602 value: 3.125,
9603 };
9604 let code = encoder.encode(&op).unwrap();
9605 assert_eq!(code.len(), 20);
9607 }
9608
9609 #[test]
9610 fn test_encode_f64_const_thumb2() {
9611 let encoder = ArmEncoder::new_thumb2();
9612 let op = ArmOp::F64Const {
9613 dd: VfpReg::D0,
9614 value: 2.5,
9615 };
9616 let code = encoder.encode(&op).unwrap();
9617 assert_eq!(code.len(), 20);
9619 }
9620
9621 #[test]
9622 fn test_encode_f64_convert_i32s_arm32() {
9623 let encoder = ArmEncoder::new_arm32();
9624 let op = ArmOp::F64ConvertI32S {
9625 dd: VfpReg::D0,
9626 rm: Reg::R0,
9627 };
9628 let code = encoder.encode(&op).unwrap();
9629 assert_eq!(code.len(), 8);
9631 }
9632
9633 #[test]
9634 fn test_encode_f64_promote_f32_arm32() {
9635 let encoder = ArmEncoder::new_arm32();
9636 let op = ArmOp::F64PromoteF32 {
9637 dd: VfpReg::D0,
9638 sm: VfpReg::S0,
9639 };
9640 let code = encoder.encode(&op).unwrap();
9641 assert_eq!(code.len(), 4); }
9643
9644 #[test]
9645 fn test_encode_f64_promote_f32_thumb2() {
9646 let encoder = ArmEncoder::new_thumb2();
9647 let op = ArmOp::F64PromoteF32 {
9648 dd: VfpReg::D0,
9649 sm: VfpReg::S0,
9650 };
9651 let code = encoder.encode(&op).unwrap();
9652 assert_eq!(code.len(), 4);
9653 }
9654
9655 #[test]
9656 fn test_encode_i32_trunc_f64s_arm32() {
9657 let encoder = ArmEncoder::new_arm32();
9658 let op = ArmOp::I32TruncF64S {
9659 rd: Reg::R0,
9660 dm: VfpReg::D0,
9661 };
9662 let code = encoder.encode(&op).unwrap();
9663 assert_eq!(code.len(), 8);
9665 }
9666
9667 #[test]
9668 fn test_encode_f64_reinterpret_i64_arm32() {
9669 let encoder = ArmEncoder::new_arm32();
9670 let op = ArmOp::F64ReinterpretI64 {
9671 dd: VfpReg::D0,
9672 rmlo: Reg::R0,
9673 rmhi: Reg::R1,
9674 };
9675 let code = encoder.encode(&op).unwrap();
9676 assert_eq!(code.len(), 4); }
9678
9679 #[test]
9680 fn test_encode_i64_reinterpret_f64_thumb2() {
9681 let encoder = ArmEncoder::new_thumb2();
9682 let op = ArmOp::I64ReinterpretF64 {
9683 rdlo: Reg::R0,
9684 rdhi: Reg::R1,
9685 dm: VfpReg::D0,
9686 };
9687 let code = encoder.encode(&op).unwrap();
9688 assert_eq!(code.len(), 4);
9689 }
9690
9691 #[test]
9692 fn test_encode_f64_trunc_thumb2() {
9693 let encoder = ArmEncoder::new_thumb2();
9694 let op = ArmOp::F64Trunc {
9695 dd: VfpReg::D0,
9696 dm: VfpReg::D1,
9697 };
9698 let code = encoder.encode(&op).unwrap();
9699 assert_eq!(code.len(), 8);
9701 }
9702
9703 #[test]
9704 fn test_encode_f64_min_arm32() {
9705 let encoder = ArmEncoder::new_arm32();
9706 let op = ArmOp::F64Min {
9707 dd: VfpReg::D0,
9708 dn: VfpReg::D1,
9709 dm: VfpReg::D2,
9710 };
9711 let code = encoder.encode(&op).unwrap();
9712 assert_eq!(code.len(), 16);
9714 }
9715
9716 #[test]
9717 fn test_f64_cp11_encoding() {
9718 let encoder = ArmEncoder::new_arm32();
9720
9721 let code = encoder
9723 .encode(&ArmOp::F64Add {
9724 dd: VfpReg::D0,
9725 dn: VfpReg::D0,
9726 dm: VfpReg::D0,
9727 })
9728 .unwrap();
9729 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9730 assert_eq!((instr >> 8) & 0xF, 0xB, "F64 should use cp11");
9731
9732 let code = encoder
9734 .encode(&ArmOp::F32Add {
9735 sd: VfpReg::S0,
9736 sn: VfpReg::S0,
9737 sm: VfpReg::S0,
9738 })
9739 .unwrap();
9740 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9741 assert_eq!((instr >> 8) & 0xF, 0xA, "F32 should use cp10");
9742 }
9743
9744 #[test]
9745 fn test_dreg_encoding_higher_registers() {
9746 let encoder = ArmEncoder::new_arm32();
9747
9748 let op = ArmOp::F64Add {
9750 dd: VfpReg::D15,
9751 dn: VfpReg::D14,
9752 dm: VfpReg::D13,
9753 };
9754 let code = encoder.encode(&op).unwrap();
9755 assert_eq!(code.len(), 4);
9756
9757 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9759 assert_eq!((instr >> 8) & 0xF, 0xB); }
9761
9762 #[test]
9767 fn test_encode_label_emits_no_bytes() {
9768 let encoder = ArmEncoder::new_thumb2();
9769 let op = ArmOp::Label {
9770 name: ".Lblock_end_0".to_string(),
9771 };
9772 let code = encoder.encode(&op).unwrap();
9773 assert!(code.is_empty(), "Label should emit zero bytes");
9774
9775 let encoder32 = ArmEncoder::new_arm32();
9776 let code32 = encoder32.encode(&op).unwrap();
9777 assert!(
9778 code32.is_empty(),
9779 "Label should emit zero bytes in ARM32 too"
9780 );
9781 }
9782
9783 #[test]
9784 fn test_encode_bcc_eq_thumb2() {
9785 use synth_synthesis::Condition;
9786 let encoder = ArmEncoder::new_thumb2();
9787 let op = ArmOp::Bcc {
9788 cond: Condition::EQ,
9789 label: "target".to_string(),
9790 };
9791 let code = encoder.encode(&op).unwrap();
9792 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xD0]);
9796 }
9797
9798 #[test]
9799 fn test_encode_bcc_ne_thumb2() {
9800 use synth_synthesis::Condition;
9801 let encoder = ArmEncoder::new_thumb2();
9802 let op = ArmOp::Bcc {
9803 cond: Condition::NE,
9804 label: "target".to_string(),
9805 };
9806 let code = encoder.encode(&op).unwrap();
9807 assert_eq!(code.len(), 2);
9808
9809 assert_eq!(code, vec![0x00, 0xD1]);
9811 }
9812
9813 #[test]
9814 fn test_encode_bcc_arm32() {
9815 use synth_synthesis::Condition;
9816 let encoder = ArmEncoder::new_arm32();
9817 let op = ArmOp::Bcc {
9818 cond: Condition::EQ,
9819 label: "target".to_string(),
9820 };
9821 let code = encoder.encode(&op).unwrap();
9822 assert_eq!(code.len(), 4); let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9825 assert_eq!(instr & 0xF0000000, 0x00000000); assert_eq!(instr & 0x0F000000, 0x0A000000); }
9829
9830 #[test]
9831 fn test_encode_udf_thumb2() {
9832 let encoder = ArmEncoder::new_thumb2();
9833 let op = ArmOp::Udf { imm: 0 };
9834 let code = encoder.encode(&op).unwrap();
9835 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xDE]);
9839 }
9840
9841 #[test]
9847 fn test_610_i64_rot_expansion_ends_with_rd_movs_and_restore() {
9848 let encoder = ArmEncoder::new_thumb2();
9849 for op in [
9850 ArmOp::I64Rotl {
9851 rdlo: Reg::R4,
9852 rdhi: Reg::R5,
9853 rnlo: Reg::R0,
9854 rnhi: Reg::R1,
9855 shift: Reg::R2,
9856 },
9857 ArmOp::I64Rotr {
9858 rdlo: Reg::R4,
9859 rdhi: Reg::R5,
9860 rnlo: Reg::R0,
9861 rnhi: Reg::R1,
9862 shift: Reg::R2,
9863 },
9864 ] {
9865 let code = encoder.encode(&op).unwrap();
9866 assert_eq!(code.len(), 102, "register-independent size (estimator pin)");
9867 let tail: Vec<u16> = code[code.len() - 12..]
9870 .chunks(2)
9871 .map(|c| u16::from_le_bytes([c[0], c[1]]))
9872 .collect();
9873 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
9874 }
9875 }
9876
9877 #[test]
9880 fn test_610_i64_div_rem_expansion_guard_and_rd() {
9881 let encoder = ArmEncoder::new_thumb2();
9882 let mk = |which: u8| {
9883 let (rdlo, rdhi, rnlo, rnhi, rmlo, rmhi) =
9884 (Reg::R4, Reg::R5, Reg::R0, Reg::R1, Reg::R2, Reg::R3);
9885 match which {
9886 0 => ArmOp::I64DivU {
9887 rdlo,
9888 rdhi,
9889 rnlo,
9890 rnhi,
9891 rmlo,
9892 rmhi,
9893 },
9894 1 => ArmOp::I64RemU {
9895 rdlo,
9896 rdhi,
9897 rnlo,
9898 rnhi,
9899 rmlo,
9900 rmhi,
9901 },
9902 2 => ArmOp::I64DivS {
9903 rdlo,
9904 rdhi,
9905 rnlo,
9906 rnhi,
9907 rmlo,
9908 rmhi,
9909 },
9910 _ => ArmOp::I64RemS {
9911 rdlo,
9912 rdhi,
9913 rnlo,
9914 rnhi,
9915 rmlo,
9916 rmhi,
9917 },
9918 }
9919 };
9920 for which in 0..4u8 {
9921 let code = encoder.encode(&mk(which)).unwrap();
9922 let guard: Vec<u16> = code[26..34]
9924 .chunks(2)
9925 .map(|c| u16::from_le_bytes([c[0], c[1]]))
9926 .collect();
9927 assert_eq!(
9928 guard,
9929 vec![0xEA52, 0x0C03, 0xD100, 0xDE00],
9930 "ORRS R12,R2,R3; BNE +0; UDF #0"
9931 );
9932 let tail: Vec<u16> = code[code.len() - 12..]
9934 .chunks(2)
9935 .map(|c| u16::from_le_bytes([c[0], c[1]]))
9936 .collect();
9937 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
9938 }
9939 }
9940
9941 #[test]
9944 fn test_610_i64_divu_rd_in_r0_r1_skips_restore() {
9945 let encoder = ArmEncoder::new_thumb2();
9946 let code = encoder
9947 .encode(&ArmOp::I64DivU {
9948 rdlo: Reg::R0,
9949 rdhi: Reg::R1,
9950 rnlo: Reg::R0,
9951 rnhi: Reg::R1,
9952 rmlo: Reg::R2,
9953 rmhi: Reg::R3,
9954 })
9955 .unwrap();
9956 let tail: Vec<u16> = code[code.len() - 12..]
9957 .chunks(2)
9958 .map(|c| u16::from_le_bytes([c[0], c[1]]))
9959 .collect();
9960 assert_eq!(tail, vec![0x4609, 0x4600, 0xB001, 0xB001, 0xBC04, 0xBC08]);
9963 }
9964
9965 #[test]
9969 fn test_610_i64_swapped_rd_pair_rejected() {
9970 let encoder = ArmEncoder::new_thumb2();
9971 let result = encoder.encode(&ArmOp::I64RemU {
9972 rdlo: Reg::R1,
9973 rdhi: Reg::R0,
9974 rnlo: Reg::R2,
9975 rnhi: Reg::R3,
9976 rmlo: Reg::R4,
9977 rmhi: Reg::R5,
9978 });
9979 assert!(result.is_err(), "swapped rd pair must be rejected loudly");
9980 }
9981
9982 #[test]
9989 fn test_632_i64_popcnt_result_survives_scratch_restore() {
9990 let encoder = ArmEncoder::new_thumb2();
9991 for rd in [
9993 Reg::R0,
9994 Reg::R2,
9995 Reg::R3,
9996 Reg::R4,
9997 Reg::R5,
9998 Reg::R6,
9999 Reg::R8,
10000 ] {
10001 let code = encoder
10002 .encode(&ArmOp::I64Popcnt {
10003 rd,
10004 rnlo: Reg::R6,
10005 rnhi: Reg::R7,
10006 })
10007 .unwrap();
10008 assert_eq!(code.len(), 180, "register-independent size (estimator pin)");
10009 let hw: Vec<u16> = code
10010 .chunks(2)
10011 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10012 .collect();
10013 let pop = hw
10014 .iter()
10015 .position(|&h| h == 0xBC38)
10016 .expect("POP {R3,R4,R5} present");
10017 assert_eq!(
10020 &hw[pop - 2..pop],
10021 &[0xEB04, 0x0C05],
10022 "total must be carried in R12 across the restore"
10023 );
10024 let rd_bits = match rd {
10026 Reg::R8 => 8u16,
10027 Reg::R6 => 6,
10028 Reg::R5 => 5,
10029 Reg::R4 => 4,
10030 Reg::R3 => 3,
10031 Reg::R2 => 2,
10032 _ => 0,
10033 };
10034 let expect_mov = 0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7);
10035 assert_eq!(hw[pop + 1], expect_mov, "MOV rd, R12 after the restore");
10036 assert!(
10039 !hw[..pop].contains(&(0x1800 | (5 << 6) | (4 << 3) | rd_bits)),
10040 "no ADDS rd, R4, R5 before the restore pop"
10041 );
10042 }
10043 }
10044
10045 #[test]
10049 fn test_632_i64_popcnt_marshal_pair_at_r3_r4() {
10050 let encoder = ArmEncoder::new_thumb2();
10051 let code = encoder
10052 .encode(&ArmOp::I64Popcnt {
10053 rd: Reg::R0,
10054 rnlo: Reg::R3,
10055 rnhi: Reg::R4,
10056 })
10057 .unwrap();
10058 let hw: Vec<u16> = code
10059 .chunks(2)
10060 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10061 .collect();
10062 assert_eq!(hw[0], 0xB438);
10065 assert_eq!(hw[1], 0x4600 | (1 << 7) | (3 << 3) | 4, "MOV R12, rnlo");
10066 assert_eq!(hw[2], 0x4600 | (4 << 3) | 5, "MOV R5, rnhi");
10067 assert_eq!(hw[3], 0x4664, "MOV R4, R12");
10068 }
10069
10070 #[test]
10073 fn test_632_a32_i64_popcnt_result_survives_scratch_restore() {
10074 let encoder = ArmEncoder::new_arm32();
10075 for rd in [Reg::R0, Reg::R3, Reg::R4, Reg::R5, Reg::R8] {
10076 let code = encoder
10077 .encode(&ArmOp::I64Popcnt {
10078 rd,
10079 rnlo: Reg::R6,
10080 rnhi: Reg::R7,
10081 })
10082 .unwrap();
10083 let words: Vec<u32> = code
10084 .chunks(4)
10085 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
10086 .collect();
10087 let pop = words
10088 .iter()
10089 .position(|&w| w == 0xE8BD_0038)
10090 .expect("POP {R3,R4,R5} present");
10091 assert_eq!(words[pop - 1], 0xE084_C005, "ADD R12, R4, R5 before POP");
10092 let rd_bits = match rd {
10093 Reg::R8 => 8u32,
10094 Reg::R5 => 5,
10095 Reg::R4 => 4,
10096 Reg::R3 => 3,
10097 _ => 0,
10098 };
10099 assert_eq!(
10100 words[pop + 1],
10101 0xE1A0_0000 | (rd_bits << 12) | 12,
10102 "MOV rd, R12 after the restore"
10103 );
10104 }
10105 }
10106
10107 #[test]
10111 fn test_633_i64_divs_overflow_guard_emitted() {
10112 let encoder = ArmEncoder::new_thumb2();
10113 let code = encoder
10114 .encode(&ArmOp::I64DivS {
10115 rdlo: Reg::R4,
10116 rdhi: Reg::R5,
10117 rnlo: Reg::R0,
10118 rnhi: Reg::R1,
10119 rmlo: Reg::R2,
10120 rmhi: Reg::R3,
10121 })
10122 .unwrap();
10123 let guard: Vec<u16> = code[34..56]
10125 .chunks(2)
10126 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10127 .collect();
10128 assert_eq!(
10129 guard,
10130 vec![
10131 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100, 0xDE00, ],
10140 "INT64_MIN/-1 overflow guard after the zero-divisor guard"
10141 );
10142 }
10143
10144 #[test]
10148 fn test_633_i64_rems_has_no_overflow_guard() {
10149 let encoder = ArmEncoder::new_thumb2();
10150 for (is_rem_s, op) in [
10151 (
10152 true,
10153 ArmOp::I64RemS {
10154 rdlo: Reg::R4,
10155 rdhi: Reg::R5,
10156 rnlo: Reg::R0,
10157 rnhi: Reg::R1,
10158 rmlo: Reg::R2,
10159 rmhi: Reg::R3,
10160 },
10161 ),
10162 (
10163 false,
10164 ArmOp::I64DivS {
10165 rdlo: Reg::R4,
10166 rdhi: Reg::R5,
10167 rnlo: Reg::R0,
10168 rnhi: Reg::R1,
10169 rmlo: Reg::R2,
10170 rmhi: Reg::R3,
10171 },
10172 ),
10173 ] {
10174 let code = encoder.encode(&op).unwrap();
10175 let udfs = code
10176 .chunks(2)
10177 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
10178 .count();
10179 let want = if is_rem_s { 1 } else { 2 };
10180 assert_eq!(
10181 udfs, want,
10182 "rem_s: zero-trap only; div_s: zero-trap + overflow trap"
10183 );
10184 }
10185 }
10186
10187 #[test]
10190 fn test_633_a32_i64_divs_overflow_guard() {
10191 let encoder = ArmEncoder::new_arm32();
10192 let mk_divs = ArmOp::I64DivS {
10193 rdlo: Reg::R4,
10194 rdhi: Reg::R5,
10195 rnlo: Reg::R0,
10196 rnhi: Reg::R1,
10197 rmlo: Reg::R2,
10198 rmhi: Reg::R3,
10199 };
10200 let code = encoder.encode(&mk_divs).unwrap();
10201 let words: Vec<u32> = code
10202 .chunks(4)
10203 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
10204 .collect();
10205 let guard = [
10206 0xE002_C003u32, 0xE37C_0001, 0x0350_0000, 0x0351_0102, 0x1A00_0000, 0xE7F0_00F0, ];
10213 assert!(
10214 words.windows(6).any(|w| w == guard),
10215 "A32 I64DivS carries the INT64_MIN/-1 overflow guard"
10216 );
10217 let rems = encoder
10218 .encode(&ArmOp::I64RemS {
10219 rdlo: Reg::R4,
10220 rdhi: Reg::R5,
10221 rnlo: Reg::R0,
10222 rnhi: Reg::R1,
10223 rmlo: Reg::R2,
10224 rmhi: Reg::R3,
10225 })
10226 .unwrap();
10227 let rems_udfs = rems
10228 .chunks(4)
10229 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
10230 .count();
10231 assert_eq!(rems_udfs, 1, "A32 I64RemS keeps only the zero-divisor trap");
10232 }
10233
10234 #[test]
10235 fn test_encode_nop_thumb2() {
10236 let encoder = ArmEncoder::new_thumb2();
10237 let op = ArmOp::Nop;
10238 let code = encoder.encode(&op).unwrap();
10239 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]);
10243 }
10244
10245 #[test]
10250 fn test_encode_i64_add_thumb2() {
10251 let encoder = ArmEncoder::new_thumb2();
10252 let op = ArmOp::I64Add {
10253 rdlo: Reg::R0,
10254 rdhi: Reg::R1,
10255 rnlo: Reg::R0,
10256 rnhi: Reg::R1,
10257 rmlo: Reg::R2,
10258 rmhi: Reg::R3,
10259 };
10260 let code = encoder.encode(&op).unwrap();
10261 assert_eq!(code.len(), 6, "I64Add should be 6 bytes (ADDS + ADC.W)");
10263 }
10264
10265 #[test]
10266 fn test_encode_i64_sub_thumb2() {
10267 let encoder = ArmEncoder::new_thumb2();
10268 let op = ArmOp::I64Sub {
10269 rdlo: Reg::R0,
10270 rdhi: Reg::R1,
10271 rnlo: Reg::R0,
10272 rnhi: Reg::R1,
10273 rmlo: Reg::R2,
10274 rmhi: Reg::R3,
10275 };
10276 let code = encoder.encode(&op).unwrap();
10277 assert_eq!(code.len(), 6, "I64Sub should be 6 bytes (SUBS + SBC.W)");
10279 }
10280
10281 #[test]
10282 fn test_encode_i64_and_thumb2() {
10283 let encoder = ArmEncoder::new_thumb2();
10284 let op = ArmOp::I64And {
10285 rdlo: Reg::R0,
10286 rdhi: Reg::R1,
10287 rnlo: Reg::R0,
10288 rnhi: Reg::R1,
10289 rmlo: Reg::R2,
10290 rmhi: Reg::R3,
10291 };
10292 let code = encoder.encode(&op).unwrap();
10293 assert!(code.len() >= 4, "I64And should emit at least 4 bytes");
10295 }
10296
10297 #[test]
10298 fn test_encode_i64_or_thumb2() {
10299 let encoder = ArmEncoder::new_thumb2();
10300 let op = ArmOp::I64Or {
10301 rdlo: Reg::R0,
10302 rdhi: Reg::R1,
10303 rnlo: Reg::R0,
10304 rnhi: Reg::R1,
10305 rmlo: Reg::R2,
10306 rmhi: Reg::R3,
10307 };
10308 let code = encoder.encode(&op).unwrap();
10309 assert!(code.len() >= 4, "I64Or should emit at least 4 bytes");
10310 }
10311
10312 #[test]
10313 fn test_encode_i64_xor_thumb2() {
10314 let encoder = ArmEncoder::new_thumb2();
10315 let op = ArmOp::I64Xor {
10316 rdlo: Reg::R0,
10317 rdhi: Reg::R1,
10318 rnlo: Reg::R0,
10319 rnhi: Reg::R1,
10320 rmlo: Reg::R2,
10321 rmhi: Reg::R3,
10322 };
10323 let code = encoder.encode(&op).unwrap();
10324 assert!(code.len() >= 4, "I64Xor should emit at least 4 bytes");
10325 }
10326
10327 #[test]
10328 fn test_encode_i64_const_small_thumb2() {
10329 let encoder = ArmEncoder::new_thumb2();
10330 let op = ArmOp::I64Const {
10332 rdlo: Reg::R0,
10333 rdhi: Reg::R1,
10334 value: 42,
10335 };
10336 let code = encoder.encode(&op).unwrap();
10337 assert!(code.len() >= 8, "I64Const should emit at least 8 bytes");
10339 }
10340
10341 #[test]
10342 fn test_encode_i64_const_large_thumb2() {
10343 let encoder = ArmEncoder::new_thumb2();
10344 let op = ArmOp::I64Const {
10346 rdlo: Reg::R0,
10347 rdhi: Reg::R1,
10348 value: 0x1234_5678_9ABC_DEF0_u64 as i64,
10349 };
10350 let code = encoder.encode(&op).unwrap();
10351 assert_eq!(
10353 code.len(),
10354 16,
10355 "I64Const with large value should be 16 bytes"
10356 );
10357 }
10358
10359 #[test]
10360 fn test_encode_i64_extend_i32_s_thumb2() {
10361 let encoder = ArmEncoder::new_thumb2();
10362 let op = ArmOp::I64ExtendI32S {
10363 rdlo: Reg::R0,
10364 rdhi: Reg::R1,
10365 rn: Reg::R0,
10366 };
10367 let code = encoder.encode(&op).unwrap();
10368 assert_eq!(
10370 code.len(),
10371 4,
10372 "I64ExtendI32S (same reg) should be 4 bytes (ASR only)"
10373 );
10374 }
10375
10376 #[test]
10377 fn test_encode_i64_extend_i32_s_diff_reg_thumb2() {
10378 let encoder = ArmEncoder::new_thumb2();
10379 let op = ArmOp::I64ExtendI32S {
10380 rdlo: Reg::R0,
10381 rdhi: Reg::R1,
10382 rn: Reg::R2,
10383 };
10384 let code = encoder.encode(&op).unwrap();
10385 assert!(
10387 code.len() >= 6,
10388 "I64ExtendI32S (diff reg) should be at least 6 bytes"
10389 );
10390 }
10391
10392 #[test]
10393 fn test_encode_i64_extend_i32_u_thumb2() {
10394 let encoder = ArmEncoder::new_thumb2();
10395 let op = ArmOp::I64ExtendI32U {
10396 rdlo: Reg::R0,
10397 rdhi: Reg::R1,
10398 rn: Reg::R0,
10399 };
10400 let code = encoder.encode(&op).unwrap();
10401 assert_eq!(
10403 code.len(),
10404 2,
10405 "I64ExtendI32U (same reg) should be 2 bytes (MOV #0 only)"
10406 );
10407 }
10408
10409 #[test]
10410 fn test_encode_i32_wrap_i64_nop_thumb2() {
10411 let encoder = ArmEncoder::new_thumb2();
10412 let op = ArmOp::I32WrapI64 {
10414 rd: Reg::R0,
10415 rnlo: Reg::R0,
10416 };
10417 let code = encoder.encode(&op).unwrap();
10418 assert_eq!(code.len(), 2, "I32WrapI64 same reg should be NOP (2 bytes)");
10419 assert_eq!(code, vec![0x00, 0xBF]); }
10421
10422 #[test]
10423 fn test_encode_i32_wrap_i64_diff_reg_thumb2() {
10424 let encoder = ArmEncoder::new_thumb2();
10425 let op = ArmOp::I32WrapI64 {
10426 rd: Reg::R2,
10427 rnlo: Reg::R0,
10428 };
10429 let code = encoder.encode(&op).unwrap();
10430 assert!(
10432 code.len() >= 2,
10433 "I32WrapI64 diff reg should emit at least 2 bytes"
10434 );
10435 }
10436
10437 #[test]
10438 fn test_encode_i64_eqz_thumb2() {
10439 let encoder = ArmEncoder::new_thumb2();
10440 let op = ArmOp::I64Eqz {
10441 rd: Reg::R0,
10442 rnlo: Reg::R0,
10443 rnhi: Reg::R1,
10444 };
10445 let code = encoder.encode(&op).unwrap();
10446 assert!(
10448 code.len() >= 6,
10449 "I64Eqz should emit at least 6 bytes for ORR+ITE+MOV+MOV"
10450 );
10451 }
10452
10453 #[test]
10454 fn test_encode_i64_eq_thumb2() {
10455 let encoder = ArmEncoder::new_thumb2();
10456 let op = ArmOp::I64Eq {
10457 rd: Reg::R0,
10458 rnlo: Reg::R0,
10459 rnhi: Reg::R1,
10460 rmlo: Reg::R2,
10461 rmhi: Reg::R3,
10462 };
10463 let code = encoder.encode(&op).unwrap();
10464 assert!(code.len() >= 10, "I64Eq should emit at least 10 bytes");
10466 }
10467
10468 #[test]
10469 fn test_encode_i64_ldr_thumb2() {
10470 let encoder = ArmEncoder::new_thumb2();
10471 let op = ArmOp::I64Ldr {
10472 rdlo: Reg::R0,
10473 rdhi: Reg::R1,
10474 addr: MemAddr::imm(Reg::SP, 0),
10475 };
10476 let code = encoder.encode(&op).unwrap();
10477 assert!(code.len() >= 4, "I64Ldr should emit at least 4 bytes");
10479 }
10480
10481 #[test]
10482 fn test_372_i64_ldr_indexed_materializes_address() {
10483 let encoder = ArmEncoder::new_thumb2();
10488 let indexed = encoder
10489 .encode(&ArmOp::I64Ldr {
10490 rdlo: Reg::R0,
10491 rdhi: Reg::R1,
10492 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 0),
10493 })
10494 .unwrap();
10495 assert_eq!(
10497 &indexed[0..4],
10498 &[0x0b, 0xeb, 0x00, 0x0c],
10499 "indexed I64Ldr must start with ADD.W ip, base, index"
10500 );
10501 let frame = encoder
10502 .encode(&ArmOp::I64Ldr {
10503 rdlo: Reg::R0,
10504 rdhi: Reg::R1,
10505 addr: MemAddr::imm(Reg::SP, 8),
10506 })
10507 .unwrap();
10508 assert_ne!(
10510 &frame[0..2],
10511 &[0x0b, 0xeb],
10512 "frame (non-indexed) I64Ldr must NOT emit an ADD.W"
10513 );
10514 }
10515
10516 #[test]
10517 fn test_382_i64_ldst_large_offset_materializes_not_skips() {
10518 let encoder = ArmEncoder::new_thumb2();
10524 let ld = encoder
10527 .encode(&ArmOp::I64Ldr {
10528 rdlo: Reg::R0,
10529 rdhi: Reg::R1,
10530 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
10531 })
10532 .expect("large-offset i64.load must lower, not skip");
10533 assert_eq!(ld.len(), 20, "expected MOVW + 2×ADD + 2×LDR");
10535 assert_ne!(
10538 &ld[0..2],
10539 &[0x0b, 0xeb],
10540 "must materialize the large offset"
10541 );
10542 assert_eq!(
10544 &ld[4..20],
10545 &[
10546 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xdc, 0xf8, 0x00, 0x00, 0xdc, 0xf8, 0x04, 0x10, ],
10551 "large-offset i64.load must fold offset into ip and access [ip,#0]/[ip,#4]"
10552 );
10553
10554 let st = encoder
10556 .encode(&ArmOp::I64Str {
10557 rdlo: Reg::R2,
10558 rdhi: Reg::R3,
10559 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
10560 })
10561 .expect("large-offset i64.store must lower, not skip");
10562 assert_eq!(st.len(), 20);
10563 assert_eq!(
10564 &st[4..20],
10565 &[
10566 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xcc, 0xf8, 0x00, 0x20, 0xcc, 0xf8, 0x04, 0x30, ],
10571 "large-offset i64.store must fold offset into ip and access [ip,#0]/[ip,#4]"
10572 );
10573
10574 let small = encoder
10578 .encode(&ArmOp::I64Ldr {
10579 rdlo: Reg::R0,
10580 rdhi: Reg::R1,
10581 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 8),
10582 })
10583 .unwrap();
10584 assert_eq!(
10585 &small[0..4],
10586 &[0x0b, 0xeb, 0x00, 0x0c],
10587 "small-offset indexed i64 must keep the single ADD.W ip, fp, r0"
10588 );
10589 assert_eq!(small.len(), 12, "ADD.W + 2×LDR.W (offset folded in imm12)");
10590 }
10591
10592 #[test]
10593 fn test_encode_i64_str_thumb2() {
10594 let encoder = ArmEncoder::new_thumb2();
10595 let op = ArmOp::I64Str {
10596 rdlo: Reg::R0,
10597 rdhi: Reg::R1,
10598 addr: MemAddr::imm(Reg::SP, 0),
10599 };
10600 let code = encoder.encode(&op).unwrap();
10601 assert!(code.len() >= 4, "I64Str should emit at least 4 bytes");
10603 }
10604
10605 #[test]
10606 fn test_encode_i64_all_comparisons_thumb2() {
10607 let encoder = ArmEncoder::new_thumb2();
10608
10609 let ops = vec![
10610 ArmOp::I64Ne {
10611 rd: Reg::R0,
10612 rnlo: Reg::R0,
10613 rnhi: Reg::R1,
10614 rmlo: Reg::R2,
10615 rmhi: Reg::R3,
10616 },
10617 ArmOp::I64LtS {
10618 rd: Reg::R0,
10619 rnlo: Reg::R0,
10620 rnhi: Reg::R1,
10621 rmlo: Reg::R2,
10622 rmhi: Reg::R3,
10623 },
10624 ArmOp::I64LtU {
10625 rd: Reg::R0,
10626 rnlo: Reg::R0,
10627 rnhi: Reg::R1,
10628 rmlo: Reg::R2,
10629 rmhi: Reg::R3,
10630 },
10631 ArmOp::I64LeS {
10632 rd: Reg::R0,
10633 rnlo: Reg::R0,
10634 rnhi: Reg::R1,
10635 rmlo: Reg::R2,
10636 rmhi: Reg::R3,
10637 },
10638 ArmOp::I64LeU {
10639 rd: Reg::R0,
10640 rnlo: Reg::R0,
10641 rnhi: Reg::R1,
10642 rmlo: Reg::R2,
10643 rmhi: Reg::R3,
10644 },
10645 ArmOp::I64GtS {
10646 rd: Reg::R0,
10647 rnlo: Reg::R0,
10648 rnhi: Reg::R1,
10649 rmlo: Reg::R2,
10650 rmhi: Reg::R3,
10651 },
10652 ArmOp::I64GtU {
10653 rd: Reg::R0,
10654 rnlo: Reg::R0,
10655 rnhi: Reg::R1,
10656 rmlo: Reg::R2,
10657 rmhi: Reg::R3,
10658 },
10659 ArmOp::I64GeS {
10660 rd: Reg::R0,
10661 rnlo: Reg::R0,
10662 rnhi: Reg::R1,
10663 rmlo: Reg::R2,
10664 rmhi: Reg::R3,
10665 },
10666 ArmOp::I64GeU {
10667 rd: Reg::R0,
10668 rnlo: Reg::R0,
10669 rnhi: Reg::R1,
10670 rmlo: Reg::R2,
10671 rmhi: Reg::R3,
10672 },
10673 ];
10674
10675 for op in &ops {
10676 let code = encoder.encode(op).unwrap();
10677 assert!(
10678 code.len() >= 8,
10679 "i64 comparison {:?} should emit at least 8 bytes, got {}",
10680 op,
10681 code.len()
10682 );
10683 }
10684 }
10685
10686 #[test]
10687 fn test_encode_i64_const_zero_thumb2() {
10688 let encoder = ArmEncoder::new_thumb2();
10689 let op = ArmOp::I64Const {
10690 rdlo: Reg::R0,
10691 rdhi: Reg::R1,
10692 value: 0,
10693 };
10694 let code = encoder.encode(&op).unwrap();
10695 assert_eq!(code.len(), 8, "I64Const(0) should be 8 bytes");
10697 }
10698
10699 #[test]
10700 fn test_encode_i64_const_negative_one_thumb2() {
10701 let encoder = ArmEncoder::new_thumb2();
10702 let op = ArmOp::I64Const {
10703 rdlo: Reg::R0,
10704 rdhi: Reg::R1,
10705 value: -1, };
10707 let code = encoder.encode(&op).unwrap();
10708 assert_eq!(code.len(), 16, "I64Const(-1) should be 16 bytes");
10710 }
10711
10712 #[test]
10717 fn test_encode_ldrb_arm32() {
10718 let encoder = ArmEncoder::new_arm32();
10719 let op = ArmOp::Ldrb {
10720 rd: Reg::R0,
10721 addr: MemAddr::imm(Reg::R1, 4),
10722 };
10723 let code = encoder.encode(&op).unwrap();
10724 assert_eq!(code.len(), 4, "ARM32 LDRB should be 4 bytes");
10725 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10727 assert_eq!(encoded, 0xE5D10004, "Should encode LDRB R0, [R1, #4]");
10728 }
10729
10730 #[test]
10731 fn test_encode_strb_arm32() {
10732 let encoder = ArmEncoder::new_arm32();
10733 let op = ArmOp::Strb {
10734 rd: Reg::R0,
10735 addr: MemAddr::imm(Reg::R1, 0),
10736 };
10737 let code = encoder.encode(&op).unwrap();
10738 assert_eq!(code.len(), 4, "ARM32 STRB should be 4 bytes");
10739 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10741 assert_eq!(encoded, 0xE5C10000, "Should encode STRB R0, [R1, #0]");
10742 }
10743
10744 #[test]
10745 fn test_encode_ldrh_arm32() {
10746 let encoder = ArmEncoder::new_arm32();
10747 let op = ArmOp::Ldrh {
10748 rd: Reg::R0,
10749 addr: MemAddr::imm(Reg::R1, 2),
10750 };
10751 let code = encoder.encode(&op).unwrap();
10752 assert_eq!(code.len(), 4, "ARM32 LDRH should be 4 bytes");
10753 }
10754
10755 #[test]
10756 fn test_encode_strh_arm32() {
10757 let encoder = ArmEncoder::new_arm32();
10758 let op = ArmOp::Strh {
10759 rd: Reg::R0,
10760 addr: MemAddr::imm(Reg::R1, 0),
10761 };
10762 let code = encoder.encode(&op).unwrap();
10763 assert_eq!(code.len(), 4, "ARM32 STRH should be 4 bytes");
10764 }
10765
10766 #[test]
10767 fn test_encode_ldrsb_arm32() {
10768 let encoder = ArmEncoder::new_arm32();
10769 let op = ArmOp::Ldrsb {
10770 rd: Reg::R0,
10771 addr: MemAddr::imm(Reg::R1, 0),
10772 };
10773 let code = encoder.encode(&op).unwrap();
10774 assert_eq!(code.len(), 4, "ARM32 LDRSB should be 4 bytes");
10775 }
10776
10777 #[test]
10778 fn test_encode_ldrsh_arm32() {
10779 let encoder = ArmEncoder::new_arm32();
10780 let op = ArmOp::Ldrsh {
10781 rd: Reg::R0,
10782 addr: MemAddr::imm(Reg::R1, 0),
10783 };
10784 let code = encoder.encode(&op).unwrap();
10785 assert_eq!(code.len(), 4, "ARM32 LDRSH should be 4 bytes");
10786 }
10787
10788 #[test]
10789 fn test_encode_ldrb_thumb2_16bit() {
10790 let encoder = ArmEncoder::new_thumb2();
10791 let op = ArmOp::Ldrb {
10792 rd: Reg::R0,
10793 addr: MemAddr::imm(Reg::R1, 4),
10794 };
10795 let code = encoder.encode(&op).unwrap();
10796 assert_eq!(
10798 code.len(),
10799 2,
10800 "Thumb-2 LDRB with small offset should be 16-bit"
10801 );
10802 }
10803
10804 #[test]
10805 fn test_encode_ldrb_thumb2_32bit() {
10806 let encoder = ArmEncoder::new_thumb2();
10807 let op = ArmOp::Ldrb {
10808 rd: Reg::R0,
10809 addr: MemAddr::imm(Reg::R1, 100), };
10811 let code = encoder.encode(&op).unwrap();
10812 assert_eq!(
10813 code.len(),
10814 4,
10815 "Thumb-2 LDRB with large offset should be 32-bit"
10816 );
10817 }
10818
10819 #[test]
10820 fn test_encode_strb_thumb2_16bit() {
10821 let encoder = ArmEncoder::new_thumb2();
10822 let op = ArmOp::Strb {
10823 rd: Reg::R0,
10824 addr: MemAddr::imm(Reg::R1, 10),
10825 };
10826 let code = encoder.encode(&op).unwrap();
10827 assert_eq!(
10828 code.len(),
10829 2,
10830 "Thumb-2 STRB with small offset should be 16-bit"
10831 );
10832 }
10833
10834 #[test]
10835 fn test_encode_ldrh_thumb2_16bit() {
10836 let encoder = ArmEncoder::new_thumb2();
10837 let op = ArmOp::Ldrh {
10838 rd: Reg::R0,
10839 addr: MemAddr::imm(Reg::R1, 4), };
10841 let code = encoder.encode(&op).unwrap();
10842 assert_eq!(
10843 code.len(),
10844 2,
10845 "Thumb-2 LDRH with small aligned offset should be 16-bit"
10846 );
10847 }
10848
10849 #[test]
10850 fn test_encode_strh_thumb2_16bit() {
10851 let encoder = ArmEncoder::new_thumb2();
10852 let op = ArmOp::Strh {
10853 rd: Reg::R0,
10854 addr: MemAddr::imm(Reg::R1, 4),
10855 };
10856 let code = encoder.encode(&op).unwrap();
10857 assert_eq!(
10858 code.len(),
10859 2,
10860 "Thumb-2 STRH with small aligned offset should be 16-bit"
10861 );
10862 }
10863
10864 #[test]
10865 fn test_encode_ldrsb_thumb2() {
10866 let encoder = ArmEncoder::new_thumb2();
10867 let op = ArmOp::Ldrsb {
10868 rd: Reg::R0,
10869 addr: MemAddr::imm(Reg::R1, 0),
10870 };
10871 let code = encoder.encode(&op).unwrap();
10872 assert_eq!(code.len(), 4, "Thumb-2 LDRSB should be 32-bit");
10874 }
10875
10876 #[test]
10877 fn test_encode_ldrsh_thumb2() {
10878 let encoder = ArmEncoder::new_thumb2();
10879 let op = ArmOp::Ldrsh {
10880 rd: Reg::R0,
10881 addr: MemAddr::imm(Reg::R1, 0),
10882 };
10883 let code = encoder.encode(&op).unwrap();
10884 assert_eq!(code.len(), 4, "Thumb-2 LDRSH should be 32-bit");
10885 }
10886
10887 #[test]
10888 fn test_encode_memory_size_thumb2() {
10889 let encoder = ArmEncoder::new_thumb2();
10890 let op = ArmOp::MemorySize { rd: Reg::R0 };
10891 let code = encoder.encode(&op).unwrap();
10892 assert!(!code.is_empty(), "MemorySize should produce code");
10894 }
10895
10896 #[test]
10897 fn test_encode_memory_grow_thumb2() {
10898 let encoder = ArmEncoder::new_thumb2();
10899 let op = ArmOp::MemoryGrow {
10900 rd: Reg::R0,
10901 rn: Reg::R0,
10902 };
10903 let code = encoder.encode(&op).unwrap();
10904 assert_eq!(code.len(), 4, "MemoryGrow (MVN) should be 32-bit Thumb-2");
10905 }
10906
10907 #[test]
10908 fn test_encode_subword_reg_offset_thumb2() {
10909 let encoder = ArmEncoder::new_thumb2();
10910
10911 let op = ArmOp::Ldrb {
10913 rd: Reg::R0,
10914 addr: MemAddr::reg(Reg::R1, Reg::R2),
10915 };
10916 let code = encoder.encode(&op).unwrap();
10917 assert_eq!(
10918 code.len(),
10919 4,
10920 "Thumb-2 LDRB with reg offset should be 32-bit"
10921 );
10922
10923 let op = ArmOp::Strb {
10925 rd: Reg::R0,
10926 addr: MemAddr::reg(Reg::R1, Reg::R2),
10927 };
10928 let code = encoder.encode(&op).unwrap();
10929 assert_eq!(
10930 code.len(),
10931 4,
10932 "Thumb-2 STRB with reg offset should be 32-bit"
10933 );
10934
10935 let op = ArmOp::Ldrh {
10937 rd: Reg::R0,
10938 addr: MemAddr::reg(Reg::R1, Reg::R2),
10939 };
10940 let code = encoder.encode(&op).unwrap();
10941 assert_eq!(
10942 code.len(),
10943 4,
10944 "Thumb-2 LDRH with reg offset should be 32-bit"
10945 );
10946
10947 let op = ArmOp::Strh {
10949 rd: Reg::R0,
10950 addr: MemAddr::reg(Reg::R1, Reg::R2),
10951 };
10952 let code = encoder.encode(&op).unwrap();
10953 assert_eq!(
10954 code.len(),
10955 4,
10956 "Thumb-2 STRH with reg offset should be 32-bit"
10957 );
10958 }
10959
10960 #[test]
10961 fn test_encode_subword_reg_imm_offset_thumb2() {
10962 let encoder = ArmEncoder::new_thumb2();
10963
10964 let op = ArmOp::Ldrb {
10966 rd: Reg::R0,
10967 addr: MemAddr::reg_imm(Reg::R1, Reg::R2, 4),
10968 };
10969 let code = encoder.encode(&op).unwrap();
10970 assert_eq!(
10972 code.len(),
10973 8,
10974 "Thumb-2 LDRB with reg+imm offset should be 8 bytes"
10975 );
10976 }
10977
10978 #[test]
10983 fn test_encode_mve_addi32_thumb2() {
10984 let encoder = ArmEncoder::new_thumb2();
10985 let op = ArmOp::MveAddI {
10986 qd: QReg::Q0,
10987 qn: QReg::Q1,
10988 qm: QReg::Q2,
10989 size: MveSize::S32,
10990 };
10991 let code = encoder.encode(&op).unwrap();
10992 assert_eq!(
10993 code.len(),
10994 4,
10995 "MVE VADD.I32 should be 4 bytes (Thumb-2 32-bit)"
10996 );
10997 }
10998
10999 #[test]
11000 fn test_encode_mve_subi16_thumb2() {
11001 let encoder = ArmEncoder::new_thumb2();
11002 let op = ArmOp::MveSubI {
11003 qd: QReg::Q0,
11004 qn: QReg::Q1,
11005 qm: QReg::Q2,
11006 size: MveSize::S16,
11007 };
11008 let code = encoder.encode(&op).unwrap();
11009 assert_eq!(code.len(), 4, "MVE VSUB.I16 should be 4 bytes");
11010 }
11011
11012 #[test]
11013 fn test_encode_mve_muli8_thumb2() {
11014 let encoder = ArmEncoder::new_thumb2();
11015 let op = ArmOp::MveMulI {
11016 qd: QReg::Q0,
11017 qn: QReg::Q1,
11018 qm: QReg::Q2,
11019 size: MveSize::S8,
11020 };
11021 let code = encoder.encode(&op).unwrap();
11022 assert_eq!(code.len(), 4, "MVE VMUL.I8 should be 4 bytes");
11023 }
11024
11025 #[test]
11026 fn test_encode_mve_bitwise_thumb2() {
11027 let encoder = ArmEncoder::new_thumb2();
11028
11029 let ops = vec![
11030 ArmOp::MveAnd {
11031 qd: QReg::Q0,
11032 qn: QReg::Q1,
11033 qm: QReg::Q2,
11034 },
11035 ArmOp::MveOrr {
11036 qd: QReg::Q0,
11037 qn: QReg::Q1,
11038 qm: QReg::Q2,
11039 },
11040 ArmOp::MveEor {
11041 qd: QReg::Q0,
11042 qn: QReg::Q1,
11043 qm: QReg::Q2,
11044 },
11045 ArmOp::MveBic {
11046 qd: QReg::Q0,
11047 qn: QReg::Q1,
11048 qm: QReg::Q2,
11049 },
11050 ];
11051 for op in ops {
11052 let code = encoder.encode(&op).unwrap();
11053 assert_eq!(code.len(), 4, "MVE bitwise op should be 4 bytes");
11054 }
11055 }
11056
11057 #[test]
11058 fn test_encode_mve_mvn_thumb2() {
11059 let encoder = ArmEncoder::new_thumb2();
11060 let op = ArmOp::MveMvn {
11061 qd: QReg::Q0,
11062 qm: QReg::Q1,
11063 };
11064 let code = encoder.encode(&op).unwrap();
11065 assert_eq!(code.len(), 4, "MVE VMVN should be 4 bytes");
11066 }
11067
11068 #[test]
11069 fn test_encode_mve_load_store_thumb2() {
11070 let encoder = ArmEncoder::new_thumb2();
11071
11072 let load = ArmOp::MveLoad {
11073 qd: QReg::Q0,
11074 addr: MemAddr::imm(Reg::R0, 16),
11075 };
11076 let code = encoder.encode(&load).unwrap();
11077 assert_eq!(code.len(), 4, "MVE VLDRW.32 should be 4 bytes");
11078
11079 let store = ArmOp::MveStore {
11080 qd: QReg::Q1,
11081 addr: MemAddr::imm(Reg::R1, 0),
11082 };
11083 let code = encoder.encode(&store).unwrap();
11084 assert_eq!(code.len(), 4, "MVE VSTRW.32 should be 4 bytes");
11085 }
11086
11087 #[test]
11088 fn test_encode_mve_const_thumb2() {
11089 let encoder = ArmEncoder::new_thumb2();
11090 let op = ArmOp::MveConst {
11091 qd: QReg::Q0,
11092 bytes: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0],
11093 };
11094 let code = encoder.encode(&op).unwrap();
11095 assert!(
11098 code.len() >= 24,
11099 "MVE const should produce multiple instructions"
11100 );
11101 }
11102
11103 #[test]
11104 fn test_encode_mve_dup_thumb2() {
11105 let encoder = ArmEncoder::new_thumb2();
11106 let op = ArmOp::MveDup {
11107 qd: QReg::Q0,
11108 rn: Reg::R0,
11109 size: MveSize::S32,
11110 };
11111 let code = encoder.encode(&op).unwrap();
11112 assert_eq!(code.len(), 4, "MVE VDUP.32 should be 4 bytes");
11113 }
11114
11115 #[test]
11116 fn test_encode_mve_extract_lane_thumb2() {
11117 let encoder = ArmEncoder::new_thumb2();
11118 let op = ArmOp::MveExtractLane {
11119 rd: Reg::R0,
11120 qn: QReg::Q1,
11121 lane: 2,
11122 size: MveSize::S32,
11123 };
11124 let code = encoder.encode(&op).unwrap();
11125 assert_eq!(code.len(), 4, "MVE extract lane should be 4 bytes");
11126 }
11127
11128 #[test]
11129 fn test_encode_mve_insert_lane_thumb2() {
11130 let encoder = ArmEncoder::new_thumb2();
11131 let op = ArmOp::MveInsertLane {
11132 qd: QReg::Q0,
11133 rn: Reg::R1,
11134 lane: 3,
11135 size: MveSize::S32,
11136 };
11137 let code = encoder.encode(&op).unwrap();
11138 assert_eq!(code.len(), 4, "MVE insert lane should be 4 bytes");
11139 }
11140
11141 #[test]
11142 fn test_encode_mve_addf32_thumb2() {
11143 let encoder = ArmEncoder::new_thumb2();
11144 let op = ArmOp::MveAddF32 {
11145 qd: QReg::Q0,
11146 qn: QReg::Q1,
11147 qm: QReg::Q2,
11148 };
11149 let code = encoder.encode(&op).unwrap();
11150 assert_eq!(code.len(), 4, "MVE VADD.F32 should be 4 bytes");
11151 }
11152
11153 #[test]
11154 fn test_encode_mve_divf32_thumb2() {
11155 let encoder = ArmEncoder::new_thumb2();
11156 let op = ArmOp::MveDivF32 {
11157 qd: QReg::Q0,
11158 qn: QReg::Q1,
11159 qm: QReg::Q2,
11160 };
11161 let code = encoder.encode(&op).unwrap();
11162 assert_eq!(
11164 code.len(),
11165 16,
11166 "MVE VDIV.F32 (lane-wise) should be 16 bytes"
11167 );
11168 }
11169
11170 #[test]
11171 fn test_encode_mve_sqrtf32_thumb2() {
11172 let encoder = ArmEncoder::new_thumb2();
11173 let op = ArmOp::MveSqrtF32 {
11174 qd: QReg::Q0,
11175 qm: QReg::Q1,
11176 };
11177 let code = encoder.encode(&op).unwrap();
11178 assert_eq!(
11180 code.len(),
11181 16,
11182 "MVE VSQRT.F32 (lane-wise) should be 16 bytes"
11183 );
11184 }
11185
11186 #[test]
11187 fn test_encode_mve_negf32_thumb2() {
11188 let encoder = ArmEncoder::new_thumb2();
11189 let op = ArmOp::MveNegF32 {
11190 qd: QReg::Q0,
11191 qm: QReg::Q1,
11192 };
11193 let code = encoder.encode(&op).unwrap();
11194 assert_eq!(code.len(), 4, "MVE VNEG.F32 should be 4 bytes");
11195 }
11196
11197 #[test]
11198 fn test_encode_mve_absf32_thumb2() {
11199 let encoder = ArmEncoder::new_thumb2();
11200 let op = ArmOp::MveAbsF32 {
11201 qd: QReg::Q0,
11202 qm: QReg::Q1,
11203 };
11204 let code = encoder.encode(&op).unwrap();
11205 assert_eq!(code.len(), 4, "MVE VABS.F32 should be 4 bytes");
11206 }
11207
11208 #[test]
11223 fn and_immediate_encodes_correctly_in_byte_range_documents_fold_bound() {
11224 let encoder = ArmEncoder::new_thumb2();
11225 let op = ArmOp::And {
11226 rd: Reg::R2,
11227 rn: Reg::R0,
11228 op2: Operand2::Imm(0x7e),
11229 };
11230 let code = encoder.encode(&op).unwrap();
11231 assert_eq!(
11232 code,
11233 vec![0x00, 0xf0, 0x7e, 0x02],
11234 "and r2, r0, #0x7e must encode to the canonical AND.W T1 (imm8=0x7e)"
11235 );
11236 }
11237
11238 #[test]
11245 fn try_thumb_expand_imm_encodes_modified_immediates() {
11246 assert_eq!(try_thumb_expand_imm(0x7e), Some(0x07e)); assert_eq!(try_thumb_expand_imm(0xff), Some(0x0ff));
11248 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);
11256 assert_eq!(try_thumb_expand_imm(0x12345), None);
11257 }
11258
11259 #[test]
11264 fn cmp_adds_subs_immediate_error_on_non_modified_imm() {
11265 let encoder = ArmEncoder::new_thumb2();
11266 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 0xff).is_ok());
11268 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 1000).is_ok());
11269 assert!(
11271 encoder.encode_thumb32_cmp_imm(&Reg::R0, 0x101).is_err(),
11272 "cmp #0x101 must error, not compare the wrong constant"
11273 );
11274 assert!(
11275 encoder
11276 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x101)
11277 .is_err()
11278 );
11279 assert!(
11280 encoder
11281 .encode_thumb32_subs(&Reg::R0, &Reg::R0, 0x101)
11282 .is_err()
11283 );
11284 assert!(
11286 encoder
11287 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x80)
11288 .is_ok()
11289 );
11290 }
11291
11292 #[test]
11295 fn mla_thumb2_encodes_correctly() {
11296 let encoder = ArmEncoder::new_thumb2();
11297 let code = encoder
11298 .encode(&ArmOp::Mla {
11299 rd: Reg::R2,
11300 rn: Reg::R3,
11301 rm: Reg::R4,
11302 ra: Reg::R8,
11303 })
11304 .unwrap();
11305 assert_eq!(code, vec![0x03, 0xfb, 0x04, 0x82]);
11307 }
11308
11309 #[test]
11314 fn ldst_imm12_offset_errors_when_out_of_range() {
11315 let encoder = ArmEncoder::new_thumb2();
11316 assert!(
11318 encoder
11319 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0xFFF)
11320 .is_ok()
11321 );
11322 assert!(
11324 encoder
11325 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0x1000)
11326 .is_err(),
11327 "ldr offset 4096 must error, not wrap to 0"
11328 );
11329 assert!(
11330 encoder
11331 .encode_thumb32_str(&Reg::R0, &Reg::R1, 0x1000)
11332 .is_err()
11333 );
11334 assert!(
11335 encoder
11336 .encode_thumb32_ldrb_imm(&Reg::R0, &Reg::R1, 5000)
11337 .is_err()
11338 );
11339 assert!(
11340 encoder
11341 .encode_thumb32_strh_imm(&Reg::R0, &Reg::R1, 5000)
11342 .is_err()
11343 );
11344 }
11345
11346 #[test]
11353 fn add_sub_large_immediate_use_addw_subw_not_misencoded() {
11354 let encoder = ArmEncoder::new_thumb2();
11355 assert_eq!(
11357 encoder
11358 .encode(&ArmOp::Add {
11359 rd: Reg::SP,
11360 rn: Reg::SP,
11361 op2: Operand2::Imm(256),
11362 })
11363 .unwrap(),
11364 vec![0x0d, 0xf2, 0x00, 0x1d],
11365 "add sp,sp,#256 must be ADDW (plain imm12), not a mis-encoded ADD.W"
11366 );
11367 assert_eq!(
11369 encoder
11370 .encode(&ArmOp::Sub {
11371 rd: Reg::SP,
11372 rn: Reg::SP,
11373 op2: Operand2::Imm(256),
11374 })
11375 .unwrap(),
11376 vec![0xad, 0xf2, 0x00, 0x1d],
11377 );
11378 assert!(
11380 encoder
11381 .encode(&ArmOp::Add {
11382 rd: Reg::SP,
11383 rn: Reg::SP,
11384 op2: Operand2::Imm(5000),
11385 })
11386 .is_err(),
11387 "add #5000 must error (no single ADDW), not mis-encode"
11388 );
11389 }
11390
11391 #[test]
11396 fn and_cmn_immediate_thumb_expand_else_error() {
11397 let encoder = ArmEncoder::new_thumb2();
11398 assert_eq!(
11400 encoder
11401 .encode(&ArmOp::And {
11402 rd: Reg::R2,
11403 rn: Reg::R0,
11404 op2: Operand2::Imm(0x7e),
11405 })
11406 .unwrap(),
11407 vec![0x00, 0xf0, 0x7e, 0x02],
11408 );
11409 assert!(
11411 encoder
11412 .encode(&ArmOp::And {
11413 rd: Reg::R2,
11414 rn: Reg::R0,
11415 op2: Operand2::Imm(0xff00ff00u32 as i32),
11416 })
11417 .is_ok()
11418 );
11419 assert!(
11421 encoder
11422 .encode(&ArmOp::And {
11423 rd: Reg::R2,
11424 rn: Reg::R0,
11425 op2: Operand2::Imm(0x101),
11426 })
11427 .is_err()
11428 );
11429 assert!(
11430 encoder
11431 .encode(&ArmOp::Cmn {
11432 rn: Reg::R0,
11433 op2: Operand2::Imm(0x101),
11434 })
11435 .is_err(),
11436 "CMN #0x101 must error, not emit a NOP"
11437 );
11438 }
11439
11440 #[test]
11444 fn orr_eor_immediate_encode_in_byte_range_else_error() {
11445 let encoder = ArmEncoder::new_thumb2();
11446 assert_eq!(
11448 encoder
11449 .encode(&ArmOp::Orr {
11450 rd: Reg::R2,
11451 rn: Reg::R0,
11452 op2: Operand2::Imm(0x7e),
11453 })
11454 .unwrap(),
11455 vec![0x40, 0xf0, 0x7e, 0x02],
11456 );
11457 assert_eq!(
11459 encoder
11460 .encode(&ArmOp::Eor {
11461 rd: Reg::R2,
11462 rn: Reg::R0,
11463 op2: Operand2::Imm(0x7e),
11464 })
11465 .unwrap(),
11466 vec![0x80, 0xf0, 0x7e, 0x02],
11467 );
11468 assert!(
11470 encoder
11471 .encode(&ArmOp::Orr {
11472 rd: Reg::R2,
11473 rn: Reg::R0,
11474 op2: Operand2::Imm(0x140),
11475 })
11476 .is_err(),
11477 "ORR #0x140 must error, not emit a NOP"
11478 );
11479 }
11480
11481 #[test]
11482 fn test_encode_mve_different_qregs() {
11483 let encoder = ArmEncoder::new_thumb2();
11484
11485 let op1 = ArmOp::MveAddI {
11487 qd: QReg::Q0,
11488 qn: QReg::Q0,
11489 qm: QReg::Q0,
11490 size: MveSize::S32,
11491 };
11492 let op2 = ArmOp::MveAddI {
11493 qd: QReg::Q3,
11494 qn: QReg::Q5,
11495 qm: QReg::Q7,
11496 size: MveSize::S32,
11497 };
11498 let code1 = encoder.encode(&op1).unwrap();
11499 let code2 = encoder.encode(&op2).unwrap();
11500 assert_ne!(
11501 code1, code2,
11502 "Different Q-registers should produce different encodings"
11503 );
11504 }
11505
11506 #[test]
11507 fn test_encode_mve_arm32_loud_err() {
11508 let encoder = ArmEncoder::new_arm32();
11512 let op = ArmOp::MveAddI {
11513 qd: QReg::Q0,
11514 qn: QReg::Q1,
11515 qm: QReg::Q2,
11516 size: MveSize::S32,
11517 };
11518 let err = encoder
11519 .encode(&op)
11520 .expect_err("ARM32 MVE must be a loud Err, not a silent NOP (#615)");
11521 assert!(
11522 err.to_string().contains("Thumb-2 only"),
11523 "unexpected error message: {err}"
11524 );
11525 }
11526}