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 w(&mut b, 0xE92D_0FF0); w(&mut b, 0xE021_9003); skip_negate_if_positive(&mut b, 1);
980 negate64(&mut b, 0, 1);
981 skip_negate_if_positive(&mut b, 3);
982 negate64(&mut b, 2, 3);
983 for r in 4..8u32 {
984 w(&mut b, 0xE3A0_0000 | (r << 12)); }
986 div_loop(&mut b, 8); w(&mut b, 0xE1A0_0004); w(&mut b, 0xE1A0_1005); skip_negate_if_positive(&mut b, 9);
990 negate64(&mut b, 0, 1);
991 w(&mut b, 0xE8BD_0FF0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
993 }
994
995 ArmOp::I64RemU {
997 rdlo,
998 rdhi,
999 rnlo,
1000 rnhi,
1001 rmlo,
1002 rmhi,
1003 } => {
1004 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1005 emit_a32_i64_divisor_zero_trap(&mut b);
1006 w(&mut b, 0xE92D_01F0); for r in 4..8u32 {
1008 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1010 div_loop(&mut b, 8);
1011 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)?;
1015 }
1016
1017 ArmOp::I64RemS {
1019 rdlo,
1020 rdhi,
1021 rnlo,
1022 rnhi,
1023 rmlo,
1024 rmhi,
1025 } => {
1026 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1027 emit_a32_i64_divisor_zero_trap(&mut b);
1028 w(&mut b, 0xE92D_0FF0); w(&mut b, 0xE1A0_9001); skip_negate_if_positive(&mut b, 1);
1031 negate64(&mut b, 0, 1);
1032 skip_negate_if_positive(&mut b, 3);
1033 negate64(&mut b, 2, 3);
1034 for r in 4..8u32 {
1035 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1037 div_loop(&mut b, 8);
1038 w(&mut b, 0xE1A0_0006); w(&mut b, 0xE1A0_1007); skip_negate_if_positive(&mut b, 9);
1041 negate64(&mut b, 0, 1);
1042 w(&mut b, 0xE8BD_0FF0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
1044 }
1045
1046 ArmOp::Popcnt { rd, rm } => {
1050 let rd_b = reg_to_bits(rd);
1051 if rd != rm {
1052 w(&mut b, 0xE1A0_0000 | (rd_b << 12) | reg_to_bits(rm)); }
1054 movw(&mut b, 12, 0x5555);
1056 movt(&mut b, 12, 0x5555);
1057 shift_imm(&mut b, LSR, 11, rd_b, 1);
1058 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);
1062 movt(&mut b, 12, 0x3333);
1063 dp_reg(&mut b, 0xE000_0000, 11, rd_b, 12); shift_imm(&mut b, LSR, rd_b, rd_b, 2);
1065 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);
1069 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11); movw(&mut b, 12, 0x0F0F);
1071 movt(&mut b, 12, 0x0F0F);
1072 dp_reg(&mut b, 0xE000_0000, rd_b, rd_b, 12); shift_imm(&mut b, LSR, 11, rd_b, 8);
1075 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11);
1076 shift_imm(&mut b, LSR, 11, rd_b, 16);
1077 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11);
1078 w(&mut b, 0xE200_003F | (rd_b << 16) | (rd_b << 12)); }
1080
1081 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
1085 let hi = reg_to_bits(rnhi);
1086 w(&mut b, 0xE92D_0038); w(&mut b, 0xE1A0_4000 | reg_to_bits(rnlo)); w(&mut b, 0xE1A0_5000 | hi); popcnt_word(&mut b, 4, 3);
1090 popcnt_word(&mut b, 5, 3);
1091 dp_reg(&mut b, 0xE080_0000, reg_to_bits(rd), 4, 5); w(&mut b, 0xE8BD_0038); w(&mut b, 0xE3A0_0000 | (hi << 12)); }
1095
1096 _ => return Ok(None),
1097 }
1098 Ok(Some(b))
1099 }
1100
1101 fn encode_arm(&self, op: &ArmOp) -> Result<Vec<u8>> {
1102 if let Some(bytes) = self.encode_arm_expanded(op)? {
1109 return Ok(bytes);
1110 }
1111 if let Some(bytes) = self.encode_arm_reg_offset_mem(op)? {
1118 return Ok(bytes);
1119 }
1120 if let ArmOp::CallIndirect {
1126 table_index_reg, ..
1127 } = op
1128 {
1129 return Ok(Self::encode_arm_call_indirect(table_index_reg));
1130 }
1131 let instr: u32 = match op {
1132 ArmOp::Add { rd, rn, op2 } => {
1134 let rd_bits = reg_to_bits(rd);
1135 let rn_bits = reg_to_bits(rn);
1136 let (op2_bits, i_flag) = encode_operand2(op2)?;
1137
1138 0xE0800000 | (i_flag << 25)
1141 | (rn_bits << 16)
1142 | (rd_bits << 12)
1143 | op2_bits
1144 }
1145
1146 ArmOp::Sub { rd, rn, op2 } => {
1147 let rd_bits = reg_to_bits(rd);
1148 let rn_bits = reg_to_bits(rn);
1149 let (op2_bits, i_flag) = encode_operand2(op2)?;
1150
1151 0xE0400000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1153 }
1154
1155 ArmOp::Adds { rd, rn, op2 } => {
1157 let rd_bits = reg_to_bits(rd);
1158 let rn_bits = reg_to_bits(rn);
1159 let (op2_bits, i_flag) = encode_operand2(op2)?;
1160
1161 0xE0900000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1163 }
1164
1165 ArmOp::Adc { rd, rn, op2 } => {
1166 let rd_bits = reg_to_bits(rd);
1167 let rn_bits = reg_to_bits(rn);
1168 let (op2_bits, i_flag) = encode_operand2(op2)?;
1169
1170 0xE0A00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1172 }
1173
1174 ArmOp::Subs { rd, rn, op2 } => {
1175 let rd_bits = reg_to_bits(rd);
1176 let rn_bits = reg_to_bits(rn);
1177 let (op2_bits, i_flag) = encode_operand2(op2)?;
1178
1179 0xE0500000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1181 }
1182
1183 ArmOp::Sbc { rd, rn, op2 } => {
1184 let rd_bits = reg_to_bits(rd);
1185 let rn_bits = reg_to_bits(rn);
1186 let (op2_bits, i_flag) = encode_operand2(op2)?;
1187
1188 0xE0C00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1190 }
1191
1192 ArmOp::Mul { rd, rn, rm } => {
1193 let rd_bits = reg_to_bits(rd);
1194 let rn_bits = reg_to_bits(rn);
1195 let rm_bits = reg_to_bits(rm);
1196
1197 0xE0000090 | (rd_bits << 16) | (rn_bits << 8) | rm_bits
1199 }
1200
1201 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
1202 let rdlo_bits = reg_to_bits(rdlo);
1203 let rdhi_bits = reg_to_bits(rdhi);
1204 let rn_bits = reg_to_bits(rn);
1205 let rm_bits = reg_to_bits(rm);
1206
1207 0xE0800090 | (rdhi_bits << 16) | (rdlo_bits << 12) | (rm_bits << 8) | rn_bits
1209 }
1210
1211 ArmOp::Sdiv { rd, rn, rm } => {
1212 let rd_bits = reg_to_bits(rd);
1213 let rn_bits = reg_to_bits(rn);
1214 let rm_bits = reg_to_bits(rm);
1215
1216 0xE710F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
1219 }
1220
1221 ArmOp::Udiv { rd, rn, rm } => {
1222 let rd_bits = reg_to_bits(rd);
1223 let rn_bits = reg_to_bits(rn);
1224 let rm_bits = reg_to_bits(rm);
1225
1226 0xE730F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
1229 }
1230
1231 ArmOp::Mls { rd, rn, rm, ra } => {
1232 let rd_bits = reg_to_bits(rd);
1233 let rn_bits = reg_to_bits(rn);
1234 let rm_bits = reg_to_bits(rm);
1235 let ra_bits = reg_to_bits(ra);
1236
1237 0xE0600090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
1240 }
1241
1242 ArmOp::Mla { rd, rn, rm, ra } => {
1243 let rd_bits = reg_to_bits(rd);
1244 let rn_bits = reg_to_bits(rn);
1245 let rm_bits = reg_to_bits(rm);
1246 let ra_bits = reg_to_bits(ra);
1247
1248 0xE0200090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
1251 }
1252
1253 ArmOp::And { rd, rn, op2 } => {
1254 let rd_bits = reg_to_bits(rd);
1255 let rn_bits = reg_to_bits(rn);
1256 let (op2_bits, i_flag) = encode_operand2(op2)?;
1257
1258 0xE0000000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1260 }
1261
1262 ArmOp::Orr { rd, rn, op2 } => {
1263 let rd_bits = reg_to_bits(rd);
1264 let rn_bits = reg_to_bits(rn);
1265 let (op2_bits, i_flag) = encode_operand2(op2)?;
1266
1267 0xE1800000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1269 }
1270
1271 ArmOp::Eor { rd, rn, op2 } => {
1272 let rd_bits = reg_to_bits(rd);
1273 let rn_bits = reg_to_bits(rn);
1274 let (op2_bits, i_flag) = encode_operand2(op2)?;
1275
1276 0xE0200000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1278 }
1279
1280 ArmOp::Lsl { rd, rn, shift } => {
1282 let rd_bits = reg_to_bits(rd);
1283 let rn_bits = reg_to_bits(rn);
1284 let shift_bits = *shift & 0x1F;
1285
1286 0xE1A00000 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1288 }
1289
1290 ArmOp::Lsr { rd, rn, shift } => {
1291 let rd_bits = reg_to_bits(rd);
1292 let rn_bits = reg_to_bits(rn);
1293 let shift_bits = *shift & 0x1F;
1294
1295 0xE1A00020 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1297 }
1298
1299 ArmOp::Asr { rd, rn, shift } => {
1300 let rd_bits = reg_to_bits(rd);
1301 let rn_bits = reg_to_bits(rn);
1302 let shift_bits = *shift & 0x1F;
1303
1304 0xE1A00040 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1306 }
1307
1308 ArmOp::Ror { rd, rn, shift } => {
1309 let rd_bits = reg_to_bits(rd);
1310 let rn_bits = reg_to_bits(rn);
1311 let shift_bits = *shift & 0x1F;
1312
1313 0xE1A00060 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1315 }
1316
1317 ArmOp::LslReg { rd, rn, rm } => {
1320 let rd_bits = reg_to_bits(rd);
1321 let rn_bits = reg_to_bits(rn);
1322 let rm_bits = reg_to_bits(rm);
1323 0xE1A00010 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1324 }
1325 ArmOp::LsrReg { rd, rn, rm } => {
1326 let rd_bits = reg_to_bits(rd);
1327 let rn_bits = reg_to_bits(rn);
1328 let rm_bits = reg_to_bits(rm);
1329 0xE1A00030 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1330 }
1331 ArmOp::AsrReg { 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 0xE1A00050 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1336 }
1337 ArmOp::RorReg { 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 0xE1A00070 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1342 }
1343
1344 ArmOp::Rsb { rd, rn, imm } => {
1346 let rd_bits = reg_to_bits(rd);
1347 let rn_bits = reg_to_bits(rn);
1348 0xE2600000 | (rn_bits << 16) | (rd_bits << 12) | (*imm & 0xFF)
1351 }
1352
1353 ArmOp::Clz { rd, rm } => {
1355 let rd_bits = reg_to_bits(rd);
1356 let rm_bits = reg_to_bits(rm);
1357
1358 0xE16F0F10 | (rd_bits << 12) | rm_bits
1361 }
1362
1363 ArmOp::Rbit { rd, rm } => {
1364 let rd_bits = reg_to_bits(rd);
1365 let rm_bits = reg_to_bits(rm);
1366
1367 0xE6FF0F30 | (rd_bits << 12) | rm_bits
1370 }
1371
1372 ArmOp::Sxtb { rd, rm } => {
1373 let rd_bits = reg_to_bits(rd);
1374 let rm_bits = reg_to_bits(rm);
1375
1376 0xE6AF0070 | (rd_bits << 12) | rm_bits
1379 }
1380
1381 ArmOp::Sxth { rd, rm } => {
1382 let rd_bits = reg_to_bits(rd);
1383 let rm_bits = reg_to_bits(rm);
1384
1385 0xE6BF0070 | (rd_bits << 12) | rm_bits
1388 }
1389
1390 ArmOp::Uxtb { rd, rm } => {
1391 let rd_bits = reg_to_bits(rd);
1392 let rm_bits = reg_to_bits(rm);
1393 0xE6EF0070 | (rd_bits << 12) | rm_bits
1395 }
1396
1397 ArmOp::Uxth { rd, rm } => {
1398 let rd_bits = reg_to_bits(rd);
1399 let rm_bits = reg_to_bits(rm);
1400 0xE6FF0070 | (rd_bits << 12) | rm_bits
1402 }
1403
1404 ArmOp::Mov { rd, op2 } => {
1406 let rd_bits = reg_to_bits(rd);
1407 let (op2_bits, i_flag) = encode_operand2(op2)?;
1408
1409 0xE1A00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
1411 }
1412
1413 ArmOp::Mvn { rd, op2 } => {
1414 let rd_bits = reg_to_bits(rd);
1415 let (op2_bits, i_flag) = encode_operand2(op2)?;
1416
1417 0xE1E00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
1419 }
1420
1421 ArmOp::Movw { rd, imm16 } => {
1424 let rd_bits = reg_to_bits(rd);
1425 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
1426 let imm12 = (*imm16 as u32) & 0xFFF;
1427 0xE3000000 | (imm4 << 16) | (rd_bits << 12) | imm12
1428 }
1429
1430 ArmOp::Movt { rd, imm16 } => {
1433 let rd_bits = reg_to_bits(rd);
1434 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
1435 let imm12 = (*imm16 as u32) & 0xFFF;
1436 0xE3400000 | (imm4 << 16) | (rd_bits << 12) | imm12
1437 }
1438
1439 ArmOp::MovwSym { rd, addend, .. } => {
1442 let rd_bits = reg_to_bits(rd);
1443 let v = (*addend as u32) & 0xffff;
1444 0xE3000000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
1445 }
1446 ArmOp::MovtSym { rd, addend, .. } => {
1447 let rd_bits = reg_to_bits(rd);
1448 let v = ((*addend as u32) >> 16) & 0xffff;
1449 0xE3400000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
1450 }
1451
1452 ArmOp::LdrSym { .. } => {
1456 return Err(synth_core::Error::synthesis(
1457 "LdrSym (literal-pool address load) is Thumb-2-only",
1458 ));
1459 }
1460
1461 ArmOp::Cmp { rn, op2 } => {
1463 let rn_bits = reg_to_bits(rn);
1464 let (op2_bits, i_flag) = encode_operand2(op2)?;
1465
1466 0xE1500000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
1468 }
1469
1470 ArmOp::Cmn { rn, op2 } => {
1472 let rn_bits = reg_to_bits(rn);
1473 let (op2_bits, i_flag) = encode_operand2(op2)?;
1474
1475 0xE1700000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
1477 }
1478
1479 ArmOp::Ldr { rd, addr } => {
1481 let rd_bits = reg_to_bits(rd);
1482 let (base_bits, offset_bits) = encode_mem_addr(addr);
1483
1484 0xE5900000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1487 }
1488
1489 ArmOp::Str { rd, addr } => {
1490 let rd_bits = reg_to_bits(rd);
1491 let (base_bits, offset_bits) = encode_mem_addr(addr);
1492
1493 0xE5800000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1495 }
1496
1497 ArmOp::Ldrb { rd, addr } => {
1499 let rd_bits = reg_to_bits(rd);
1500 let (base_bits, offset_bits) = encode_mem_addr(addr);
1501 0xE5D00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1503 }
1504
1505 ArmOp::Ldrsb { rd, addr } => {
1506 let rd_bits = reg_to_bits(rd);
1507 let (base_bits, offset_bits) = encode_mem_addr(addr);
1508 let offset_val = offset_bits & 0xFF;
1511 let imm4h = (offset_val >> 4) & 0xF;
1512 let imm4l = offset_val & 0xF;
1513 0xE1D000D0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1514 }
1515
1516 ArmOp::Ldrh { rd, addr } => {
1517 let rd_bits = reg_to_bits(rd);
1518 let (base_bits, offset_bits) = encode_mem_addr(addr);
1519 let offset_val = offset_bits & 0xFF;
1521 let imm4h = (offset_val >> 4) & 0xF;
1522 let imm4l = offset_val & 0xF;
1523 0xE1D000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1524 }
1525
1526 ArmOp::Ldrsh { rd, addr } => {
1527 let rd_bits = reg_to_bits(rd);
1528 let (base_bits, offset_bits) = encode_mem_addr(addr);
1529 let offset_val = offset_bits & 0xFF;
1531 let imm4h = (offset_val >> 4) & 0xF;
1532 let imm4l = offset_val & 0xF;
1533 0xE1D000F0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1534 }
1535
1536 ArmOp::Strb { rd, addr } => {
1538 let rd_bits = reg_to_bits(rd);
1539 let (base_bits, offset_bits) = encode_mem_addr(addr);
1540 0xE5C00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1542 }
1543
1544 ArmOp::Strh { rd, addr } => {
1545 let rd_bits = reg_to_bits(rd);
1546 let (base_bits, offset_bits) = encode_mem_addr(addr);
1547 let offset_val = offset_bits & 0xFF;
1549 let imm4h = (offset_val >> 4) & 0xF;
1550 let imm4l = offset_val & 0xF;
1551 0xE1C000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1552 }
1553
1554 ArmOp::MemorySize { rd } => {
1556 let rd_bits = reg_to_bits(rd);
1557 0xE1A00820 | (rd_bits << 12) | 0x0A }
1562
1563 ArmOp::MemoryGrow { rd, .. } => {
1564 let rd_bits = reg_to_bits(rd);
1565 0xE3E00000 | (rd_bits << 12) }
1568
1569 ArmOp::Label { .. } => {
1571 return Ok(Vec::new());
1572 }
1573
1574 ArmOp::B { label: _ } => {
1576 0xEA000000
1579 }
1580
1581 ArmOp::Bcc { cond, label: _ } => {
1583 use synth_synthesis::Condition;
1584 let cond_bits: u32 = match cond {
1585 Condition::EQ => 0x0,
1586 Condition::NE => 0x1,
1587 Condition::HS => 0x2,
1588 Condition::LO => 0x3,
1589 Condition::HI => 0x8,
1590 Condition::LS => 0x9,
1591 Condition::GE => 0xA,
1592 Condition::LT => 0xB,
1593 Condition::GT => 0xC,
1594 Condition::LE => 0xD,
1595 };
1596 (cond_bits << 28) | 0x0A000000
1598 }
1599
1600 ArmOp::Bhs { label: _ } => {
1602 0x2A000000 }
1605
1606 ArmOp::Blo { label: _ } => {
1608 0x3A000000 }
1611
1612 ArmOp::BOffset { offset } => {
1616 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
1626 0xEA000000 | offset_bits
1627 }
1628
1629 ArmOp::BCondOffset { cond, offset } => {
1631 use synth_synthesis::Condition;
1632 let cond_bits: u32 = match cond {
1633 Condition::EQ => 0x0,
1634 Condition::NE => 0x1,
1635 Condition::HS => 0x2,
1636 Condition::LO => 0x3,
1637 Condition::HI => 0x8,
1638 Condition::LS => 0x9,
1639 Condition::GE => 0xA,
1640 Condition::LT => 0xB,
1641 Condition::GT => 0xC,
1642 Condition::LE => 0xD,
1643 };
1644 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
1648 (cond_bits << 28) | 0x0A000000 | offset_bits
1649 }
1650
1651 ArmOp::Bl { label: _ } => {
1652 0xEB000000
1654 }
1655
1656 ArmOp::Bx { rm } => {
1657 let rm_bits = reg_to_bits(rm);
1658
1659 0xE12FFF10 | rm_bits
1661 }
1662
1663 ArmOp::Blx { rm } => {
1664 let rm_bits = reg_to_bits(rm);
1665
1666 0xE12FFF30 | rm_bits
1668 }
1669
1670 ArmOp::Push { regs } => {
1671 let mut reg_list: u32 = 0;
1673 for r in regs {
1674 reg_list |= 1 << reg_to_bits(r);
1675 }
1676 0xE92D0000 | reg_list
1677 }
1678
1679 ArmOp::Pop { regs } => {
1680 let mut reg_list: u32 = 0;
1682 for r in regs {
1683 reg_list |= 1 << reg_to_bits(r);
1684 }
1685 0xE8BD0000 | reg_list
1686 }
1687
1688 ArmOp::Nop => {
1689 0xE1A00000
1691 }
1692
1693 ArmOp::Udf { imm } => {
1694 let imm8 = *imm as u32;
1697 0xE7F000F0 | ((imm8 & 0xF0) << 4) | (imm8 & 0x0F)
1698 }
1699
1700 ArmOp::Popcnt { .. } | ArmOp::SetCond { .. } | ArmOp::SelectMove { .. } => {
1704 unreachable!("handled by encode_arm_expanded (#615)")
1705 }
1706
1707 ArmOp::Select { .. }
1715 | ArmOp::LocalGet { .. }
1716 | ArmOp::LocalSet { .. }
1717 | ArmOp::LocalTee { .. }
1718 | ArmOp::GlobalGet { .. }
1719 | ArmOp::GlobalSet { .. }
1720 | ArmOp::BrTable { .. }
1721 | ArmOp::Call { .. } => {
1722 return Err(synth_core::Error::synthesis(format!(
1723 "verification-only pseudo-op {op:?} reached the A32 encoder — \
1724 codegen lowers it before encoding; refusing to emit a silent NOP (#615)"
1725 )));
1726 }
1727
1728 ArmOp::CallIndirect { .. } => {
1732 unreachable!("CallIndirect handled by encode_arm_call_indirect (#594)")
1733 }
1734
1735 ArmOp::I64Add { .. }
1740 | ArmOp::I64Sub { .. }
1741 | ArmOp::I64DivS { .. }
1742 | ArmOp::I64DivU { .. }
1743 | ArmOp::I64RemS { .. }
1744 | ArmOp::I64RemU { .. }
1745 | ArmOp::I64Clz { .. }
1746 | ArmOp::I64Ctz { .. }
1747 | ArmOp::I64Popcnt { .. }
1748 | ArmOp::I64And { .. }
1749 | ArmOp::I64Or { .. }
1750 | ArmOp::I64Xor { .. }
1751 | ArmOp::I64Eqz { .. }
1752 | ArmOp::I64Eq { .. }
1753 | ArmOp::I64Ne { .. }
1754 | ArmOp::I64LtS { .. }
1755 | ArmOp::I64LtU { .. }
1756 | ArmOp::I64LeS { .. }
1757 | ArmOp::I64LeU { .. }
1758 | ArmOp::I64GtS { .. }
1759 | ArmOp::I64GtU { .. }
1760 | ArmOp::I64GeS { .. }
1761 | ArmOp::I64GeU { .. }
1762 | ArmOp::I64Const { .. }
1763 | ArmOp::I64Ldr { .. }
1764 | ArmOp::I64Str { .. }
1765 | ArmOp::I64ExtendI32S { .. }
1766 | ArmOp::I64ExtendI32U { .. }
1767 | ArmOp::I64Extend8S { .. }
1768 | ArmOp::I64Extend16S { .. }
1769 | ArmOp::I64Extend32S { .. }
1770 | ArmOp::I32WrapI64 { .. } => {
1771 unreachable!("handled by encode_arm_expanded (#615)")
1772 }
1773
1774 ArmOp::F32Add { sd, sn, sm } => encode_vfp_3reg(0xEE300A00, sd, sn, sm)?,
1776 ArmOp::F32Sub { sd, sn, sm } => encode_vfp_3reg(0xEE300A40, sd, sn, sm)?,
1777 ArmOp::F32Mul { sd, sn, sm } => encode_vfp_3reg(0xEE200A00, sd, sn, sm)?,
1778 ArmOp::F32Div { sd, sn, sm } => encode_vfp_3reg(0xEE800A00, sd, sn, sm)?,
1779 ArmOp::F32Abs { sd, sm } => encode_vfp_2reg(0xEEB00AC0, sd, sm)?,
1780 ArmOp::F32Neg { sd, sm } => encode_vfp_2reg(0xEEB10A40, sd, sm)?,
1781 ArmOp::F32Sqrt { sd, sm } => encode_vfp_2reg(0xEEB10AC0, sd, sm)?,
1782
1783 ArmOp::F32Ceil { sd, sm } => {
1786 return self.encode_arm_f32_rounding(sd, sm, 0b01); }
1788 ArmOp::F32Floor { sd, sm } => {
1789 return self.encode_arm_f32_rounding(sd, sm, 0b10); }
1791 ArmOp::F32Trunc { sd, sm } => {
1792 return self.encode_arm_f32_rounding(sd, sm, 0b11); }
1794 ArmOp::F32Nearest { sd, sm } => {
1795 return self.encode_arm_f32_rounding(sd, sm, 0b00); }
1797 ArmOp::F32Min { sd, sn, sm } => {
1798 return self.encode_arm_f32_minmax(sd, sn, sm, true);
1799 }
1800 ArmOp::F32Max { sd, sn, sm } => {
1801 return self.encode_arm_f32_minmax(sd, sn, sm, false);
1802 }
1803 ArmOp::F32Copysign { sd, sn, sm } => {
1804 return self.encode_arm_f32_copysign(sd, sn, sm);
1805 }
1806
1807 ArmOp::F32Eq { rd, sn, sm } => {
1809 return self.encode_arm_f32_compare(rd, sn, sm, 0x0); }
1811 ArmOp::F32Ne { rd, sn, sm } => {
1812 return self.encode_arm_f32_compare(rd, sn, sm, 0x1); }
1814 ArmOp::F32Lt { rd, sn, sm } => {
1815 return self.encode_arm_f32_compare(rd, sn, sm, 0x4); }
1817 ArmOp::F32Le { rd, sn, sm } => {
1818 return self.encode_arm_f32_compare(rd, sn, sm, 0x9); }
1820 ArmOp::F32Gt { rd, sn, sm } => {
1821 return self.encode_arm_f32_compare(rd, sn, sm, 0xC); }
1823 ArmOp::F32Ge { rd, sn, sm } => {
1824 return self.encode_arm_f32_compare(rd, sn, sm, 0xA); }
1826
1827 ArmOp::F32Const { sd, value } => {
1829 return self.encode_arm_f32_const(sd, *value);
1830 }
1831
1832 ArmOp::F32Load { sd, addr } => encode_vfp_ldst(0xED900A00, sd, addr)?,
1833 ArmOp::F32Store { sd, addr } => encode_vfp_ldst(0xED800A00, sd, addr)?,
1834
1835 ArmOp::F32ConvertI32S { sd, rm } => {
1837 return self.encode_arm_f32_convert_i32(sd, rm, true);
1838 }
1839 ArmOp::F32ConvertI32U { sd, rm } => {
1840 return self.encode_arm_f32_convert_i32(sd, rm, false);
1841 }
1842 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
1843 return Err(synth_core::Error::synthesis(
1844 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
1845 ));
1846 }
1847 ArmOp::F32ReinterpretI32 { sd, rm } => encode_vmov_core_sreg(true, sd, rm)?,
1848 ArmOp::I32ReinterpretF32 { rd, sm } => encode_vmov_core_sreg(false, sm, rd)?,
1849 ArmOp::I32TruncF32S { rd, sm } => {
1850 return self.encode_arm_i32_trunc_f32(rd, sm, true);
1851 }
1852 ArmOp::I32TruncF32U { rd, sm } => {
1853 return self.encode_arm_i32_trunc_f32(rd, sm, false);
1854 }
1855
1856 ArmOp::F64Add { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B00, dd, dn, dm)?,
1859 ArmOp::F64Sub { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B40, dd, dn, dm)?,
1860 ArmOp::F64Mul { dd, dn, dm } => encode_vfp_3reg_f64(0xEE200B00, dd, dn, dm)?,
1861 ArmOp::F64Div { dd, dn, dm } => encode_vfp_3reg_f64(0xEE800B00, dd, dn, dm)?,
1862 ArmOp::F64Abs { dd, dm } => encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?,
1863 ArmOp::F64Neg { dd, dm } => encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?,
1864 ArmOp::F64Sqrt { dd, dm } => encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?,
1865
1866 ArmOp::F64Ceil { dd, dm } => {
1869 return self.encode_arm_f64_rounding(dd, dm, 0b01);
1870 }
1871 ArmOp::F64Floor { dd, dm } => {
1872 return self.encode_arm_f64_rounding(dd, dm, 0b10);
1873 }
1874 ArmOp::F64Trunc { dd, dm } => {
1875 return self.encode_arm_f64_rounding(dd, dm, 0b11);
1876 }
1877 ArmOp::F64Nearest { dd, dm } => {
1878 return self.encode_arm_f64_rounding(dd, dm, 0b00);
1879 }
1880 ArmOp::F64Min { dd, dn, dm } => {
1881 return self.encode_arm_f64_minmax(dd, dn, dm, true);
1882 }
1883 ArmOp::F64Max { dd, dn, dm } => {
1884 return self.encode_arm_f64_minmax(dd, dn, dm, false);
1885 }
1886 ArmOp::F64Copysign { dd, dn, dm } => {
1887 return self.encode_arm_f64_copysign(dd, dn, dm);
1888 }
1889
1890 ArmOp::F64Eq { rd, dn, dm } => {
1892 return self.encode_arm_f64_compare(rd, dn, dm, 0x0);
1893 }
1894 ArmOp::F64Ne { rd, dn, dm } => {
1895 return self.encode_arm_f64_compare(rd, dn, dm, 0x1);
1896 }
1897 ArmOp::F64Lt { rd, dn, dm } => {
1898 return self.encode_arm_f64_compare(rd, dn, dm, 0x4);
1899 }
1900 ArmOp::F64Le { rd, dn, dm } => {
1901 return self.encode_arm_f64_compare(rd, dn, dm, 0x9);
1902 }
1903 ArmOp::F64Gt { rd, dn, dm } => {
1904 return self.encode_arm_f64_compare(rd, dn, dm, 0xC);
1905 }
1906 ArmOp::F64Ge { rd, dn, dm } => {
1907 return self.encode_arm_f64_compare(rd, dn, dm, 0xA);
1908 }
1909
1910 ArmOp::F64Const { dd, value } => {
1911 return self.encode_arm_f64_const(dd, *value);
1912 }
1913
1914 ArmOp::F64Load { dd, addr } => encode_vfp_ldst_f64(0xED900B00, dd, addr)?,
1915 ArmOp::F64Store { dd, addr } => encode_vfp_ldst_f64(0xED800B00, dd, addr)?,
1916
1917 ArmOp::F64ConvertI32S { dd, rm } => {
1918 return self.encode_arm_f64_convert_i32(dd, rm, true);
1919 }
1920 ArmOp::F64ConvertI32U { dd, rm } => {
1921 return self.encode_arm_f64_convert_i32(dd, rm, false);
1922 }
1923 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
1924 return Err(synth_core::Error::synthesis(
1925 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
1926 ));
1927 }
1928 ArmOp::F64PromoteF32 { dd, sm } => {
1929 return self.encode_arm_f64_promote_f32(dd, sm);
1930 }
1931 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => {
1932 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?
1933 }
1934 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => {
1935 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?
1936 }
1937 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
1938 return Err(synth_core::Error::synthesis(
1939 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
1940 ));
1941 }
1942 ArmOp::I32TruncF64S { rd, dm } => {
1943 return self.encode_arm_i32_trunc_f64(rd, dm, true);
1944 }
1945 ArmOp::I32TruncF64U { rd, dm } => {
1946 return self.encode_arm_i32_trunc_f64(rd, dm, false);
1947 }
1948 ArmOp::I64SetCond { .. }
1951 | ArmOp::I64SetCondZ { .. }
1952 | ArmOp::I64Mul { .. }
1953 | ArmOp::I64Shl { .. }
1954 | ArmOp::I64ShrS { .. }
1955 | ArmOp::I64ShrU { .. }
1956 | ArmOp::I64Rotl { .. }
1957 | ArmOp::I64Rotr { .. } => {
1958 unreachable!("handled by encode_arm_expanded (#615)")
1959 }
1960
1961 ArmOp::MveLoad { .. }
1963 | ArmOp::MveStore { .. }
1964 | ArmOp::MveConst { .. }
1965 | ArmOp::MveAnd { .. }
1966 | ArmOp::MveOrr { .. }
1967 | ArmOp::MveEor { .. }
1968 | ArmOp::MveMvn { .. }
1969 | ArmOp::MveBic { .. }
1970 | ArmOp::MveAddI { .. }
1971 | ArmOp::MveSubI { .. }
1972 | ArmOp::MveMulI { .. }
1973 | ArmOp::MveNegI { .. }
1974 | ArmOp::MveCmpEqI { .. }
1975 | ArmOp::MveCmpNeI { .. }
1976 | ArmOp::MveCmpLtS { .. }
1977 | ArmOp::MveCmpLtU { .. }
1978 | ArmOp::MveCmpGtS { .. }
1979 | ArmOp::MveCmpGtU { .. }
1980 | ArmOp::MveCmpLeS { .. }
1981 | ArmOp::MveCmpLeU { .. }
1982 | ArmOp::MveCmpGeS { .. }
1983 | ArmOp::MveCmpGeU { .. }
1984 | ArmOp::MveDup { .. }
1985 | ArmOp::MveExtractLane { .. }
1986 | ArmOp::MveInsertLane { .. }
1987 | ArmOp::MveAddF32 { .. }
1988 | ArmOp::MveSubF32 { .. }
1989 | ArmOp::MveMulF32 { .. }
1990 | ArmOp::MveNegF32 { .. }
1991 | ArmOp::MveAbsF32 { .. }
1992 | ArmOp::MveCmpEqF32 { .. }
1993 | ArmOp::MveCmpNeF32 { .. }
1994 | ArmOp::MveCmpLtF32 { .. }
1995 | ArmOp::MveCmpLeF32 { .. }
1996 | ArmOp::MveCmpGtF32 { .. }
1997 | ArmOp::MveCmpGeF32 { .. }
1998 | ArmOp::MveDupF32 { .. }
1999 | ArmOp::MveExtractLaneF32 { .. }
2000 | ArmOp::MveReplaceLaneF32 { .. }
2001 | ArmOp::MveDivF32 { .. }
2002 | ArmOp::MveSqrtF32 { .. } => {
2003 return Err(synth_core::Error::synthesis(format!(
2009 "MVE op {op:?} has no A32 (ARM-mode) encoding — MVE is Thumb-2 only (#615)"
2010 )));
2011 }
2012 };
2013
2014 Ok(instr.to_le_bytes().to_vec())
2016 }
2017
2018 fn encode_arm_f32_compare(
2022 &self,
2023 rd: &Reg,
2024 sn: &VfpReg,
2025 sm: &VfpReg,
2026 cond_code: u32,
2027 ) -> Result<Vec<u8>> {
2028 let mut bytes = Vec::new();
2029
2030 let sn_num = vfp_sreg_to_num(sn)?;
2032 let sm_num = vfp_sreg_to_num(sm)?;
2033 let (vd, d) = encode_sreg(sn_num);
2034 let (vm, m) = encode_sreg(sm_num);
2035 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2036 bytes.extend_from_slice(&vcmp.to_le_bytes());
2037
2038 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2040
2041 let rd_bits = reg_to_bits(rd);
2043 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2044 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2045
2046 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2048 bytes.extend_from_slice(&mov_one.to_le_bytes());
2049
2050 Ok(bytes)
2051 }
2052
2053 fn encode_arm_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
2055 let mut bytes = Vec::new();
2056 let bits = value.to_bits();
2057
2058 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
2063 let movw = 0xE3000000 | (rt << 12) | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2064 bytes.extend_from_slice(&movw.to_le_bytes());
2065
2066 let hi16 = (bits >> 16) & 0xFFFF;
2068 let movt = 0xE3400000 | (rt << 12) | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2069 bytes.extend_from_slice(&movt.to_le_bytes());
2070
2071 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
2073 bytes.extend_from_slice(&vmov.to_le_bytes());
2074
2075 Ok(bytes)
2076 }
2077
2078 fn encode_arm_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2080 let mut bytes = Vec::new();
2081
2082 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
2084 bytes.extend_from_slice(&vmov.to_le_bytes());
2085
2086 let sd_num = vfp_sreg_to_num(sd)?;
2089 let (vd, d) = encode_sreg(sd_num);
2090 let (vm, m) = encode_sreg(sd_num); let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
2092 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2093 bytes.extend_from_slice(&vcvt.to_le_bytes());
2094
2095 Ok(bytes)
2096 }
2097
2098 fn encode_arm_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2110 let mut bytes = Vec::new();
2111 let sm_num = vfp_sreg_to_num(sm)?;
2112 let sd_num = vfp_sreg_to_num(sd)?;
2113 let (vd_s, d_s) = encode_sreg(sd_num);
2114 let (vm_s, m_s) = encode_sreg(sm_num);
2115
2116 if mode == 0b11 {
2117 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2120 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2121 } else {
2122 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
2127 bytes.extend_from_slice(&vmrs.to_le_bytes());
2128
2129 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2132 bytes.extend_from_slice(&bic.to_le_bytes());
2133
2134 if mode != 0 {
2136 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2138 bytes.extend_from_slice(&orr.to_le_bytes());
2139 }
2140
2141 let vmsr = 0xEEE10A10 | (rt << 12);
2143 bytes.extend_from_slice(&vmsr.to_le_bytes());
2144
2145 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2147 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2148
2149 bytes.extend_from_slice(&vmrs.to_le_bytes());
2151 bytes.extend_from_slice(&bic.to_le_bytes());
2152 bytes.extend_from_slice(&vmsr.to_le_bytes());
2153 }
2154
2155 let (vd2, d2) = encode_sreg(sd_num);
2157 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
2158 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2159
2160 Ok(bytes)
2161 }
2162
2163 fn encode_arm_f32_minmax(
2165 &self,
2166 sd: &VfpReg,
2167 sn: &VfpReg,
2168 sm: &VfpReg,
2169 is_min: bool,
2170 ) -> Result<Vec<u8>> {
2171 let mut bytes = Vec::new();
2172 let sn_num = vfp_sreg_to_num(sn)?;
2173 let sm_num = vfp_sreg_to_num(sm)?;
2174 let sd_num = vfp_sreg_to_num(sd)?;
2175
2176 let (vd, d) = encode_sreg(sd_num);
2178 let (vn, n) = encode_sreg(sn_num);
2179 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2180 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2181
2182 let (vm, m) = encode_sreg(sm_num);
2184 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2185 bytes.extend_from_slice(&vcmp.to_le_bytes());
2186
2187 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2189
2190 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2193
2194 let vmov_cond = (cond << 28) | 0x0EB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2196 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2197
2198 Ok(bytes)
2199 }
2200
2201 fn encode_arm_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2203 let mut bytes = Vec::new();
2204
2205 let vmov_sm = encode_vmov_core_sreg(false, sm, &Reg::R12)?;
2207 bytes.extend_from_slice(&vmov_sm.to_le_bytes());
2208
2209 let vmov_sn = encode_vmov_core_sreg(false, sn, &Reg::R0)?;
2211 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2212
2213 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2217 bytes.extend_from_slice(&and_sign.to_le_bytes());
2218
2219 let bic_sign = 0xE3C00000u32 | (1 << 8) | 0x02;
2222 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2223
2224 let orr = 0xE1800000u32 | 12;
2227 bytes.extend_from_slice(&orr.to_le_bytes());
2228
2229 let vmov_result = encode_vmov_core_sreg(true, sd, &Reg::R0)?;
2231 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2232
2233 Ok(bytes)
2234 }
2235
2236 fn encode_arm_f64_compare(
2238 &self,
2239 rd: &Reg,
2240 dn: &VfpReg,
2241 dm: &VfpReg,
2242 cond_code: u32,
2243 ) -> Result<Vec<u8>> {
2244 let mut bytes = Vec::new();
2245
2246 let dn_num = vfp_dreg_to_num(dn)?;
2248 let dm_num = vfp_dreg_to_num(dm)?;
2249 let (vd, d) = encode_dreg(dn_num);
2250 let (vm, m) = encode_dreg(dm_num);
2251 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2252 bytes.extend_from_slice(&vcmp.to_le_bytes());
2253
2254 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2256
2257 let rd_bits = reg_to_bits(rd);
2259 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2260 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2261
2262 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2264 bytes.extend_from_slice(&mov_one.to_le_bytes());
2265
2266 Ok(bytes)
2267 }
2268
2269 fn encode_arm_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
2271 let mut bytes = Vec::new();
2272 let bits = value.to_bits();
2273 let lo32 = bits as u32;
2274 let hi32 = (bits >> 32) as u32;
2275
2276 let lo16 = lo32 & 0xFFFF;
2278 let movw_r0 = 0xE3000000 | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2279 bytes.extend_from_slice(&movw_r0.to_le_bytes());
2280 let hi16 = (lo32 >> 16) & 0xFFFF;
2281 let movt_r0 = 0xE3400000 | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2282 bytes.extend_from_slice(&movt_r0.to_le_bytes());
2283
2284 let lo16 = hi32 & 0xFFFF;
2286 let movw_r12 = 0xE3000000 | ((lo16 >> 12) << 16) | (12 << 12) | (lo16 & 0xFFF);
2287 bytes.extend_from_slice(&movw_r12.to_le_bytes());
2288 let hi16 = (hi32 >> 16) & 0xFFFF;
2289 let movt_r12 = 0xE3400000 | ((hi16 >> 12) << 16) | (12 << 12) | (hi16 & 0xFFF);
2290 bytes.extend_from_slice(&movt_r12.to_le_bytes());
2291
2292 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
2294 bytes.extend_from_slice(&vmov.to_le_bytes());
2295
2296 Ok(bytes)
2297 }
2298
2299 fn encode_arm_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2301 let mut bytes = Vec::new();
2302
2303 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
2305 bytes.extend_from_slice(&vmov.to_le_bytes());
2306
2307 let dd_num = vfp_dreg_to_num(dd)?;
2310 let (vd, d) = encode_dreg(dd_num);
2311 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
2312 let vcvt = base | (d << 22) | (vd << 12);
2314 bytes.extend_from_slice(&vcvt.to_le_bytes());
2315
2316 Ok(bytes)
2317 }
2318
2319 fn encode_arm_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2321 let dd_num = vfp_dreg_to_num(dd)?;
2322 let sm_num = vfp_sreg_to_num(sm)?;
2323 let (vd, d) = encode_dreg(dd_num);
2324 let (vm, m) = encode_sreg(sm_num);
2325
2326 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
2328 Ok(vcvt.to_le_bytes().to_vec())
2329 }
2330
2331 fn encode_arm_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2333 let mut bytes = Vec::new();
2334 let dm_num = vfp_dreg_to_num(dm)?;
2335 let (vm, m) = encode_dreg(dm_num);
2336
2337 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
2340 let vcvt = base | (m << 5) | vm;
2341 bytes.extend_from_slice(&vcvt.to_le_bytes());
2342
2343 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
2345 bytes.extend_from_slice(&vmov.to_le_bytes());
2346
2347 Ok(bytes)
2348 }
2349
2350 fn encode_arm_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2358 let mut bytes = Vec::new();
2359 let dm_num = vfp_dreg_to_num(dm)?;
2360 let dd_num = vfp_dreg_to_num(dd)?;
2361 let (vm, m) = encode_dreg(dm_num);
2362 let (vd, d) = encode_dreg(dd_num);
2363
2364 if mode == 0b11 {
2365 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
2367 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2368 } else {
2369 let rt: u32 = 12;
2371
2372 let vmrs = 0xEEF10A10 | (rt << 12);
2374 bytes.extend_from_slice(&vmrs.to_le_bytes());
2375
2376 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2378 bytes.extend_from_slice(&bic.to_le_bytes());
2379
2380 if mode != 0 {
2382 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2383 bytes.extend_from_slice(&orr.to_le_bytes());
2384 }
2385
2386 let vmsr = 0xEEE10A10 | (rt << 12);
2388 bytes.extend_from_slice(&vmsr.to_le_bytes());
2389
2390 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
2392 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2393
2394 bytes.extend_from_slice(&vmrs.to_le_bytes());
2396 bytes.extend_from_slice(&bic.to_le_bytes());
2397 bytes.extend_from_slice(&vmsr.to_le_bytes());
2398 }
2399
2400 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
2402 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2403
2404 Ok(bytes)
2405 }
2406
2407 fn encode_arm_f64_minmax(
2409 &self,
2410 dd: &VfpReg,
2411 dn: &VfpReg,
2412 dm: &VfpReg,
2413 is_min: bool,
2414 ) -> Result<Vec<u8>> {
2415 let mut bytes = Vec::new();
2416 let dn_num = vfp_dreg_to_num(dn)?;
2417 let dm_num = vfp_dreg_to_num(dm)?;
2418 let dd_num = vfp_dreg_to_num(dd)?;
2419
2420 let (vd, d) = encode_dreg(dd_num);
2422 let (vn, n) = encode_dreg(dn_num);
2423 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2424 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2425
2426 let (vm, m) = encode_dreg(dm_num);
2428 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2429 bytes.extend_from_slice(&vcmp.to_le_bytes());
2430
2431 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2433
2434 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2435 let vmov_cond = (cond << 28) | 0x0EB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2436 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2437
2438 Ok(bytes)
2439 }
2440
2441 fn encode_arm_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
2443 let mut bytes = Vec::new();
2444
2445 let vmov_dm = encode_vmov_core_dreg(false, dm, &Reg::R0, &Reg::R12)?;
2447 bytes.extend_from_slice(&vmov_dm.to_le_bytes());
2448
2449 let vmov_dn = encode_vmov_core_dreg(false, dn, &Reg::R1, &Reg::R2)?;
2452 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2453
2454 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2456 bytes.extend_from_slice(&and_sign.to_le_bytes());
2457
2458 let bic_sign = 0xE3C00000u32 | (2 << 16) | (2 << 12) | (1 << 8) | 0x02;
2460 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2461
2462 let orr = 0xE1800000u32 | (2 << 16) | (2 << 12) | 12;
2464 bytes.extend_from_slice(&orr.to_le_bytes());
2465
2466 let vmov_result = encode_vmov_core_dreg(true, dd, &Reg::R1, &Reg::R2)?;
2468 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2469
2470 Ok(bytes)
2471 }
2472
2473 fn encode_arm_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2475 let mut bytes = Vec::new();
2476
2477 let sm_num = vfp_sreg_to_num(sm)?;
2480 let (vd, d) = encode_sreg(sm_num);
2481 let (vm, m) = encode_sreg(sm_num);
2482 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
2483 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2484 bytes.extend_from_slice(&vcvt.to_le_bytes());
2485
2486 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
2488 bytes.extend_from_slice(&vmov.to_le_bytes());
2489
2490 Ok(bytes)
2491 }
2492
2493 fn encode_thumb(&self, op: &ArmOp) -> Result<Vec<u8>> {
2495 match op {
2498 ArmOp::Add { rd, rn, op2 } => {
2500 let rd_bits = reg_to_bits(rd) as u16;
2501 let rn_bits = reg_to_bits(rn) as u16;
2502
2503 if let Operand2::Reg(rm) = op2 {
2504 let rm_bits = reg_to_bits(rm) as u16;
2505 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2513 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2515 Ok(instr.to_le_bytes().to_vec())
2516 } else {
2517 self.encode_thumb32_add_reg_raw(
2519 rd_bits as u32,
2520 rn_bits as u32,
2521 rm_bits as u32,
2522 )
2523 }
2524 } else if let Operand2::Imm(imm) = op2 {
2525 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2526 let instr: u16 = 0x1C00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2528 Ok(instr.to_le_bytes().to_vec())
2529 } else {
2530 self.encode_thumb32_add(rd, rn, *imm as u32)
2532 }
2533 } else {
2534 self.encode_thumb32_add(rd, rn, 0)
2536 }
2537 }
2538
2539 ArmOp::Sub { rd, rn, op2 } => {
2540 let rd_bits = reg_to_bits(rd) as u16;
2541 let rn_bits = reg_to_bits(rn) as u16;
2542
2543 if let Operand2::Reg(rm) = op2 {
2544 let rm_bits = reg_to_bits(rm) as u16;
2545 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2547 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2549 Ok(instr.to_le_bytes().to_vec())
2550 } else {
2551 self.encode_thumb32_sub_reg_raw(
2553 rd_bits as u32,
2554 rn_bits as u32,
2555 rm_bits as u32,
2556 )
2557 }
2558 } else if let Operand2::Imm(imm) = op2 {
2559 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2560 let instr: u16 = 0x1E00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2562 Ok(instr.to_le_bytes().to_vec())
2563 } else {
2564 self.encode_thumb32_sub(rd, rn, *imm as u32)
2565 }
2566 } else {
2567 self.encode_thumb32_sub(rd, rn, 0)
2568 }
2569 }
2570
2571 ArmOp::Mov { rd, op2 } => {
2572 let rd_bits = reg_to_bits(rd) as u16;
2573
2574 if let Operand2::Imm(imm) = op2 {
2575 if *imm <= 255 && rd_bits < 8 {
2576 let imm_bits = (*imm as u16) & 0xFF;
2578 let instr: u16 = 0x2000 | (rd_bits << 8) | imm_bits;
2579 Ok(instr.to_le_bytes().to_vec())
2580 } else {
2581 self.encode_thumb32_movw(rd, *imm as u32)
2583 }
2584 } else if let Operand2::Reg(rm) = op2 {
2585 let rm_bits = reg_to_bits(rm) as u16;
2586 let d_bit = (rd_bits >> 3) & 1;
2589 let instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
2590 Ok(instr.to_le_bytes().to_vec())
2591 } else {
2592 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2594 }
2595 }
2596
2597 ArmOp::Push { regs } => {
2598 let mut reg_list: u16 = 0;
2602 let mut need_32bit = false;
2603 for r in regs {
2604 let bit = reg_to_bits(r);
2605 if bit >= 8 && *r != Reg::LR {
2606 need_32bit = true;
2607 }
2608 reg_list |= 1 << bit;
2609 }
2610 if !need_32bit {
2611 let m_bit = if reg_list & (1 << 14) != 0 {
2613 1u16
2614 } else {
2615 0u16
2616 };
2617 let low_regs = reg_list & 0xFF;
2618 let instr: u16 = 0xB400 | (m_bit << 8) | low_regs;
2619 Ok(instr.to_le_bytes().to_vec())
2620 } else {
2621 let hw1: u16 = 0xE92D;
2623 let hw2: u16 = reg_list;
2624 let mut bytes = hw1.to_le_bytes().to_vec();
2625 bytes.extend_from_slice(&hw2.to_le_bytes());
2626 Ok(bytes)
2627 }
2628 }
2629
2630 ArmOp::Pop { regs } => {
2631 let mut reg_list: u16 = 0;
2635 let mut need_32bit = false;
2636 for r in regs {
2637 let bit = reg_to_bits(r);
2638 if bit >= 8 && *r != Reg::PC {
2639 need_32bit = true;
2640 }
2641 reg_list |= 1 << bit;
2642 }
2643 if !need_32bit {
2644 let p_bit = if reg_list & (1 << 15) != 0 {
2646 1u16
2647 } else {
2648 0u16
2649 };
2650 let low_regs = reg_list & 0xFF;
2651 let instr: u16 = 0xBC00 | (p_bit << 8) | low_regs;
2652 Ok(instr.to_le_bytes().to_vec())
2653 } else {
2654 let hw1: u16 = 0xE8BD;
2656 let hw2: u16 = reg_list;
2657 let mut bytes = hw1.to_le_bytes().to_vec();
2658 bytes.extend_from_slice(&hw2.to_le_bytes());
2659 Ok(bytes)
2660 }
2661 }
2662
2663 ArmOp::Nop => {
2664 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2666 }
2667
2668 ArmOp::Udf { imm } => {
2669 let instr: u16 = 0xDE00 | (*imm as u16);
2672 let bytes = instr.to_le_bytes().to_vec();
2673 encoding_contracts::verify_thumb16(&bytes);
2674 Ok(bytes)
2675 }
2676
2677 ArmOp::Adds { rd, rn, op2 } => {
2680 let rd_bits = reg_to_bits(rd) as u16;
2681 let rn_bits = reg_to_bits(rn) as u16;
2682
2683 if let Operand2::Reg(rm) = op2 {
2684 let rm_bits = reg_to_bits(rm) as u16;
2685 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2690 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2692 Ok(instr.to_le_bytes().to_vec())
2693 } else {
2694 self.encode_thumb32_adds_reg_raw(
2695 rd_bits as u32,
2696 rn_bits as u32,
2697 rm_bits as u32,
2698 )
2699 }
2700 } else {
2701 self.encode_thumb32_adds(rd, rn, 0)
2703 }
2704 }
2705
2706 ArmOp::Adc { rd, rn, op2 } => {
2709 let rd_bits = reg_to_bits(rd);
2710 let rn_bits = reg_to_bits(rn);
2711
2712 if let Operand2::Reg(rm) = op2 {
2713 let rm_bits = reg_to_bits(rm);
2714 let hw1: u16 = (0xEB40 | rn_bits) as u16;
2716 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2717
2718 let mut bytes = hw1.to_le_bytes().to_vec();
2719 bytes.extend_from_slice(&hw2.to_le_bytes());
2720 Ok(bytes)
2721 } else {
2722 let hw1: u16 = (0xF140 | rn_bits) as u16;
2724 let hw2: u16 = (rd_bits << 8) as u16;
2725 let mut bytes = hw1.to_le_bytes().to_vec();
2726 bytes.extend_from_slice(&hw2.to_le_bytes());
2727 Ok(bytes)
2728 }
2729 }
2730
2731 ArmOp::Subs { rd, rn, op2 } => {
2733 let rd_bits = reg_to_bits(rd) as u16;
2734 let rn_bits = reg_to_bits(rn) as u16;
2735
2736 if let Operand2::Reg(rm) = op2 {
2737 let rm_bits = reg_to_bits(rm) as u16;
2738 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2742 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2744 Ok(instr.to_le_bytes().to_vec())
2745 } else {
2746 self.encode_thumb32_subs_reg_raw(
2747 rd_bits as u32,
2748 rn_bits as u32,
2749 rm_bits as u32,
2750 )
2751 }
2752 } else {
2753 self.encode_thumb32_subs(rd, rn, 0)
2755 }
2756 }
2757
2758 ArmOp::Sbc { rd, rn, op2 } => {
2761 let rd_bits = reg_to_bits(rd);
2762 let rn_bits = reg_to_bits(rn);
2763
2764 if let Operand2::Reg(rm) = op2 {
2765 let rm_bits = reg_to_bits(rm);
2766 let hw1: u16 = (0xEB60 | rn_bits) as u16;
2768 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2769
2770 let mut bytes = hw1.to_le_bytes().to_vec();
2771 bytes.extend_from_slice(&hw2.to_le_bytes());
2772 Ok(bytes)
2773 } else {
2774 let hw1: u16 = (0xF160 | rn_bits) as u16;
2776 let hw2: u16 = (rd_bits << 8) as u16;
2777 let mut bytes = hw1.to_le_bytes().to_vec();
2778 bytes.extend_from_slice(&hw2.to_le_bytes());
2779 Ok(bytes)
2780 }
2781 }
2782
2783 ArmOp::Sdiv { rd, rn, rm } => {
2787 let rd_bits = reg_to_bits(rd);
2788 let rn_bits = reg_to_bits(rn);
2789 let rm_bits = reg_to_bits(rm);
2790 reg_bits_checked(rd_bits)?;
2791 reg_bits_checked(rn_bits)?;
2792 reg_bits_checked(rm_bits)?;
2793
2794 let hw1: u16 = (0xFB90 | rn_bits) as u16;
2798 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2799
2800 let mut bytes = hw1.to_le_bytes().to_vec();
2802 bytes.extend_from_slice(&hw2.to_le_bytes());
2803 encoding_contracts::verify_thumb32(&bytes);
2804 Ok(bytes)
2805 }
2806
2807 ArmOp::Udiv { rd, rn, rm } => {
2809 let rd_bits = reg_to_bits(rd);
2810 let rn_bits = reg_to_bits(rn);
2811 let rm_bits = reg_to_bits(rm);
2812 reg_bits_checked(rd_bits)?;
2813 reg_bits_checked(rn_bits)?;
2814 reg_bits_checked(rm_bits)?;
2815
2816 let hw1: u16 = (0xFBB0 | rn_bits) as u16;
2818 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2819
2820 let mut bytes = hw1.to_le_bytes().to_vec();
2821 bytes.extend_from_slice(&hw2.to_le_bytes());
2822 encoding_contracts::verify_thumb32(&bytes);
2823 Ok(bytes)
2824 }
2825
2826 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
2827 let rdlo_bits = reg_to_bits(rdlo);
2828 let rdhi_bits = reg_to_bits(rdhi);
2829 let rn_bits = reg_to_bits(rn);
2830 let rm_bits = reg_to_bits(rm);
2831 reg_bits_checked(rdlo_bits)?;
2832 reg_bits_checked(rdhi_bits)?;
2833 reg_bits_checked(rn_bits)?;
2834 reg_bits_checked(rm_bits)?;
2835
2836 let hw1: u16 = (0xFBA0 | rn_bits) as u16;
2838 let hw2: u16 = ((rdlo_bits << 12) | (rdhi_bits << 8) | rm_bits) as u16;
2839
2840 let mut bytes = hw1.to_le_bytes().to_vec();
2841 bytes.extend_from_slice(&hw2.to_le_bytes());
2842 encoding_contracts::verify_thumb32(&bytes);
2843 Ok(bytes)
2844 }
2845
2846 ArmOp::Mul { rd, rn, rm } => {
2848 let rd_bits = reg_to_bits(rd);
2849 let rn_bits = reg_to_bits(rn);
2850 let rm_bits = reg_to_bits(rm);
2851
2852 let hw1: u16 = (0xFB00 | rn_bits) as u16;
2855 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
2856
2857 let mut bytes = hw1.to_le_bytes().to_vec();
2858 bytes.extend_from_slice(&hw2.to_le_bytes());
2859 Ok(bytes)
2860 }
2861
2862 ArmOp::Mls { rd, rn, rm, ra } => {
2864 let rd_bits = reg_to_bits(rd);
2865 let rn_bits = reg_to_bits(rn);
2866 let rm_bits = reg_to_bits(rm);
2867 let ra_bits = reg_to_bits(ra);
2868
2869 let hw1: u16 = (0xFB00 | rn_bits) as u16;
2872 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | 0x10 | rm_bits) as u16;
2873
2874 let mut bytes = hw1.to_le_bytes().to_vec();
2875 bytes.extend_from_slice(&hw2.to_le_bytes());
2876 Ok(bytes)
2877 }
2878
2879 ArmOp::Mla { rd, rn, rm, ra } => {
2880 let rd_bits = reg_to_bits(rd);
2881 let rn_bits = reg_to_bits(rn);
2882 let rm_bits = reg_to_bits(rm);
2883 let ra_bits = reg_to_bits(ra);
2884
2885 let hw1: u16 = (0xFB00 | rn_bits) as u16;
2888 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | rm_bits) as u16;
2889
2890 let mut bytes = hw1.to_le_bytes().to_vec();
2891 bytes.extend_from_slice(&hw2.to_le_bytes());
2892 Ok(bytes)
2893 }
2894
2895 ArmOp::And { rd, rn, op2 } => {
2897 if let Operand2::Reg(rm) = op2 {
2898 let rd_bits = reg_to_bits(rd);
2899 let rn_bits = reg_to_bits(rn);
2900 let rm_bits = reg_to_bits(rm);
2901
2902 let hw1: u16 = (0xEA00 | rn_bits) as u16;
2904 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2905
2906 let mut bytes = hw1.to_le_bytes().to_vec();
2907 bytes.extend_from_slice(&hw2.to_le_bytes());
2908 Ok(bytes)
2909 } else if let Operand2::Imm(imm) = op2 {
2910 let rd_bits = reg_to_bits(rd);
2911 let rn_bits = reg_to_bits(rn);
2912
2913 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
2920 synth_core::Error::synthesis(
2921 "AND immediate is not a valid ThumbExpandImm — materialize into a register",
2922 )
2923 })?;
2924 let i_bit = (field >> 11) & 1;
2925 let imm3 = (field >> 8) & 0x7;
2926 let imm8 = field & 0xFF;
2927
2928 let hw1: u16 = (0xF000 | (i_bit << 10) | rn_bits) as u16;
2929 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
2930
2931 let mut bytes = hw1.to_le_bytes().to_vec();
2932 bytes.extend_from_slice(&hw2.to_le_bytes());
2933 Ok(bytes)
2934 } else {
2935 let instr: u16 = 0xBF00;
2937 Ok(instr.to_le_bytes().to_vec())
2938 }
2939 }
2940
2941 ArmOp::Orr { rd, rn, op2 } => {
2943 if let Operand2::Reg(rm) = op2 {
2944 let rd_bits = reg_to_bits(rd);
2945 let rn_bits = reg_to_bits(rn);
2946 let rm_bits = reg_to_bits(rm);
2947
2948 let hw1: u16 = (0xEA40 | rn_bits) as u16;
2950 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2951
2952 let mut bytes = hw1.to_le_bytes().to_vec();
2953 bytes.extend_from_slice(&hw2.to_le_bytes());
2954 Ok(bytes)
2955 } else if let Operand2::Imm(imm) = op2 {
2956 let imm_val = *imm as u32;
2961 if imm_val > 0xFF {
2962 return Err(synth_core::Error::synthesis(
2963 "ORR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
2964 ));
2965 }
2966 let rd_bits = reg_to_bits(rd);
2967 let rn_bits = reg_to_bits(rn);
2968 let hw1: u16 = (0xF040 | rn_bits) as u16;
2969 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
2970 let mut bytes = hw1.to_le_bytes().to_vec();
2971 bytes.extend_from_slice(&hw2.to_le_bytes());
2972 Ok(bytes)
2973 } else {
2974 let instr: u16 = 0xBF00;
2975 Ok(instr.to_le_bytes().to_vec())
2976 }
2977 }
2978
2979 ArmOp::Eor { rd, rn, op2 } => {
2981 if let Operand2::Reg(rm) = op2 {
2982 let rd_bits = reg_to_bits(rd);
2983 let rn_bits = reg_to_bits(rn);
2984 let rm_bits = reg_to_bits(rm);
2985
2986 let hw1: u16 = (0xEA80 | rn_bits) as u16;
2988 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2989
2990 let mut bytes = hw1.to_le_bytes().to_vec();
2991 bytes.extend_from_slice(&hw2.to_le_bytes());
2992 Ok(bytes)
2993 } else if let Operand2::Imm(imm) = op2 {
2994 let imm_val = *imm as u32;
2998 if imm_val > 0xFF {
2999 return Err(synth_core::Error::synthesis(
3000 "EOR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
3001 ));
3002 }
3003 let rd_bits = reg_to_bits(rd);
3004 let rn_bits = reg_to_bits(rn);
3005 let hw1: u16 = (0xF080 | rn_bits) as u16;
3006 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
3007 let mut bytes = hw1.to_le_bytes().to_vec();
3008 bytes.extend_from_slice(&hw2.to_le_bytes());
3009 Ok(bytes)
3010 } else {
3011 let instr: u16 = 0xBF00;
3012 Ok(instr.to_le_bytes().to_vec())
3013 }
3014 }
3015
3016 ArmOp::Lsl { rd, rn, shift } => {
3018 let rd_bits = reg_to_bits(rd) as u16;
3019 let rn_bits = reg_to_bits(rn) as u16;
3020 let shift_bits = (*shift as u16) & 0x1F;
3021
3022 if rd_bits < 8 && rn_bits < 8 {
3023 let instr: u16 = (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3025 Ok(instr.to_le_bytes().to_vec())
3026 } else {
3027 self.encode_thumb32_shift(rd, rn, *shift, 0b00) }
3030 }
3031
3032 ArmOp::Lsr { rd, rn, shift } => {
3033 let rd_bits = reg_to_bits(rd) as u16;
3034 let rn_bits = reg_to_bits(rn) as u16;
3035 let shift_bits = (*shift as u16) & 0x1F;
3036
3037 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3038 let instr: u16 = 0x0800 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3040 Ok(instr.to_le_bytes().to_vec())
3041 } else {
3042 self.encode_thumb32_shift(rd, rn, *shift, 0b01) }
3044 }
3045
3046 ArmOp::Asr { rd, rn, shift } => {
3047 let rd_bits = reg_to_bits(rd) as u16;
3048 let rn_bits = reg_to_bits(rn) as u16;
3049 let shift_bits = (*shift as u16) & 0x1F;
3050
3051 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3052 let instr: u16 = 0x1000 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3054 Ok(instr.to_le_bytes().to_vec())
3055 } else {
3056 self.encode_thumb32_shift(rd, rn, *shift, 0b10) }
3058 }
3059
3060 ArmOp::Ror { rd, rn, shift } => {
3061 self.encode_thumb32_shift(rd, rn, *shift, 0b11) }
3064
3065 ArmOp::LslReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b00),
3069 ArmOp::LsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b01),
3070 ArmOp::AsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b10),
3071 ArmOp::RorReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b11),
3072
3073 ArmOp::Rsb { rd, rn, imm } => {
3076 let rd_bits = reg_to_bits(rd);
3077 let rn_bits = reg_to_bits(rn);
3078 let imm_val = *imm;
3079
3080 let i_bit = (imm_val >> 11) & 1;
3081 let imm3 = (imm_val >> 8) & 0x7;
3082 let imm8 = imm_val & 0xFF;
3083
3084 let hw1: u16 = (0xF1C0 | (i_bit << 10) | rn_bits) as u16;
3086 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
3088
3089 let mut bytes = hw1.to_le_bytes().to_vec();
3090 bytes.extend_from_slice(&hw2.to_le_bytes());
3091 Ok(bytes)
3092 }
3093
3094 ArmOp::Clz { rd, rm } => {
3096 let rd_bits = reg_to_bits(rd);
3097 let rm_bits = reg_to_bits(rm);
3098
3099 let hw1: u16 = (0xFAB0 | rm_bits) as u16;
3102 let hw2: u16 = (0xF080 | (rd_bits << 8) | rm_bits) as u16;
3103
3104 let mut bytes = hw1.to_le_bytes().to_vec();
3105 bytes.extend_from_slice(&hw2.to_le_bytes());
3106 Ok(bytes)
3107 }
3108
3109 ArmOp::Rbit { rd, rm } => {
3111 let rd_bits = reg_to_bits(rd);
3112 let rm_bits = reg_to_bits(rm);
3113
3114 let hw1: u16 = (0xFA90 | rm_bits) as u16;
3117 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rm_bits) as u16;
3118
3119 let mut bytes = hw1.to_le_bytes().to_vec();
3120 bytes.extend_from_slice(&hw2.to_le_bytes());
3121 Ok(bytes)
3122 }
3123
3124 ArmOp::Sxtb { rd, rm } => {
3126 let rd_bits = reg_to_bits(rd) as u16;
3127 let rm_bits = reg_to_bits(rm) as u16;
3128
3129 if rd_bits < 8 && rm_bits < 8 {
3130 let instr: u16 = 0xB240 | (rm_bits << 3) | rd_bits;
3132 Ok(instr.to_le_bytes().to_vec())
3133 } else {
3134 let rd_bits32 = rd_bits as u32;
3137 let rm_bits32 = rm_bits as u32;
3138 let hw1: u16 = 0xFA4F;
3139 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3140 let mut bytes = hw1.to_le_bytes().to_vec();
3141 bytes.extend_from_slice(&hw2.to_le_bytes());
3142 Ok(bytes)
3143 }
3144 }
3145
3146 ArmOp::Sxth { rd, rm } => {
3148 let rd_bits = reg_to_bits(rd) as u16;
3149 let rm_bits = reg_to_bits(rm) as u16;
3150
3151 if rd_bits < 8 && rm_bits < 8 {
3152 let instr: u16 = 0xB200 | (rm_bits << 3) | rd_bits;
3154 Ok(instr.to_le_bytes().to_vec())
3155 } else {
3156 let rd_bits32 = rd_bits as u32;
3159 let rm_bits32 = rm_bits as u32;
3160 let hw1: u16 = 0xFA0F;
3161 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3162 let mut bytes = hw1.to_le_bytes().to_vec();
3163 bytes.extend_from_slice(&hw2.to_le_bytes());
3164 Ok(bytes)
3165 }
3166 }
3167
3168 ArmOp::Uxtb { rd, rm } => {
3170 let rd_bits = reg_to_bits(rd) as u16;
3171 let rm_bits = reg_to_bits(rm) as u16;
3172 if rd_bits < 8 && rm_bits < 8 {
3173 let instr: u16 = 0xB2C0 | (rm_bits << 3) | rd_bits;
3175 Ok(instr.to_le_bytes().to_vec())
3176 } else {
3177 let hw1: u16 = 0xFA5F;
3179 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3180 let mut bytes = hw1.to_le_bytes().to_vec();
3181 bytes.extend_from_slice(&hw2.to_le_bytes());
3182 Ok(bytes)
3183 }
3184 }
3185
3186 ArmOp::Uxth { rd, rm } => {
3188 let rd_bits = reg_to_bits(rd) as u16;
3189 let rm_bits = reg_to_bits(rm) as u16;
3190 if rd_bits < 8 && rm_bits < 8 {
3191 let instr: u16 = 0xB280 | (rm_bits << 3) | rd_bits;
3193 Ok(instr.to_le_bytes().to_vec())
3194 } else {
3195 let hw1: u16 = 0xFA1F;
3197 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3198 let mut bytes = hw1.to_le_bytes().to_vec();
3199 bytes.extend_from_slice(&hw2.to_le_bytes());
3200 Ok(bytes)
3201 }
3202 }
3203
3204 ArmOp::Cmp { rn, op2 } => {
3206 let rn_bits = reg_to_bits(rn) as u16;
3207
3208 if let Operand2::Imm(imm) = op2 {
3209 if *imm >= 0 && *imm <= 255 && rn_bits < 8 {
3212 let instr: u16 = 0x2800 | (rn_bits << 8) | (*imm as u16 & 0xFF);
3214 Ok(instr.to_le_bytes().to_vec())
3215 } else {
3216 self.encode_thumb32_cmp_imm(rn, *imm as u32)
3217 }
3218 } else if let Operand2::Reg(rm) = op2 {
3219 let rm_bits = reg_to_bits(rm) as u16;
3220 if rn_bits < 8 && rm_bits < 8 {
3221 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
3223 Ok(instr.to_le_bytes().to_vec())
3224 } else {
3225 let n_bit = (rn_bits >> 3) & 1;
3227 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
3228 Ok(instr.to_le_bytes().to_vec())
3229 }
3230 } else {
3231 let instr: u16 = 0xBF00;
3232 Ok(instr.to_le_bytes().to_vec())
3233 }
3234 }
3235
3236 ArmOp::Cmn { rn, op2 } => {
3239 let rn_bits = reg_to_bits(rn) as u16;
3240
3241 if let Operand2::Imm(imm) = op2 {
3242 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
3248 synth_core::Error::synthesis(
3249 "CMN immediate is not a valid ThumbExpandImm — materialize into a register",
3250 )
3251 })?;
3252 let i_bit = (field >> 11) & 1;
3253 let imm3 = (field >> 8) & 0x7;
3254 let imm8 = field & 0xFF;
3255 let hw1: u16 = (0xF110 | (i_bit << 10) as u16) | rn_bits;
3256 let hw2: u16 = (imm3 << 12) as u16 | 0x0F00 | imm8 as u16;
3257 let mut bytes = hw1.to_le_bytes().to_vec();
3258 bytes.extend_from_slice(&hw2.to_le_bytes());
3259 Ok(bytes)
3260 } else if let Operand2::Reg(rm) = op2 {
3261 let rm_bits = reg_to_bits(rm) as u16;
3262 if rn_bits < 8 && rm_bits < 8 {
3268 let instr: u16 = 0x42C0 | (rm_bits << 3) | rn_bits;
3270 Ok(instr.to_le_bytes().to_vec())
3271 } else {
3272 let hw1: u16 = 0xEB10 | rn_bits;
3273 let hw2: u16 = 0x0F00 | rm_bits;
3274 let mut bytes = hw1.to_le_bytes().to_vec();
3275 bytes.extend_from_slice(&hw2.to_le_bytes());
3276 Ok(bytes)
3277 }
3278 } else {
3279 Ok(vec![0xBF, 0x00])
3280 }
3281 }
3282
3283 ArmOp::Ldr { rd, addr } => {
3285 let rd_bits = reg_to_bits(rd);
3286 let base_bits = reg_to_bits(&addr.base);
3287
3288 if let Some(offset_reg) = &addr.offset_reg {
3290 let rm_bits = reg_to_bits(offset_reg);
3291
3292 if addr.offset != 0 {
3294 let scratch = Reg::R12;
3297 let mut bytes =
3298 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3299 bytes.extend(self.encode_thumb32_ldr_reg(rd, &addr.base, &scratch)?);
3300 return Ok(bytes);
3301 }
3302
3303 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3306 let instr: u16 = 0x5800
3308 | ((rm_bits as u16) << 6)
3309 | ((base_bits as u16) << 3)
3310 | (rd_bits as u16);
3311 return Ok(instr.to_le_bytes().to_vec());
3312 }
3313
3314 return self.encode_thumb32_ldr_reg(rd, &addr.base, offset_reg);
3316 }
3317
3318 let offset = addr.offset as u32;
3320
3321 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3322 let imm5 = (offset >> 2) as u16;
3324 let instr: u16 =
3325 0x6800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3326 Ok(instr.to_le_bytes().to_vec())
3327 } else {
3328 self.encode_thumb32_ldr(rd, &addr.base, offset)
3329 }
3330 }
3331
3332 ArmOp::Str { rd, addr } => {
3334 let rd_bits = reg_to_bits(rd);
3335 let base_bits = reg_to_bits(&addr.base);
3336
3337 if let Some(offset_reg) = &addr.offset_reg {
3339 let rm_bits = reg_to_bits(offset_reg);
3340
3341 if addr.offset != 0 {
3343 let scratch = Reg::R12;
3346 let mut bytes =
3347 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3348 bytes.extend(self.encode_thumb32_str_reg(rd, &addr.base, &scratch)?);
3349 return Ok(bytes);
3350 }
3351
3352 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3355 let instr: u16 = 0x5000
3357 | ((rm_bits as u16) << 6)
3358 | ((base_bits as u16) << 3)
3359 | (rd_bits as u16);
3360 return Ok(instr.to_le_bytes().to_vec());
3361 }
3362
3363 return self.encode_thumb32_str_reg(rd, &addr.base, offset_reg);
3365 }
3366
3367 let offset = addr.offset as u32;
3369
3370 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3371 let imm5 = (offset >> 2) as u16;
3373 let instr: u16 =
3374 0x6000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3375 Ok(instr.to_le_bytes().to_vec())
3376 } else {
3377 self.encode_thumb32_str(rd, &addr.base, offset)
3378 }
3379 }
3380
3381 ArmOp::Ldrb { rd, addr } => {
3383 let rd_bits = reg_to_bits(rd);
3384 let base_bits = reg_to_bits(&addr.base);
3385
3386 if let Some(offset_reg) = &addr.offset_reg {
3387 if addr.offset != 0 {
3388 let scratch = Reg::R12;
3389 let mut bytes =
3390 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3391 bytes.extend(self.encode_thumb32_ldrb_reg(rd, &addr.base, &scratch)?);
3392 return Ok(bytes);
3393 }
3394 return self.encode_thumb32_ldrb_reg(rd, &addr.base, offset_reg);
3395 }
3396
3397 let offset = addr.offset as u32;
3398 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3399 let instr: u16 = 0x7800
3401 | ((offset as u16) << 6)
3402 | ((base_bits as u16) << 3)
3403 | (rd_bits as u16);
3404 Ok(instr.to_le_bytes().to_vec())
3405 } else {
3406 self.encode_thumb32_ldrb_imm(rd, &addr.base, offset)
3407 }
3408 }
3409
3410 ArmOp::Ldrsb { rd, addr } => {
3412 let rd_bits = reg_to_bits(rd);
3413 let base_bits = reg_to_bits(&addr.base);
3414
3415 if let Some(offset_reg) = &addr.offset_reg {
3416 if addr.offset != 0 {
3417 let scratch = Reg::R12;
3418 let mut bytes =
3419 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3420 bytes.extend(self.encode_thumb32_ldrsb_reg(rd, &addr.base, &scratch)?);
3421 return Ok(bytes);
3422 }
3423 return self.encode_thumb32_ldrsb_reg(rd, &addr.base, offset_reg);
3424 }
3425
3426 let offset = addr.offset as u32;
3427 if rd_bits < 8 && base_bits < 8 && offset == 0 {
3430 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3432 } else {
3433 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3434 }
3435 }
3436
3437 ArmOp::Ldrh { rd, addr } => {
3439 let rd_bits = reg_to_bits(rd);
3440 let base_bits = reg_to_bits(&addr.base);
3441
3442 if let Some(offset_reg) = &addr.offset_reg {
3443 if addr.offset != 0 {
3444 let scratch = Reg::R12;
3445 let mut bytes =
3446 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3447 bytes.extend(self.encode_thumb32_ldrh_reg(rd, &addr.base, &scratch)?);
3448 return Ok(bytes);
3449 }
3450 return self.encode_thumb32_ldrh_reg(rd, &addr.base, offset_reg);
3451 }
3452
3453 let offset = addr.offset as u32;
3454 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3455 let imm5 = (offset >> 1) as u16;
3457 let instr: u16 =
3458 0x8800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3459 Ok(instr.to_le_bytes().to_vec())
3460 } else {
3461 self.encode_thumb32_ldrh_imm(rd, &addr.base, offset)
3462 }
3463 }
3464
3465 ArmOp::Ldrsh { rd, addr } => {
3467 if let Some(offset_reg) = &addr.offset_reg {
3468 if addr.offset != 0 {
3469 let scratch = Reg::R12;
3470 let mut bytes =
3471 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3472 bytes.extend(self.encode_thumb32_ldrsh_reg(rd, &addr.base, &scratch)?);
3473 return Ok(bytes);
3474 }
3475 return self.encode_thumb32_ldrsh_reg(rd, &addr.base, offset_reg);
3476 }
3477
3478 let offset = addr.offset as u32;
3479 self.encode_thumb32_ldrsh_imm(rd, &addr.base, offset)
3480 }
3481
3482 ArmOp::Strb { rd, addr } => {
3484 let rd_bits = reg_to_bits(rd);
3485 let base_bits = reg_to_bits(&addr.base);
3486
3487 if let Some(offset_reg) = &addr.offset_reg {
3488 if addr.offset != 0 {
3489 let scratch = Reg::R12;
3490 let mut bytes =
3491 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3492 bytes.extend(self.encode_thumb32_strb_reg(rd, &addr.base, &scratch)?);
3493 return Ok(bytes);
3494 }
3495 return self.encode_thumb32_strb_reg(rd, &addr.base, offset_reg);
3496 }
3497
3498 let offset = addr.offset as u32;
3499 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3500 let instr: u16 = 0x7000
3502 | ((offset as u16) << 6)
3503 | ((base_bits as u16) << 3)
3504 | (rd_bits as u16);
3505 Ok(instr.to_le_bytes().to_vec())
3506 } else {
3507 self.encode_thumb32_strb_imm(rd, &addr.base, offset)
3508 }
3509 }
3510
3511 ArmOp::Strh { rd, addr } => {
3513 let rd_bits = reg_to_bits(rd);
3514 let base_bits = reg_to_bits(&addr.base);
3515
3516 if let Some(offset_reg) = &addr.offset_reg {
3517 if addr.offset != 0 {
3518 let scratch = Reg::R12;
3519 let mut bytes =
3520 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3521 bytes.extend(self.encode_thumb32_strh_reg(rd, &addr.base, &scratch)?);
3522 return Ok(bytes);
3523 }
3524 return self.encode_thumb32_strh_reg(rd, &addr.base, offset_reg);
3525 }
3526
3527 let offset = addr.offset as u32;
3528 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3529 let imm5 = (offset >> 1) as u16;
3531 let instr: u16 =
3532 0x8000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3533 Ok(instr.to_le_bytes().to_vec())
3534 } else {
3535 self.encode_thumb32_strh_imm(rd, &addr.base, offset)
3536 }
3537 }
3538
3539 ArmOp::MemorySize { rd } => {
3541 let rd_bits = reg_to_bits(rd);
3544 let r10_bits = reg_to_bits(&Reg::R10);
3545 if rd_bits < 8 && r10_bits < 8 {
3546 let instr: u16 =
3547 0x0800 | (16u16 << 6) | ((r10_bits as u16) << 3) | (rd_bits as u16);
3548 Ok(instr.to_le_bytes().to_vec())
3549 } else {
3550 let imm5: u32 = 16;
3552 let imm3 = (imm5 >> 2) & 0x7;
3553 let imm2 = imm5 & 0x3;
3554 let hw1: u16 = 0xEA4F;
3555 let hw2: u16 =
3556 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | 0x10 | r10_bits) as u16;
3557 let mut bytes = hw1.to_le_bytes().to_vec();
3558 bytes.extend_from_slice(&hw2.to_le_bytes());
3559 Ok(bytes)
3560 }
3561 }
3562
3563 ArmOp::MemoryGrow { rd, .. } => {
3565 let rd_bits = reg_to_bits(rd);
3569 let hw1: u16 = 0xF06F; let hw2: u16 = (rd_bits << 8) as u16; let mut bytes = hw1.to_le_bytes().to_vec();
3572 bytes.extend_from_slice(&hw2.to_le_bytes());
3573 Ok(bytes)
3574 }
3575
3576 ArmOp::Bx { rm } => {
3578 let rm_bits = reg_to_bits(rm) as u16;
3579 let instr: u16 = 0x4700 | (rm_bits << 3);
3581 Ok(instr.to_le_bytes().to_vec())
3582 }
3583
3584 ArmOp::Blx { rm } => {
3587 let rm_bits = reg_to_bits(rm) as u16;
3588 let instr: u16 = 0x4780 | (rm_bits << 3);
3589 Ok(instr.to_le_bytes().to_vec())
3590 }
3591
3592 ArmOp::CallIndirect {
3596 rd: _,
3597 type_idx: _,
3598 table_index_reg,
3599 } => {
3600 let idx_reg = reg_to_bits(table_index_reg);
3601 let mut bytes = Vec::new();
3602
3603 let hw1: u16 = 0xEA4F_u16; let hw2: u16 = ((0x0C00 | (0b10 << 6)) | idx_reg) as u16;
3623 bytes.extend_from_slice(&hw1.to_le_bytes());
3624 bytes.extend_from_slice(&hw2.to_le_bytes());
3625
3626 let ldr_hw1: u16 = 0xF85B; let ldr_hw2: u16 = 0xC00C; bytes.extend_from_slice(&ldr_hw1.to_le_bytes());
3632 bytes.extend_from_slice(&ldr_hw2.to_le_bytes());
3633
3634 let blx: u16 = 0x47E0; bytes.extend_from_slice(&blx.to_le_bytes());
3638
3639 Ok(bytes)
3640 }
3641
3642 ArmOp::Label { .. } => Ok(Vec::new()),
3644
3645 ArmOp::Bcc { cond, label: _ } => {
3647 use synth_synthesis::Condition;
3648 let cond_bits: u16 = match cond {
3649 Condition::EQ => 0x0,
3650 Condition::NE => 0x1,
3651 Condition::HS => 0x2,
3652 Condition::LO => 0x3,
3653 Condition::HI => 0x8,
3654 Condition::LS => 0x9,
3655 Condition::GE => 0xA,
3656 Condition::LT => 0xB,
3657 Condition::GT => 0xC,
3658 Condition::LE => 0xD,
3659 };
3660 let instr: u16 = 0xD000 | (cond_bits << 8);
3662 Ok(instr.to_le_bytes().to_vec())
3663 }
3664
3665 ArmOp::B { label: _ } => {
3667 let instr: u16 = 0xE000; Ok(instr.to_le_bytes().to_vec())
3671 }
3672
3673 ArmOp::Bhs { label: _ } => {
3676 let instr: u16 = 0xD200; Ok(instr.to_le_bytes().to_vec())
3680 }
3681
3682 ArmOp::Blo { label: _ } => {
3685 let instr: u16 = 0xD300; Ok(instr.to_le_bytes().to_vec())
3689 }
3690
3691 ArmOp::BOffset { offset } => {
3694 let halfword_offset = *offset;
3697
3698 if (-1024..=1022).contains(&halfword_offset) {
3701 let imm11 = (halfword_offset as u16) & 0x7FF;
3703 let instr: u16 = 0xE000 | imm11;
3704 Ok(instr.to_le_bytes().to_vec())
3705 } else {
3706 let signed_offset = halfword_offset << 1; let s = if signed_offset < 0 { 1u32 } else { 0u32 };
3722 let uoffset = signed_offset as u32;
3723 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;
3731 let hw2: u16 = (0x9000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
3732
3733 let mut bytes = hw1.to_le_bytes().to_vec();
3734 bytes.extend_from_slice(&hw2.to_le_bytes());
3735 Ok(bytes)
3736 }
3737 }
3738
3739 ArmOp::BCondOffset { cond, offset } => {
3741 use synth_synthesis::Condition;
3742 let cond_bits: u16 = match cond {
3743 Condition::EQ => 0x0,
3744 Condition::NE => 0x1,
3745 Condition::HS => 0x2,
3746 Condition::LO => 0x3,
3747 Condition::HI => 0x8,
3748 Condition::LS => 0x9,
3749 Condition::GE => 0xA,
3750 Condition::LT => 0xB,
3751 Condition::GT => 0xC,
3752 Condition::LE => 0xD,
3753 };
3754
3755 let halfword_offset = *offset;
3758
3759 if (-128..=127).contains(&halfword_offset) {
3762 let imm8 = (halfword_offset as u16) & 0xFF;
3763 let instr: u16 = 0xD000 | (cond_bits << 8) | imm8;
3764 Ok(instr.to_le_bytes().to_vec())
3765 } else {
3766 let offset = halfword_offset >> 1;
3770 let s = if offset < 0 { 1u32 } else { 0u32 };
3771 let imm6 = ((offset >> 11) as u32) & 0x3F;
3772 let imm11 = (offset as u32) & 0x7FF;
3773 let j1 = if s == 1 { 1 } else { 0 };
3774 let j2 = if s == 1 { 1 } else { 0 };
3775
3776 let hw1: u16 = (0xF000 | (s << 10) | ((cond_bits as u32) << 6) | imm6) as u16;
3777 let hw2: u16 = (0x8000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
3778
3779 let mut bytes = hw1.to_le_bytes().to_vec();
3780 bytes.extend_from_slice(&hw2.to_le_bytes());
3781 Ok(bytes)
3782 }
3783 }
3784
3785 ArmOp::Bl { label: _ } => {
3786 let hw1: u16 = 0xF7FF;
3801 let hw2: u16 = 0xFFFE;
3802 let mut bytes = hw1.to_le_bytes().to_vec();
3803 bytes.extend_from_slice(&hw2.to_le_bytes());
3804 Ok(bytes)
3805 }
3806
3807 ArmOp::Mvn { rd, op2 } => {
3809 if let Operand2::Reg(rm) = op2 {
3810 let rd_bits = reg_to_bits(rd) as u16;
3811 let rm_bits = reg_to_bits(rm) as u16;
3812
3813 if rd_bits < 8 && rm_bits < 8 {
3814 let instr: u16 = 0x43C0 | (rm_bits << 3) | rd_bits;
3816 Ok(instr.to_le_bytes().to_vec())
3817 } else {
3818 let hw1: u16 = 0xEA6F_u16;
3820 let hw2: u16 = ((reg_to_bits(rd) << 8) | reg_to_bits(rm)) as u16;
3821 let mut bytes = hw1.to_le_bytes().to_vec();
3822 bytes.extend_from_slice(&hw2.to_le_bytes());
3823 Ok(bytes)
3824 }
3825 } else {
3826 let instr: u16 = 0xBF00;
3827 Ok(instr.to_le_bytes().to_vec())
3828 }
3829 }
3830
3831 ArmOp::Movw { rd, imm16 } => {
3833 self.encode_thumb32_movw_raw(reg_to_bits(rd), *imm16 as u32)
3834 }
3835
3836 ArmOp::Movt { rd, imm16 } => {
3838 self.encode_thumb32_movt_raw(reg_to_bits(rd), *imm16 as u32)
3839 }
3840
3841 ArmOp::MovwSym { rd, addend, .. } => {
3846 self.encode_thumb32_movw_raw(reg_to_bits(rd), (*addend as u32) & 0xffff)
3847 }
3848 ArmOp::MovtSym { rd, addend, .. } => {
3849 self.encode_thumb32_movt_raw(reg_to_bits(rd), ((*addend as u32) >> 16) & 0xffff)
3850 }
3851
3852 ArmOp::LdrSym { rd, .. } => {
3860 let rt = reg_to_bits(rd) as u16;
3861 let hw1: u16 = 0xF8DF; let hw2: u16 = rt << 12; let mut bytes = Vec::with_capacity(4);
3864 bytes.extend_from_slice(&hw1.to_le_bytes());
3865 bytes.extend_from_slice(&hw2.to_le_bytes());
3866 Ok(bytes)
3867 }
3868
3869 ArmOp::SetCond { rd, cond } => {
3875 let rd_bits = reg_to_bits(rd) as u16;
3876
3877 use synth_synthesis::Condition;
3879 let cond_bits: u16 = match cond {
3880 Condition::EQ => 0x0,
3881 Condition::NE => 0x1,
3882 Condition::LT => 0xB,
3883 Condition::LE => 0xD,
3884 Condition::GT => 0xC,
3885 Condition::GE => 0xA,
3886 Condition::LO => 0x3, Condition::LS => 0x9, Condition::HI => 0x8, Condition::HS => 0x2, };
3891
3892 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
3897 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
3898
3899 let mut bytes = ite_instr.to_le_bytes().to_vec();
3910 let push_mov = |bytes: &mut Vec<u8>, imm: u16| {
3911 if rd_bits <= 7 {
3912 let m: u16 = 0x2000 | (rd_bits << 8) | imm; bytes.extend_from_slice(&m.to_le_bytes());
3914 } else {
3915 let hw1: u16 = 0xF04F;
3917 let hw2: u16 = (rd_bits << 8) | imm;
3918 bytes.extend_from_slice(&hw1.to_le_bytes());
3919 bytes.extend_from_slice(&hw2.to_le_bytes());
3920 }
3921 };
3922 push_mov(&mut bytes, 1); push_mov(&mut bytes, 0); Ok(bytes)
3925 }
3926
3927 ArmOp::I64SetCond {
3932 rd,
3933 rn_lo,
3934 rn_hi,
3935 rm_lo,
3936 rm_hi,
3937 cond,
3938 } => {
3939 use synth_synthesis::Condition;
3940 let rd_bits = reg_to_bits(rd) as u16;
3941 let mut bytes = Vec::new();
3942
3943 let encode_cmp_reg = |rn: &synth_synthesis::Reg,
3945 rm: &synth_synthesis::Reg|
3946 -> Vec<u8> {
3947 let rn_bits = reg_to_bits(rn) as u16;
3948 let rm_bits = reg_to_bits(rm) as u16;
3949 if rn_bits < 8 && rm_bits < 8 {
3950 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
3951 instr.to_le_bytes().to_vec()
3952 } else {
3953 let n_bit = (rn_bits >> 3) & 1;
3954 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
3955 instr.to_le_bytes().to_vec()
3956 }
3957 };
3958
3959 let encode_ite = |cond_bits: u16| -> Vec<u8> {
3961 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
3962 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
3963 ite_instr.to_le_bytes().to_vec()
3964 };
3965
3966 let encode_setcond = |cond_bits: u16, rd_bits: u16| -> Vec<u8> {
3968 let mut b = encode_ite(cond_bits);
3969 if rd_bits < 8 {
3970 let mov_one: u16 = 0x2001 | (rd_bits << 8);
3971 let mov_zero: u16 = 0x2000 | (rd_bits << 8);
3972 b.extend_from_slice(&mov_one.to_le_bytes());
3973 b.extend_from_slice(&mov_zero.to_le_bytes());
3974 } else {
3975 for imm in [1u16, 0u16] {
3983 let hw1: u16 = 0xF04F;
3984 let hw2: u16 = (rd_bits << 8) | imm;
3985 b.extend_from_slice(&hw1.to_le_bytes());
3986 b.extend_from_slice(&hw2.to_le_bytes());
3987 }
3988 }
3989 b
3990 };
3991
3992 match cond {
3993 Condition::EQ | Condition::NE => {
3994 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
3996
3997 let it_eq: u16 = 0xBF08; bytes.extend_from_slice(&it_eq.to_le_bytes());
4000
4001 bytes.extend_from_slice(&encode_cmp_reg(rn_hi, rm_hi));
4003
4004 let cond_bits: u16 = match cond {
4006 Condition::EQ => 0x0,
4007 Condition::NE => 0x1,
4008 _ => unreachable!(),
4009 };
4010 bytes.extend_from_slice(&encode_setcond(cond_bits, rd_bits));
4011 }
4012
4013 Condition::LT => {
4014 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4016
4017 let rn_hi_bits = reg_to_bits(rn_hi);
4020 let rm_hi_bits = reg_to_bits(rm_hi);
4021 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4022 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4023 bytes.extend_from_slice(&hw1.to_le_bytes());
4024 bytes.extend_from_slice(&hw2.to_le_bytes());
4025
4026 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4029
4030 Condition::GT => {
4031 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4034
4035 let rm_hi_bits = reg_to_bits(rm_hi);
4037 let rn_hi_bits = reg_to_bits(rn_hi);
4038 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4039 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4040 bytes.extend_from_slice(&hw1.to_le_bytes());
4041 bytes.extend_from_slice(&hw2.to_le_bytes());
4042
4043 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4046
4047 Condition::LE => {
4048 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4052
4053 let rm_hi_bits = reg_to_bits(rm_hi);
4055 let rn_hi_bits = reg_to_bits(rn_hi);
4056 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4057 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4058 bytes.extend_from_slice(&hw1.to_le_bytes());
4059 bytes.extend_from_slice(&hw2.to_le_bytes());
4060
4061 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4064
4065 Condition::GE => {
4066 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4069
4070 let rn_hi_bits = reg_to_bits(rn_hi);
4072 let rm_hi_bits = reg_to_bits(rm_hi);
4073 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4074 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4075 bytes.extend_from_slice(&hw1.to_le_bytes());
4076 bytes.extend_from_slice(&hw2.to_le_bytes());
4077
4078 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4081
4082 Condition::LO => {
4084 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4086 let rn_hi_bits = reg_to_bits(rn_hi);
4087 let rm_hi_bits = reg_to_bits(rm_hi);
4088 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4089 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4090 bytes.extend_from_slice(&hw1.to_le_bytes());
4091 bytes.extend_from_slice(&hw2.to_le_bytes());
4092 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4094
4095 Condition::HI => {
4096 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4098 let rm_hi_bits = reg_to_bits(rm_hi);
4099 let rn_hi_bits = reg_to_bits(rn_hi);
4100 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4101 let hw2: u16 = ((rd_bits as u32) << 8 | rn_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::LS => {
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(0x2, rd_bits)); }
4118
4119 Condition::HS => {
4120 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4122 let rn_hi_bits = reg_to_bits(rn_hi);
4123 let rm_hi_bits = reg_to_bits(rm_hi);
4124 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4125 let hw2: u16 = ((rd_bits as u32) << 8 | rm_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
4132 Ok(bytes)
4133 }
4134
4135 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
4138 let rd_bits = reg_to_bits(rd);
4139 let rn_lo_bits = reg_to_bits(rn_lo);
4140 let rn_hi_bits = reg_to_bits(rn_hi);
4141 let mut bytes = Vec::new();
4142
4143 let hw1: u16 = (0xEA40 | rn_lo_bits) as u16;
4145 let hw2: u16 = ((rd_bits << 8) | rn_hi_bits) as u16;
4146 bytes.extend_from_slice(&hw1.to_le_bytes());
4147 bytes.extend_from_slice(&hw2.to_le_bytes());
4148
4149 if rd_bits < 8 {
4154 let cmp_instr: u16 = 0x2800 | ((rd_bits as u16) << 8);
4155 bytes.extend_from_slice(&cmp_instr.to_le_bytes());
4156 } else {
4157 let hw1: u16 = 0xF1B0 | (rd_bits as u16);
4158 let hw2: u16 = 0x0F00;
4159 bytes.extend_from_slice(&hw1.to_le_bytes());
4160 bytes.extend_from_slice(&hw2.to_le_bytes());
4161 }
4162
4163 let mask = 0xC_u16; let ite_instr: u16 = 0xBF00 | mask;
4167 bytes.extend_from_slice(&ite_instr.to_le_bytes());
4168 if rd_bits < 8 {
4169 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
4170 let mov_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
4171 bytes.extend_from_slice(&mov_one.to_le_bytes());
4172 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4173 } else {
4174 for imm in [1u16, 0u16] {
4175 let hw1: u16 = 0xF04F;
4176 let hw2: u16 = ((rd_bits as u16) << 8) | imm;
4177 bytes.extend_from_slice(&hw1.to_le_bytes());
4178 bytes.extend_from_slice(&hw2.to_le_bytes());
4179 }
4180 }
4181
4182 Ok(bytes)
4183 }
4184
4185 ArmOp::I64Mul {
4189 rd_lo,
4190 rd_hi,
4191 rn_lo,
4192 rn_hi,
4193 rm_lo,
4194 rm_hi,
4195 } => {
4196 let rd_lo_bits = reg_to_bits(rd_lo);
4197 let rd_hi_bits = reg_to_bits(rd_hi);
4198 let rn_lo_bits = reg_to_bits(rn_lo);
4199 let rn_hi_bits = reg_to_bits(rn_hi);
4200 let rm_lo_bits = reg_to_bits(rm_lo);
4201 let rm_hi_bits = reg_to_bits(rm_hi);
4202 let r12: u32 = 12; let mut bytes = Vec::new();
4204
4205 let hw1: u16 = (0xFB00 | rn_lo_bits) as u16;
4208 let hw2: u16 = (0xF000 | (r12 << 8) | rm_hi_bits) as u16;
4209 bytes.extend_from_slice(&hw1.to_le_bytes());
4210 bytes.extend_from_slice(&hw2.to_le_bytes());
4211
4212 let hw1: u16 = (0xFB00 | rn_hi_bits) as u16;
4215 let hw2: u16 = ((r12 << 12) | (r12 << 8) | rm_lo_bits) as u16;
4216 bytes.extend_from_slice(&hw1.to_le_bytes());
4217 bytes.extend_from_slice(&hw2.to_le_bytes());
4218
4219 let hw1: u16 = (0xFBA0 | rn_lo_bits) as u16;
4222 let hw2: u16 = ((rd_lo_bits << 12) | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4223 bytes.extend_from_slice(&hw1.to_le_bytes());
4224 bytes.extend_from_slice(&hw2.to_le_bytes());
4225
4226 let d_bit = (rd_hi_bits >> 3) & 1;
4229 let add_instr: u16 =
4230 (0x4400 | (d_bit << 7) | (r12 << 3) | (rd_hi_bits & 0x7)) as u16;
4231 bytes.extend_from_slice(&add_instr.to_le_bytes());
4232
4233 Ok(bytes)
4234 }
4235
4236 ArmOp::I64Shl {
4239 rd_lo,
4240 rd_hi,
4241 rn_lo,
4242 rn_hi,
4243 rm_lo,
4244 rm_hi,
4245 } => {
4246 let rd_lo_bits = reg_to_bits(rd_lo);
4247 let rd_hi_bits = reg_to_bits(rd_hi);
4248 let rn_lo_bits = reg_to_bits(rn_lo);
4249 let rn_hi_bits = reg_to_bits(rn_hi);
4250 let rm_lo_bits = reg_to_bits(rm_lo);
4251 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4253
4254 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4256 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4257 bytes.extend_from_slice(&hw1.to_le_bytes());
4258 bytes.extend_from_slice(&hw2.to_le_bytes());
4259
4260 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4262 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4263 bytes.extend_from_slice(&hw1.to_le_bytes());
4264 bytes.extend_from_slice(&hw2.to_le_bytes());
4265
4266 let bpl: u16 = 0xD50A;
4268 bytes.extend_from_slice(&bpl.to_le_bytes());
4269
4270 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4273 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4274 bytes.extend_from_slice(&hw1.to_le_bytes());
4275 bytes.extend_from_slice(&hw2.to_le_bytes());
4276
4277 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4279 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4280 bytes.extend_from_slice(&hw1.to_le_bytes());
4281 bytes.extend_from_slice(&hw2.to_le_bytes());
4282
4283 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4285 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) 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 = (0xEA40 | rd_hi_bits) as u16;
4291 let hw2: u16 = ((rd_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_lo_bits) as u16;
4297 let hw2: u16 = (0xF000 | (rd_lo_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 b_done: u16 = 0xE002;
4303 bytes.extend_from_slice(&b_done.to_le_bytes());
4304
4305 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4308 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_hi_bits) as u16;
4309 bytes.extend_from_slice(&hw1.to_le_bytes());
4310 bytes.extend_from_slice(&hw2.to_le_bytes());
4311
4312 let mov_zero: u16 = 0x2000 | ((rd_lo_bits as u16) << 8);
4314 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4315
4316 Ok(bytes) }
4318
4319 ArmOp::I64ShrU {
4321 rd_lo,
4322 rd_hi,
4323 rn_lo,
4324 rn_hi,
4325 rm_lo,
4326 rm_hi,
4327 } => {
4328 let rd_lo_bits = reg_to_bits(rd_lo);
4329 let rd_hi_bits = reg_to_bits(rd_hi);
4330 let rn_lo_bits = reg_to_bits(rn_lo);
4331 let rn_hi_bits = reg_to_bits(rn_hi);
4332 let rm_lo_bits = reg_to_bits(rm_lo);
4333 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4335
4336 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4338 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4339 bytes.extend_from_slice(&hw1.to_le_bytes());
4340 bytes.extend_from_slice(&hw2.to_le_bytes());
4341
4342 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4344 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4345 bytes.extend_from_slice(&hw1.to_le_bytes());
4346 bytes.extend_from_slice(&hw2.to_le_bytes());
4347
4348 let bpl: u16 = 0xD50A;
4350 bytes.extend_from_slice(&bpl.to_le_bytes());
4351
4352 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4355 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4356 bytes.extend_from_slice(&hw1.to_le_bytes());
4357 bytes.extend_from_slice(&hw2.to_le_bytes());
4358
4359 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4361 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4362 bytes.extend_from_slice(&hw1.to_le_bytes());
4363 bytes.extend_from_slice(&hw2.to_le_bytes());
4364
4365 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4367 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) 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 = (0xEA40 | rd_lo_bits) as u16;
4373 let hw2: u16 = ((rd_lo_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_hi_bits) as u16;
4379 let hw2: u16 = (0xF000 | (rd_hi_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 b_done: u16 = 0xE002;
4385 bytes.extend_from_slice(&b_done.to_le_bytes());
4386
4387 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4390 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4391 bytes.extend_from_slice(&hw1.to_le_bytes());
4392 bytes.extend_from_slice(&hw2.to_le_bytes());
4393
4394 let mov_zero: u16 = 0x2000 | ((rd_hi_bits as u16) << 8);
4396 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4397
4398 Ok(bytes) }
4400
4401 ArmOp::I64ShrS {
4403 rd_lo,
4404 rd_hi,
4405 rn_lo,
4406 rn_hi,
4407 rm_lo,
4408 rm_hi,
4409 } => {
4410 let rd_lo_bits = reg_to_bits(rd_lo);
4411 let rd_hi_bits = reg_to_bits(rd_hi);
4412 let rn_lo_bits = reg_to_bits(rn_lo);
4413 let rn_hi_bits = reg_to_bits(rn_hi);
4414 let rm_lo_bits = reg_to_bits(rm_lo);
4415 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4417
4418 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4420 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4421 bytes.extend_from_slice(&hw1.to_le_bytes());
4422 bytes.extend_from_slice(&hw2.to_le_bytes());
4423
4424 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4426 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4427 bytes.extend_from_slice(&hw1.to_le_bytes());
4428 bytes.extend_from_slice(&hw2.to_le_bytes());
4429
4430 let bpl: u16 = 0xD50A;
4432 bytes.extend_from_slice(&bpl.to_le_bytes());
4433
4434 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4437 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4438 bytes.extend_from_slice(&hw1.to_le_bytes());
4439 bytes.extend_from_slice(&hw2.to_le_bytes());
4440
4441 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4443 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4444 bytes.extend_from_slice(&hw1.to_le_bytes());
4445 bytes.extend_from_slice(&hw2.to_le_bytes());
4446
4447 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4449 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) 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 = (0xEA40 | rd_lo_bits) as u16;
4455 let hw2: u16 = ((rd_lo_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 = (0xFA40 | rn_hi_bits) as u16;
4461 let hw2: u16 = (0xF000 | (rd_hi_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 b_done: u16 = 0xE003;
4467 bytes.extend_from_slice(&b_done.to_le_bytes());
4468
4469 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4472 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4473 bytes.extend_from_slice(&hw1.to_le_bytes());
4474 bytes.extend_from_slice(&hw2.to_le_bytes());
4475
4476 let hw1: u16 = 0xEA4F;
4480 let hw2: u16 = (0x7000 | (rd_hi_bits << 8) | 0x00E0 | rn_hi_bits) as u16;
4481 bytes.extend_from_slice(&hw1.to_le_bytes());
4482 bytes.extend_from_slice(&hw2.to_le_bytes());
4483
4484 Ok(bytes) }
4486
4487 ArmOp::I64Rotl {
4498 rdlo,
4499 rdhi,
4500 rnlo,
4501 rnhi,
4502 shift,
4503 } => {
4504 let mut bytes = Vec::new();
4505 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4506
4507 let core: [u16; 35] = [
4508 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, ];
4531 for hw in core {
4532 bytes.extend_from_slice(&hw.to_le_bytes());
4533 }
4534
4535 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4536 Ok(bytes) }
4538
4539 ArmOp::I64Rotr {
4546 rdlo,
4547 rdhi,
4548 rnlo,
4549 rnhi,
4550 shift,
4551 } => {
4552 let mut bytes = Vec::new();
4553 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4554
4555 let core: [u16; 35] = [
4556 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, ];
4579 for hw in core {
4580 bytes.extend_from_slice(&hw.to_le_bytes());
4581 }
4582
4583 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4584 Ok(bytes) }
4586
4587 ArmOp::I64Clz { rd, rnlo, rnhi } => {
4601 let rd_bits = reg_to_bits(rd);
4602 let rn_lo_bits = reg_to_bits(rnlo);
4603 let rn_hi_bits = reg_to_bits(rnhi);
4604 let mut bytes = Vec::new();
4605
4606 let hw1: u16 = (0xF1B0 | rn_hi_bits) as u16;
4608 let hw2: u16 = 0x0F00;
4609 bytes.extend_from_slice(&hw1.to_le_bytes());
4610 bytes.extend_from_slice(&hw2.to_le_bytes());
4611
4612 let beq: u16 = 0xD003;
4615 bytes.extend_from_slice(&beq.to_le_bytes());
4616
4617 let hw1: u16 = (0xFAB0 | rn_hi_bits) as u16;
4620 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_hi_bits) as u16;
4621 bytes.extend_from_slice(&hw1.to_le_bytes());
4622 bytes.extend_from_slice(&hw2.to_le_bytes());
4623
4624 let b_done: u16 = 0xE004;
4627 bytes.extend_from_slice(&b_done.to_le_bytes());
4628
4629 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
4631
4632 let hw1: u16 = (0xFAB0 | rn_lo_bits) as u16;
4636 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_lo_bits) as u16;
4637 bytes.extend_from_slice(&hw1.to_le_bytes());
4638 bytes.extend_from_slice(&hw2.to_le_bytes());
4639
4640 let hw1: u16 = (0xF100 | rd_bits) as u16;
4642 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
4643 bytes.extend_from_slice(&hw1.to_le_bytes());
4644 bytes.extend_from_slice(&hw2.to_le_bytes());
4645
4646 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4650 bytes.extend_from_slice(&mov0.to_le_bytes());
4651
4652 Ok(bytes)
4653 }
4654
4655 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
4671 let rd_bits = reg_to_bits(rd);
4672 let rn_lo_bits = reg_to_bits(rnlo);
4673 let rn_hi_bits = reg_to_bits(rnhi);
4674 let mut bytes = Vec::new();
4675
4676 let hw1: u16 = (0xF1B0 | rn_lo_bits) as u16;
4678 let hw2: u16 = 0x0F00;
4679 bytes.extend_from_slice(&hw1.to_le_bytes());
4680 bytes.extend_from_slice(&hw2.to_le_bytes());
4681
4682 let beq: u16 = 0xD005;
4685 bytes.extend_from_slice(&beq.to_le_bytes());
4686
4687 let hw1: u16 = (0xFA90 | rn_lo_bits) as u16;
4690 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_lo_bits) as u16;
4691 bytes.extend_from_slice(&hw1.to_le_bytes());
4692 bytes.extend_from_slice(&hw2.to_le_bytes());
4693
4694 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
4697 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
4698 bytes.extend_from_slice(&hw1.to_le_bytes());
4699 bytes.extend_from_slice(&hw2.to_le_bytes());
4700
4701 let b_done: u16 = 0xE006;
4704 bytes.extend_from_slice(&b_done.to_le_bytes());
4705
4706 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
4708
4709 let hw1: u16 = (0xFA90 | rn_hi_bits) as u16;
4713 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_hi_bits) as u16;
4714 bytes.extend_from_slice(&hw1.to_le_bytes());
4715 bytes.extend_from_slice(&hw2.to_le_bytes());
4716
4717 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
4720 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
4721 bytes.extend_from_slice(&hw1.to_le_bytes());
4722 bytes.extend_from_slice(&hw2.to_le_bytes());
4723
4724 let hw1: u16 = (0xF100 | rd_bits) as u16;
4726 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
4727 bytes.extend_from_slice(&hw1.to_le_bytes());
4728 bytes.extend_from_slice(&hw2.to_le_bytes());
4729
4730 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4733 bytes.extend_from_slice(&mov0.to_le_bytes());
4734
4735 Ok(bytes)
4736 }
4737
4738 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
4742 let rd_bits = reg_to_bits(rd);
4743 let rn_lo_bits = reg_to_bits(rnlo);
4744 let rn_hi_bits = reg_to_bits(rnhi);
4745 let r12: u32 = 12; let r3: u32 = 3; let mut bytes = Vec::new();
4748
4749 bytes.extend_from_slice(&0xB438u16.to_le_bytes());
4751
4752 let d_bit: u32 = 0; let mov: u16 = (0x4600 | (d_bit << 7) | (rn_lo_bits << 3) | (4 & 0x7)) as u16;
4762 bytes.extend_from_slice(&mov.to_le_bytes());
4763
4764 let d_bit: u32 = 0; let mov: u16 = (0x4600 | (d_bit << 7) | (rn_hi_bits << 3) | (5 & 0x7)) as u16;
4767 bytes.extend_from_slice(&mov.to_le_bytes());
4768
4769 let hw1: u16 = 0xEA4F;
4773 let hw2: u16 = ((r12 << 8) | 0x50 | 4) as u16;
4774 bytes.extend_from_slice(&hw1.to_le_bytes());
4775 bytes.extend_from_slice(&hw2.to_le_bytes());
4776
4777 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
4780 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4781 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
4783 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4784
4785 let hw1: u16 = (0xEA00 | r12) as u16;
4787 let hw2: u16 = ((r12 << 8) | r3) as u16;
4788 bytes.extend_from_slice(&hw1.to_le_bytes());
4789 bytes.extend_from_slice(&hw2.to_le_bytes());
4790
4791 let hw1: u16 = (0xEBA0 | 4) as u16;
4793 let hw2: u16 = ((4 << 8) | r12) as u16;
4794 bytes.extend_from_slice(&hw1.to_le_bytes());
4795 bytes.extend_from_slice(&hw2.to_le_bytes());
4796
4797 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
4801 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4802 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
4804 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4805
4806 let hw1: u16 = (0xEA00 | 4) as u16;
4808 let hw2: u16 = ((r12 << 8) | r3) as u16;
4809 bytes.extend_from_slice(&hw1.to_le_bytes());
4810 bytes.extend_from_slice(&hw2.to_le_bytes());
4811
4812 let hw1: u16 = 0xEA4F;
4814 let hw2: u16 = ((4 << 8) | 0x90 | 4) as u16;
4815 bytes.extend_from_slice(&hw1.to_le_bytes());
4816 bytes.extend_from_slice(&hw2.to_le_bytes());
4817
4818 let hw1: u16 = (0xEA00 | 4) as u16;
4820 let hw2: u16 = ((4 << 8) | r3) as u16;
4821 bytes.extend_from_slice(&hw1.to_le_bytes());
4822 bytes.extend_from_slice(&hw2.to_le_bytes());
4823
4824 let hw1: u16 = (0xEB00 | 4) as u16;
4826 let hw2: u16 = ((4 << 8) | r12) as u16;
4827 bytes.extend_from_slice(&hw1.to_le_bytes());
4828 bytes.extend_from_slice(&hw2.to_le_bytes());
4829
4830 let hw1: u16 = 0xEA4F;
4835 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 4) 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 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
4850 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4851 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
4853 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4854
4855 let hw1: u16 = (0xEA00 | 4) as u16;
4857 let hw2: u16 = ((4 << 8) | r3) as u16;
4858 bytes.extend_from_slice(&hw1.to_le_bytes());
4859 bytes.extend_from_slice(&hw2.to_le_bytes());
4860
4861 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
4865 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4866 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
4868 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4869
4870 let hw1: u16 = (0xFB00 | 4) as u16;
4873 let hw2: u16 = (0xF000 | (4 << 8) | r3) as u16;
4874 bytes.extend_from_slice(&hw1.to_le_bytes());
4875 bytes.extend_from_slice(&hw2.to_le_bytes());
4876
4877 let hw1: u16 = 0xEA4F;
4880 let hw2: u16 = (0x6000 | (4 << 8) | 0x10 | 4) as u16;
4881 bytes.extend_from_slice(&hw1.to_le_bytes());
4882 bytes.extend_from_slice(&hw2.to_le_bytes());
4883
4884 let hw1: u16 = 0xEA4F;
4887 let hw2: u16 = ((r12 << 8) | 0x50 | 5) as u16;
4888 bytes.extend_from_slice(&hw1.to_le_bytes());
4889 bytes.extend_from_slice(&hw2.to_le_bytes());
4890
4891 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
4893 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4894 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
4895 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4896
4897 let hw1: u16 = (0xEA00 | r12) as u16;
4898 let hw2: u16 = ((r12 << 8) | r3) as u16;
4899 bytes.extend_from_slice(&hw1.to_le_bytes());
4900 bytes.extend_from_slice(&hw2.to_le_bytes());
4901
4902 let hw1: u16 = (0xEBA0 | 5) as u16;
4903 let hw2: u16 = ((5 << 8) | r12) as u16;
4904 bytes.extend_from_slice(&hw1.to_le_bytes());
4905 bytes.extend_from_slice(&hw2.to_le_bytes());
4906
4907 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
4909 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4910 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
4911 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4912
4913 let hw1: u16 = (0xEA00 | 5) as u16;
4914 let hw2: u16 = ((r12 << 8) | r3) as u16;
4915 bytes.extend_from_slice(&hw1.to_le_bytes());
4916 bytes.extend_from_slice(&hw2.to_le_bytes());
4917
4918 let hw1: u16 = 0xEA4F;
4919 let hw2: u16 = ((5 << 8) | 0x90 | 5) as u16;
4920 bytes.extend_from_slice(&hw1.to_le_bytes());
4921 bytes.extend_from_slice(&hw2.to_le_bytes());
4922
4923 let hw1: u16 = (0xEA00 | 5) as u16;
4924 let hw2: u16 = ((5 << 8) | r3) as u16;
4925 bytes.extend_from_slice(&hw1.to_le_bytes());
4926 bytes.extend_from_slice(&hw2.to_le_bytes());
4927
4928 let hw1: u16 = (0xEB00 | 5) as u16;
4929 let hw2: u16 = ((5 << 8) | r12) 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;
4936 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 5) as u16;
4937 bytes.extend_from_slice(&hw1.to_le_bytes());
4938 bytes.extend_from_slice(&hw2.to_le_bytes());
4939
4940 let hw1: u16 = (0xEB00 | 5) as u16;
4941 let hw2: u16 = ((5 << 8) | r12) as u16;
4942 bytes.extend_from_slice(&hw1.to_le_bytes());
4943 bytes.extend_from_slice(&hw2.to_le_bytes());
4944
4945 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
4947 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4948 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
4949 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4950
4951 let hw1: u16 = (0xEA00 | 5) as u16;
4952 let hw2: u16 = ((5 << 8) | r3) as u16;
4953 bytes.extend_from_slice(&hw1.to_le_bytes());
4954 bytes.extend_from_slice(&hw2.to_le_bytes());
4955
4956 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
4958 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4959 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
4960 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4961
4962 let hw1: u16 = (0xFB00 | 5) as u16;
4965 let hw2: u16 = (0xF000 | (5 << 8) | r3) as u16;
4966 bytes.extend_from_slice(&hw1.to_le_bytes());
4967 bytes.extend_from_slice(&hw2.to_le_bytes());
4968
4969 let hw1: u16 = 0xEA4F;
4972 let hw2: u16 = (0x6000 | (5 << 8) | 0x10 | 5) as u16;
4973 bytes.extend_from_slice(&hw1.to_le_bytes());
4974 bytes.extend_from_slice(&hw2.to_le_bytes());
4975
4976 let rd_bits_u16 = rd_bits as u16;
4979 let instr: u16 = 0x1800 | (5 << 6) | (4 << 3) | rd_bits_u16;
4980 bytes.extend_from_slice(&instr.to_le_bytes());
4981
4982 bytes.extend_from_slice(&0xBC38u16.to_le_bytes());
4984
4985 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4987 bytes.extend_from_slice(&mov0.to_le_bytes());
4988
4989 Ok(bytes)
4990 }
4991
4992 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
4995 let rdlo_bits = reg_to_bits(rdlo);
4996 let rdhi_bits = reg_to_bits(rdhi);
4997 let rnlo_bits = reg_to_bits(rnlo);
4998 let mut bytes = Vec::new();
4999
5000 let hw1: u16 = 0xFA4F_u16;
5003 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5004 bytes.extend_from_slice(&hw1.to_le_bytes());
5005 bytes.extend_from_slice(&hw2.to_le_bytes());
5006
5007 let hw1: u16 = 0xEA4F;
5012 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5013 bytes.extend_from_slice(&hw1.to_le_bytes());
5014 bytes.extend_from_slice(&hw2.to_le_bytes());
5015
5016 Ok(bytes)
5017 }
5018
5019 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
5022 let rdlo_bits = reg_to_bits(rdlo);
5023 let rdhi_bits = reg_to_bits(rdhi);
5024 let rnlo_bits = reg_to_bits(rnlo);
5025 let mut bytes = Vec::new();
5026
5027 let hw1: u16 = 0xFA0F_u16;
5030 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5031 bytes.extend_from_slice(&hw1.to_le_bytes());
5032 bytes.extend_from_slice(&hw2.to_le_bytes());
5033
5034 let hw1: u16 = 0xEA4F;
5036 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5037 bytes.extend_from_slice(&hw1.to_le_bytes());
5038 bytes.extend_from_slice(&hw2.to_le_bytes());
5039
5040 Ok(bytes)
5041 }
5042
5043 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
5046 let rdlo_bits = reg_to_bits(rdlo);
5047 let rdhi_bits = reg_to_bits(rdhi);
5048 let rnlo_bits = reg_to_bits(rnlo);
5049 let mut bytes = Vec::new();
5050
5051 if rdlo_bits != rnlo_bits {
5053 let d_bit = ((rdlo_bits >> 3) & 1) as u16;
5055 let mov: u16 = 0x4600
5056 | (d_bit << 7)
5057 | ((rnlo_bits as u16) << 3)
5058 | ((rdlo_bits & 0x7) as u16);
5059 bytes.extend_from_slice(&mov.to_le_bytes());
5060 }
5061
5062 let hw1: u16 = 0xEA4F;
5064 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rnlo_bits) as u16;
5065 bytes.extend_from_slice(&hw1.to_le_bytes());
5066 bytes.extend_from_slice(&hw2.to_le_bytes());
5067
5068 Ok(bytes)
5069 }
5070
5071 ArmOp::SelectMove { rd, rm, cond } => {
5074 let rd_bits = reg_to_bits(rd) as u16;
5075 let rm_bits = reg_to_bits(rm) as u16;
5076
5077 use synth_synthesis::Condition;
5079 let cond_bits: u16 = match cond {
5080 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, };
5091
5092 let it_instr: u16 = 0xBF00 | (cond_bits << 4) | 0x8;
5095
5096 let d_bit = (rd_bits >> 3) & 1;
5099 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5100
5101 let mut bytes = it_instr.to_le_bytes().to_vec();
5103 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5104 Ok(bytes)
5105 }
5106
5107 ArmOp::Popcnt { rd, rm } => {
5118 let mut bytes = Vec::new();
5119
5120 if rd != rm {
5122 let rd_bits = reg_to_bits(rd) as u16;
5123 let rm_bits = reg_to_bits(rm) as u16;
5124 let d_bit = (rd_bits >> 3) & 1;
5126 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5127 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5128 }
5129
5130 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x5555)?);
5133 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x5555)?);
5134
5135 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 1)?);
5138
5139 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(11, 11, 12)?);
5141
5142 bytes.extend_from_slice(&self.encode_thumb32_sub_reg_raw(
5144 reg_to_bits(rd),
5145 reg_to_bits(rd),
5146 11,
5147 )?);
5148
5149 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x3333)?);
5152 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x3333)?);
5153
5154 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5156 11,
5157 reg_to_bits(rd),
5158 12,
5159 )?);
5160
5161 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(
5163 reg_to_bits(rd),
5164 reg_to_bits(rd),
5165 2,
5166 )?);
5167
5168 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5170 reg_to_bits(rd),
5171 reg_to_bits(rd),
5172 12,
5173 )?);
5174
5175 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5177 reg_to_bits(rd),
5178 reg_to_bits(rd),
5179 11,
5180 )?);
5181
5182 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 4)?);
5185
5186 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5188 reg_to_bits(rd),
5189 reg_to_bits(rd),
5190 11,
5191 )?);
5192
5193 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x0F0F)?);
5195 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x0F0F)?);
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_lsr_raw(11, reg_to_bits(rd), 8)?);
5207
5208 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5210 reg_to_bits(rd),
5211 reg_to_bits(rd),
5212 11,
5213 )?);
5214
5215 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 16)?);
5218
5219 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5221 reg_to_bits(rd),
5222 reg_to_bits(rd),
5223 11,
5224 )?);
5225
5226 bytes.extend_from_slice(&self.encode_thumb32_and_imm_raw(
5229 reg_to_bits(rd),
5230 reg_to_bits(rd),
5231 0x3F,
5232 )?);
5233
5234 Ok(bytes)
5235 }
5236
5237 ArmOp::I64DivU {
5248 rdlo,
5249 rdhi,
5250 rnlo,
5251 rnhi,
5252 rmlo,
5253 rmhi,
5254 } => {
5255 let mut bytes = Vec::new();
5256 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5257 emit_i64_divisor_zero_trap(&mut bytes);
5258
5259 bytes.extend_from_slice(&0xB4F0u16.to_le_bytes());
5263
5264 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());
5275 bytes.extend_from_slice(&0x0C40u16.to_le_bytes());
5276
5277 let loop_start = bytes.len();
5279
5280 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes());
5291 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());
5300 bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
5301 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes());
5305 bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5306
5307 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes());
5312 bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5313 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());
5344 bytes.extend_from_slice(&0x0703u16.to_le_bytes());
5345 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5348
5349 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
5353 bytes.extend_from_slice(&0x0C01u16.to_le_bytes());
5354
5355 let branch_offset_bytes = bytes.len() - loop_start + 4; let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5358 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5359 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5360
5361 bytes.extend_from_slice(&0x4620u16.to_le_bytes()); bytes.extend_from_slice(&0x4629u16.to_le_bytes()); bytes.extend_from_slice(&0xBCF0u16.to_le_bytes());
5369
5370 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5371 Ok(bytes)
5372 }
5373
5374 ArmOp::I64DivS {
5380 rdlo,
5381 rdhi,
5382 rnlo,
5383 rnhi,
5384 rmlo,
5385 rmhi,
5386 } => {
5387 let mut bytes = Vec::new();
5388 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5389 emit_i64_divisor_zero_trap(&mut bytes);
5390
5391 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5393 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5394
5395 bytes.extend_from_slice(&0xEA81u16.to_le_bytes());
5398 bytes.extend_from_slice(&0x0903u16.to_le_bytes());
5399
5400 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());
5413
5414 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());
5424
5425 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5428 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5429 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5431 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5432 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5434 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5435
5436 let loop_start = bytes.len();
5437
5438 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5442 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());
5448 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5451
5452 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5456 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());
5469 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5471
5472 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5475
5476 let branch_offset_bytes = bytes.len() - loop_start + 4;
5477 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5478 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5479 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5480
5481 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());
5488 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());
5496
5497 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5499 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5500
5501 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5502 Ok(bytes)
5503 }
5504
5505 ArmOp::I64RemU {
5510 rdlo,
5511 rdhi,
5512 rnlo,
5513 rnhi,
5514 rmlo,
5515 rmhi,
5516 } => {
5517 let mut bytes = Vec::new();
5518 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5519 emit_i64_divisor_zero_trap(&mut bytes);
5520
5521 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5523 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5524
5525 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5527 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5528 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5530 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5531 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5533 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5534
5535 let loop_start = bytes.len();
5536
5537 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5541 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());
5547 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5550
5551 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5555 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());
5568 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5570
5571 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5574
5575 let branch_offset_bytes = bytes.len() - loop_start + 4;
5576 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5577 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5578 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5579
5580 bytes.extend_from_slice(&0x4630u16.to_le_bytes()); bytes.extend_from_slice(&0x4639u16.to_le_bytes()); bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5586 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5587
5588 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5589 Ok(bytes)
5590 }
5591
5592 ArmOp::I64RemS {
5598 rdlo,
5599 rdhi,
5600 rnlo,
5601 rnhi,
5602 rmlo,
5603 rmhi,
5604 } => {
5605 let mut bytes = Vec::new();
5606 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5607 emit_i64_divisor_zero_trap(&mut bytes);
5608
5609 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5611 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5612
5613 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());
5627
5628 bytes.extend_from_slice(&0x421Bu16.to_le_bytes()); bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43D2u16.to_le_bytes()); bytes.extend_from_slice(&0x43DBu16.to_le_bytes()); bytes.extend_from_slice(&0x1C52u16.to_le_bytes()); bytes.extend_from_slice(&0xF143u16.to_le_bytes()); bytes.extend_from_slice(&0x0300u16.to_le_bytes());
5638
5639 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5642 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5643 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5645 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5646 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5648 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5649
5650 let loop_start = bytes.len();
5651
5652 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5656 bytes.extend_from_slice(&0x0064u16.to_le_bytes()); bytes.extend_from_slice(&0x007Fu16.to_le_bytes()); bytes.extend_from_slice(&0xEA47u16.to_le_bytes()); bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
5662 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5665
5666 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5670 bytes.extend_from_slice(&0x0040u16.to_le_bytes()); bytes.extend_from_slice(&0x429Fu16.to_le_bytes()); bytes.extend_from_slice(&0xD802u16.to_le_bytes()); bytes.extend_from_slice(&0xD306u16.to_le_bytes()); bytes.extend_from_slice(&0x4296u16.to_le_bytes()); bytes.extend_from_slice(&0xD304u16.to_le_bytes()); bytes.extend_from_slice(&0x1AB6u16.to_le_bytes()); bytes.extend_from_slice(&0xEB67u16.to_le_bytes()); bytes.extend_from_slice(&0x0703u16.to_le_bytes());
5683 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5685
5686 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5689
5690 let branch_offset_bytes = bytes.len() - loop_start + 4;
5691 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5692 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5693 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5694
5695 bytes.extend_from_slice(&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());
5702 bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43C0u16.to_le_bytes()); bytes.extend_from_slice(&0x43C9u16.to_le_bytes()); bytes.extend_from_slice(&0x1C40u16.to_le_bytes()); bytes.extend_from_slice(&0xF141u16.to_le_bytes()); bytes.extend_from_slice(&0x0100u16.to_le_bytes());
5710
5711 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5713 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5714
5715 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5716 Ok(bytes)
5717 }
5718
5719 ArmOp::F32Add { sd, sn, sm } => {
5722 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A00, sd, sn, sm)?))
5723 }
5724 ArmOp::F32Sub { sd, sn, sm } => {
5725 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A40, sd, sn, sm)?))
5726 }
5727 ArmOp::F32Mul { sd, sn, sm } => {
5728 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE200A00, sd, sn, sm)?))
5729 }
5730 ArmOp::F32Div { sd, sn, sm } => {
5731 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE800A00, sd, sn, sm)?))
5732 }
5733 ArmOp::F32Abs { sd, sm } => {
5734 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB00AC0, sd, sm)?))
5735 }
5736 ArmOp::F32Neg { sd, sm } => {
5737 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10A40, sd, sm)?))
5738 }
5739 ArmOp::F32Sqrt { sd, sm } => {
5740 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10AC0, sd, sm)?))
5741 }
5742
5743 ArmOp::F32Ceil { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b01),
5746 ArmOp::F32Floor { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b10),
5747 ArmOp::F32Trunc { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b11),
5748 ArmOp::F32Nearest { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b00),
5749 ArmOp::F32Min { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, true),
5750 ArmOp::F32Max { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, false),
5751 ArmOp::F32Copysign { sd, sn, sm } => self.encode_thumb_f32_copysign(sd, sn, sm),
5752
5753 ArmOp::F32Eq { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x0),
5755 ArmOp::F32Ne { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x1),
5756 ArmOp::F32Lt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x4),
5757 ArmOp::F32Le { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x9),
5758 ArmOp::F32Gt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xC),
5759 ArmOp::F32Ge { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xA),
5760
5761 ArmOp::F32Const { sd, value } => self.encode_thumb_f32_const(sd, *value),
5762
5763 ArmOp::F32Load { sd, addr } => {
5764 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED900A00, sd, addr)?))
5765 }
5766 ArmOp::F32Store { sd, addr } => {
5767 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED800A00, sd, addr)?))
5768 }
5769
5770 ArmOp::F32ConvertI32S { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, true),
5771 ArmOp::F32ConvertI32U { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, false),
5772 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
5773 Err(synth_core::Error::synthesis(
5774 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
5775 ))
5776 }
5777 ArmOp::F32ReinterpretI32 { sd, rm } => {
5778 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(true, sd, rm)?))
5779 }
5780 ArmOp::I32ReinterpretF32 { rd, sm } => {
5781 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(false, sm, rd)?))
5782 }
5783 ArmOp::I32TruncF32S { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, true),
5784 ArmOp::I32TruncF32U { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, false),
5785
5786 ArmOp::F64Add { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5789 0xEE300B00, dd, dn, dm,
5790 )?)),
5791 ArmOp::F64Sub { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5792 0xEE300B40, dd, dn, dm,
5793 )?)),
5794 ArmOp::F64Mul { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5795 0xEE200B00, dd, dn, dm,
5796 )?)),
5797 ArmOp::F64Div { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5798 0xEE800B00, dd, dn, dm,
5799 )?)),
5800 ArmOp::F64Abs { dd, dm } => {
5801 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?))
5802 }
5803 ArmOp::F64Neg { dd, dm } => {
5804 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?))
5805 }
5806 ArmOp::F64Sqrt { dd, dm } => {
5807 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?))
5808 }
5809
5810 ArmOp::F64Ceil { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b01),
5813 ArmOp::F64Floor { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b10),
5814 ArmOp::F64Trunc { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b11),
5815 ArmOp::F64Nearest { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b00),
5816 ArmOp::F64Min { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, true),
5817 ArmOp::F64Max { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, false),
5818 ArmOp::F64Copysign { dd, dn, dm } => self.encode_thumb_f64_copysign(dd, dn, dm),
5819
5820 ArmOp::F64Eq { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x0),
5822 ArmOp::F64Ne { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x1),
5823 ArmOp::F64Lt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x4),
5824 ArmOp::F64Le { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x9),
5825 ArmOp::F64Gt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xC),
5826 ArmOp::F64Ge { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xA),
5827
5828 ArmOp::F64Const { dd, value } => self.encode_thumb_f64_const(dd, *value),
5829
5830 ArmOp::F64Load { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
5831 0xED900B00, dd, addr,
5832 )?)),
5833 ArmOp::F64Store { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
5834 0xED800B00, dd, addr,
5835 )?)),
5836
5837 ArmOp::F64ConvertI32S { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, true),
5838 ArmOp::F64ConvertI32U { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, false),
5839 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
5840 Err(synth_core::Error::synthesis(
5841 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
5842 ))
5843 }
5844 ArmOp::F64PromoteF32 { dd, sm } => self.encode_thumb_f64_promote_f32(dd, sm),
5845 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => Ok(vfp_to_thumb_bytes(
5846 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?,
5847 )),
5848 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => Ok(vfp_to_thumb_bytes(
5849 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?,
5850 )),
5851 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
5852 Err(synth_core::Error::synthesis(
5853 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
5854 ))
5855 }
5856 ArmOp::I32TruncF64S { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, true),
5857 ArmOp::I32TruncF64U { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, false),
5858
5859 ArmOp::I64Add {
5863 rdlo,
5864 rdhi,
5865 rnlo,
5866 rnhi,
5867 rmlo,
5868 rmhi,
5869 } => {
5870 let mut bytes = Vec::new();
5871 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adds {
5873 rd: *rdlo,
5874 rn: *rnlo,
5875 op2: Operand2::Reg(*rmlo),
5876 })?);
5877 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adc {
5879 rd: *rdhi,
5880 rn: *rnhi,
5881 op2: Operand2::Reg(*rmhi),
5882 })?);
5883 Ok(bytes)
5884 }
5885
5886 ArmOp::I64Sub {
5888 rdlo,
5889 rdhi,
5890 rnlo,
5891 rnhi,
5892 rmlo,
5893 rmhi,
5894 } => {
5895 let mut bytes = Vec::new();
5896 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Subs {
5898 rd: *rdlo,
5899 rn: *rnlo,
5900 op2: Operand2::Reg(*rmlo),
5901 })?);
5902 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Sbc {
5904 rd: *rdhi,
5905 rn: *rnhi,
5906 op2: Operand2::Reg(*rmhi),
5907 })?);
5908 Ok(bytes)
5909 }
5910
5911 ArmOp::I64And {
5913 rdlo,
5914 rdhi,
5915 rnlo,
5916 rnhi,
5917 rmlo,
5918 rmhi,
5919 } => {
5920 let mut bytes = Vec::new();
5921 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
5922 rd: *rdlo,
5923 rn: *rnlo,
5924 op2: Operand2::Reg(*rmlo),
5925 })?);
5926 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
5927 rd: *rdhi,
5928 rn: *rnhi,
5929 op2: Operand2::Reg(*rmhi),
5930 })?);
5931 Ok(bytes)
5932 }
5933
5934 ArmOp::I64Or {
5936 rdlo,
5937 rdhi,
5938 rnlo,
5939 rnhi,
5940 rmlo,
5941 rmhi,
5942 } => {
5943 let mut bytes = Vec::new();
5944 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
5945 rd: *rdlo,
5946 rn: *rnlo,
5947 op2: Operand2::Reg(*rmlo),
5948 })?);
5949 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
5950 rd: *rdhi,
5951 rn: *rnhi,
5952 op2: Operand2::Reg(*rmhi),
5953 })?);
5954 Ok(bytes)
5955 }
5956
5957 ArmOp::I64Xor {
5959 rdlo,
5960 rdhi,
5961 rnlo,
5962 rnhi,
5963 rmlo,
5964 rmhi,
5965 } => {
5966 let mut bytes = Vec::new();
5967 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
5968 rd: *rdlo,
5969 rn: *rnlo,
5970 op2: Operand2::Reg(*rmlo),
5971 })?);
5972 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
5973 rd: *rdhi,
5974 rn: *rnhi,
5975 op2: Operand2::Reg(*rmhi),
5976 })?);
5977 Ok(bytes)
5978 }
5979
5980 ArmOp::I64Eqz { rd, rnlo, rnhi } => self.encode_thumb(&ArmOp::I64SetCondZ {
5982 rd: *rd,
5983 rn_lo: *rnlo,
5984 rn_hi: *rnhi,
5985 }),
5986
5987 ArmOp::I64Eq {
5989 rd,
5990 rnlo,
5991 rnhi,
5992 rmlo,
5993 rmhi,
5994 } => self.encode_thumb(&ArmOp::I64SetCond {
5995 rd: *rd,
5996 rn_lo: *rnlo,
5997 rn_hi: *rnhi,
5998 rm_lo: *rmlo,
5999 rm_hi: *rmhi,
6000 cond: synth_synthesis::Condition::EQ,
6001 }),
6002
6003 ArmOp::I64Ne {
6004 rd,
6005 rnlo,
6006 rnhi,
6007 rmlo,
6008 rmhi,
6009 } => self.encode_thumb(&ArmOp::I64SetCond {
6010 rd: *rd,
6011 rn_lo: *rnlo,
6012 rn_hi: *rnhi,
6013 rm_lo: *rmlo,
6014 rm_hi: *rmhi,
6015 cond: synth_synthesis::Condition::NE,
6016 }),
6017
6018 ArmOp::I64LtS {
6019 rd,
6020 rnlo,
6021 rnhi,
6022 rmlo,
6023 rmhi,
6024 } => self.encode_thumb(&ArmOp::I64SetCond {
6025 rd: *rd,
6026 rn_lo: *rnlo,
6027 rn_hi: *rnhi,
6028 rm_lo: *rmlo,
6029 rm_hi: *rmhi,
6030 cond: synth_synthesis::Condition::LT,
6031 }),
6032
6033 ArmOp::I64LtU {
6034 rd,
6035 rnlo,
6036 rnhi,
6037 rmlo,
6038 rmhi,
6039 } => self.encode_thumb(&ArmOp::I64SetCond {
6040 rd: *rd,
6041 rn_lo: *rnlo,
6042 rn_hi: *rnhi,
6043 rm_lo: *rmlo,
6044 rm_hi: *rmhi,
6045 cond: synth_synthesis::Condition::LO,
6046 }),
6047
6048 ArmOp::I64LeS {
6049 rd,
6050 rnlo,
6051 rnhi,
6052 rmlo,
6053 rmhi,
6054 } => self.encode_thumb(&ArmOp::I64SetCond {
6055 rd: *rd,
6056 rn_lo: *rnlo,
6057 rn_hi: *rnhi,
6058 rm_lo: *rmlo,
6059 rm_hi: *rmhi,
6060 cond: synth_synthesis::Condition::LE,
6061 }),
6062
6063 ArmOp::I64LeU {
6064 rd,
6065 rnlo,
6066 rnhi,
6067 rmlo,
6068 rmhi,
6069 } => self.encode_thumb(&ArmOp::I64SetCond {
6070 rd: *rd,
6071 rn_lo: *rnlo,
6072 rn_hi: *rnhi,
6073 rm_lo: *rmlo,
6074 rm_hi: *rmhi,
6075 cond: synth_synthesis::Condition::LS,
6076 }),
6077
6078 ArmOp::I64GtS {
6079 rd,
6080 rnlo,
6081 rnhi,
6082 rmlo,
6083 rmhi,
6084 } => self.encode_thumb(&ArmOp::I64SetCond {
6085 rd: *rd,
6086 rn_lo: *rnlo,
6087 rn_hi: *rnhi,
6088 rm_lo: *rmlo,
6089 rm_hi: *rmhi,
6090 cond: synth_synthesis::Condition::GT,
6091 }),
6092
6093 ArmOp::I64GtU {
6094 rd,
6095 rnlo,
6096 rnhi,
6097 rmlo,
6098 rmhi,
6099 } => self.encode_thumb(&ArmOp::I64SetCond {
6100 rd: *rd,
6101 rn_lo: *rnlo,
6102 rn_hi: *rnhi,
6103 rm_lo: *rmlo,
6104 rm_hi: *rmhi,
6105 cond: synth_synthesis::Condition::HI,
6106 }),
6107
6108 ArmOp::I64GeS {
6109 rd,
6110 rnlo,
6111 rnhi,
6112 rmlo,
6113 rmhi,
6114 } => self.encode_thumb(&ArmOp::I64SetCond {
6115 rd: *rd,
6116 rn_lo: *rnlo,
6117 rn_hi: *rnhi,
6118 rm_lo: *rmlo,
6119 rm_hi: *rmhi,
6120 cond: synth_synthesis::Condition::GE,
6121 }),
6122
6123 ArmOp::I64GeU {
6124 rd,
6125 rnlo,
6126 rnhi,
6127 rmlo,
6128 rmhi,
6129 } => self.encode_thumb(&ArmOp::I64SetCond {
6130 rd: *rd,
6131 rn_lo: *rnlo,
6132 rn_hi: *rnhi,
6133 rm_lo: *rmlo,
6134 rm_hi: *rmhi,
6135 cond: synth_synthesis::Condition::HS,
6136 }),
6137
6138 ArmOp::I64Const { rdlo, rdhi, value } => {
6140 let lo32 = *value as u32;
6141 let hi32 = (*value >> 32) as u32;
6142 let mut bytes = Vec::new();
6143 bytes.extend_from_slice(
6145 &self.encode_thumb32_movw_raw(reg_to_bits(rdlo), lo32 & 0xFFFF)?,
6146 );
6147 if lo32 > 0xFFFF {
6148 bytes.extend_from_slice(
6149 &self.encode_thumb32_movt_raw(reg_to_bits(rdlo), lo32 >> 16)?,
6150 );
6151 }
6152 bytes.extend_from_slice(
6154 &self.encode_thumb32_movw_raw(reg_to_bits(rdhi), hi32 & 0xFFFF)?,
6155 );
6156 if hi32 > 0xFFFF {
6157 bytes.extend_from_slice(
6158 &self.encode_thumb32_movt_raw(reg_to_bits(rdhi), hi32 >> 16)?,
6159 );
6160 }
6161 Ok(bytes)
6162 }
6163
6164 ArmOp::I64Ldr { rdlo, rdhi, addr } => {
6166 let mut bytes = Vec::new();
6167 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6178 bytes.extend_from_slice(&self.encode_thumb32_ldr(rdlo, &base, offset)?);
6179 bytes.extend_from_slice(&self.encode_thumb32_ldr(
6180 rdhi,
6181 &base,
6182 offset.wrapping_add(4),
6183 )?);
6184 Ok(bytes)
6185 }
6186
6187 ArmOp::I64Str { rdlo, rdhi, addr } => {
6189 let mut bytes = Vec::new();
6190 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6193 bytes.extend_from_slice(&self.encode_thumb32_str(rdlo, &base, offset)?);
6194 bytes.extend_from_slice(&self.encode_thumb32_str(
6195 rdhi,
6196 &base,
6197 offset.wrapping_add(4),
6198 )?);
6199 Ok(bytes)
6200 }
6201
6202 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
6204 let mut bytes = Vec::new();
6205 if rdlo != rn {
6206 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6208 rd: *rdlo,
6209 op2: Operand2::Reg(*rn),
6210 })?);
6211 }
6212 bytes.extend_from_slice(
6214 &self.encode_thumb32_shift(rdhi, rdlo, 31, 0b10)?, );
6216 Ok(bytes)
6217 }
6218
6219 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
6221 let mut bytes = Vec::new();
6222 if rdlo != rn {
6223 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6225 rd: *rdlo,
6226 op2: Operand2::Reg(*rn),
6227 })?);
6228 }
6229 let rdhi_bits = reg_to_bits(rdhi) as u16;
6231 let instr: u16 = 0x2000 | (rdhi_bits << 8);
6232 bytes.extend_from_slice(&instr.to_le_bytes());
6233 Ok(bytes)
6234 }
6235
6236 ArmOp::I32WrapI64 { rd, rnlo } => {
6238 if rd == rnlo {
6239 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6242 } else {
6243 self.encode_thumb(&ArmOp::Mov {
6245 rd: *rd,
6246 op2: Operand2::Reg(*rnlo),
6247 })
6248 }
6249 }
6250
6251 ArmOp::MveLoad { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vldrw(qd, addr))),
6253 ArmOp::MveStore { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vstrw(qd, addr))),
6254 ArmOp::MveConst { qd, bytes } => self.encode_thumb_mve_const(qd, bytes),
6255 ArmOp::MveAnd { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6256 0xEF000150, qd, qn, qm,
6257 ))),
6258 ArmOp::MveOrr { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6259 0xEF200150, qd, qn, qm,
6260 ))),
6261 ArmOp::MveEor { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6262 0xFF000150, qd, qn, qm,
6263 ))),
6264 ArmOp::MveMvn { qd, qm } => {
6265 let qd_enc = qreg_to_num(qd);
6267 let qm_enc = qreg_to_num(qm);
6268 let instr: u32 = 0xFFB005C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6269 Ok(vfp_to_thumb_bytes(instr))
6270 }
6271 ArmOp::MveBic { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6272 0xEF100150, qd, qn, qm,
6273 ))),
6274 ArmOp::MveAddI { qd, qn, qm, size } => {
6275 let sz = mve_size_bits(size);
6276 let base: u32 = 0xEF000840 | (sz << 20);
6277 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6278 }
6279 ArmOp::MveSubI { qd, qn, qm, size } => {
6280 let sz = mve_size_bits(size);
6281 let base: u32 = 0xFF000840 | (sz << 20);
6282 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6283 }
6284 ArmOp::MveMulI { qd, qn, qm, size } => {
6285 let sz = mve_size_bits(size);
6286 let base: u32 = 0xEF000950 | (sz << 20);
6287 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6288 }
6289 ArmOp::MveNegI { qd, qm, size } => {
6290 let sz = mve_size_bits(size);
6291 let qd_enc = qreg_to_num(qd);
6293 let qm_enc = qreg_to_num(qm);
6294 let base: u32 = 0xFFB103C0 | (sz << 18);
6295 let instr = base | ((qd_enc * 2) << 12) | (qm_enc * 2);
6296 Ok(vfp_to_thumb_bytes(instr))
6297 }
6298 ArmOp::MveDup { qd, rn, size } => {
6299 let sz = mve_size_bits(size);
6300 let qd_enc = qreg_to_num(qd);
6301 let rn_bits = reg_to_bits(rn);
6302 let be = match sz {
6305 0 => 0b00u32, 1 => 0b01, _ => 0b00, };
6309 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12) | (be << 5);
6310 Ok(vfp_to_thumb_bytes(instr))
6311 }
6312 ArmOp::MveExtractLane { rd, qn, lane, size } => {
6313 let qn_enc = qreg_to_num(qn);
6314 let rd_bits = reg_to_bits(rd);
6315 let d_reg = qn_enc * 2 + ((*lane as u32) >> 1);
6318 let lane_in_d = (*lane as u32) & 1;
6319 let _sz = mve_size_bits(size);
6320 let instr: u32 = 0xEE100B10 | (d_reg << 16) | (rd_bits << 12) | (lane_in_d << 21);
6322 Ok(vfp_to_thumb_bytes(instr))
6323 }
6324 ArmOp::MveInsertLane { qd, rn, lane, size } => {
6325 let qd_enc = qreg_to_num(qd);
6326 let rn_bits = reg_to_bits(rn);
6327 let d_reg = qd_enc * 2 + ((*lane as u32) >> 1);
6328 let lane_in_d = (*lane as u32) & 1;
6329 let _sz = mve_size_bits(size);
6330 let instr: u32 = 0xEE000B10 | (d_reg << 16) | (rn_bits << 12) | (lane_in_d << 21);
6332 Ok(vfp_to_thumb_bytes(instr))
6333 }
6334
6335 ArmOp::MveCmpEqI { qd, qn, qm, size }
6337 | ArmOp::MveCmpNeI { qd, qn, qm, size }
6338 | ArmOp::MveCmpLtS { qd, qn, qm, size }
6339 | ArmOp::MveCmpLtU { qd, qn, qm, size }
6340 | ArmOp::MveCmpGtS { qd, qn, qm, size }
6341 | ArmOp::MveCmpGtU { qd, qn, qm, size }
6342 | ArmOp::MveCmpLeS { qd, qn, qm, size }
6343 | ArmOp::MveCmpLeU { qd, qn, qm, size }
6344 | ArmOp::MveCmpGeS { qd, qn, qm, size }
6345 | ArmOp::MveCmpGeU { qd, qn, qm, size } => {
6346 let sz = mve_size_bits(size);
6349 let base: u32 = 0xEF000840 | (sz << 20);
6350 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6351 }
6352
6353 ArmOp::MveAddF32 { qd, qn, qm } => {
6355 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6357 }
6358 ArmOp::MveSubF32 { qd, qn, qm } => {
6359 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF200D40, qd, qn, qm)))
6361 }
6362 ArmOp::MveMulF32 { qd, qn, qm } => {
6363 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xFF000D50, qd, qn, qm)))
6365 }
6366 ArmOp::MveNegF32 { qd, qm } => {
6367 let qd_enc = qreg_to_num(qd);
6368 let qm_enc = qreg_to_num(qm);
6369 let instr: u32 = 0xFFB907C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6371 Ok(vfp_to_thumb_bytes(instr))
6372 }
6373 ArmOp::MveAbsF32 { qd, qm } => {
6374 let qd_enc = qreg_to_num(qd);
6375 let qm_enc = qreg_to_num(qm);
6376 let instr: u32 = 0xFFB90740 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6378 Ok(vfp_to_thumb_bytes(instr))
6379 }
6380 ArmOp::MveCmpEqF32 { qd, qn, qm }
6381 | ArmOp::MveCmpNeF32 { qd, qn, qm }
6382 | ArmOp::MveCmpLtF32 { qd, qn, qm }
6383 | ArmOp::MveCmpLeF32 { qd, qn, qm }
6384 | ArmOp::MveCmpGtF32 { qd, qn, qm }
6385 | ArmOp::MveCmpGeF32 { qd, qn, qm } => {
6386 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6388 }
6389 ArmOp::MveDupF32 { qd, rn } => {
6390 let qd_enc = qreg_to_num(qd);
6391 let rn_bits = reg_to_bits(rn);
6392 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12);
6394 Ok(vfp_to_thumb_bytes(instr))
6395 }
6396 ArmOp::MveExtractLaneF32 { rd, qn, lane } => {
6397 let qn_enc = qreg_to_num(qn);
6398 let rd_bits = reg_to_bits(rd);
6399 let s_num = qn_enc * 4 + (*lane as u32);
6401 let (vn, n) = encode_sreg(s_num);
6402 let instr: u32 = 0xEE100A10 | (vn << 16) | (rd_bits << 12) | (n << 7);
6403 Ok(vfp_to_thumb_bytes(instr))
6404 }
6405 ArmOp::MveReplaceLaneF32 { qd, rn, lane } => {
6406 let qd_enc = qreg_to_num(qd);
6407 let rn_bits = reg_to_bits(rn);
6408 let s_num = qd_enc * 4 + (*lane as u32);
6410 let (vn, n) = encode_sreg(s_num);
6411 let instr: u32 = 0xEE000A10 | (vn << 16) | (rn_bits << 12) | (n << 7);
6412 Ok(vfp_to_thumb_bytes(instr))
6413 }
6414 ArmOp::MveDivF32 { qd, qn, qm } => {
6415 self.encode_thumb_mve_lane_wise_f32_binop(qd, qn, qm, 0xEE800A00)
6417 }
6418 ArmOp::MveSqrtF32 { qd, qm } => {
6419 self.encode_thumb_mve_lane_wise_f32_sqrt(qd, qm)
6421 }
6422
6423 _ => {
6425 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6427 }
6428 }
6429 }
6430
6431 fn encode_thumb_f32_compare(
6435 &self,
6436 rd: &Reg,
6437 sn: &VfpReg,
6438 sm: &VfpReg,
6439 cond_code: u32,
6440 ) -> Result<Vec<u8>> {
6441 let mut bytes = Vec::new();
6442 let rd_bits = reg_to_bits(rd);
6443
6444 let sn_num = vfp_sreg_to_num(sn)?;
6446 let sm_num = vfp_sreg_to_num(sm)?;
6447 let (vd, d) = encode_sreg(sn_num);
6448 let (vm, m) = encode_sreg(sm_num);
6449 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6450 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6451
6452 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6454
6455 if rd_bits < 8 {
6457 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
6458 bytes.extend_from_slice(&movs_zero.to_le_bytes());
6459 } else {
6460 let hw1: u16 = 0xF04F;
6462 let hw2: u16 = (rd_bits as u16) << 8;
6463 bytes.extend_from_slice(&hw1.to_le_bytes());
6464 bytes.extend_from_slice(&hw2.to_le_bytes());
6465 }
6466
6467 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
6471 bytes.extend_from_slice(&it.to_le_bytes());
6472
6473 if rd_bits < 8 {
6475 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
6476 bytes.extend_from_slice(&mov_one.to_le_bytes());
6477 } else {
6478 let hw1: u16 = 0xF04F;
6480 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
6481 bytes.extend_from_slice(&hw1.to_le_bytes());
6482 bytes.extend_from_slice(&hw2.to_le_bytes());
6483 }
6484
6485 Ok(bytes)
6486 }
6487
6488 fn encode_thumb_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
6490 let mut bytes = Vec::new();
6491 let bits = value.to_bits();
6492 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
6497 let imm4 = (lo16 >> 12) & 0xF;
6498 let i_bit = (lo16 >> 11) & 1;
6499 let imm3 = (lo16 >> 8) & 0x7;
6500 let imm8 = lo16 & 0xFF;
6501 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
6502 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6503 bytes.extend_from_slice(&hw1.to_le_bytes());
6504 bytes.extend_from_slice(&hw2.to_le_bytes());
6505
6506 let hi16 = (bits >> 16) & 0xFFFF;
6508 let imm4 = (hi16 >> 12) & 0xF;
6509 let i_bit = (hi16 >> 11) & 1;
6510 let imm3 = (hi16 >> 8) & 0x7;
6511 let imm8 = hi16 & 0xFF;
6512 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
6513 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6514 bytes.extend_from_slice(&hw1.to_le_bytes());
6515 bytes.extend_from_slice(&hw2.to_le_bytes());
6516
6517 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
6519 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6520
6521 Ok(bytes)
6522 }
6523
6524 fn encode_thumb_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
6526 let mut bytes = Vec::new();
6527
6528 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
6530 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6531
6532 let sd_num = vfp_sreg_to_num(sd)?;
6534 let (vd, d) = encode_sreg(sd_num);
6535 let (vm, m) = encode_sreg(sd_num);
6536 let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
6537 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
6538 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6539
6540 Ok(bytes)
6541 }
6542
6543 fn encode_thumb_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
6551 let mut bytes = Vec::new();
6552 let sm_num = vfp_sreg_to_num(sm)?;
6553 let sd_num = vfp_sreg_to_num(sd)?;
6554 let (vd_s, d_s) = encode_sreg(sd_num);
6555 let (vm_s, m_s) = encode_sreg(sm_num);
6556
6557 if mode == 0b11 {
6558 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6560 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6561 } else {
6562 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
6567 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6568
6569 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF); let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
6575 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6576 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6577
6578 if mode != 0 {
6580 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF); let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
6582 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
6583 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
6584 }
6585
6586 let vmsr = 0xEEE10A10 | (rt << 12);
6588 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6589
6590 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6592 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6593
6594 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6596 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6597 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6598 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6599 }
6600
6601 let (vd2, d2) = encode_sreg(sd_num);
6603 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
6604 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
6605
6606 Ok(bytes)
6607 }
6608
6609 fn encode_thumb_f32_minmax(
6611 &self,
6612 sd: &VfpReg,
6613 sn: &VfpReg,
6614 sm: &VfpReg,
6615 is_min: bool,
6616 ) -> Result<Vec<u8>> {
6617 let mut bytes = Vec::new();
6618 let sn_num = vfp_sreg_to_num(sn)?;
6619 let sm_num = vfp_sreg_to_num(sm)?;
6620 let sd_num = vfp_sreg_to_num(sd)?;
6621
6622 let (vd, d) = encode_sreg(sd_num);
6624 let (vn, n) = encode_sreg(sn_num);
6625 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
6626 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sn));
6627
6628 let (vm, m) = encode_sreg(sm_num);
6630 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
6631 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6632
6633 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6635
6636 let cond: u16 = if is_min { 0xC } else { 0x4 };
6638 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
6639 bytes.extend_from_slice(&it.to_le_bytes());
6640
6641 let vmov_sm = 0xEEB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6643 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sm));
6644
6645 Ok(bytes)
6646 }
6647
6648 fn encode_thumb_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
6650 let mut bytes = Vec::new();
6651
6652 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
6654 false,
6655 sm,
6656 &Reg::R12,
6657 )?));
6658
6659 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
6661 false,
6662 sn,
6663 &Reg::R0,
6664 )?));
6665
6666 let hw1: u16 = 0xF000 | 12; let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
6678 bytes.extend_from_slice(&hw2.to_le_bytes());
6679
6680 let hw1: u16 = 0xF020; let hw2: u16 = (0x1 << 12) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
6684 bytes.extend_from_slice(&hw2.to_le_bytes());
6685
6686 let hw1: u16 = 0xEA40; let hw2: u16 = 12; bytes.extend_from_slice(&hw1.to_le_bytes());
6690 bytes.extend_from_slice(&hw2.to_le_bytes());
6691
6692 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
6694 true,
6695 sd,
6696 &Reg::R0,
6697 )?));
6698
6699 Ok(bytes)
6700 }
6701
6702 fn encode_thumb_f64_compare(
6704 &self,
6705 rd: &Reg,
6706 dn: &VfpReg,
6707 dm: &VfpReg,
6708 cond_code: u32,
6709 ) -> Result<Vec<u8>> {
6710 let mut bytes = Vec::new();
6711 let rd_bits = reg_to_bits(rd);
6712
6713 let dn_num = vfp_dreg_to_num(dn)?;
6715 let dm_num = vfp_dreg_to_num(dm)?;
6716 let (vd, d) = encode_dreg(dn_num);
6717 let (vm, m) = encode_dreg(dm_num);
6718 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6719 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6720
6721 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6723
6724 if rd_bits < 8 {
6726 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
6727 bytes.extend_from_slice(&movs_zero.to_le_bytes());
6728 } else {
6729 let hw1: u16 = 0xF04F;
6730 let hw2: u16 = (rd_bits as u16) << 8;
6731 bytes.extend_from_slice(&hw1.to_le_bytes());
6732 bytes.extend_from_slice(&hw2.to_le_bytes());
6733 }
6734
6735 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
6737 bytes.extend_from_slice(&it.to_le_bytes());
6738
6739 if rd_bits < 8 {
6741 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
6742 bytes.extend_from_slice(&mov_one.to_le_bytes());
6743 } else {
6744 let hw1: u16 = 0xF04F;
6745 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
6746 bytes.extend_from_slice(&hw1.to_le_bytes());
6747 bytes.extend_from_slice(&hw2.to_le_bytes());
6748 }
6749
6750 Ok(bytes)
6751 }
6752
6753 fn encode_thumb_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
6755 let mut bytes = Vec::new();
6756 let bits = value.to_bits();
6757 let lo32 = bits as u32;
6758 let hi32 = (bits >> 32) as u32;
6759
6760 let lo16 = lo32 & 0xFFFF;
6762 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(0, lo16)?);
6763
6764 let hi16 = (lo32 >> 16) & 0xFFFF;
6766 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(0, hi16)?);
6767
6768 let lo16 = hi32 & 0xFFFF;
6770 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
6771
6772 let hi16 = (hi32 >> 16) & 0xFFFF;
6774 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
6775
6776 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
6778 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6779
6780 Ok(bytes)
6781 }
6782
6783 fn encode_thumb_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
6785 let mut bytes = Vec::new();
6786
6787 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
6789 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6790
6791 let dd_num = vfp_dreg_to_num(dd)?;
6793 let (vd, d) = encode_dreg(dd_num);
6794 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
6795 let vcvt = base | (d << 22) | (vd << 12);
6796 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6797
6798 Ok(bytes)
6799 }
6800
6801 fn encode_thumb_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
6803 let dd_num = vfp_dreg_to_num(dd)?;
6804 let sm_num = vfp_sreg_to_num(sm)?;
6805 let (vd, d) = encode_dreg(dd_num);
6806 let (vm, m) = encode_sreg(sm_num);
6807
6808 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
6809 Ok(vfp_to_thumb_bytes(vcvt))
6810 }
6811
6812 fn encode_thumb_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
6814 let mut bytes = Vec::new();
6815 let dm_num = vfp_dreg_to_num(dm)?;
6816 let (vm, m) = encode_dreg(dm_num);
6817
6818 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
6820 let vcvt = base | (m << 5) | vm;
6821 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6822
6823 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
6825 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6826
6827 Ok(bytes)
6828 }
6829
6830 fn encode_thumb_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
6834 let mut bytes = Vec::new();
6835 let dm_num = vfp_dreg_to_num(dm)?;
6836 let dd_num = vfp_dreg_to_num(dd)?;
6837 let (vm, m) = encode_dreg(dm_num);
6838 let (vd, d) = encode_dreg(dd_num);
6839
6840 if mode == 0b11 {
6841 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
6843 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6844 } else {
6845 let rt: u32 = 12;
6846
6847 let vmrs = 0xEEF10A10 | (rt << 12);
6849 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6850
6851 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF);
6853 let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
6854 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6855 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6856
6857 if mode != 0 {
6859 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF);
6860 let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
6861 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
6862 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
6863 }
6864
6865 let vmsr = 0xEEE10A10 | (rt << 12);
6867 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6868
6869 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
6871 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6872
6873 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6875 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6876 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6877 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6878 }
6879
6880 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
6882 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
6883
6884 Ok(bytes)
6885 }
6886
6887 fn encode_thumb_f64_minmax(
6889 &self,
6890 dd: &VfpReg,
6891 dn: &VfpReg,
6892 dm: &VfpReg,
6893 is_min: bool,
6894 ) -> Result<Vec<u8>> {
6895 let mut bytes = Vec::new();
6896 let dn_num = vfp_dreg_to_num(dn)?;
6897 let dm_num = vfp_dreg_to_num(dm)?;
6898 let dd_num = vfp_dreg_to_num(dd)?;
6899
6900 let (vd, d) = encode_dreg(dd_num);
6902 let (vn, n) = encode_dreg(dn_num);
6903 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
6904 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dn));
6905
6906 let (vm, m) = encode_dreg(dm_num);
6908 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
6909 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6910
6911 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6913
6914 let cond: u16 = if is_min { 0xC } else { 0x4 };
6916 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
6917 bytes.extend_from_slice(&it.to_le_bytes());
6918
6919 let vmov_dm = 0xEEB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6921 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dm));
6922
6923 Ok(bytes)
6924 }
6925
6926 fn encode_thumb_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
6928 let mut bytes = Vec::new();
6929
6930 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
6932 false,
6933 dm,
6934 &Reg::R0,
6935 &Reg::R12,
6936 )?));
6937
6938 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
6940 false,
6941 dn,
6942 &Reg::R1,
6943 &Reg::R2,
6944 )?));
6945
6946 let hw1: u16 = 0xF000 | 12;
6948 let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02;
6949 bytes.extend_from_slice(&hw1.to_le_bytes());
6950 bytes.extend_from_slice(&hw2.to_le_bytes());
6951
6952 let hw1: u16 = 0xF020 | 2;
6954 let hw2: u16 = (0x1 << 12) | (2 << 8) | 0x02;
6955 bytes.extend_from_slice(&hw1.to_le_bytes());
6956 bytes.extend_from_slice(&hw2.to_le_bytes());
6957
6958 let hw1: u16 = 0xEA40 | 2;
6960 let hw2: u16 = (2 << 8) | 12;
6961 bytes.extend_from_slice(&hw1.to_le_bytes());
6962 bytes.extend_from_slice(&hw2.to_le_bytes());
6963
6964 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
6966 true,
6967 dd,
6968 &Reg::R1,
6969 &Reg::R2,
6970 )?));
6971
6972 Ok(bytes)
6973 }
6974
6975 fn encode_thumb_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
6977 let mut bytes = Vec::new();
6978
6979 let sm_num = vfp_sreg_to_num(sm)?;
6980 let (vd, d) = encode_sreg(sm_num);
6981 let (vm, m) = encode_sreg(sm_num);
6982 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
6983 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
6984 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6985
6986 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
6988 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6989
6990 Ok(bytes)
6991 }
6992
6993 fn encode_thumb32_add(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6997 let rd_bits = reg_to_bits(rd);
6998 let rn_bits = reg_to_bits(rn);
6999
7000 let i_bit = (imm >> 11) & 1;
7002 let imm3 = (imm >> 8) & 0x7;
7003 let imm8 = imm & 0xFF;
7004
7005 let hw1_base = if imm <= 0xFF {
7006 0xF100
7010 } else if imm <= 0xFFF {
7011 0xF200
7015 } else {
7016 return Err(synth_core::Error::synthesis(
7017 "ADD immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7018 ));
7019 };
7020
7021 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7022 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7023
7024 let mut bytes = hw1.to_le_bytes().to_vec();
7025 bytes.extend_from_slice(&hw2.to_le_bytes());
7026 Ok(bytes)
7027 }
7028
7029 fn encode_thumb32_sub(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7031 let rd_bits = reg_to_bits(rd);
7032 let rn_bits = reg_to_bits(rn);
7033
7034 let i_bit = (imm >> 11) & 1;
7035 let imm3 = (imm >> 8) & 0x7;
7036 let imm8 = imm & 0xFF;
7037
7038 let hw1_base = if imm <= 0xFF {
7039 0xF1A0
7042 } else if imm <= 0xFFF {
7043 0xF2A0
7046 } else {
7047 return Err(synth_core::Error::synthesis(
7048 "SUB immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7049 ));
7050 };
7051
7052 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7053 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7054
7055 let mut bytes = hw1.to_le_bytes().to_vec();
7056 bytes.extend_from_slice(&hw2.to_le_bytes());
7057 Ok(bytes)
7058 }
7059
7060 fn encode_thumb32_adds(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7062 let rd_bits = reg_to_bits(rd);
7063 let rn_bits = reg_to_bits(rn);
7064
7065 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7068 synth_core::Error::synthesis(
7069 "ADDS immediate is not a valid ThumbExpandImm — materialize into a register",
7070 )
7071 })?;
7072 let i_bit = (field >> 11) & 1;
7073 let imm3 = (field >> 8) & 0x7;
7074 let imm8 = field & 0xFF;
7075
7076 let hw1: u16 = (0xF110 | (i_bit << 10) | rn_bits) as u16;
7079 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7080
7081 let mut bytes = hw1.to_le_bytes().to_vec();
7082 bytes.extend_from_slice(&hw2.to_le_bytes());
7083 Ok(bytes)
7084 }
7085
7086 fn encode_thumb32_subs(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7088 let rd_bits = reg_to_bits(rd);
7089 let rn_bits = reg_to_bits(rn);
7090
7091 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7094 synth_core::Error::synthesis(
7095 "SUBS immediate is not a valid ThumbExpandImm — materialize into a register",
7096 )
7097 })?;
7098 let i_bit = (field >> 11) & 1;
7099 let imm3 = (field >> 8) & 0x7;
7100 let imm8 = field & 0xFF;
7101
7102 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7105 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7106
7107 let mut bytes = hw1.to_le_bytes().to_vec();
7108 bytes.extend_from_slice(&hw2.to_le_bytes());
7109 Ok(bytes)
7110 }
7111
7112 fn encode_thumb32_movw(&self, rd: &Reg, imm: u32) -> Result<Vec<u8>> {
7121 let rd_bits = reg_to_bits(rd);
7122 reg_bits_checked(rd_bits)?;
7123 let imm16 = imm & 0xFFFF;
7124
7125 let imm4 = (imm16 >> 12) & 0xF;
7128 let i_bit = (imm16 >> 11) & 1;
7129 let imm3 = (imm16 >> 8) & 0x7;
7130 let imm8 = imm16 & 0xFF;
7131
7132 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7133 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7134
7135 let mut bytes = hw1.to_le_bytes().to_vec();
7136 bytes.extend_from_slice(&hw2.to_le_bytes());
7137 encoding_contracts::verify_thumb32(&bytes);
7138 Ok(bytes)
7139 }
7140
7141 fn encode_thumb32_shift(
7149 &self,
7150 rd: &Reg,
7151 rm: &Reg,
7152 shift: u32,
7153 shift_type: u8,
7154 ) -> Result<Vec<u8>> {
7155 let rd_bits = reg_to_bits(rd);
7156 let rm_bits = reg_to_bits(rm);
7157 reg_bits_checked(rd_bits)?;
7158 reg_bits_checked(rm_bits)?;
7159 let imm5 = shift & 0x1F;
7160 let imm2 = imm5 & 0x3;
7161 let imm3 = (imm5 >> 2) & 0x7;
7162
7163 let hw1: u16 = 0xEA4F;
7166 let hw2: u16 =
7167 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | ((shift_type as u32) << 4) | rm_bits)
7168 as u16;
7169
7170 let mut bytes = hw1.to_le_bytes().to_vec();
7171 bytes.extend_from_slice(&hw2.to_le_bytes());
7172 Ok(bytes)
7173 }
7174
7175 fn encode_thumb32_shift_reg(
7179 &self,
7180 rd: &Reg,
7181 rn: &Reg,
7182 rm: &Reg,
7183 shift_type: u8,
7184 ) -> Result<Vec<u8>> {
7185 let rd_bits = reg_to_bits(rd);
7186 let rn_bits = reg_to_bits(rn);
7187 let rm_bits = reg_to_bits(rm);
7188
7189 let hw1: u16 = (0xFA00 | ((shift_type as u32) << 5) | rn_bits) as u16;
7191 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
7193
7194 let mut bytes = hw1.to_le_bytes().to_vec();
7195 bytes.extend_from_slice(&hw2.to_le_bytes());
7196 Ok(bytes)
7197 }
7198
7199 fn encode_thumb32_cmp_imm(&self, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7201 let rn_bits = reg_to_bits(rn);
7202
7203 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7207 synth_core::Error::synthesis(
7208 "CMP immediate is not a valid ThumbExpandImm — materialize into a register",
7209 )
7210 })?;
7211 let i_bit = (field >> 11) & 1;
7212 let imm3 = (field >> 8) & 0x7;
7213 let imm8 = field & 0xFF;
7214
7215 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7217 let hw2: u16 = ((imm3 << 12) | 0x0F00 | imm8) as u16;
7218
7219 let mut bytes = hw1.to_le_bytes().to_vec();
7220 bytes.extend_from_slice(&hw2.to_le_bytes());
7221 Ok(bytes)
7222 }
7223
7224 fn i64_effective_base(&self, bytes: &mut Vec<u8>, addr: &MemAddr) -> Result<(Reg, u32)> {
7246 let offset = if addr.offset < 0 {
7247 0u32
7248 } else {
7249 addr.offset as u32
7250 };
7251 match addr.offset_reg {
7252 Some(idx) => {
7253 let ip = Reg::R12;
7254 if offset.wrapping_add(4) > 0xFFF {
7255 bytes.extend_from_slice(&self.encode_thumb32_add_imm(&ip, &idx, offset)?);
7259 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
7261 reg_to_bits(&ip),
7262 reg_to_bits(&ip),
7263 reg_to_bits(&addr.base),
7264 )?);
7265 Ok((ip, 0))
7266 } else {
7267 let hw1: u16 = 0xEB00 | reg_to_bits(&addr.base) as u16;
7269 let hw2: u16 = 0x0C00 | reg_to_bits(&idx) as u16;
7270 bytes.extend_from_slice(&hw1.to_le_bytes());
7271 bytes.extend_from_slice(&hw2.to_le_bytes());
7272 Ok((ip, offset))
7273 }
7274 }
7275 None => Ok((addr.base, offset)),
7276 }
7277 }
7278
7279 fn encode_thumb32_ldr(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7281 let rd_bits = reg_to_bits(rd);
7282 let base_bits = reg_to_bits(base);
7283
7284 check_ldst_imm12(offset)?;
7286 let hw1: u16 = (0xF8D0 | base_bits) as u16;
7287 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7288
7289 let mut bytes = hw1.to_le_bytes().to_vec();
7290 bytes.extend_from_slice(&hw2.to_le_bytes());
7291 Ok(bytes)
7292 }
7293
7294 fn encode_thumb32_str(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7296 let rd_bits = reg_to_bits(rd);
7297 let base_bits = reg_to_bits(base);
7298
7299 check_ldst_imm12(offset)?;
7301 let hw1: u16 = (0xF8C0 | base_bits) as u16;
7302 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7303
7304 let mut bytes = hw1.to_le_bytes().to_vec();
7305 bytes.extend_from_slice(&hw2.to_le_bytes());
7306 Ok(bytes)
7307 }
7308
7309 fn encode_thumb32_ldr_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7311 let rd_bits = reg_to_bits(rd);
7312 let base_bits = reg_to_bits(base);
7313 let rm_bits = reg_to_bits(offset_reg);
7314
7315 let hw1: u16 = (0xF850 | base_bits) as u16;
7319 let hw2: u16 = ((rd_bits << 12) | rm_bits) 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_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7328 let rd_bits = reg_to_bits(rd);
7329 let base_bits = reg_to_bits(base);
7330 let rm_bits = reg_to_bits(offset_reg);
7331
7332 let hw1: u16 = (0xF840 | base_bits) as u16;
7336 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7337
7338 let mut bytes = hw1.to_le_bytes().to_vec();
7339 bytes.extend_from_slice(&hw2.to_le_bytes());
7340 Ok(bytes)
7341 }
7342
7343 fn encode_thumb32_ldrb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7347 let rd_bits = reg_to_bits(rd);
7348 let base_bits = reg_to_bits(base);
7349 check_ldst_imm12(offset)?;
7351 let hw1: u16 = (0xF890 | base_bits) as u16;
7352 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
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_ldrb_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 let hw1: u16 = (0xF810 | base_bits) as u16;
7365 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7366 let mut bytes = hw1.to_le_bytes().to_vec();
7367 bytes.extend_from_slice(&hw2.to_le_bytes());
7368 Ok(bytes)
7369 }
7370
7371 fn encode_thumb32_ldrsb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7373 let rd_bits = reg_to_bits(rd);
7374 let base_bits = reg_to_bits(base);
7375 check_ldst_imm12(offset)?;
7377 let hw1: u16 = (0xF990 | base_bits) as u16;
7378 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7379 let mut bytes = hw1.to_le_bytes().to_vec();
7380 bytes.extend_from_slice(&hw2.to_le_bytes());
7381 Ok(bytes)
7382 }
7383
7384 fn encode_thumb32_ldrsb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7386 let rd_bits = reg_to_bits(rd);
7387 let base_bits = reg_to_bits(base);
7388 let rm_bits = reg_to_bits(offset_reg);
7389 let hw1: u16 = (0xF910 | base_bits) as u16;
7391 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7392 let mut bytes = hw1.to_le_bytes().to_vec();
7393 bytes.extend_from_slice(&hw2.to_le_bytes());
7394 Ok(bytes)
7395 }
7396
7397 fn encode_thumb32_ldrh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7399 let rd_bits = reg_to_bits(rd);
7400 let base_bits = reg_to_bits(base);
7401 check_ldst_imm12(offset)?;
7403 let hw1: u16 = (0xF8B0 | base_bits) as u16;
7404 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7405 let mut bytes = hw1.to_le_bytes().to_vec();
7406 bytes.extend_from_slice(&hw2.to_le_bytes());
7407 Ok(bytes)
7408 }
7409
7410 fn encode_thumb32_ldrh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7412 let rd_bits = reg_to_bits(rd);
7413 let base_bits = reg_to_bits(base);
7414 let rm_bits = reg_to_bits(offset_reg);
7415 let hw1: u16 = (0xF830 | base_bits) as u16;
7417 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7418 let mut bytes = hw1.to_le_bytes().to_vec();
7419 bytes.extend_from_slice(&hw2.to_le_bytes());
7420 Ok(bytes)
7421 }
7422
7423 fn encode_thumb32_ldrsh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7425 let rd_bits = reg_to_bits(rd);
7426 let base_bits = reg_to_bits(base);
7427 check_ldst_imm12(offset)?;
7429 let hw1: u16 = (0xF9B0 | base_bits) as u16;
7430 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7431 let mut bytes = hw1.to_le_bytes().to_vec();
7432 bytes.extend_from_slice(&hw2.to_le_bytes());
7433 Ok(bytes)
7434 }
7435
7436 fn encode_thumb32_ldrsh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7438 let rd_bits = reg_to_bits(rd);
7439 let base_bits = reg_to_bits(base);
7440 let rm_bits = reg_to_bits(offset_reg);
7441 let hw1: u16 = (0xF930 | base_bits) as u16;
7443 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7444 let mut bytes = hw1.to_le_bytes().to_vec();
7445 bytes.extend_from_slice(&hw2.to_le_bytes());
7446 Ok(bytes)
7447 }
7448
7449 fn encode_thumb32_strb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7451 let rd_bits = reg_to_bits(rd);
7452 let base_bits = reg_to_bits(base);
7453 check_ldst_imm12(offset)?;
7455 let hw1: u16 = (0xF880 | base_bits) as u16;
7456 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7457 let mut bytes = hw1.to_le_bytes().to_vec();
7458 bytes.extend_from_slice(&hw2.to_le_bytes());
7459 Ok(bytes)
7460 }
7461
7462 fn encode_thumb32_strb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7464 let rd_bits = reg_to_bits(rd);
7465 let base_bits = reg_to_bits(base);
7466 let rm_bits = reg_to_bits(offset_reg);
7467 let hw1: u16 = (0xF800 | base_bits) as u16;
7469 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7470 let mut bytes = hw1.to_le_bytes().to_vec();
7471 bytes.extend_from_slice(&hw2.to_le_bytes());
7472 Ok(bytes)
7473 }
7474
7475 fn encode_thumb32_strh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7477 let rd_bits = reg_to_bits(rd);
7478 let base_bits = reg_to_bits(base);
7479 check_ldst_imm12(offset)?;
7481 let hw1: u16 = (0xF8A0 | base_bits) as u16;
7482 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7483 let mut bytes = hw1.to_le_bytes().to_vec();
7484 bytes.extend_from_slice(&hw2.to_le_bytes());
7485 Ok(bytes)
7486 }
7487
7488 fn encode_thumb32_strh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7490 let rd_bits = reg_to_bits(rd);
7491 let base_bits = reg_to_bits(base);
7492 let rm_bits = reg_to_bits(offset_reg);
7493 let hw1: u16 = (0xF820 | base_bits) as u16;
7495 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7496 let mut bytes = hw1.to_le_bytes().to_vec();
7497 bytes.extend_from_slice(&hw2.to_le_bytes());
7498 Ok(bytes)
7499 }
7500
7501 fn encode_thumb32_add_imm(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7503 let rd_bits = reg_to_bits(rd);
7504 let rn_bits = reg_to_bits(rn);
7505
7506 if imm <= 0xFFF {
7512 let i_bit = (imm >> 11) & 1;
7513 let imm3 = (imm >> 8) & 0x7;
7514 let imm8 = imm & 0xFF;
7515
7516 let hw1: u16 = (0xF100 | (i_bit << 10) | rn_bits) as u16;
7517 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7518
7519 let mut bytes = hw1.to_le_bytes().to_vec();
7520 bytes.extend_from_slice(&hw2.to_le_bytes());
7521 Ok(bytes)
7522 } else {
7523 let scratch: u32 = if rd_bits == rn_bits {
7537 12 } else {
7539 rd_bits };
7541 if scratch == rn_bits {
7549 return Err(synth_core::Error::synthesis(format!(
7550 "ADD #imm: cannot lower #{imm:#x} for Rd==Rn==R12 — no free scratch \
7551 register (R12 is the reserved encoder scratch and aliases Rn here)"
7552 )));
7553 }
7554
7555 let lo16 = imm & 0xFFFF;
7556 let hi16 = (imm >> 16) & 0xFFFF;
7557
7558 let mut bytes = self.encode_thumb32_movw_raw(scratch, lo16)?;
7559 if hi16 != 0 {
7560 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(scratch, hi16)?);
7561 }
7562 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(rd_bits, rn_bits, scratch)?);
7563 Ok(bytes)
7564 }
7565 }
7566
7567 fn encode_thumb32_movw_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7577 reg_bits_checked(rd)?;
7578 encoding_contracts::verify_imm16(imm16);
7579 let imm16 = imm16 & 0xFFFF;
7582 let imm4 = (imm16 >> 12) & 0xF;
7583 let i_bit = (imm16 >> 11) & 1;
7584 let imm3 = (imm16 >> 8) & 0x7;
7585 let imm8 = imm16 & 0xFF;
7586
7587 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7588 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7589
7590 let mut bytes = hw1.to_le_bytes().to_vec();
7591 bytes.extend_from_slice(&hw2.to_le_bytes());
7592 encoding_contracts::verify_thumb32(&bytes);
7593 Ok(bytes)
7594 }
7595
7596 fn encode_thumb32_movt_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7604 reg_bits_checked(rd)?;
7605 encoding_contracts::verify_imm16(imm16);
7606 let imm16 = imm16 & 0xFFFF;
7609 let imm4 = (imm16 >> 12) & 0xF;
7610 let i_bit = (imm16 >> 11) & 1;
7611 let imm3 = (imm16 >> 8) & 0x7;
7612 let imm8 = imm16 & 0xFF;
7613
7614 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
7615 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7616
7617 let mut bytes = hw1.to_le_bytes().to_vec();
7618 bytes.extend_from_slice(&hw2.to_le_bytes());
7619 encoding_contracts::verify_thumb32(&bytes);
7620 Ok(bytes)
7621 }
7622
7623 fn encode_thumb32_lsr_raw(&self, rd: u32, rm: u32, shift: u32) -> Result<Vec<u8>> {
7625 let imm5 = shift & 0x1F;
7628 let imm2 = imm5 & 0x3;
7629 let imm3 = (imm5 >> 2) & 0x7;
7630
7631 let hw1: u16 = 0xEA4F;
7632 let hw2: u16 = ((imm3 << 12) | (rd << 8) | (imm2 << 6) | (0b01 << 4) | rm) as u16;
7633
7634 let mut bytes = hw1.to_le_bytes().to_vec();
7635 bytes.extend_from_slice(&hw2.to_le_bytes());
7636 Ok(bytes)
7637 }
7638
7639 fn encode_thumb32_and_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7641 let hw1: u16 = (0xEA00 | rn) as u16;
7644 let hw2: u16 = ((rd << 8) | rm) as u16;
7645
7646 let mut bytes = hw1.to_le_bytes().to_vec();
7647 bytes.extend_from_slice(&hw2.to_le_bytes());
7648 Ok(bytes)
7649 }
7650
7651 fn encode_thumb32_and_imm_raw(&self, rd: u32, rn: u32, imm: u32) -> Result<Vec<u8>> {
7653 let i_bit = (imm >> 11) & 1;
7657 let imm3 = (imm >> 8) & 0x7;
7658 let imm8 = imm & 0xFF;
7659
7660 let hw1: u16 = (0xF000 | (i_bit << 10) | rn) as u16;
7661 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7662
7663 let mut bytes = hw1.to_le_bytes().to_vec();
7664 bytes.extend_from_slice(&hw2.to_le_bytes());
7665 Ok(bytes)
7666 }
7667
7668 fn encode_thumb32_sub_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7670 let hw1: u16 = (0xEBA0 | rn) as u16;
7673 let hw2: u16 = ((rd << 8) | rm) as u16;
7674
7675 let mut bytes = hw1.to_le_bytes().to_vec();
7676 bytes.extend_from_slice(&hw2.to_le_bytes());
7677 Ok(bytes)
7678 }
7679
7680 fn encode_thumb32_add_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7682 let hw1: u16 = (0xEB00 | rn) as u16;
7685 let hw2: u16 = ((rd << 8) | rm) as u16;
7686
7687 let mut bytes = hw1.to_le_bytes().to_vec();
7688 bytes.extend_from_slice(&hw2.to_le_bytes());
7689 Ok(bytes)
7690 }
7691
7692 fn encode_thumb32_adds_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7696 let hw1: u16 = (0xEB10 | rn) as u16;
7698 let hw2: u16 = ((rd << 8) | rm) as u16;
7699 let mut bytes = hw1.to_le_bytes().to_vec();
7700 bytes.extend_from_slice(&hw2.to_le_bytes());
7701 Ok(bytes)
7702 }
7703
7704 fn encode_thumb32_subs_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7707 let hw1: u16 = (0xEBB0 | rn) as u16;
7709 let hw2: u16 = ((rd << 8) | rm) as u16;
7710 let mut bytes = hw1.to_le_bytes().to_vec();
7711 bytes.extend_from_slice(&hw2.to_le_bytes());
7712 Ok(bytes)
7713 }
7714
7715 pub fn encode_sequence(&self, ops: &[ArmOp]) -> Result<Vec<u8>> {
7717 let mut code = Vec::new();
7718
7719 for op in ops {
7720 let encoded = self.encode(op)?;
7721 code.extend_from_slice(&encoded);
7722 }
7723
7724 Ok(code)
7725 }
7726}
7727
7728fn try_thumb_expand_imm(value: u32) -> Option<u32> {
7736 if value <= 0xFF {
7738 return Some(value);
7739 }
7740 let b0 = value & 0xFF; let b1 = (value >> 8) & 0xFF; if value == (b0 << 16) | b0 {
7744 return Some(0x100 | b0);
7745 }
7746 if value == (b1 << 24) | (b1 << 8) {
7748 return Some(0x200 | b1);
7749 }
7750 if value == (b0 << 24) | (b0 << 16) | (b0 << 8) | b0 {
7752 return Some(0x300 | b0);
7753 }
7754 for rot in 8..=31u32 {
7758 let unrot = value.rotate_left(rot);
7759 if (0x80..=0xFF).contains(&unrot) {
7760 return Some((rot << 7) | (unrot & 0x7F));
7761 }
7762 }
7763 None
7764}
7765
7766fn check_ldst_imm12(offset: u32) -> Result<()> {
7772 if offset > 0xFFF {
7773 Err(synth_core::Error::synthesis(
7774 "load/store immediate offset > 0xFFF (4095) — materialize the offset into a register",
7775 ))
7776 } else {
7777 Ok(())
7778 }
7779}
7780
7781fn reg_to_bits(reg: &Reg) -> u32 {
7782 match reg {
7783 Reg::R0 => 0,
7784 Reg::R1 => 1,
7785 Reg::R2 => 2,
7786 Reg::R3 => 3,
7787 Reg::R4 => 4,
7788 Reg::R5 => 5,
7789 Reg::R6 => 6,
7790 Reg::R7 => 7,
7791 Reg::R8 => 8,
7792 Reg::R9 => 9,
7793 Reg::R10 => 10,
7794 Reg::R11 => 11,
7795 Reg::R12 => 12,
7796 Reg::SP => 13,
7797 Reg::LR => 14,
7798 Reg::PC => 15,
7799 }
7800}
7801
7802fn emit_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
7833 debug_assert!(srcs.len() <= 4);
7834 bytes.extend_from_slice(&0xB40Fu16.to_le_bytes());
7836 for src in srcs.iter().rev() {
7838 let rt = reg_to_bits(src) as u16;
7839 bytes.extend_from_slice(&0xF84Du16.to_le_bytes());
7840 bytes.extend_from_slice(&((rt << 12) | 0x0D04).to_le_bytes());
7841 }
7842 for i in 0..srcs.len() as u16 {
7844 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes());
7845 }
7846}
7847
7848fn emit_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
7852 let lo = reg_to_bits(rdlo);
7853 let hi = reg_to_bits(rdhi);
7854 if lo == 1 && hi == 0 {
7855 return Err(synth_core::Error::synthesis(
7858 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
7859 ));
7860 }
7861 let mov16 = |bytes: &mut Vec<u8>, rd: u32, rm: u32| {
7862 let d = ((rd >> 3) & 1) as u16;
7863 bytes.extend_from_slice(
7864 &(0x4600u16 | (d << 7) | ((rm as u16) << 3) | ((rd & 7) as u16)).to_le_bytes(),
7865 );
7866 };
7867 if hi == 0 {
7868 mov16(bytes, lo, 0);
7870 mov16(bytes, hi, 1);
7871 } else {
7872 mov16(bytes, hi, 1);
7874 mov16(bytes, lo, 0);
7875 }
7876 for i in 0..4u32 {
7877 if i == lo || i == hi {
7878 bytes.extend_from_slice(&0xB001u16.to_le_bytes()); } else {
7881 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes()); }
7883 }
7884 Ok(())
7885}
7886
7887fn emit_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
7891 bytes.extend_from_slice(&0xEA52u16.to_le_bytes()); bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
7893 bytes.extend_from_slice(&0xD100u16.to_le_bytes()); bytes.extend_from_slice(&0xDE00u16.to_le_bytes()); }
7896
7897fn emit_a32_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
7911 debug_assert!(srcs.len() <= 4);
7912 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
7913 w(bytes, 0xE92D_000F);
7915 for src in srcs.iter().rev() {
7917 w(bytes, 0xE52D_0004 | (reg_to_bits(src) << 12));
7918 }
7919 for i in 0..srcs.len() as u32 {
7921 w(bytes, 0xE49D_0004 | (i << 12));
7922 }
7923}
7924
7925fn emit_a32_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
7929 let lo = reg_to_bits(rdlo);
7930 let hi = reg_to_bits(rdhi);
7931 if lo == 1 && hi == 0 {
7932 return Err(synth_core::Error::synthesis(
7935 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
7936 ));
7937 }
7938 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
7939 let mov = |bytes: &mut Vec<u8>, rd: u32, rm: u32| w(bytes, 0xE1A0_0000 | (rd << 12) | rm);
7940 if hi == 0 {
7941 mov(bytes, lo, 0);
7943 mov(bytes, hi, 1);
7944 } else {
7945 mov(bytes, hi, 1);
7947 mov(bytes, lo, 0);
7948 }
7949 for i in 0..4u32 {
7950 if i == lo || i == hi {
7951 w(bytes, 0xE28D_D004); } else {
7954 w(bytes, 0xE49D_0004 | (i << 12)); }
7956 }
7957 Ok(())
7958}
7959
7960fn emit_a32_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
7964 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
7965 w(bytes, 0xE192_C003); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
7969
7970fn reg_bits_checked(bits: u32) -> Result<()> {
7978 if bits > 14 {
7979 return Err(synth_core::Error::synthesis(format!(
7980 "register bits {bits} (PC/R15) is not a valid operand for this Thumb-2 encoding"
7981 )));
7982 }
7983 Ok(())
7984}
7985
7986fn try_encode_rotated_imm(val: u32) -> Option<(u32, u32)> {
7989 if val == 0 {
7990 return Some((0, 1));
7991 }
7992 for rot in 0..16u32 {
7993 let shift = rot * 2;
7994 let unrotated = val.rotate_left(shift);
7996 if unrotated <= 0xFF {
7997 return Some(((rot << 8) | unrotated, 1));
7999 }
8000 }
8001 None
8002}
8003
8004fn encode_operand2(op2: &Operand2) -> Result<(u32, u32)> {
8009 match op2 {
8010 Operand2::Imm(val) => {
8011 let uval = *val as u32;
8012 if let Some(encoded) = try_encode_rotated_imm(uval) {
8014 Ok(encoded)
8015 } else {
8016 Err(synth_core::Error::synthesis(format!(
8025 "encode_operand2: immediate {uval:#x} ({val}) is not an ARM32 \
8026 rotated immediate — the selector must materialize large \
8027 constants via MOVW/MOVT"
8028 )))
8029 }
8030 }
8031
8032 Operand2::Reg(reg) => {
8033 let reg_bits = reg_to_bits(reg);
8034 Ok((reg_bits, 0)) }
8036
8037 Operand2::RegShift {
8038 rm,
8039 shift: _,
8040 amount,
8041 } => {
8042 let rm_bits = reg_to_bits(rm);
8044 let shift_bits = (*amount & 0x1F) << 7;
8045 Ok((shift_bits | rm_bits, 0))
8046 }
8047 }
8048}
8049
8050fn encode_mem_addr(addr: &MemAddr) -> (u32, u32) {
8052 let base_bits = reg_to_bits(&addr.base);
8053 let offset_bits = (addr.offset as u32) & 0xFFF; (base_bits, offset_bits)
8055}
8056
8057fn vfp_sreg_to_num(reg: &VfpReg) -> Result<u32> {
8059 match reg {
8060 VfpReg::S0 => Ok(0),
8061 VfpReg::S1 => Ok(1),
8062 VfpReg::S2 => Ok(2),
8063 VfpReg::S3 => Ok(3),
8064 VfpReg::S4 => Ok(4),
8065 VfpReg::S5 => Ok(5),
8066 VfpReg::S6 => Ok(6),
8067 VfpReg::S7 => Ok(7),
8068 VfpReg::S8 => Ok(8),
8069 VfpReg::S9 => Ok(9),
8070 VfpReg::S10 => Ok(10),
8071 VfpReg::S11 => Ok(11),
8072 VfpReg::S12 => Ok(12),
8073 VfpReg::S13 => Ok(13),
8074 VfpReg::S14 => Ok(14),
8075 VfpReg::S15 => Ok(15),
8076 VfpReg::S16 => Ok(16),
8077 VfpReg::S17 => Ok(17),
8078 VfpReg::S18 => Ok(18),
8079 VfpReg::S19 => Ok(19),
8080 VfpReg::S20 => Ok(20),
8081 VfpReg::S21 => Ok(21),
8082 VfpReg::S22 => Ok(22),
8083 VfpReg::S23 => Ok(23),
8084 VfpReg::S24 => Ok(24),
8085 VfpReg::S25 => Ok(25),
8086 VfpReg::S26 => Ok(26),
8087 VfpReg::S27 => Ok(27),
8088 VfpReg::S28 => Ok(28),
8089 VfpReg::S29 => Ok(29),
8090 VfpReg::S30 => Ok(30),
8091 VfpReg::S31 => Ok(31),
8092 _ => Err(synth_core::Error::SynthesisError(
8094 "D-register not supported in single-precision VFP encoding".to_string(),
8095 )),
8096 }
8097}
8098
8099fn vfp_dreg_to_num(reg: &VfpReg) -> Result<u32> {
8101 match reg {
8102 VfpReg::D0 => Ok(0),
8103 VfpReg::D1 => Ok(1),
8104 VfpReg::D2 => Ok(2),
8105 VfpReg::D3 => Ok(3),
8106 VfpReg::D4 => Ok(4),
8107 VfpReg::D5 => Ok(5),
8108 VfpReg::D6 => Ok(6),
8109 VfpReg::D7 => Ok(7),
8110 VfpReg::D8 => Ok(8),
8111 VfpReg::D9 => Ok(9),
8112 VfpReg::D10 => Ok(10),
8113 VfpReg::D11 => Ok(11),
8114 VfpReg::D12 => Ok(12),
8115 VfpReg::D13 => Ok(13),
8116 VfpReg::D14 => Ok(14),
8117 VfpReg::D15 => Ok(15),
8118 _ => Err(synth_core::Error::SynthesisError(
8120 "S-register not supported in double-precision VFP encoding".to_string(),
8121 )),
8122 }
8123}
8124
8125fn encode_sreg(s: u32) -> (u32, u32) {
8129 (s >> 1, s & 1)
8130}
8131
8132fn encode_dreg(d: u32) -> (u32, u32) {
8136 (d & 0xF, (d >> 4) & 1)
8137}
8138
8139fn encode_vfp_3reg(base: u32, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<u32> {
8145 let sd_num = vfp_sreg_to_num(sd)?;
8146 let sn_num = vfp_sreg_to_num(sn)?;
8147 let sm_num = vfp_sreg_to_num(sm)?;
8148 let (vd, d) = encode_sreg(sd_num);
8149 let (vn, n) = encode_sreg(sn_num);
8150 let (vm, m) = encode_sreg(sm_num);
8151
8152 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8153}
8154
8155fn encode_vfp_2reg(base: u32, sd: &VfpReg, sm: &VfpReg) -> Result<u32> {
8158 let sd_num = vfp_sreg_to_num(sd)?;
8159 let sm_num = vfp_sreg_to_num(sm)?;
8160 let (vd, d) = encode_sreg(sd_num);
8161 let (vm, m) = encode_sreg(sm_num);
8162
8163 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8164}
8165
8166fn encode_vfp_ldst(base: u32, sd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8170 let sd_num = vfp_sreg_to_num(sd)?;
8171 let (vd, d) = encode_sreg(sd_num);
8172 let rn = reg_to_bits(&addr.base);
8173
8174 let offset = addr.offset;
8175 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8176 let abs_offset = offset.unsigned_abs();
8177 let imm8 = (abs_offset / 4) & 0xFF;
8178
8179 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8180}
8181
8182fn encode_vmov_core_sreg(to_sreg: bool, sreg: &VfpReg, core: &Reg) -> Result<u32> {
8186 let s_num = vfp_sreg_to_num(sreg)?;
8187 let (vn, n) = encode_sreg(s_num);
8188 let rt = reg_to_bits(core);
8189
8190 let base = if to_sreg { 0xEE000A10 } else { 0xEE100A10 };
8191 Ok(base | (vn << 16) | (rt << 12) | (n << 7))
8192}
8193
8194fn encode_vfp_3reg_f64(base: u32, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<u32> {
8198 let dd_num = vfp_dreg_to_num(dd)?;
8199 let dn_num = vfp_dreg_to_num(dn)?;
8200 let dm_num = vfp_dreg_to_num(dm)?;
8201 let (vd, d) = encode_dreg(dd_num);
8202 let (vn, n) = encode_dreg(dn_num);
8203 let (vm, m) = encode_dreg(dm_num);
8204
8205 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8206}
8207
8208fn encode_vfp_2reg_f64(base: u32, dd: &VfpReg, dm: &VfpReg) -> Result<u32> {
8210 let dd_num = vfp_dreg_to_num(dd)?;
8211 let dm_num = vfp_dreg_to_num(dm)?;
8212 let (vd, d) = encode_dreg(dd_num);
8213 let (vm, m) = encode_dreg(dm_num);
8214
8215 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8216}
8217
8218fn encode_vfp_ldst_f64(base: u32, dd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8221 let dd_num = vfp_dreg_to_num(dd)?;
8222 let (vd, d) = encode_dreg(dd_num);
8223 let rn = reg_to_bits(&addr.base);
8224
8225 let offset = addr.offset;
8226 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8227 let abs_offset = offset.unsigned_abs();
8228 let imm8 = (abs_offset / 4) & 0xFF;
8229
8230 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8231}
8232
8233fn encode_vmov_core_dreg(
8237 to_dreg: bool,
8238 dreg: &VfpReg,
8239 core_lo: &Reg,
8240 core_hi: &Reg,
8241) -> Result<u32> {
8242 let d_num = vfp_dreg_to_num(dreg)?;
8243 let (vm, m) = encode_dreg(d_num);
8244 let rt = reg_to_bits(core_lo);
8245 let rt2 = reg_to_bits(core_hi);
8246
8247 let base = if to_dreg { 0xEC400B10 } else { 0xEC500B10 };
8248 Ok(base | (rt2 << 16) | (rt << 12) | (m << 5) | vm)
8249}
8250
8251fn vfp_to_thumb_bytes(instr: u32) -> Vec<u8> {
8253 let hw1 = ((instr >> 16) & 0xFFFF) as u16;
8254 let hw2 = (instr & 0xFFFF) as u16;
8255 let mut bytes = hw1.to_le_bytes().to_vec();
8256 bytes.extend_from_slice(&hw2.to_le_bytes());
8257 bytes
8258}
8259
8260fn qreg_to_num(reg: &QReg) -> u32 {
8266 match reg {
8267 QReg::Q0 => 0,
8268 QReg::Q1 => 1,
8269 QReg::Q2 => 2,
8270 QReg::Q3 => 3,
8271 QReg::Q4 => 4,
8272 QReg::Q5 => 5,
8273 QReg::Q6 => 6,
8274 QReg::Q7 => 7,
8275 }
8276}
8277
8278fn mve_size_bits(size: &MveSize) -> u32 {
8280 match size {
8281 MveSize::S8 => 0b00,
8282 MveSize::S16 => 0b01,
8283 MveSize::S32 => 0b10,
8284 }
8285}
8286
8287fn encode_mve_3reg(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8291 let d = qreg_to_num(qd) * 2;
8292 let n = qreg_to_num(qn) * 2;
8293 let m = qreg_to_num(qm) * 2;
8294
8295 let vd = d & 0xF;
8300 let d_bit = (d >> 4) & 1;
8301 let vn = n & 0xF;
8302 let n_bit = (n >> 4) & 1;
8303 let vm = m & 0xF;
8304 let m_bit = (m >> 4) & 1;
8305
8306 base | (d_bit << 22) | (vn << 16) | (vd << 12) | (n_bit << 7) | (m_bit << 5) | vm
8307}
8308
8309fn encode_mve_3reg_bitwise(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8311 encode_mve_3reg(base, qd, qn, qm)
8312}
8313
8314fn encode_mve_vldrw(qd: &QReg, addr: &MemAddr) -> u32 {
8317 let qd_enc = qreg_to_num(qd) * 2;
8318 let rn = reg_to_bits(&addr.base);
8319 let offset = addr.offset;
8320 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8321 let abs_offset = offset.unsigned_abs();
8322 let imm7 = (abs_offset / 4) & 0x7F; 0xED100E80
8326 | (u_bit << 23)
8327 | ((qd_enc >> 4) << 22)
8328 | (rn << 16)
8329 | ((qd_enc & 0xF) << 12)
8330 | (imm7 & 0x7F)
8331}
8332
8333fn encode_mve_vstrw(qd: &QReg, addr: &MemAddr) -> u32 {
8335 let qd_enc = qreg_to_num(qd) * 2;
8336 let rn = reg_to_bits(&addr.base);
8337 let offset = addr.offset;
8338 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8339 let abs_offset = offset.unsigned_abs();
8340 let imm7 = (abs_offset / 4) & 0x7F;
8341
8342 0xED000E80
8343 | (u_bit << 23)
8344 | ((qd_enc >> 4) << 22)
8345 | (rn << 16)
8346 | ((qd_enc & 0xF) << 12)
8347 | (imm7 & 0x7F)
8348}
8349
8350impl ArmEncoder {
8351 fn encode_thumb_mve_const(&self, qd: &QReg, bytes: &[u8; 16]) -> Result<Vec<u8>> {
8353 let mut result = Vec::new();
8354 let qd_num = qreg_to_num(qd);
8355
8356 for i in 0..4 {
8358 let word = u32::from_le_bytes([
8359 bytes[i * 4],
8360 bytes[i * 4 + 1],
8361 bytes[i * 4 + 2],
8362 bytes[i * 4 + 3],
8363 ]);
8364 let lo16 = word & 0xFFFF;
8365 let hi16 = (word >> 16) & 0xFFFF;
8366
8367 result.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
8369 if hi16 != 0 {
8371 result.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
8372 }
8373
8374 let s_num = qd_num * 4 + i as u32;
8376 let (vn, n) = encode_sreg(s_num);
8377 let vmov: u32 = 0xEE000A10 | (vn << 16) | (12 << 12) | (n << 7);
8378 result.extend_from_slice(&vfp_to_thumb_bytes(vmov));
8379 }
8380
8381 Ok(result)
8382 }
8383
8384 fn encode_thumb_mve_lane_wise_f32_binop(
8386 &self,
8387 qd: &QReg,
8388 qn: &QReg,
8389 qm: &QReg,
8390 vfp_base: u32,
8391 ) -> Result<Vec<u8>> {
8392 let mut result = Vec::new();
8393 let qd_num = qreg_to_num(qd);
8394 let qn_num = qreg_to_num(qn);
8395 let qm_num = qreg_to_num(qm);
8396
8397 for i in 0..4u32 {
8399 let sd = qd_num * 4 + i;
8400 let sn = qn_num * 4 + i;
8401 let sm = qm_num * 4 + i;
8402
8403 let (vd, d) = encode_sreg(sd);
8404 let (vn, n) = encode_sreg(sn);
8405 let (vm, m) = encode_sreg(sm);
8406
8407 let instr = vfp_base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
8408 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8409 }
8410
8411 Ok(result)
8412 }
8413
8414 fn encode_thumb_mve_lane_wise_f32_sqrt(&self, qd: &QReg, qm: &QReg) -> Result<Vec<u8>> {
8416 let mut result = Vec::new();
8417 let qd_num = qreg_to_num(qd);
8418 let qm_num = qreg_to_num(qm);
8419
8420 for i in 0..4u32 {
8422 let sd = qd_num * 4 + i;
8423 let sm = qm_num * 4 + i;
8424
8425 let (vd, d) = encode_sreg(sd);
8426 let (vm, m) = encode_sreg(sm);
8427
8428 let instr: u32 = 0xEEB10AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
8429 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8430 }
8431
8432 Ok(result)
8433 }
8434}
8435
8436#[cfg(test)]
8437mod tests {
8438 use super::*;
8439
8440 #[test]
8441 fn test_encoder_creation() {
8442 let encoder_arm = ArmEncoder::new_arm32();
8443 assert!(!encoder_arm.thumb_mode);
8444
8445 let encoder_thumb = ArmEncoder::new_thumb2();
8446 assert!(encoder_thumb.thumb_mode);
8447 }
8448
8449 #[test]
8461 fn test_encode_i64setcond_high_reg_uses_mov_w_311() {
8462 use synth_synthesis::{ArmOp, Condition, Reg};
8463 let enc = ArmEncoder::new_thumb2();
8464 let bytes = enc
8465 .encode(&ArmOp::I64SetCond {
8466 rd: Reg::R8,
8467 rn_lo: Reg::R2,
8468 rn_hi: Reg::R3,
8469 rm_lo: Reg::R6,
8470 rm_hi: Reg::R7,
8471 cond: Condition::EQ,
8472 })
8473 .unwrap();
8474 let halfwords: Vec<u16> = bytes
8477 .chunks(2)
8478 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8479 .collect();
8480 assert!(
8481 halfwords.iter().filter(|&&h| h == 0xF04F).count() == 2,
8482 "high rd must use two MOV.W (T2) encodings, got {halfwords:04x?}"
8483 );
8484 assert!(
8485 !halfwords.contains(&0x2801) && !halfwords.contains(&0x2800),
8486 "no transmuted 16-bit CMP imm: {halfwords:04x?}"
8487 );
8488
8489 let bytes_z = enc
8490 .encode(&ArmOp::I64SetCondZ {
8491 rd: Reg::R8,
8492 rn_lo: Reg::R2,
8493 rn_hi: Reg::R3,
8494 })
8495 .unwrap();
8496 let hw_z: Vec<u16> = bytes_z
8497 .chunks(2)
8498 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8499 .collect();
8500 assert!(
8501 hw_z.iter().filter(|&&h| h == 0xF04F).count() == 2,
8502 "SetCondZ high rd MOV.W: {hw_z:04x?}"
8503 );
8504 assert!(
8506 hw_z.contains(&(0xF1B0 | 8)),
8507 "SetCondZ high rd must use CMP.W: {hw_z:04x?}"
8508 );
8509 }
8510
8511 #[test]
8512 fn test_encode_setcond_high_reg_uses_mov_w_204() {
8513 use synth_synthesis::{ArmOp, Condition, Reg};
8514 let enc = ArmEncoder::new_thumb2();
8515 let hi = enc
8517 .encode(&ArmOp::SetCond {
8518 rd: Reg::R12,
8519 cond: Condition::NE,
8520 })
8521 .unwrap();
8522 assert_eq!(hi.len(), 10, "ITE(2) + MOV.W(4) + MOV.W(4): {hi:02x?}");
8523 assert_eq!(&hi[2..4], &[0x4F, 0xF0], "then = MOV.W: {hi:02x?}");
8525 assert_eq!(&hi[6..8], &[0x4F, 0xF0], "else = MOV.W: {hi:02x?}");
8526 assert_eq!(hi[4] & 0x0F, 0x01, "then imm = #1");
8527 assert_eq!(hi[8] & 0x0F, 0x00, "else imm = #0");
8528 let lo = enc
8530 .encode(&ArmOp::SetCond {
8531 rd: Reg::R0,
8532 cond: Condition::NE,
8533 })
8534 .unwrap();
8535 assert_eq!(lo.len(), 6, "ITE(2) + MOVS(2) + MOVS(2): {lo:02x?}");
8536 assert_eq!(lo[2..4], [0x01, 0x20], "then = MOVS R0,#1");
8537 assert_eq!(lo[4..6], [0x00, 0x20], "else = MOVS R0,#0");
8538 }
8539
8540 #[test]
8544 fn test_encode_umull_209b() {
8545 use synth_synthesis::{ArmOp, Reg};
8546 let op = ArmOp::Umull {
8547 rdlo: Reg::R4,
8548 rdhi: Reg::R5,
8549 rn: Reg::R0,
8550 rm: Reg::R3,
8551 };
8552 let t = ArmEncoder::new_thumb2().encode(&op).unwrap();
8554 assert_eq!(
8555 t,
8556 vec![0xA0, 0xFB, 0x03, 0x45],
8557 "umull r4,r5,r0,r3 (T2): {t:02x?}"
8558 );
8559 let a = ArmEncoder::new_arm32().encode(&op).unwrap();
8561 assert_eq!(
8562 a,
8563 0xE085_4390u32.to_le_bytes().to_vec(),
8564 "umull (A32): {a:02x?}"
8565 );
8566 }
8567
8568 #[test]
8575 fn test_encode_arm32_indexed_load_keeps_index_206() {
8576 use synth_synthesis::{ArmOp, MemAddr, Reg};
8577 let enc = ArmEncoder::new_arm32();
8578 let bytes = enc
8580 .encode(&ArmOp::Ldr {
8581 rd: Reg::R0,
8582 addr: MemAddr::reg_imm(Reg::R11, Reg::R1, 8),
8583 })
8584 .unwrap();
8585 assert_eq!(
8586 bytes.len(),
8587 8,
8588 "expected ADD ip + LDR (2 words): {bytes:02x?}"
8589 );
8590 let add = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
8591 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
8592 assert_eq!(add, 0xE08B_C001, "ADD ip,r11,r1: {add:#010x}");
8594 assert_eq!(ldr, 0xE59C_0008, "LDR r0,[ip,#8]: {ldr:#010x}");
8596 assert_ne!(ldr, 0xE59B_0008, "index must not be dropped");
8598 }
8599
8600 #[test]
8606 fn test_encode_arm32_call_indirect_is_real_call_594() {
8607 use synth_synthesis::{ArmOp, Reg};
8608 let enc = ArmEncoder::new_arm32();
8609 let bytes = enc
8610 .encode(&ArmOp::CallIndirect {
8611 rd: Reg::R0,
8612 type_idx: 0,
8613 table_index_reg: Reg::R0,
8614 })
8615 .unwrap();
8616 assert_eq!(
8617 bytes.len(),
8618 12,
8619 "expected MOV + LDR + BLX (3 words): {bytes:02x?}"
8620 );
8621 let mov = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
8622 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
8623 let blx = u32::from_le_bytes(bytes[8..12].try_into().unwrap());
8624 assert_eq!(mov, 0xE1A0_C100, "MOV r12,r0,LSL#2: {mov:#010x}");
8626 assert_eq!(ldr, 0xE79B_C00C, "LDR r12,[r11,r12]: {ldr:#010x}");
8628 assert_eq!(blx, 0xE12F_FF3C, "BLX r12: {blx:#010x}");
8630 assert!(
8632 !bytes
8633 .chunks_exact(4)
8634 .any(|w| w == 0xE1A0_0000u32.to_le_bytes()),
8635 "call_indirect must not contain a NOP (#594): {bytes:02x?}"
8636 );
8637
8638 let bytes = enc
8640 .encode(&ArmOp::CallIndirect {
8641 rd: Reg::R0,
8642 type_idx: 0,
8643 table_index_reg: Reg::R4,
8644 })
8645 .unwrap();
8646 let mov = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
8647 assert_eq!(mov, 0xE1A0_C104, "MOV r12,r4,LSL#2: {mov:#010x}");
8648 }
8649
8650 #[test]
8666 fn test_encode_thumb_call_indirect_lsl2_597() {
8667 use synth_synthesis::{ArmOp, Reg};
8668 let enc = ArmEncoder::new_thumb2();
8669 let bytes = enc
8670 .encode(&ArmOp::CallIndirect {
8671 rd: Reg::R0,
8672 type_idx: 0,
8673 table_index_reg: Reg::R0,
8674 })
8675 .unwrap();
8676 assert_eq!(
8677 bytes,
8678 vec![0x4F, 0xEA, 0x80, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47],
8679 "Thumb-2 CallIndirect: mov.w ip,r0,LSL#2; ldr.w ip,[r11,ip]; blx ip: {bytes:02x?}"
8680 );
8681 assert_ne!(
8683 &bytes[0..4],
8684 &[0x4F, 0xEA, 0x20, 0x0C],
8685 "mov.w ip, rm, ASR #32 — the #597 type-field bug"
8686 );
8687
8688 let bytes = enc
8690 .encode(&ArmOp::CallIndirect {
8691 rd: Reg::R0,
8692 type_idx: 0,
8693 table_index_reg: Reg::R4,
8694 })
8695 .unwrap();
8696 assert_eq!(
8697 &bytes[0..4],
8698 &[0x4F, 0xEA, 0x84, 0x0C],
8699 "mov.w ip, r4, LSL #2: {bytes:02x?}"
8700 );
8701 }
8702
8703 #[test]
8710 fn test_encode_thumb_add_high_reg_uses_add_w_178_180() {
8711 let encoder = ArmEncoder::new_thumb2();
8712
8713 let code = encoder
8715 .encode(&ArmOp::Add {
8716 rd: Reg::R12,
8717 rn: Reg::R12,
8718 op2: Operand2::Reg(Reg::R0),
8719 })
8720 .unwrap();
8721 assert_eq!(
8723 code,
8724 vec![0x0C, 0xEB, 0x00, 0x0C],
8725 "high-reg Thumb ADD must be 32-bit ADD.W (EB0C 0C00), not corrupt 16-bit; got {code:02X?}"
8726 );
8727 assert_ne!(code, vec![0x6C, 0x18], "regressed to corrupt 16-bit ADDS");
8729
8730 let lo = encoder
8732 .encode(&ArmOp::Add {
8733 rd: Reg::R1,
8734 rn: Reg::R2,
8735 op2: Operand2::Reg(Reg::R3),
8736 })
8737 .unwrap();
8738 assert_eq!(
8739 lo.len(),
8740 2,
8741 "low-reg ADD should remain 16-bit, got {lo:02X?}"
8742 );
8743 }
8744
8745 #[test]
8748 fn test_encode_thumb_adds_subs_high_reg_use_32bit_178_180() {
8749 let encoder = ArmEncoder::new_thumb2();
8750
8751 let adds = encoder
8753 .encode(&ArmOp::Adds {
8754 rd: Reg::R10,
8755 rn: Reg::R10,
8756 op2: Operand2::Reg(Reg::R8),
8757 })
8758 .unwrap();
8759 assert_eq!(
8760 adds,
8761 vec![0x1A, 0xEB, 0x08, 0x0A],
8762 "high-reg ADDS must be 32-bit ADDS.W (EB1A 0A08); got {adds:02X?}"
8763 );
8764
8765 let subs = encoder
8767 .encode(&ArmOp::Subs {
8768 rd: Reg::R10,
8769 rn: Reg::R10,
8770 op2: Operand2::Reg(Reg::R8),
8771 })
8772 .unwrap();
8773 assert_eq!(
8774 subs,
8775 vec![0xBA, 0xEB, 0x08, 0x0A],
8776 "high-reg SUBS must be 32-bit SUBS.W (EBBA 0A08); got {subs:02X?}"
8777 );
8778 }
8779
8780 #[test]
8783 fn test_encode_thumb_cmn_high_reg_uses_cmn_w_184() {
8784 let encoder = ArmEncoder::new_thumb2();
8785
8786 let cmn = encoder
8788 .encode(&ArmOp::Cmn {
8789 rn: Reg::R10,
8790 op2: Operand2::Reg(Reg::R8),
8791 })
8792 .unwrap();
8793 assert_eq!(
8794 cmn,
8795 vec![0x1A, 0xEB, 0x08, 0x0F],
8796 "high-reg CMN must be 32-bit CMN.W (EB1A 0F08); got {cmn:02X?}"
8797 );
8798
8799 let lo = encoder
8801 .encode(&ArmOp::Cmn {
8802 rn: Reg::R1,
8803 op2: Operand2::Reg(Reg::R2),
8804 })
8805 .unwrap();
8806 assert_eq!(
8807 lo.len(),
8808 2,
8809 "low-reg CMN should remain 16-bit, got {lo:02X?}"
8810 );
8811 assert_eq!(lo, vec![0xD1, 0x42], "low-reg CMN bytes wrong: {lo:02X?}");
8812 }
8813
8814 #[test]
8818 fn test_encode_pc_operand_returns_err_not_panic_185() {
8819 let encoder = ArmEncoder::new_thumb2();
8820 for op in [
8821 ArmOp::Sdiv {
8822 rd: Reg::PC,
8823 rn: Reg::R0,
8824 rm: Reg::R1,
8825 },
8826 ArmOp::Udiv {
8827 rd: Reg::R0,
8828 rn: Reg::PC,
8829 rm: Reg::R1,
8830 },
8831 ArmOp::Sdiv {
8832 rd: Reg::R0,
8833 rn: Reg::R1,
8834 rm: Reg::PC,
8835 },
8836 ] {
8837 let r = encoder.encode(&op);
8838 assert!(
8839 r.is_err(),
8840 "encode({op:?}) must return Err for a PC operand, got {r:?}"
8841 );
8842 }
8843 assert!(
8845 encoder
8846 .encode(&ArmOp::Sdiv {
8847 rd: Reg::R0,
8848 rn: Reg::R1,
8849 rm: Reg::R2
8850 })
8851 .is_ok()
8852 );
8853 }
8854
8855 #[test]
8856 fn test_encode_nop_arm32() {
8857 let encoder = ArmEncoder::new_arm32();
8858 let code = encoder.encode(&ArmOp::Nop).unwrap();
8859
8860 assert_eq!(code.len(), 4); assert_eq!(code, vec![0x00, 0x00, 0xA0, 0xE1]); }
8863
8864 #[test]
8865 fn test_encode_nop_thumb() {
8866 let encoder = ArmEncoder::new_thumb2();
8867 let code = encoder.encode(&ArmOp::Nop).unwrap();
8868
8869 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]); }
8872
8873 #[test]
8874 fn test_encode_mov_immediate_arm32() {
8875 let encoder = ArmEncoder::new_arm32();
8876 let op = ArmOp::Mov {
8877 rd: Reg::R0,
8878 op2: Operand2::Imm(42),
8879 };
8880
8881 let code = encoder.encode(&op).unwrap();
8882 assert_eq!(code.len(), 4);
8883
8884 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8886 assert_eq!(instr & 0x0E000000, 0x02000000); }
8888
8889 #[test]
8890 fn test_encode_add_registers_arm32() {
8891 let encoder = ArmEncoder::new_arm32();
8892 let op = ArmOp::Add {
8893 rd: Reg::R0,
8894 rn: Reg::R1,
8895 op2: Operand2::Reg(Reg::R2),
8896 };
8897
8898 let code = encoder.encode(&op).unwrap();
8899 assert_eq!(code.len(), 4);
8900
8901 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8902 assert_eq!(instr & 0x0FE00000, 0x00800000);
8904 }
8905
8906 #[test]
8910 fn test_encode_add_imm_large_350() {
8911 let enc = ArmEncoder::new_thumb2();
8912
8913 let small = enc
8915 .encode_thumb32_add_imm(&Reg::R0, &Reg::R1, 0x123)
8916 .unwrap();
8917 assert_eq!(small.len(), 4, "small imm must stay a single instruction");
8918
8919 fn movx_imm16(b: &[u8]) -> u32 {
8921 let hw1 = u16::from_le_bytes([b[0], b[1]]) as u32;
8922 let hw2 = u16::from_le_bytes([b[2], b[3]]) as u32;
8923 let imm4 = hw1 & 0xF;
8924 let i = (hw1 >> 10) & 1;
8925 let imm3 = (hw2 >> 12) & 0x7;
8926 let imm8 = hw2 & 0xFF;
8927 (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8
8928 }
8929 fn movx_rd(b: &[u8]) -> u32 {
8930 (u16::from_le_bytes([b[2], b[3]]) as u32 >> 8) & 0xF
8931 }
8932
8933 let seq = enc
8936 .encode_thumb32_add_imm(&Reg::R12, &Reg::R0, 70000)
8937 .unwrap();
8938 assert_eq!(seq.len(), 12, "MOVW + MOVT + ADD = 12 bytes");
8939 assert_eq!(u16::from_le_bytes([seq[0], seq[1]]) & 0xFBF0, 0xF240);
8941 assert_eq!(movx_rd(&seq[0..4]), 12);
8942 assert_eq!(movx_imm16(&seq[0..4]), 0x1170);
8943 assert_eq!(u16::from_le_bytes([seq[4], seq[5]]) & 0xFBF0, 0xF2C0);
8945 assert_eq!(movx_rd(&seq[4..8]), 12);
8946 assert_eq!(movx_imm16(&seq[4..8]), 0x0001);
8947 let add1 = u16::from_le_bytes([seq[8], seq[9]]) as u32;
8949 let add2 = u16::from_le_bytes([seq[10], seq[11]]) as u32;
8950 assert_eq!(add1 & 0xFFF0, 0xEB00);
8951 assert_eq!(add1 & 0xF, 0); assert_eq!((add2 >> 8) & 0xF, 12); assert_eq!(add2 & 0xF, 12); assert_eq!(
8956 (movx_imm16(&seq[4..8]) << 16) | movx_imm16(&seq[0..4]),
8957 70000
8958 );
8959
8960 let seq16 = enc
8962 .encode_thumb32_add_imm(&Reg::R3, &Reg::R0, 0xABCD)
8963 .unwrap();
8964 assert_eq!(seq16.len(), 8, "imm <= 0xFFFF skips MOVT");
8965 assert_eq!(movx_imm16(&seq16[0..4]), 0xABCD);
8966 assert_eq!(movx_rd(&seq16[0..4]), 3); let inplace = enc
8971 .encode_thumb32_add_imm(&Reg::R5, &Reg::R5, 0x12345)
8972 .unwrap();
8973 assert_eq!(inplace.len(), 12);
8974 assert_eq!(movx_rd(&inplace[0..4]), 12, "rd==rn must use R12 scratch");
8975 assert_eq!(
8976 (movx_imm16(&inplace[4..8]) << 16) | movx_imm16(&inplace[0..4]),
8977 0x12345
8978 );
8979 let ip_add2 = u16::from_le_bytes([inplace[10], inplace[11]]) as u32;
8981 assert_eq!(ip_add2 & 0xF, 12);
8982 assert_eq!((ip_add2 >> 8) & 0xF, 5);
8983 }
8984
8985 #[test]
8993 fn test_encode_add_imm_large_rd_rn_r12_errs_not_panics_350() {
8994 let enc = ArmEncoder::new_thumb2();
8995 let r = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 70000);
8997 assert!(
8998 r.is_err(),
8999 "rd==rn==R12 with out-of-range imm must Err (no free scratch), got {r:?}"
9000 );
9001 let small = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 0x10);
9005 assert!(small.is_ok(), "small imm needs no scratch, must stay Ok");
9006 }
9007
9008 #[test]
9017 fn test_encode_operand2_non_rotatable_imm_errs_not_masks_378() {
9018 let enc = ArmEncoder::new_arm32();
9019 let bad = enc.encode(&ArmOp::Add {
9020 rd: Reg::R0,
9021 rn: Reg::R1,
9022 op2: Operand2::Imm(0x1FF),
9023 });
9024 assert!(
9025 bad.is_err(),
9026 "non-rotatable ARM32 immediate 0x1FF must Err (was silently masked \
9027 to 0xFF), got {bad:?}"
9028 );
9029 let ok = enc.encode(&ArmOp::Add {
9031 rd: Reg::R0,
9032 rn: Reg::R1,
9033 op2: Operand2::Imm(0xFF),
9034 });
9035 assert!(
9036 ok.is_ok(),
9037 "0xFF is a valid rotated immediate, must stay Ok"
9038 );
9039 }
9040
9041 #[test]
9042 fn test_encode_ldr_arm32() {
9043 let encoder = ArmEncoder::new_arm32();
9044 let op = ArmOp::Ldr {
9045 rd: Reg::R0,
9046 addr: MemAddr::imm(Reg::R1, 4),
9047 };
9048
9049 let code = encoder.encode(&op).unwrap();
9050 assert_eq!(code.len(), 4);
9051
9052 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9053 assert_eq!(instr & 0x00100000, 0x00100000);
9055 }
9056
9057 #[test]
9058 fn test_encode_str_arm32() {
9059 let encoder = ArmEncoder::new_arm32();
9060 let op = ArmOp::Str {
9061 rd: Reg::R0,
9062 addr: MemAddr::imm(Reg::SP, 0),
9063 };
9064
9065 let code = encoder.encode(&op).unwrap();
9066 assert_eq!(code.len(), 4);
9067 }
9068
9069 #[test]
9070 fn test_encode_branch_arm32() {
9071 let encoder = ArmEncoder::new_arm32();
9072 let op = ArmOp::Bl {
9073 label: "main".to_string(),
9074 };
9075
9076 let code = encoder.encode(&op).unwrap();
9077 assert_eq!(code.len(), 4);
9078
9079 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9080 assert_eq!(instr & 0x0F000000, 0x0B000000);
9082 }
9083
9084 #[test]
9094 fn test_encode_thumb_bl_placeholder_addend_167_174() {
9095 let encoder = ArmEncoder::new_thumb2();
9096 let op = ArmOp::Bl {
9097 label: "callee".to_string(),
9098 };
9099
9100 let code = encoder.encode(&op).unwrap();
9101 assert_eq!(code.len(), 4, "Thumb-2 BL is 32-bit");
9102
9103 let hw1 = u16::from_le_bytes([code[0], code[1]]);
9104 let hw2 = u16::from_le_bytes([code[2], code[3]]);
9105 assert_eq!(hw1, 0xF7FF, "BL first halfword (matches gas `bl <extern>`)");
9106 assert_eq!(
9107 hw2, 0xFFFE,
9108 "BL second halfword must be 0xFFFE (-4 addend → nets to S), not 0xF800 (→ S+4, #174) or 0xD000 (#167)"
9109 );
9110 assert_ne!(hw2, 0xF800, "0xF800 (addend 0) lands at S+4 (#174)");
9111 assert_ne!(hw2, 0xD000, "0xD000 bakes in a ~+0x600000 addend (#167)");
9112 }
9113
9114 #[test]
9115 fn test_encode_sequence() {
9116 let encoder = ArmEncoder::new_arm32();
9117 let ops = vec![
9118 ArmOp::Mov {
9119 rd: Reg::R0,
9120 op2: Operand2::Imm(42),
9121 },
9122 ArmOp::Mov {
9123 rd: Reg::R1,
9124 op2: Operand2::Imm(10),
9125 },
9126 ArmOp::Add {
9127 rd: Reg::R2,
9128 rn: Reg::R0,
9129 op2: Operand2::Reg(Reg::R1),
9130 },
9131 ];
9132
9133 let code = encoder.encode_sequence(&ops).unwrap();
9134 assert_eq!(code.len(), 12); }
9136
9137 #[test]
9138 fn test_reg_to_bits() {
9139 assert_eq!(reg_to_bits(&Reg::R0), 0);
9140 assert_eq!(reg_to_bits(&Reg::R7), 7);
9141 assert_eq!(reg_to_bits(&Reg::SP), 13);
9142 assert_eq!(reg_to_bits(&Reg::LR), 14);
9143 assert_eq!(reg_to_bits(&Reg::PC), 15);
9144 }
9145
9146 #[test]
9147 fn test_encode_bitwise_operations() {
9148 let encoder = ArmEncoder::new_arm32();
9149
9150 let and_op = ArmOp::And {
9151 rd: Reg::R0,
9152 rn: Reg::R1,
9153 op2: Operand2::Reg(Reg::R2),
9154 };
9155 let and_code = encoder.encode(&and_op).unwrap();
9156 assert_eq!(and_code.len(), 4);
9157
9158 let orr_op = ArmOp::Orr {
9159 rd: Reg::R0,
9160 rn: Reg::R1,
9161 op2: Operand2::Reg(Reg::R2),
9162 };
9163 let orr_code = encoder.encode(&orr_op).unwrap();
9164 assert_eq!(orr_code.len(), 4);
9165
9166 let eor_op = ArmOp::Eor {
9167 rd: Reg::R0,
9168 rn: Reg::R1,
9169 op2: Operand2::Reg(Reg::R2),
9170 };
9171 let eor_code = encoder.encode(&eor_op).unwrap();
9172 assert_eq!(eor_code.len(), 4);
9173 }
9174
9175 #[test]
9178 fn test_encode_sdiv_thumb2() {
9179 let encoder = ArmEncoder::new_thumb2();
9180 let op = ArmOp::Sdiv {
9181 rd: Reg::R0,
9182 rn: Reg::R1,
9183 rm: Reg::R2,
9184 };
9185
9186 let code = encoder.encode(&op).unwrap();
9187 assert_eq!(code.len(), 4); assert_eq!(code[0], 0x91);
9194 assert_eq!(code[1], 0xFB);
9195 assert_eq!(code[2], 0xF2);
9196 assert_eq!(code[3], 0xF0);
9197 }
9198
9199 #[test]
9200 fn test_encode_udiv_thumb2() {
9201 let encoder = ArmEncoder::new_thumb2();
9202 let op = ArmOp::Udiv {
9203 rd: Reg::R0,
9204 rn: Reg::R1,
9205 rm: Reg::R2,
9206 };
9207
9208 let code = encoder.encode(&op).unwrap();
9209 assert_eq!(code.len(), 4); assert_eq!(code[0], 0xB1);
9214 assert_eq!(code[1], 0xFB);
9215 assert_eq!(code[2], 0xF2);
9216 assert_eq!(code[3], 0xF0);
9217 }
9218
9219 #[test]
9220 fn test_encode_mul_thumb2() {
9221 let encoder = ArmEncoder::new_thumb2();
9222 let op = ArmOp::Mul {
9223 rd: Reg::R0,
9224 rn: Reg::R1,
9225 rm: Reg::R2,
9226 };
9227
9228 let code = encoder.encode(&op).unwrap();
9229 assert_eq!(code.len(), 4); }
9231
9232 #[test]
9233 fn test_encode_and_thumb2() {
9234 let encoder = ArmEncoder::new_thumb2();
9235 let op = ArmOp::And {
9236 rd: Reg::R0,
9237 rn: Reg::R1,
9238 op2: Operand2::Reg(Reg::R2),
9239 };
9240
9241 let code = encoder.encode(&op).unwrap();
9242 assert_eq!(code.len(), 4); }
9244
9245 #[test]
9246 fn test_encode_lsl_thumb2_low_regs() {
9247 let encoder = ArmEncoder::new_thumb2();
9248 let op = ArmOp::Lsl {
9249 rd: Reg::R0,
9250 rn: Reg::R1,
9251 shift: 5,
9252 };
9253
9254 let code = encoder.encode(&op).unwrap();
9255 assert_eq!(code.len(), 2); }
9257
9258 #[test]
9259 fn test_encode_clz_thumb2() {
9260 let encoder = ArmEncoder::new_thumb2();
9261 let op = ArmOp::Clz {
9262 rd: Reg::R0,
9263 rm: Reg::R1,
9264 };
9265
9266 let code = encoder.encode(&op).unwrap();
9267 assert_eq!(code.len(), 4); }
9269
9270 #[test]
9271 fn test_encode_bx_thumb2() {
9272 let encoder = ArmEncoder::new_thumb2();
9273 let op = ArmOp::Bx { rm: Reg::LR };
9274
9275 let code = encoder.encode(&op).unwrap();
9276 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x70, 0x47]);
9280 }
9281
9282 #[test]
9287 fn test_encode_f32_abs_arm32() {
9288 let encoder = ArmEncoder::new_arm32();
9289 let op = ArmOp::F32Abs {
9290 sd: VfpReg::S0,
9291 sm: VfpReg::S2,
9292 };
9293 let code = encoder.encode(&op).unwrap();
9294 assert_eq!(code.len(), 4); }
9296
9297 #[test]
9298 fn test_encode_f32_neg_arm32() {
9299 let encoder = ArmEncoder::new_arm32();
9300 let op = ArmOp::F32Neg {
9301 sd: VfpReg::S0,
9302 sm: VfpReg::S2,
9303 };
9304 let code = encoder.encode(&op).unwrap();
9305 assert_eq!(code.len(), 4);
9306 }
9307
9308 #[test]
9309 fn test_encode_f32_sqrt_arm32() {
9310 let encoder = ArmEncoder::new_arm32();
9311 let op = ArmOp::F32Sqrt {
9312 sd: VfpReg::S0,
9313 sm: VfpReg::S2,
9314 };
9315 let code = encoder.encode(&op).unwrap();
9316 assert_eq!(code.len(), 4);
9317 }
9318
9319 #[test]
9320 fn test_encode_f32_ceil_arm32() {
9321 let encoder = ArmEncoder::new_arm32();
9322 let op = ArmOp::F32Ceil {
9323 sd: VfpReg::S0,
9324 sm: VfpReg::S2,
9325 };
9326 let code = encoder.encode(&op).unwrap();
9327 assert_eq!(code.len(), 36);
9329 }
9330
9331 #[test]
9332 fn test_encode_f32_floor_thumb2() {
9333 let encoder = ArmEncoder::new_thumb2();
9334 let op = ArmOp::F32Floor {
9335 sd: VfpReg::S0,
9336 sm: VfpReg::S2,
9337 };
9338 let code = encoder.encode(&op).unwrap();
9339 assert_eq!(code.len(), 36);
9341 }
9342
9343 #[test]
9344 fn test_encode_f32_min_arm32() {
9345 let encoder = ArmEncoder::new_arm32();
9346 let op = ArmOp::F32Min {
9347 sd: VfpReg::S0,
9348 sn: VfpReg::S2,
9349 sm: VfpReg::S4,
9350 };
9351 let code = encoder.encode(&op).unwrap();
9352 assert_eq!(code.len(), 16); }
9354
9355 #[test]
9356 fn test_encode_f32_max_thumb2() {
9357 let encoder = ArmEncoder::new_thumb2();
9358 let op = ArmOp::F32Max {
9359 sd: VfpReg::S0,
9360 sn: VfpReg::S2,
9361 sm: VfpReg::S4,
9362 };
9363 let code = encoder.encode(&op).unwrap();
9364 assert_eq!(code.len(), 18);
9366 }
9367
9368 #[test]
9369 fn test_encode_f32_copysign_arm32() {
9370 let encoder = ArmEncoder::new_arm32();
9371 let op = ArmOp::F32Copysign {
9372 sd: VfpReg::S0,
9373 sn: VfpReg::S2,
9374 sm: VfpReg::S4,
9375 };
9376 let code = encoder.encode(&op).unwrap();
9377 assert_eq!(code.len(), 24);
9379 }
9380
9381 #[test]
9386 fn test_encode_f64_add_arm32() {
9387 let encoder = ArmEncoder::new_arm32();
9388 let op = ArmOp::F64Add {
9389 dd: VfpReg::D0,
9390 dn: VfpReg::D1,
9391 dm: VfpReg::D2,
9392 };
9393 let code = encoder.encode(&op).unwrap();
9394 assert_eq!(code.len(), 4);
9395 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9397 assert_eq!((instr >> 8) & 0xF, 0xB); }
9399
9400 #[test]
9401 fn test_encode_f64_sub_thumb2() {
9402 let encoder = ArmEncoder::new_thumb2();
9403 let op = ArmOp::F64Sub {
9404 dd: VfpReg::D0,
9405 dn: VfpReg::D1,
9406 dm: VfpReg::D2,
9407 };
9408 let code = encoder.encode(&op).unwrap();
9409 assert_eq!(code.len(), 4); }
9411
9412 #[test]
9413 fn test_encode_f64_mul_arm32() {
9414 let encoder = ArmEncoder::new_arm32();
9415 let op = ArmOp::F64Mul {
9416 dd: VfpReg::D0,
9417 dn: VfpReg::D1,
9418 dm: VfpReg::D2,
9419 };
9420 let code = encoder.encode(&op).unwrap();
9421 assert_eq!(code.len(), 4);
9422 }
9423
9424 #[test]
9425 fn test_encode_f64_div_arm32() {
9426 let encoder = ArmEncoder::new_arm32();
9427 let op = ArmOp::F64Div {
9428 dd: VfpReg::D0,
9429 dn: VfpReg::D1,
9430 dm: VfpReg::D2,
9431 };
9432 let code = encoder.encode(&op).unwrap();
9433 assert_eq!(code.len(), 4);
9434 }
9435
9436 #[test]
9437 fn test_encode_f64_abs_arm32() {
9438 let encoder = ArmEncoder::new_arm32();
9439 let op = ArmOp::F64Abs {
9440 dd: VfpReg::D0,
9441 dm: VfpReg::D2,
9442 };
9443 let code = encoder.encode(&op).unwrap();
9444 assert_eq!(code.len(), 4);
9445 }
9446
9447 #[test]
9448 fn test_encode_f64_neg_arm32() {
9449 let encoder = ArmEncoder::new_arm32();
9450 let op = ArmOp::F64Neg {
9451 dd: VfpReg::D0,
9452 dm: VfpReg::D2,
9453 };
9454 let code = encoder.encode(&op).unwrap();
9455 assert_eq!(code.len(), 4);
9456 }
9457
9458 #[test]
9459 fn test_encode_f64_sqrt_arm32() {
9460 let encoder = ArmEncoder::new_arm32();
9461 let op = ArmOp::F64Sqrt {
9462 dd: VfpReg::D0,
9463 dm: VfpReg::D2,
9464 };
9465 let code = encoder.encode(&op).unwrap();
9466 assert_eq!(code.len(), 4);
9467 }
9468
9469 #[test]
9470 fn test_encode_f64_load_arm32() {
9471 let encoder = ArmEncoder::new_arm32();
9472 let op = ArmOp::F64Load {
9473 dd: VfpReg::D0,
9474 addr: MemAddr::imm(Reg::R0, 8),
9475 };
9476 let code = encoder.encode(&op).unwrap();
9477 assert_eq!(code.len(), 4);
9478 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9479 assert_eq!((instr >> 8) & 0xF, 0xB); assert_eq!(instr & 0xFF, 2); }
9482
9483 #[test]
9484 fn test_encode_f64_store_thumb2() {
9485 let encoder = ArmEncoder::new_thumb2();
9486 let op = ArmOp::F64Store {
9487 dd: VfpReg::D0,
9488 addr: MemAddr::imm(Reg::SP, 0),
9489 };
9490 let code = encoder.encode(&op).unwrap();
9491 assert_eq!(code.len(), 4);
9492 }
9493
9494 #[test]
9495 fn test_encode_f64_compare_arm32() {
9496 let encoder = ArmEncoder::new_arm32();
9497 let op = ArmOp::F64Eq {
9498 rd: Reg::R0,
9499 dn: VfpReg::D0,
9500 dm: VfpReg::D1,
9501 };
9502 let code = encoder.encode(&op).unwrap();
9503 assert_eq!(code.len(), 16); }
9505
9506 #[test]
9507 fn test_encode_f64_compare_thumb2() {
9508 let encoder = ArmEncoder::new_thumb2();
9509 let op = ArmOp::F64Lt {
9510 rd: Reg::R0,
9511 dn: VfpReg::D0,
9512 dm: VfpReg::D1,
9513 };
9514 let code = encoder.encode(&op).unwrap();
9515 assert_eq!(code.len(), 14);
9517 }
9518
9519 #[test]
9520 fn test_encode_f64_const_arm32() {
9521 let encoder = ArmEncoder::new_arm32();
9522 let op = ArmOp::F64Const {
9523 dd: VfpReg::D0,
9524 value: 3.125,
9525 };
9526 let code = encoder.encode(&op).unwrap();
9527 assert_eq!(code.len(), 20);
9529 }
9530
9531 #[test]
9532 fn test_encode_f64_const_thumb2() {
9533 let encoder = ArmEncoder::new_thumb2();
9534 let op = ArmOp::F64Const {
9535 dd: VfpReg::D0,
9536 value: 2.5,
9537 };
9538 let code = encoder.encode(&op).unwrap();
9539 assert_eq!(code.len(), 20);
9541 }
9542
9543 #[test]
9544 fn test_encode_f64_convert_i32s_arm32() {
9545 let encoder = ArmEncoder::new_arm32();
9546 let op = ArmOp::F64ConvertI32S {
9547 dd: VfpReg::D0,
9548 rm: Reg::R0,
9549 };
9550 let code = encoder.encode(&op).unwrap();
9551 assert_eq!(code.len(), 8);
9553 }
9554
9555 #[test]
9556 fn test_encode_f64_promote_f32_arm32() {
9557 let encoder = ArmEncoder::new_arm32();
9558 let op = ArmOp::F64PromoteF32 {
9559 dd: VfpReg::D0,
9560 sm: VfpReg::S0,
9561 };
9562 let code = encoder.encode(&op).unwrap();
9563 assert_eq!(code.len(), 4); }
9565
9566 #[test]
9567 fn test_encode_f64_promote_f32_thumb2() {
9568 let encoder = ArmEncoder::new_thumb2();
9569 let op = ArmOp::F64PromoteF32 {
9570 dd: VfpReg::D0,
9571 sm: VfpReg::S0,
9572 };
9573 let code = encoder.encode(&op).unwrap();
9574 assert_eq!(code.len(), 4);
9575 }
9576
9577 #[test]
9578 fn test_encode_i32_trunc_f64s_arm32() {
9579 let encoder = ArmEncoder::new_arm32();
9580 let op = ArmOp::I32TruncF64S {
9581 rd: Reg::R0,
9582 dm: VfpReg::D0,
9583 };
9584 let code = encoder.encode(&op).unwrap();
9585 assert_eq!(code.len(), 8);
9587 }
9588
9589 #[test]
9590 fn test_encode_f64_reinterpret_i64_arm32() {
9591 let encoder = ArmEncoder::new_arm32();
9592 let op = ArmOp::F64ReinterpretI64 {
9593 dd: VfpReg::D0,
9594 rmlo: Reg::R0,
9595 rmhi: Reg::R1,
9596 };
9597 let code = encoder.encode(&op).unwrap();
9598 assert_eq!(code.len(), 4); }
9600
9601 #[test]
9602 fn test_encode_i64_reinterpret_f64_thumb2() {
9603 let encoder = ArmEncoder::new_thumb2();
9604 let op = ArmOp::I64ReinterpretF64 {
9605 rdlo: Reg::R0,
9606 rdhi: Reg::R1,
9607 dm: VfpReg::D0,
9608 };
9609 let code = encoder.encode(&op).unwrap();
9610 assert_eq!(code.len(), 4);
9611 }
9612
9613 #[test]
9614 fn test_encode_f64_trunc_thumb2() {
9615 let encoder = ArmEncoder::new_thumb2();
9616 let op = ArmOp::F64Trunc {
9617 dd: VfpReg::D0,
9618 dm: VfpReg::D1,
9619 };
9620 let code = encoder.encode(&op).unwrap();
9621 assert_eq!(code.len(), 8);
9623 }
9624
9625 #[test]
9626 fn test_encode_f64_min_arm32() {
9627 let encoder = ArmEncoder::new_arm32();
9628 let op = ArmOp::F64Min {
9629 dd: VfpReg::D0,
9630 dn: VfpReg::D1,
9631 dm: VfpReg::D2,
9632 };
9633 let code = encoder.encode(&op).unwrap();
9634 assert_eq!(code.len(), 16);
9636 }
9637
9638 #[test]
9639 fn test_f64_cp11_encoding() {
9640 let encoder = ArmEncoder::new_arm32();
9642
9643 let code = encoder
9645 .encode(&ArmOp::F64Add {
9646 dd: VfpReg::D0,
9647 dn: VfpReg::D0,
9648 dm: VfpReg::D0,
9649 })
9650 .unwrap();
9651 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9652 assert_eq!((instr >> 8) & 0xF, 0xB, "F64 should use cp11");
9653
9654 let code = encoder
9656 .encode(&ArmOp::F32Add {
9657 sd: VfpReg::S0,
9658 sn: VfpReg::S0,
9659 sm: VfpReg::S0,
9660 })
9661 .unwrap();
9662 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9663 assert_eq!((instr >> 8) & 0xF, 0xA, "F32 should use cp10");
9664 }
9665
9666 #[test]
9667 fn test_dreg_encoding_higher_registers() {
9668 let encoder = ArmEncoder::new_arm32();
9669
9670 let op = ArmOp::F64Add {
9672 dd: VfpReg::D15,
9673 dn: VfpReg::D14,
9674 dm: VfpReg::D13,
9675 };
9676 let code = encoder.encode(&op).unwrap();
9677 assert_eq!(code.len(), 4);
9678
9679 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9681 assert_eq!((instr >> 8) & 0xF, 0xB); }
9683
9684 #[test]
9689 fn test_encode_label_emits_no_bytes() {
9690 let encoder = ArmEncoder::new_thumb2();
9691 let op = ArmOp::Label {
9692 name: ".Lblock_end_0".to_string(),
9693 };
9694 let code = encoder.encode(&op).unwrap();
9695 assert!(code.is_empty(), "Label should emit zero bytes");
9696
9697 let encoder32 = ArmEncoder::new_arm32();
9698 let code32 = encoder32.encode(&op).unwrap();
9699 assert!(
9700 code32.is_empty(),
9701 "Label should emit zero bytes in ARM32 too"
9702 );
9703 }
9704
9705 #[test]
9706 fn test_encode_bcc_eq_thumb2() {
9707 use synth_synthesis::Condition;
9708 let encoder = ArmEncoder::new_thumb2();
9709 let op = ArmOp::Bcc {
9710 cond: Condition::EQ,
9711 label: "target".to_string(),
9712 };
9713 let code = encoder.encode(&op).unwrap();
9714 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xD0]);
9718 }
9719
9720 #[test]
9721 fn test_encode_bcc_ne_thumb2() {
9722 use synth_synthesis::Condition;
9723 let encoder = ArmEncoder::new_thumb2();
9724 let op = ArmOp::Bcc {
9725 cond: Condition::NE,
9726 label: "target".to_string(),
9727 };
9728 let code = encoder.encode(&op).unwrap();
9729 assert_eq!(code.len(), 2);
9730
9731 assert_eq!(code, vec![0x00, 0xD1]);
9733 }
9734
9735 #[test]
9736 fn test_encode_bcc_arm32() {
9737 use synth_synthesis::Condition;
9738 let encoder = ArmEncoder::new_arm32();
9739 let op = ArmOp::Bcc {
9740 cond: Condition::EQ,
9741 label: "target".to_string(),
9742 };
9743 let code = encoder.encode(&op).unwrap();
9744 assert_eq!(code.len(), 4); let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9747 assert_eq!(instr & 0xF0000000, 0x00000000); assert_eq!(instr & 0x0F000000, 0x0A000000); }
9751
9752 #[test]
9753 fn test_encode_udf_thumb2() {
9754 let encoder = ArmEncoder::new_thumb2();
9755 let op = ArmOp::Udf { imm: 0 };
9756 let code = encoder.encode(&op).unwrap();
9757 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xDE]);
9761 }
9762
9763 #[test]
9769 fn test_610_i64_rot_expansion_ends_with_rd_movs_and_restore() {
9770 let encoder = ArmEncoder::new_thumb2();
9771 for op in [
9772 ArmOp::I64Rotl {
9773 rdlo: Reg::R4,
9774 rdhi: Reg::R5,
9775 rnlo: Reg::R0,
9776 rnhi: Reg::R1,
9777 shift: Reg::R2,
9778 },
9779 ArmOp::I64Rotr {
9780 rdlo: Reg::R4,
9781 rdhi: Reg::R5,
9782 rnlo: Reg::R0,
9783 rnhi: Reg::R1,
9784 shift: Reg::R2,
9785 },
9786 ] {
9787 let code = encoder.encode(&op).unwrap();
9788 assert_eq!(code.len(), 102, "register-independent size (estimator pin)");
9789 let tail: Vec<u16> = code[code.len() - 12..]
9792 .chunks(2)
9793 .map(|c| u16::from_le_bytes([c[0], c[1]]))
9794 .collect();
9795 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
9796 }
9797 }
9798
9799 #[test]
9802 fn test_610_i64_div_rem_expansion_guard_and_rd() {
9803 let encoder = ArmEncoder::new_thumb2();
9804 let mk = |which: u8| {
9805 let (rdlo, rdhi, rnlo, rnhi, rmlo, rmhi) =
9806 (Reg::R4, Reg::R5, Reg::R0, Reg::R1, Reg::R2, Reg::R3);
9807 match which {
9808 0 => ArmOp::I64DivU {
9809 rdlo,
9810 rdhi,
9811 rnlo,
9812 rnhi,
9813 rmlo,
9814 rmhi,
9815 },
9816 1 => ArmOp::I64RemU {
9817 rdlo,
9818 rdhi,
9819 rnlo,
9820 rnhi,
9821 rmlo,
9822 rmhi,
9823 },
9824 2 => ArmOp::I64DivS {
9825 rdlo,
9826 rdhi,
9827 rnlo,
9828 rnhi,
9829 rmlo,
9830 rmhi,
9831 },
9832 _ => ArmOp::I64RemS {
9833 rdlo,
9834 rdhi,
9835 rnlo,
9836 rnhi,
9837 rmlo,
9838 rmhi,
9839 },
9840 }
9841 };
9842 for which in 0..4u8 {
9843 let code = encoder.encode(&mk(which)).unwrap();
9844 let guard: Vec<u16> = code[26..34]
9846 .chunks(2)
9847 .map(|c| u16::from_le_bytes([c[0], c[1]]))
9848 .collect();
9849 assert_eq!(
9850 guard,
9851 vec![0xEA52, 0x0C03, 0xD100, 0xDE00],
9852 "ORRS R12,R2,R3; BNE +0; UDF #0"
9853 );
9854 let tail: Vec<u16> = code[code.len() - 12..]
9856 .chunks(2)
9857 .map(|c| u16::from_le_bytes([c[0], c[1]]))
9858 .collect();
9859 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
9860 }
9861 }
9862
9863 #[test]
9866 fn test_610_i64_divu_rd_in_r0_r1_skips_restore() {
9867 let encoder = ArmEncoder::new_thumb2();
9868 let code = encoder
9869 .encode(&ArmOp::I64DivU {
9870 rdlo: Reg::R0,
9871 rdhi: Reg::R1,
9872 rnlo: Reg::R0,
9873 rnhi: Reg::R1,
9874 rmlo: Reg::R2,
9875 rmhi: Reg::R3,
9876 })
9877 .unwrap();
9878 let tail: Vec<u16> = code[code.len() - 12..]
9879 .chunks(2)
9880 .map(|c| u16::from_le_bytes([c[0], c[1]]))
9881 .collect();
9882 assert_eq!(tail, vec![0x4609, 0x4600, 0xB001, 0xB001, 0xBC04, 0xBC08]);
9885 }
9886
9887 #[test]
9891 fn test_610_i64_swapped_rd_pair_rejected() {
9892 let encoder = ArmEncoder::new_thumb2();
9893 let result = encoder.encode(&ArmOp::I64RemU {
9894 rdlo: Reg::R1,
9895 rdhi: Reg::R0,
9896 rnlo: Reg::R2,
9897 rnhi: Reg::R3,
9898 rmlo: Reg::R4,
9899 rmhi: Reg::R5,
9900 });
9901 assert!(result.is_err(), "swapped rd pair must be rejected loudly");
9902 }
9903
9904 #[test]
9905 fn test_encode_nop_thumb2() {
9906 let encoder = ArmEncoder::new_thumb2();
9907 let op = ArmOp::Nop;
9908 let code = encoder.encode(&op).unwrap();
9909 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]);
9913 }
9914
9915 #[test]
9920 fn test_encode_i64_add_thumb2() {
9921 let encoder = ArmEncoder::new_thumb2();
9922 let op = ArmOp::I64Add {
9923 rdlo: Reg::R0,
9924 rdhi: Reg::R1,
9925 rnlo: Reg::R0,
9926 rnhi: Reg::R1,
9927 rmlo: Reg::R2,
9928 rmhi: Reg::R3,
9929 };
9930 let code = encoder.encode(&op).unwrap();
9931 assert_eq!(code.len(), 6, "I64Add should be 6 bytes (ADDS + ADC.W)");
9933 }
9934
9935 #[test]
9936 fn test_encode_i64_sub_thumb2() {
9937 let encoder = ArmEncoder::new_thumb2();
9938 let op = ArmOp::I64Sub {
9939 rdlo: Reg::R0,
9940 rdhi: Reg::R1,
9941 rnlo: Reg::R0,
9942 rnhi: Reg::R1,
9943 rmlo: Reg::R2,
9944 rmhi: Reg::R3,
9945 };
9946 let code = encoder.encode(&op).unwrap();
9947 assert_eq!(code.len(), 6, "I64Sub should be 6 bytes (SUBS + SBC.W)");
9949 }
9950
9951 #[test]
9952 fn test_encode_i64_and_thumb2() {
9953 let encoder = ArmEncoder::new_thumb2();
9954 let op = ArmOp::I64And {
9955 rdlo: Reg::R0,
9956 rdhi: Reg::R1,
9957 rnlo: Reg::R0,
9958 rnhi: Reg::R1,
9959 rmlo: Reg::R2,
9960 rmhi: Reg::R3,
9961 };
9962 let code = encoder.encode(&op).unwrap();
9963 assert!(code.len() >= 4, "I64And should emit at least 4 bytes");
9965 }
9966
9967 #[test]
9968 fn test_encode_i64_or_thumb2() {
9969 let encoder = ArmEncoder::new_thumb2();
9970 let op = ArmOp::I64Or {
9971 rdlo: Reg::R0,
9972 rdhi: Reg::R1,
9973 rnlo: Reg::R0,
9974 rnhi: Reg::R1,
9975 rmlo: Reg::R2,
9976 rmhi: Reg::R3,
9977 };
9978 let code = encoder.encode(&op).unwrap();
9979 assert!(code.len() >= 4, "I64Or should emit at least 4 bytes");
9980 }
9981
9982 #[test]
9983 fn test_encode_i64_xor_thumb2() {
9984 let encoder = ArmEncoder::new_thumb2();
9985 let op = ArmOp::I64Xor {
9986 rdlo: Reg::R0,
9987 rdhi: Reg::R1,
9988 rnlo: Reg::R0,
9989 rnhi: Reg::R1,
9990 rmlo: Reg::R2,
9991 rmhi: Reg::R3,
9992 };
9993 let code = encoder.encode(&op).unwrap();
9994 assert!(code.len() >= 4, "I64Xor should emit at least 4 bytes");
9995 }
9996
9997 #[test]
9998 fn test_encode_i64_const_small_thumb2() {
9999 let encoder = ArmEncoder::new_thumb2();
10000 let op = ArmOp::I64Const {
10002 rdlo: Reg::R0,
10003 rdhi: Reg::R1,
10004 value: 42,
10005 };
10006 let code = encoder.encode(&op).unwrap();
10007 assert!(code.len() >= 8, "I64Const should emit at least 8 bytes");
10009 }
10010
10011 #[test]
10012 fn test_encode_i64_const_large_thumb2() {
10013 let encoder = ArmEncoder::new_thumb2();
10014 let op = ArmOp::I64Const {
10016 rdlo: Reg::R0,
10017 rdhi: Reg::R1,
10018 value: 0x1234_5678_9ABC_DEF0_u64 as i64,
10019 };
10020 let code = encoder.encode(&op).unwrap();
10021 assert_eq!(
10023 code.len(),
10024 16,
10025 "I64Const with large value should be 16 bytes"
10026 );
10027 }
10028
10029 #[test]
10030 fn test_encode_i64_extend_i32_s_thumb2() {
10031 let encoder = ArmEncoder::new_thumb2();
10032 let op = ArmOp::I64ExtendI32S {
10033 rdlo: Reg::R0,
10034 rdhi: Reg::R1,
10035 rn: Reg::R0,
10036 };
10037 let code = encoder.encode(&op).unwrap();
10038 assert_eq!(
10040 code.len(),
10041 4,
10042 "I64ExtendI32S (same reg) should be 4 bytes (ASR only)"
10043 );
10044 }
10045
10046 #[test]
10047 fn test_encode_i64_extend_i32_s_diff_reg_thumb2() {
10048 let encoder = ArmEncoder::new_thumb2();
10049 let op = ArmOp::I64ExtendI32S {
10050 rdlo: Reg::R0,
10051 rdhi: Reg::R1,
10052 rn: Reg::R2,
10053 };
10054 let code = encoder.encode(&op).unwrap();
10055 assert!(
10057 code.len() >= 6,
10058 "I64ExtendI32S (diff reg) should be at least 6 bytes"
10059 );
10060 }
10061
10062 #[test]
10063 fn test_encode_i64_extend_i32_u_thumb2() {
10064 let encoder = ArmEncoder::new_thumb2();
10065 let op = ArmOp::I64ExtendI32U {
10066 rdlo: Reg::R0,
10067 rdhi: Reg::R1,
10068 rn: Reg::R0,
10069 };
10070 let code = encoder.encode(&op).unwrap();
10071 assert_eq!(
10073 code.len(),
10074 2,
10075 "I64ExtendI32U (same reg) should be 2 bytes (MOV #0 only)"
10076 );
10077 }
10078
10079 #[test]
10080 fn test_encode_i32_wrap_i64_nop_thumb2() {
10081 let encoder = ArmEncoder::new_thumb2();
10082 let op = ArmOp::I32WrapI64 {
10084 rd: Reg::R0,
10085 rnlo: Reg::R0,
10086 };
10087 let code = encoder.encode(&op).unwrap();
10088 assert_eq!(code.len(), 2, "I32WrapI64 same reg should be NOP (2 bytes)");
10089 assert_eq!(code, vec![0x00, 0xBF]); }
10091
10092 #[test]
10093 fn test_encode_i32_wrap_i64_diff_reg_thumb2() {
10094 let encoder = ArmEncoder::new_thumb2();
10095 let op = ArmOp::I32WrapI64 {
10096 rd: Reg::R2,
10097 rnlo: Reg::R0,
10098 };
10099 let code = encoder.encode(&op).unwrap();
10100 assert!(
10102 code.len() >= 2,
10103 "I32WrapI64 diff reg should emit at least 2 bytes"
10104 );
10105 }
10106
10107 #[test]
10108 fn test_encode_i64_eqz_thumb2() {
10109 let encoder = ArmEncoder::new_thumb2();
10110 let op = ArmOp::I64Eqz {
10111 rd: Reg::R0,
10112 rnlo: Reg::R0,
10113 rnhi: Reg::R1,
10114 };
10115 let code = encoder.encode(&op).unwrap();
10116 assert!(
10118 code.len() >= 6,
10119 "I64Eqz should emit at least 6 bytes for ORR+ITE+MOV+MOV"
10120 );
10121 }
10122
10123 #[test]
10124 fn test_encode_i64_eq_thumb2() {
10125 let encoder = ArmEncoder::new_thumb2();
10126 let op = ArmOp::I64Eq {
10127 rd: Reg::R0,
10128 rnlo: Reg::R0,
10129 rnhi: Reg::R1,
10130 rmlo: Reg::R2,
10131 rmhi: Reg::R3,
10132 };
10133 let code = encoder.encode(&op).unwrap();
10134 assert!(code.len() >= 10, "I64Eq should emit at least 10 bytes");
10136 }
10137
10138 #[test]
10139 fn test_encode_i64_ldr_thumb2() {
10140 let encoder = ArmEncoder::new_thumb2();
10141 let op = ArmOp::I64Ldr {
10142 rdlo: Reg::R0,
10143 rdhi: Reg::R1,
10144 addr: MemAddr::imm(Reg::SP, 0),
10145 };
10146 let code = encoder.encode(&op).unwrap();
10147 assert!(code.len() >= 4, "I64Ldr should emit at least 4 bytes");
10149 }
10150
10151 #[test]
10152 fn test_372_i64_ldr_indexed_materializes_address() {
10153 let encoder = ArmEncoder::new_thumb2();
10158 let indexed = encoder
10159 .encode(&ArmOp::I64Ldr {
10160 rdlo: Reg::R0,
10161 rdhi: Reg::R1,
10162 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 0),
10163 })
10164 .unwrap();
10165 assert_eq!(
10167 &indexed[0..4],
10168 &[0x0b, 0xeb, 0x00, 0x0c],
10169 "indexed I64Ldr must start with ADD.W ip, base, index"
10170 );
10171 let frame = encoder
10172 .encode(&ArmOp::I64Ldr {
10173 rdlo: Reg::R0,
10174 rdhi: Reg::R1,
10175 addr: MemAddr::imm(Reg::SP, 8),
10176 })
10177 .unwrap();
10178 assert_ne!(
10180 &frame[0..2],
10181 &[0x0b, 0xeb],
10182 "frame (non-indexed) I64Ldr must NOT emit an ADD.W"
10183 );
10184 }
10185
10186 #[test]
10187 fn test_382_i64_ldst_large_offset_materializes_not_skips() {
10188 let encoder = ArmEncoder::new_thumb2();
10194 let ld = encoder
10197 .encode(&ArmOp::I64Ldr {
10198 rdlo: Reg::R0,
10199 rdhi: Reg::R1,
10200 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
10201 })
10202 .expect("large-offset i64.load must lower, not skip");
10203 assert_eq!(ld.len(), 20, "expected MOVW + 2×ADD + 2×LDR");
10205 assert_ne!(
10208 &ld[0..2],
10209 &[0x0b, 0xeb],
10210 "must materialize the large offset"
10211 );
10212 assert_eq!(
10214 &ld[4..20],
10215 &[
10216 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xdc, 0xf8, 0x00, 0x00, 0xdc, 0xf8, 0x04, 0x10, ],
10221 "large-offset i64.load must fold offset into ip and access [ip,#0]/[ip,#4]"
10222 );
10223
10224 let st = encoder
10226 .encode(&ArmOp::I64Str {
10227 rdlo: Reg::R2,
10228 rdhi: Reg::R3,
10229 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
10230 })
10231 .expect("large-offset i64.store must lower, not skip");
10232 assert_eq!(st.len(), 20);
10233 assert_eq!(
10234 &st[4..20],
10235 &[
10236 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xcc, 0xf8, 0x00, 0x20, 0xcc, 0xf8, 0x04, 0x30, ],
10241 "large-offset i64.store must fold offset into ip and access [ip,#0]/[ip,#4]"
10242 );
10243
10244 let small = encoder
10248 .encode(&ArmOp::I64Ldr {
10249 rdlo: Reg::R0,
10250 rdhi: Reg::R1,
10251 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 8),
10252 })
10253 .unwrap();
10254 assert_eq!(
10255 &small[0..4],
10256 &[0x0b, 0xeb, 0x00, 0x0c],
10257 "small-offset indexed i64 must keep the single ADD.W ip, fp, r0"
10258 );
10259 assert_eq!(small.len(), 12, "ADD.W + 2×LDR.W (offset folded in imm12)");
10260 }
10261
10262 #[test]
10263 fn test_encode_i64_str_thumb2() {
10264 let encoder = ArmEncoder::new_thumb2();
10265 let op = ArmOp::I64Str {
10266 rdlo: Reg::R0,
10267 rdhi: Reg::R1,
10268 addr: MemAddr::imm(Reg::SP, 0),
10269 };
10270 let code = encoder.encode(&op).unwrap();
10271 assert!(code.len() >= 4, "I64Str should emit at least 4 bytes");
10273 }
10274
10275 #[test]
10276 fn test_encode_i64_all_comparisons_thumb2() {
10277 let encoder = ArmEncoder::new_thumb2();
10278
10279 let ops = vec![
10280 ArmOp::I64Ne {
10281 rd: Reg::R0,
10282 rnlo: Reg::R0,
10283 rnhi: Reg::R1,
10284 rmlo: Reg::R2,
10285 rmhi: Reg::R3,
10286 },
10287 ArmOp::I64LtS {
10288 rd: Reg::R0,
10289 rnlo: Reg::R0,
10290 rnhi: Reg::R1,
10291 rmlo: Reg::R2,
10292 rmhi: Reg::R3,
10293 },
10294 ArmOp::I64LtU {
10295 rd: Reg::R0,
10296 rnlo: Reg::R0,
10297 rnhi: Reg::R1,
10298 rmlo: Reg::R2,
10299 rmhi: Reg::R3,
10300 },
10301 ArmOp::I64LeS {
10302 rd: Reg::R0,
10303 rnlo: Reg::R0,
10304 rnhi: Reg::R1,
10305 rmlo: Reg::R2,
10306 rmhi: Reg::R3,
10307 },
10308 ArmOp::I64LeU {
10309 rd: Reg::R0,
10310 rnlo: Reg::R0,
10311 rnhi: Reg::R1,
10312 rmlo: Reg::R2,
10313 rmhi: Reg::R3,
10314 },
10315 ArmOp::I64GtS {
10316 rd: Reg::R0,
10317 rnlo: Reg::R0,
10318 rnhi: Reg::R1,
10319 rmlo: Reg::R2,
10320 rmhi: Reg::R3,
10321 },
10322 ArmOp::I64GtU {
10323 rd: Reg::R0,
10324 rnlo: Reg::R0,
10325 rnhi: Reg::R1,
10326 rmlo: Reg::R2,
10327 rmhi: Reg::R3,
10328 },
10329 ArmOp::I64GeS {
10330 rd: Reg::R0,
10331 rnlo: Reg::R0,
10332 rnhi: Reg::R1,
10333 rmlo: Reg::R2,
10334 rmhi: Reg::R3,
10335 },
10336 ArmOp::I64GeU {
10337 rd: Reg::R0,
10338 rnlo: Reg::R0,
10339 rnhi: Reg::R1,
10340 rmlo: Reg::R2,
10341 rmhi: Reg::R3,
10342 },
10343 ];
10344
10345 for op in &ops {
10346 let code = encoder.encode(op).unwrap();
10347 assert!(
10348 code.len() >= 8,
10349 "i64 comparison {:?} should emit at least 8 bytes, got {}",
10350 op,
10351 code.len()
10352 );
10353 }
10354 }
10355
10356 #[test]
10357 fn test_encode_i64_const_zero_thumb2() {
10358 let encoder = ArmEncoder::new_thumb2();
10359 let op = ArmOp::I64Const {
10360 rdlo: Reg::R0,
10361 rdhi: Reg::R1,
10362 value: 0,
10363 };
10364 let code = encoder.encode(&op).unwrap();
10365 assert_eq!(code.len(), 8, "I64Const(0) should be 8 bytes");
10367 }
10368
10369 #[test]
10370 fn test_encode_i64_const_negative_one_thumb2() {
10371 let encoder = ArmEncoder::new_thumb2();
10372 let op = ArmOp::I64Const {
10373 rdlo: Reg::R0,
10374 rdhi: Reg::R1,
10375 value: -1, };
10377 let code = encoder.encode(&op).unwrap();
10378 assert_eq!(code.len(), 16, "I64Const(-1) should be 16 bytes");
10380 }
10381
10382 #[test]
10387 fn test_encode_ldrb_arm32() {
10388 let encoder = ArmEncoder::new_arm32();
10389 let op = ArmOp::Ldrb {
10390 rd: Reg::R0,
10391 addr: MemAddr::imm(Reg::R1, 4),
10392 };
10393 let code = encoder.encode(&op).unwrap();
10394 assert_eq!(code.len(), 4, "ARM32 LDRB should be 4 bytes");
10395 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10397 assert_eq!(encoded, 0xE5D10004, "Should encode LDRB R0, [R1, #4]");
10398 }
10399
10400 #[test]
10401 fn test_encode_strb_arm32() {
10402 let encoder = ArmEncoder::new_arm32();
10403 let op = ArmOp::Strb {
10404 rd: Reg::R0,
10405 addr: MemAddr::imm(Reg::R1, 0),
10406 };
10407 let code = encoder.encode(&op).unwrap();
10408 assert_eq!(code.len(), 4, "ARM32 STRB should be 4 bytes");
10409 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10411 assert_eq!(encoded, 0xE5C10000, "Should encode STRB R0, [R1, #0]");
10412 }
10413
10414 #[test]
10415 fn test_encode_ldrh_arm32() {
10416 let encoder = ArmEncoder::new_arm32();
10417 let op = ArmOp::Ldrh {
10418 rd: Reg::R0,
10419 addr: MemAddr::imm(Reg::R1, 2),
10420 };
10421 let code = encoder.encode(&op).unwrap();
10422 assert_eq!(code.len(), 4, "ARM32 LDRH should be 4 bytes");
10423 }
10424
10425 #[test]
10426 fn test_encode_strh_arm32() {
10427 let encoder = ArmEncoder::new_arm32();
10428 let op = ArmOp::Strh {
10429 rd: Reg::R0,
10430 addr: MemAddr::imm(Reg::R1, 0),
10431 };
10432 let code = encoder.encode(&op).unwrap();
10433 assert_eq!(code.len(), 4, "ARM32 STRH should be 4 bytes");
10434 }
10435
10436 #[test]
10437 fn test_encode_ldrsb_arm32() {
10438 let encoder = ArmEncoder::new_arm32();
10439 let op = ArmOp::Ldrsb {
10440 rd: Reg::R0,
10441 addr: MemAddr::imm(Reg::R1, 0),
10442 };
10443 let code = encoder.encode(&op).unwrap();
10444 assert_eq!(code.len(), 4, "ARM32 LDRSB should be 4 bytes");
10445 }
10446
10447 #[test]
10448 fn test_encode_ldrsh_arm32() {
10449 let encoder = ArmEncoder::new_arm32();
10450 let op = ArmOp::Ldrsh {
10451 rd: Reg::R0,
10452 addr: MemAddr::imm(Reg::R1, 0),
10453 };
10454 let code = encoder.encode(&op).unwrap();
10455 assert_eq!(code.len(), 4, "ARM32 LDRSH should be 4 bytes");
10456 }
10457
10458 #[test]
10459 fn test_encode_ldrb_thumb2_16bit() {
10460 let encoder = ArmEncoder::new_thumb2();
10461 let op = ArmOp::Ldrb {
10462 rd: Reg::R0,
10463 addr: MemAddr::imm(Reg::R1, 4),
10464 };
10465 let code = encoder.encode(&op).unwrap();
10466 assert_eq!(
10468 code.len(),
10469 2,
10470 "Thumb-2 LDRB with small offset should be 16-bit"
10471 );
10472 }
10473
10474 #[test]
10475 fn test_encode_ldrb_thumb2_32bit() {
10476 let encoder = ArmEncoder::new_thumb2();
10477 let op = ArmOp::Ldrb {
10478 rd: Reg::R0,
10479 addr: MemAddr::imm(Reg::R1, 100), };
10481 let code = encoder.encode(&op).unwrap();
10482 assert_eq!(
10483 code.len(),
10484 4,
10485 "Thumb-2 LDRB with large offset should be 32-bit"
10486 );
10487 }
10488
10489 #[test]
10490 fn test_encode_strb_thumb2_16bit() {
10491 let encoder = ArmEncoder::new_thumb2();
10492 let op = ArmOp::Strb {
10493 rd: Reg::R0,
10494 addr: MemAddr::imm(Reg::R1, 10),
10495 };
10496 let code = encoder.encode(&op).unwrap();
10497 assert_eq!(
10498 code.len(),
10499 2,
10500 "Thumb-2 STRB with small offset should be 16-bit"
10501 );
10502 }
10503
10504 #[test]
10505 fn test_encode_ldrh_thumb2_16bit() {
10506 let encoder = ArmEncoder::new_thumb2();
10507 let op = ArmOp::Ldrh {
10508 rd: Reg::R0,
10509 addr: MemAddr::imm(Reg::R1, 4), };
10511 let code = encoder.encode(&op).unwrap();
10512 assert_eq!(
10513 code.len(),
10514 2,
10515 "Thumb-2 LDRH with small aligned offset should be 16-bit"
10516 );
10517 }
10518
10519 #[test]
10520 fn test_encode_strh_thumb2_16bit() {
10521 let encoder = ArmEncoder::new_thumb2();
10522 let op = ArmOp::Strh {
10523 rd: Reg::R0,
10524 addr: MemAddr::imm(Reg::R1, 4),
10525 };
10526 let code = encoder.encode(&op).unwrap();
10527 assert_eq!(
10528 code.len(),
10529 2,
10530 "Thumb-2 STRH with small aligned offset should be 16-bit"
10531 );
10532 }
10533
10534 #[test]
10535 fn test_encode_ldrsb_thumb2() {
10536 let encoder = ArmEncoder::new_thumb2();
10537 let op = ArmOp::Ldrsb {
10538 rd: Reg::R0,
10539 addr: MemAddr::imm(Reg::R1, 0),
10540 };
10541 let code = encoder.encode(&op).unwrap();
10542 assert_eq!(code.len(), 4, "Thumb-2 LDRSB should be 32-bit");
10544 }
10545
10546 #[test]
10547 fn test_encode_ldrsh_thumb2() {
10548 let encoder = ArmEncoder::new_thumb2();
10549 let op = ArmOp::Ldrsh {
10550 rd: Reg::R0,
10551 addr: MemAddr::imm(Reg::R1, 0),
10552 };
10553 let code = encoder.encode(&op).unwrap();
10554 assert_eq!(code.len(), 4, "Thumb-2 LDRSH should be 32-bit");
10555 }
10556
10557 #[test]
10558 fn test_encode_memory_size_thumb2() {
10559 let encoder = ArmEncoder::new_thumb2();
10560 let op = ArmOp::MemorySize { rd: Reg::R0 };
10561 let code = encoder.encode(&op).unwrap();
10562 assert!(!code.is_empty(), "MemorySize should produce code");
10564 }
10565
10566 #[test]
10567 fn test_encode_memory_grow_thumb2() {
10568 let encoder = ArmEncoder::new_thumb2();
10569 let op = ArmOp::MemoryGrow {
10570 rd: Reg::R0,
10571 rn: Reg::R0,
10572 };
10573 let code = encoder.encode(&op).unwrap();
10574 assert_eq!(code.len(), 4, "MemoryGrow (MVN) should be 32-bit Thumb-2");
10575 }
10576
10577 #[test]
10578 fn test_encode_subword_reg_offset_thumb2() {
10579 let encoder = ArmEncoder::new_thumb2();
10580
10581 let op = ArmOp::Ldrb {
10583 rd: Reg::R0,
10584 addr: MemAddr::reg(Reg::R1, Reg::R2),
10585 };
10586 let code = encoder.encode(&op).unwrap();
10587 assert_eq!(
10588 code.len(),
10589 4,
10590 "Thumb-2 LDRB with reg offset should be 32-bit"
10591 );
10592
10593 let op = ArmOp::Strb {
10595 rd: Reg::R0,
10596 addr: MemAddr::reg(Reg::R1, Reg::R2),
10597 };
10598 let code = encoder.encode(&op).unwrap();
10599 assert_eq!(
10600 code.len(),
10601 4,
10602 "Thumb-2 STRB with reg offset should be 32-bit"
10603 );
10604
10605 let op = ArmOp::Ldrh {
10607 rd: Reg::R0,
10608 addr: MemAddr::reg(Reg::R1, Reg::R2),
10609 };
10610 let code = encoder.encode(&op).unwrap();
10611 assert_eq!(
10612 code.len(),
10613 4,
10614 "Thumb-2 LDRH with reg offset should be 32-bit"
10615 );
10616
10617 let op = ArmOp::Strh {
10619 rd: Reg::R0,
10620 addr: MemAddr::reg(Reg::R1, Reg::R2),
10621 };
10622 let code = encoder.encode(&op).unwrap();
10623 assert_eq!(
10624 code.len(),
10625 4,
10626 "Thumb-2 STRH with reg offset should be 32-bit"
10627 );
10628 }
10629
10630 #[test]
10631 fn test_encode_subword_reg_imm_offset_thumb2() {
10632 let encoder = ArmEncoder::new_thumb2();
10633
10634 let op = ArmOp::Ldrb {
10636 rd: Reg::R0,
10637 addr: MemAddr::reg_imm(Reg::R1, Reg::R2, 4),
10638 };
10639 let code = encoder.encode(&op).unwrap();
10640 assert_eq!(
10642 code.len(),
10643 8,
10644 "Thumb-2 LDRB with reg+imm offset should be 8 bytes"
10645 );
10646 }
10647
10648 #[test]
10653 fn test_encode_mve_addi32_thumb2() {
10654 let encoder = ArmEncoder::new_thumb2();
10655 let op = ArmOp::MveAddI {
10656 qd: QReg::Q0,
10657 qn: QReg::Q1,
10658 qm: QReg::Q2,
10659 size: MveSize::S32,
10660 };
10661 let code = encoder.encode(&op).unwrap();
10662 assert_eq!(
10663 code.len(),
10664 4,
10665 "MVE VADD.I32 should be 4 bytes (Thumb-2 32-bit)"
10666 );
10667 }
10668
10669 #[test]
10670 fn test_encode_mve_subi16_thumb2() {
10671 let encoder = ArmEncoder::new_thumb2();
10672 let op = ArmOp::MveSubI {
10673 qd: QReg::Q0,
10674 qn: QReg::Q1,
10675 qm: QReg::Q2,
10676 size: MveSize::S16,
10677 };
10678 let code = encoder.encode(&op).unwrap();
10679 assert_eq!(code.len(), 4, "MVE VSUB.I16 should be 4 bytes");
10680 }
10681
10682 #[test]
10683 fn test_encode_mve_muli8_thumb2() {
10684 let encoder = ArmEncoder::new_thumb2();
10685 let op = ArmOp::MveMulI {
10686 qd: QReg::Q0,
10687 qn: QReg::Q1,
10688 qm: QReg::Q2,
10689 size: MveSize::S8,
10690 };
10691 let code = encoder.encode(&op).unwrap();
10692 assert_eq!(code.len(), 4, "MVE VMUL.I8 should be 4 bytes");
10693 }
10694
10695 #[test]
10696 fn test_encode_mve_bitwise_thumb2() {
10697 let encoder = ArmEncoder::new_thumb2();
10698
10699 let ops = vec![
10700 ArmOp::MveAnd {
10701 qd: QReg::Q0,
10702 qn: QReg::Q1,
10703 qm: QReg::Q2,
10704 },
10705 ArmOp::MveOrr {
10706 qd: QReg::Q0,
10707 qn: QReg::Q1,
10708 qm: QReg::Q2,
10709 },
10710 ArmOp::MveEor {
10711 qd: QReg::Q0,
10712 qn: QReg::Q1,
10713 qm: QReg::Q2,
10714 },
10715 ArmOp::MveBic {
10716 qd: QReg::Q0,
10717 qn: QReg::Q1,
10718 qm: QReg::Q2,
10719 },
10720 ];
10721 for op in ops {
10722 let code = encoder.encode(&op).unwrap();
10723 assert_eq!(code.len(), 4, "MVE bitwise op should be 4 bytes");
10724 }
10725 }
10726
10727 #[test]
10728 fn test_encode_mve_mvn_thumb2() {
10729 let encoder = ArmEncoder::new_thumb2();
10730 let op = ArmOp::MveMvn {
10731 qd: QReg::Q0,
10732 qm: QReg::Q1,
10733 };
10734 let code = encoder.encode(&op).unwrap();
10735 assert_eq!(code.len(), 4, "MVE VMVN should be 4 bytes");
10736 }
10737
10738 #[test]
10739 fn test_encode_mve_load_store_thumb2() {
10740 let encoder = ArmEncoder::new_thumb2();
10741
10742 let load = ArmOp::MveLoad {
10743 qd: QReg::Q0,
10744 addr: MemAddr::imm(Reg::R0, 16),
10745 };
10746 let code = encoder.encode(&load).unwrap();
10747 assert_eq!(code.len(), 4, "MVE VLDRW.32 should be 4 bytes");
10748
10749 let store = ArmOp::MveStore {
10750 qd: QReg::Q1,
10751 addr: MemAddr::imm(Reg::R1, 0),
10752 };
10753 let code = encoder.encode(&store).unwrap();
10754 assert_eq!(code.len(), 4, "MVE VSTRW.32 should be 4 bytes");
10755 }
10756
10757 #[test]
10758 fn test_encode_mve_const_thumb2() {
10759 let encoder = ArmEncoder::new_thumb2();
10760 let op = ArmOp::MveConst {
10761 qd: QReg::Q0,
10762 bytes: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0],
10763 };
10764 let code = encoder.encode(&op).unwrap();
10765 assert!(
10768 code.len() >= 24,
10769 "MVE const should produce multiple instructions"
10770 );
10771 }
10772
10773 #[test]
10774 fn test_encode_mve_dup_thumb2() {
10775 let encoder = ArmEncoder::new_thumb2();
10776 let op = ArmOp::MveDup {
10777 qd: QReg::Q0,
10778 rn: Reg::R0,
10779 size: MveSize::S32,
10780 };
10781 let code = encoder.encode(&op).unwrap();
10782 assert_eq!(code.len(), 4, "MVE VDUP.32 should be 4 bytes");
10783 }
10784
10785 #[test]
10786 fn test_encode_mve_extract_lane_thumb2() {
10787 let encoder = ArmEncoder::new_thumb2();
10788 let op = ArmOp::MveExtractLane {
10789 rd: Reg::R0,
10790 qn: QReg::Q1,
10791 lane: 2,
10792 size: MveSize::S32,
10793 };
10794 let code = encoder.encode(&op).unwrap();
10795 assert_eq!(code.len(), 4, "MVE extract lane should be 4 bytes");
10796 }
10797
10798 #[test]
10799 fn test_encode_mve_insert_lane_thumb2() {
10800 let encoder = ArmEncoder::new_thumb2();
10801 let op = ArmOp::MveInsertLane {
10802 qd: QReg::Q0,
10803 rn: Reg::R1,
10804 lane: 3,
10805 size: MveSize::S32,
10806 };
10807 let code = encoder.encode(&op).unwrap();
10808 assert_eq!(code.len(), 4, "MVE insert lane should be 4 bytes");
10809 }
10810
10811 #[test]
10812 fn test_encode_mve_addf32_thumb2() {
10813 let encoder = ArmEncoder::new_thumb2();
10814 let op = ArmOp::MveAddF32 {
10815 qd: QReg::Q0,
10816 qn: QReg::Q1,
10817 qm: QReg::Q2,
10818 };
10819 let code = encoder.encode(&op).unwrap();
10820 assert_eq!(code.len(), 4, "MVE VADD.F32 should be 4 bytes");
10821 }
10822
10823 #[test]
10824 fn test_encode_mve_divf32_thumb2() {
10825 let encoder = ArmEncoder::new_thumb2();
10826 let op = ArmOp::MveDivF32 {
10827 qd: QReg::Q0,
10828 qn: QReg::Q1,
10829 qm: QReg::Q2,
10830 };
10831 let code = encoder.encode(&op).unwrap();
10832 assert_eq!(
10834 code.len(),
10835 16,
10836 "MVE VDIV.F32 (lane-wise) should be 16 bytes"
10837 );
10838 }
10839
10840 #[test]
10841 fn test_encode_mve_sqrtf32_thumb2() {
10842 let encoder = ArmEncoder::new_thumb2();
10843 let op = ArmOp::MveSqrtF32 {
10844 qd: QReg::Q0,
10845 qm: QReg::Q1,
10846 };
10847 let code = encoder.encode(&op).unwrap();
10848 assert_eq!(
10850 code.len(),
10851 16,
10852 "MVE VSQRT.F32 (lane-wise) should be 16 bytes"
10853 );
10854 }
10855
10856 #[test]
10857 fn test_encode_mve_negf32_thumb2() {
10858 let encoder = ArmEncoder::new_thumb2();
10859 let op = ArmOp::MveNegF32 {
10860 qd: QReg::Q0,
10861 qm: QReg::Q1,
10862 };
10863 let code = encoder.encode(&op).unwrap();
10864 assert_eq!(code.len(), 4, "MVE VNEG.F32 should be 4 bytes");
10865 }
10866
10867 #[test]
10868 fn test_encode_mve_absf32_thumb2() {
10869 let encoder = ArmEncoder::new_thumb2();
10870 let op = ArmOp::MveAbsF32 {
10871 qd: QReg::Q0,
10872 qm: QReg::Q1,
10873 };
10874 let code = encoder.encode(&op).unwrap();
10875 assert_eq!(code.len(), 4, "MVE VABS.F32 should be 4 bytes");
10876 }
10877
10878 #[test]
10893 fn and_immediate_encodes_correctly_in_byte_range_documents_fold_bound() {
10894 let encoder = ArmEncoder::new_thumb2();
10895 let op = ArmOp::And {
10896 rd: Reg::R2,
10897 rn: Reg::R0,
10898 op2: Operand2::Imm(0x7e),
10899 };
10900 let code = encoder.encode(&op).unwrap();
10901 assert_eq!(
10902 code,
10903 vec![0x00, 0xf0, 0x7e, 0x02],
10904 "and r2, r0, #0x7e must encode to the canonical AND.W T1 (imm8=0x7e)"
10905 );
10906 }
10907
10908 #[test]
10915 fn try_thumb_expand_imm_encodes_modified_immediates() {
10916 assert_eq!(try_thumb_expand_imm(0x7e), Some(0x07e)); assert_eq!(try_thumb_expand_imm(0xff), Some(0x0ff));
10918 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);
10926 assert_eq!(try_thumb_expand_imm(0x12345), None);
10927 }
10928
10929 #[test]
10934 fn cmp_adds_subs_immediate_error_on_non_modified_imm() {
10935 let encoder = ArmEncoder::new_thumb2();
10936 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 0xff).is_ok());
10938 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 1000).is_ok());
10939 assert!(
10941 encoder.encode_thumb32_cmp_imm(&Reg::R0, 0x101).is_err(),
10942 "cmp #0x101 must error, not compare the wrong constant"
10943 );
10944 assert!(
10945 encoder
10946 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x101)
10947 .is_err()
10948 );
10949 assert!(
10950 encoder
10951 .encode_thumb32_subs(&Reg::R0, &Reg::R0, 0x101)
10952 .is_err()
10953 );
10954 assert!(
10956 encoder
10957 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x80)
10958 .is_ok()
10959 );
10960 }
10961
10962 #[test]
10965 fn mla_thumb2_encodes_correctly() {
10966 let encoder = ArmEncoder::new_thumb2();
10967 let code = encoder
10968 .encode(&ArmOp::Mla {
10969 rd: Reg::R2,
10970 rn: Reg::R3,
10971 rm: Reg::R4,
10972 ra: Reg::R8,
10973 })
10974 .unwrap();
10975 assert_eq!(code, vec![0x03, 0xfb, 0x04, 0x82]);
10977 }
10978
10979 #[test]
10984 fn ldst_imm12_offset_errors_when_out_of_range() {
10985 let encoder = ArmEncoder::new_thumb2();
10986 assert!(
10988 encoder
10989 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0xFFF)
10990 .is_ok()
10991 );
10992 assert!(
10994 encoder
10995 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0x1000)
10996 .is_err(),
10997 "ldr offset 4096 must error, not wrap to 0"
10998 );
10999 assert!(
11000 encoder
11001 .encode_thumb32_str(&Reg::R0, &Reg::R1, 0x1000)
11002 .is_err()
11003 );
11004 assert!(
11005 encoder
11006 .encode_thumb32_ldrb_imm(&Reg::R0, &Reg::R1, 5000)
11007 .is_err()
11008 );
11009 assert!(
11010 encoder
11011 .encode_thumb32_strh_imm(&Reg::R0, &Reg::R1, 5000)
11012 .is_err()
11013 );
11014 }
11015
11016 #[test]
11023 fn add_sub_large_immediate_use_addw_subw_not_misencoded() {
11024 let encoder = ArmEncoder::new_thumb2();
11025 assert_eq!(
11027 encoder
11028 .encode(&ArmOp::Add {
11029 rd: Reg::SP,
11030 rn: Reg::SP,
11031 op2: Operand2::Imm(256),
11032 })
11033 .unwrap(),
11034 vec![0x0d, 0xf2, 0x00, 0x1d],
11035 "add sp,sp,#256 must be ADDW (plain imm12), not a mis-encoded ADD.W"
11036 );
11037 assert_eq!(
11039 encoder
11040 .encode(&ArmOp::Sub {
11041 rd: Reg::SP,
11042 rn: Reg::SP,
11043 op2: Operand2::Imm(256),
11044 })
11045 .unwrap(),
11046 vec![0xad, 0xf2, 0x00, 0x1d],
11047 );
11048 assert!(
11050 encoder
11051 .encode(&ArmOp::Add {
11052 rd: Reg::SP,
11053 rn: Reg::SP,
11054 op2: Operand2::Imm(5000),
11055 })
11056 .is_err(),
11057 "add #5000 must error (no single ADDW), not mis-encode"
11058 );
11059 }
11060
11061 #[test]
11066 fn and_cmn_immediate_thumb_expand_else_error() {
11067 let encoder = ArmEncoder::new_thumb2();
11068 assert_eq!(
11070 encoder
11071 .encode(&ArmOp::And {
11072 rd: Reg::R2,
11073 rn: Reg::R0,
11074 op2: Operand2::Imm(0x7e),
11075 })
11076 .unwrap(),
11077 vec![0x00, 0xf0, 0x7e, 0x02],
11078 );
11079 assert!(
11081 encoder
11082 .encode(&ArmOp::And {
11083 rd: Reg::R2,
11084 rn: Reg::R0,
11085 op2: Operand2::Imm(0xff00ff00u32 as i32),
11086 })
11087 .is_ok()
11088 );
11089 assert!(
11091 encoder
11092 .encode(&ArmOp::And {
11093 rd: Reg::R2,
11094 rn: Reg::R0,
11095 op2: Operand2::Imm(0x101),
11096 })
11097 .is_err()
11098 );
11099 assert!(
11100 encoder
11101 .encode(&ArmOp::Cmn {
11102 rn: Reg::R0,
11103 op2: Operand2::Imm(0x101),
11104 })
11105 .is_err(),
11106 "CMN #0x101 must error, not emit a NOP"
11107 );
11108 }
11109
11110 #[test]
11114 fn orr_eor_immediate_encode_in_byte_range_else_error() {
11115 let encoder = ArmEncoder::new_thumb2();
11116 assert_eq!(
11118 encoder
11119 .encode(&ArmOp::Orr {
11120 rd: Reg::R2,
11121 rn: Reg::R0,
11122 op2: Operand2::Imm(0x7e),
11123 })
11124 .unwrap(),
11125 vec![0x40, 0xf0, 0x7e, 0x02],
11126 );
11127 assert_eq!(
11129 encoder
11130 .encode(&ArmOp::Eor {
11131 rd: Reg::R2,
11132 rn: Reg::R0,
11133 op2: Operand2::Imm(0x7e),
11134 })
11135 .unwrap(),
11136 vec![0x80, 0xf0, 0x7e, 0x02],
11137 );
11138 assert!(
11140 encoder
11141 .encode(&ArmOp::Orr {
11142 rd: Reg::R2,
11143 rn: Reg::R0,
11144 op2: Operand2::Imm(0x140),
11145 })
11146 .is_err(),
11147 "ORR #0x140 must error, not emit a NOP"
11148 );
11149 }
11150
11151 #[test]
11152 fn test_encode_mve_different_qregs() {
11153 let encoder = ArmEncoder::new_thumb2();
11154
11155 let op1 = ArmOp::MveAddI {
11157 qd: QReg::Q0,
11158 qn: QReg::Q0,
11159 qm: QReg::Q0,
11160 size: MveSize::S32,
11161 };
11162 let op2 = ArmOp::MveAddI {
11163 qd: QReg::Q3,
11164 qn: QReg::Q5,
11165 qm: QReg::Q7,
11166 size: MveSize::S32,
11167 };
11168 let code1 = encoder.encode(&op1).unwrap();
11169 let code2 = encoder.encode(&op2).unwrap();
11170 assert_ne!(
11171 code1, code2,
11172 "Different Q-registers should produce different encodings"
11173 );
11174 }
11175
11176 #[test]
11177 fn test_encode_mve_arm32_loud_err() {
11178 let encoder = ArmEncoder::new_arm32();
11182 let op = ArmOp::MveAddI {
11183 qd: QReg::Q0,
11184 qn: QReg::Q1,
11185 qm: QReg::Q2,
11186 size: MveSize::S32,
11187 };
11188 let err = encoder
11189 .encode(&op)
11190 .expect_err("ARM32 MVE must be a loud Err, not a silent NOP (#615)");
11191 assert!(
11192 err.to_string().contains("Thumb-2 only"),
11193 "unexpected error message: {err}"
11194 );
11195 }
11196}