1#![allow(clippy::eq_op, clippy::erasing_op, dead_code, unused)]
10use crate::AsmError;
11use crate::aarch64::emit::Handler;
12use crate::aarch64::encoder_tables::{SIZE_OP_MAP, SIZE_OP_TABLE};
13use crate::aarch64::operands::*;
14use crate::aarch64::{Assembler, instdb::*};
15use crate::core::buffer::LabelUse;
16use crate::core::operand::*;
17
18macro_rules! B {
19 ($e: expr) => {
20 1 << $e
21 };
22}
23
24macro_rules! check_signature {
25 ($op0: expr, $op1: expr) => {
26 $op0.signature() == $op1.signature()
27 };
28 ($op0: expr, $op1: expr, $op2: expr) => {
29 $op0.signature() == $op1.signature() && $op1.signature() == $op2.signature()
30 };
31
32 ($op0: expr, $op1: expr, $op2: expr, $op3: expr) => {
33 $op0.signature() == $op1.signature()
34 && $op1.signature() == $op2.signature()
35 && $op2.signature() == $op3.signature()
36 };
37}
38
39pub(crate) struct A64EmitState {
43 pub opcode: Opc,
45 pub offset_format: OffsetFormat,
47 pub offset_value: i64,
49 pub multiple_op_data: [u32; 4],
51 pub multiple_op_count: usize,
53 pub rm_rel: Operand,
56}
57
58impl A64EmitState {
59 pub(crate) fn new() -> Self {
60 Self {
61 opcode: Opc(0),
62 offset_format: OffsetFormat::new(OffsetType::SignedOffset, 0, 0, 0, 0, 0, 0, 0),
63 offset_value: 0,
64 multiple_op_data: [0; 4],
65 multiple_op_count: 0,
66 rm_rel: Operand::new(),
67 }
68 }
69}
70
71impl Assembler<'_> {
72 pub(crate) fn emit_handler(&mut self, handler: Handler, st: &mut A64EmitState) -> bool {
79 match handler {
80 Handler::Op => {
81 self.buffer.write_u32(st.opcode.get());
82 true
83 }
84 Handler::OpDispImm => {
85 self.emit_disp_imm(st);
86 true
87 }
88 Handler::OpRel => self.emit_rel(st),
89 Handler::Multi => {
90 for word in st.multiple_op_data.iter().take(st.multiple_op_count) {
91 self.buffer.write_u32(*word);
92 }
93 true
94 }
95 }
96 }
97
98 fn emit_disp_imm(&mut self, st: &mut A64EmitState) {
102 if (st.offset_value & ((1 << st.offset_format.imm_discard_lsb()) - 1)) != 0 {
103 self.last_error = Some(AsmError::InvalidOperand);
104 return;
105 }
106
107 let disp_imm64 = (st.offset_value as i64) >> st.offset_format.imm_discard_lsb() as i64;
108 let disp_imm32 = (disp_imm64 & ((1 << st.offset_format.imm_bit_count()) - 1)) as u32;
109
110 match st.offset_format.typ() {
111 OffsetType::SignedOffset => {
112 st.opcode
113 .add_imm(disp_imm32 as _, st.offset_format.imm_bit_shift() as _);
114 self.buffer.write_u32(st.opcode.get());
115 }
116
117 _ => {
118 let imm_lo = disp_imm32 & 0x3;
119 let imm_hi = disp_imm32 >> 2;
120 st.opcode.add_imm(imm_lo, 29);
121 st.opcode.add_imm(imm_hi, 5);
122 self.buffer.write_u32(st.opcode.get());
123 }
124 }
125 }
126
127 fn emit_rel(&mut self, st: &mut A64EmitState) -> bool {
131 if st.rm_rel.is_label() || (st.rm_rel.is_mem() && st.rm_rel.as_::<Mem>().has_base_label()) {
132 let label_id;
133 let mut label_offset = 0;
134
135 if st.rm_rel.is_label() {
136 label_id = st.rm_rel.as_::<Label>().id();
137 } else {
138 label_id = st.rm_rel.as_::<Mem>().base_id();
139 label_offset = st.rm_rel.as_::<Mem>().offset();
140 }
141
142 if self.buffer.is_bound(Label::from_id(label_id)) {
143 st.offset_value = self.buffer.label_offset(Label::from_id(label_id)) as i64
144 + label_offset
145 - self.buffer.cur_offset() as i64;
146 self.emit_disp_imm(st);
147 } else {
148 let offset = self.buffer.cur_offset();
149 self.buffer.use_label_at_offset(
150 offset,
151 Label::from_id(label_id),
152 match st.offset_format.typ() {
153 OffsetType::Adrp => LabelUse::A64Adrp21,
154 OffsetType::Adr => LabelUse::A64Adr21,
155 OffsetType::Ldr => LabelUse::A64Ldr19,
156 OffsetType::SignedOffset => {
157 if st.offset_format.imm_bit_count() == 26 {
158 LabelUse::A64Branch26
159 } else if st.offset_format.imm_bit_count() == 19 {
160 LabelUse::A64Branch19
161 } else if st.offset_format.imm_bit_count() == 14 {
162 LabelUse::A64Branch14
163 } else {
164 unreachable!(
165 "SignedOffset label uses only have 26/19/14-bit branch formats"
166 )
167 }
168 }
169 },
170 );
171
172 self.buffer.write_u32(st.opcode.get());
173 }
174
175 return true;
176 }
177
178 if st.rm_rel.is_imm() {
179 let target_offset = st.rm_rel.as_::<Imm>().value() as u64;
180 let mut pc = self.buffer.cur_offset() as u64 + 4;
181 if st.offset_format.typ() == OffsetType::Adrp {
182 pc &= !(4096 - 1);
183 }
184 st.offset_value = target_offset as i64 - pc as i64;
185 self.emit_disp_imm(st);
186 return true;
187 }
188
189 false
190 }
191}
192
193#[derive(Copy, Clone, PartialEq, Eq, Debug)]
194#[repr(transparent)]
195pub(crate) struct Opc(pub(crate) u32);
196
197impl Opc {
198 const N: u32 = 1 << 2;
199 const Q: u32 = 1 << 30;
200 const X: u32 = 1 << 31;
201
202 pub fn reset(&mut self, value: u32) {
203 self.0 = value;
204 }
205
206 pub fn get(&self) -> u32 {
207 self.0
208 }
209
210 pub const fn has_q(&self) -> bool {
211 (self.0 & Self::Q) != 0
212 }
213 pub const fn has_x(&self) -> bool {
214 (self.0 & Self::X) != 0
215 }
216
217 pub fn add_imm(&mut self, value: u32, bit_index: u32) -> &mut Self {
218 self.0 |= value << bit_index;
219 self
220 }
221
222 pub fn xor_imm(&mut self, value: u32, bit_index: u32) -> &mut Self {
223 self.0 ^= value << bit_index;
224 self
225 }
226
227 pub fn add_if(&mut self, condition: bool, value: u32, bit_index: u32) -> &mut Self {
228 if condition {
229 self.0 |= value << bit_index;
230 }
231 self
232 }
233
234 pub fn add_logical_imm(&mut self, logical_imm: &LogicalImm) -> &mut Self {
235 self.add_imm(logical_imm.n, 22)
236 .add_imm(logical_imm.s, 10)
237 .add_imm(logical_imm.r, 16);
238 self
239 }
240
241 pub fn add_reg(&mut self, id: u32, bit_index: u32) -> &mut Self {
242 self.0 |= (id & 31) << bit_index;
243 self
244 }
245}
246
247impl core::ops::BitOr<u32> for Opc {
248 type Output = Self;
249
250 fn bitor(self, rhs: u32) -> Self::Output {
251 Self(self.0 | rhs)
252 }
253}
254
255impl core::ops::BitOrAssign<u32> for Opc {
256 fn bitor_assign(&mut self, rhs: u32) {
257 self.0 |= rhs;
258 }
259}
260
261impl core::ops::BitAnd<u32> for Opc {
262 type Output = Self;
263
264 fn bitand(self, rhs: u32) -> Self::Output {
265 Self(self.0 & rhs)
266 }
267}
268
269impl core::ops::BitAndAssign<u32> for Opc {
270 fn bitand_assign(&mut self, rhs: u32) {
271 self.0 &= rhs;
272 }
273}
274
275impl core::ops::Not for Opc {
276 type Output = Self;
277
278 fn not(self) -> Self::Output {
279 Self(!self.0)
280 }
281}
282
283impl core::ops::BitXor<u32> for Opc {
284 type Output = Self;
285
286 fn bitxor(self, rhs: u32) -> Self::Output {
287 Self(self.0 ^ rhs)
288 }
289}
290
291impl core::ops::BitXorAssign<u32> for Opc {
292 fn bitxor_assign(&mut self, rhs: u32) {
293 self.0 ^= rhs;
294 }
295}
296
297impl core::ops::Shl<u32> for Opc {
298 type Output = Self;
299
300 fn shl(self, rhs: u32) -> Self::Output {
301 Self(self.0 << rhs)
302 }
303}
304
305impl core::ops::ShlAssign<u32> for Opc {
306 fn shl_assign(&mut self, rhs: u32) {
307 self.0 <<= rhs;
308 }
309}
310
311impl core::ops::Shr<u32> for Opc {
312 type Output = Self;
313
314 fn shr(self, rhs: u32) -> Self::Output {
315 Self(self.0 >> rhs)
316 }
317}
318
319impl core::ops::ShrAssign<u32> for Opc {
320 fn shr_assign(&mut self, rhs: u32) {
321 self.0 >>= rhs;
322 }
323}
324
325#[derive(Copy, Clone, PartialEq, Eq, Debug)]
326pub struct LogicalImm {
327 pub n: u32,
328 pub s: u32,
329 pub r: u32,
330}
331
332pub(crate) fn check_gp_type(op: &Operand, allowed: u32) -> bool {
333 let typ = op.as_::<Reg>().typ() as u32;
334 let mask = allowed << RegType::Gp32 as u32;
335 bit_test(mask, typ)
336}
337
338pub(crate) fn check_gp_typex(op: &Operand, allowed: u32, x: &mut u32) -> bool {
339 let typ = op.as_::<Reg>().typ() as u32;
340 *x = typ.wrapping_sub(RegType::Gp32 as u32) & allowed;
341 bit_test(allowed << RegType::Gp32 as u32, typ)
342}
343
344pub(crate) fn check_gp_typex2(o0: &Operand, o1: &Operand, allowed: u32, x: &mut u32) -> bool {
345 check_gp_typex(o0, allowed, x) && check_signature!(o0, o1)
346}
347
348pub(crate) fn check_gp_typex3(
349 o0: &Operand,
350 o1: &Operand,
351 o2: &Operand,
352 allowed: u32,
353 x: &mut u32,
354) -> bool {
355 check_gp_typex(o0, allowed, x) && check_signature!(o0, o1, o2)
356}
357
358pub(crate) fn check_gp_id(op: &Operand, hi_id: u32) -> bool {
359 op.id() < 31 || op.id() == hi_id
360}
361
362pub(crate) fn check_gp_id2(o0: &Operand, o1: &Operand, hi_id: u32) -> bool {
363 let id0 = o0.id();
364 let id1 = o1.id();
365 (id0 < 31 || id0 == hi_id) && (id1 < 31 || id1 == hi_id)
366}
367
368pub(crate) fn check_gp_id3(o0: &Operand, o1: &Operand, o2: &Operand, hi_id: u32) -> bool {
369 let id0 = o0.id();
370 let id1 = o1.id();
371 let id2 = o2.id();
372 (id0 < 31 || id0 == hi_id) && (id1 < 31 || id1 == hi_id) && (id2 < 31 || id2 == hi_id)
373}
374
375pub(crate) fn check_vec_id(o0: &Operand) -> bool {
376 let id = o0.id();
377 id < 31
378}
379
380pub(crate) fn check_vec_id2(o0: &Operand, o1: &Operand) -> bool {
381 let id0 = o0.id();
382 let id1 = o1.id();
383 id0 < 31 && id1 < 31
384}
385
386pub(crate) fn check_vec_id3(o0: &Operand, o1: &Operand, o2: &Operand) -> bool {
387 let id0 = o0.id();
388 let id1 = o1.id();
389 let id2 = o2.id();
390 id0 < 31 && id1 < 31 && id2 < 31
391}
392
393pub(crate) fn bit_test(value: u32, n: u32) -> bool {
394 n < 32 && value & (1 << n) != 0
395}
396
397pub(crate) fn encode_mov_sequence64(out: &mut [u32; 4], mut imm: u64, rd: u32, x: u32) -> usize {
398 const MOVZ: u32 = 0b11010010100000000000000000000000;
399 const MOVN: u32 = 0b10010010100000000000000000000000;
400 const MOVK: u32 = 0b11110010100000000000000000000000;
401
402 if imm <= 0xFFFFFFFF {
403 return encode_mov_sequence32(out, imm as u32, rd, x);
404 }
405
406 let zhw = count_zero_half_words_64(imm);
407 let ohw = count_zero_half_words_64(!imm);
408
409 if zhw >= ohw {
410 let mut op = MOVZ;
411 let mut count = 0;
412 for hw_index in 0..4 {
413 let hw_imm = (imm & 0xFFFF) as u32;
414 if hw_imm == 0 {
415 imm >>= 16;
416 continue;
417 }
418 out[count] = op | (hw_index << 21) | (hw_imm << 5) | rd;
419 op = MOVK;
420 count += 1;
421
422 imm >>= 16;
423 }
424
425 return count;
426 }
427
428 let mut op = MOVN;
429 let mut count = 0;
430 let mut neg_mask = 0xFFFF;
431
432 for hw_index in 0..4 {
433 let hw_imm = (imm & 0xFFFF) as u32;
434 if hw_imm == 0xFFFF {
435 imm >>= 16;
436 continue;
437 }
438
439 out[count] = op | (hw_index << 21) | ((hw_imm ^ neg_mask) << 5) | rd;
440 count += 1;
441 op = MOVK;
442 neg_mask = 0;
443 imm >>= 16;
444 }
445
446 count
447}
448
449pub(crate) fn encode_mov_sequence32(out: &mut [u32], imm: u32, rd: u32, x: u32) -> usize {
450 let movz = 0b11010010100000000000000000000000 | (x << 31);
451 let movn = 0b10010010100000000000000000000000;
452 let movk = 0b11110010100000000000000000000000;
453 if (imm & 0xFFFF0000) == 0 {
454 out[0] = movz | (0 << 21) | ((imm & 0xffff) << 5) | rd;
455 return 1;
456 }
457
458 if (imm & 0xFFFF0000) == 0xFFFF0000 {
459 out[0] = movn | (0 << 21) | ((!imm & 0xFFFF) << 5) | rd;
460 return 1;
461 }
462
463 if (imm & 0x0000FFFF) == 0x00000000 {
464 out[0] = movz | (1 << 21) | ((imm >> 16) << 5) | rd;
465 return 1;
466 }
467
468 if (imm & 0x0000FFFF) == 0x0000FFFF {
469 out[0] = movn | (1 << 21) | ((!imm >> 16) << 5) | rd;
470 return 1;
471 }
472
473 out[0] = movz | (0 << 21) | ((imm & 0xFFFF) << 5) | rd;
474 out[1] = movk | (1 << 21) | ((imm >> 16) << 5) | rd;
475 return 2;
476}
477
478pub const fn count_zero_half_words_64(imm: u64) -> u32 {
479 let mut count = 0;
480 if (imm & 0x000000000000FFFF) == 0 {
481 count += 1;
482 }
483 if (imm & 0x00000000FFFF0000) == 0 {
484 count += 1;
485 }
486 if (imm & 0x0000FFFF00000000) == 0 {
487 count += 1;
488 }
489 if (imm & 0xFFFF000000000000) == 0 {
490 count += 1;
491 }
492 count
493}
494
495pub const fn encode_logical_imm(mut imm: u64, mut width: u32) -> Option<LogicalImm> {
513 loop {
514 width /= 2;
515 let mask = (1u64 << width) - 1;
516 if (imm & mask) != (imm >> width) & mask {
517 width *= 2;
518 break;
519 }
520 if width <= 2 {
521 break;
522 }
523 }
524
525 let width_mask = lsb_mask::<u64>(width);
526 imm &= width_mask;
527
528 if imm == 0 || width_mask == imm {
530 return None;
531 }
532
533 let z_index = (!imm).trailing_zeros();
540 let z_imm = imm ^ ((1u64 << z_index) - 1);
541 let z_count = (if z_imm != 0 {
542 z_imm.trailing_zeros()
543 } else {
544 width
545 })
546 .wrapping_sub(z_index);
547
548 let o_index = z_index + z_count;
549 let o_imm = !(z_imm ^ lsb_mask::<u64>(o_index));
550 let o_count = (if o_imm != 0 {
551 o_imm.trailing_zeros()
552 } else {
553 width
554 })
555 .wrapping_sub(o_index);
556
557 let must_be_zero = o_imm ^ !lsb_mask::<u64>((o_index + o_count) & 63);
558 if must_be_zero != 0 || (z_index > 0 && width.wrapping_sub(o_index + o_count) != 0) {
559 return None;
560 }
561
562 Some(LogicalImm {
563 n: if width == 64 { 1 } else { 0 },
564 s: (o_count + z_index).wrapping_sub(1) | 0u32.wrapping_sub(width * 2) & 0x3f,
565 r: width.wrapping_sub(o_index),
566 })
567}
568
569#[derive(Copy, Clone, PartialEq, Eq, Debug)]
570#[repr(u8)]
571pub(crate) enum OffsetType {
572 SignedOffset,
573 Adr,
574 Adrp,
575 Ldr,
576}
577
578impl TryFrom<u8> for OffsetType {
579 type Error = ();
580
581 fn try_from(value: u8) -> Result<Self, Self::Error> {
582 match value {
583 0 => Ok(Self::SignedOffset),
584 1 => Ok(Self::Adr),
585 2 => Ok(Self::Adrp),
586 3 => Ok(Self::Ldr),
587 _ => Err(()),
588 }
589 }
590}
591
592pub(crate) struct OffsetFormat {
593 pub(crate) typ: OffsetType,
594 pub(crate) flags: u8,
595 pub(crate) region_size: u8,
596 pub(crate) value_size: u8,
597 pub(crate) value_offset: u8,
598 pub(crate) imm_bit_count: u8,
599 pub(crate) imm_bit_shift: u8,
600 pub(crate) imm_discard_lsb: u8,
601}
602
603impl OffsetFormat {
604 pub const fn new(
605 typ: OffsetType,
606 flags: u8,
607 region_size: u8,
608 value_size: u8,
609 value_offset: u8,
610 imm_bit_count: u8,
611 imm_bit_shift: u8,
612 imm_discard_lsb: u8,
613 ) -> Self {
614 Self {
615 typ,
616 flags,
617 region_size,
618 value_size,
619 value_offset,
620 imm_bit_count,
621 imm_bit_shift,
622 imm_discard_lsb,
623 }
624 }
625
626 pub fn reset_to_imm_type(
627 &mut self,
628 typ: OffsetType,
629 value_size: usize,
630 imm_bit_shift: u32,
631 imm_bit_count: u32,
632 imm_discard_lsb: u32,
633 ) {
634 self.typ = typ;
635 self.value_size = value_size as u8;
636 self.region_size = value_size as u8;
637 self.imm_bit_shift = imm_bit_shift as u8;
638 self.imm_bit_count = imm_bit_count as u8;
639 self.imm_discard_lsb = imm_discard_lsb as u8;
640 self.flags = 0;
641 self.value_offset = 0;
642 }
643
644 fn set_region(&mut self, region_size: usize, value_offset: usize) {
645 self.region_size = region_size as u8;
646 self.value_offset = value_offset as u8;
647 }
648
649 fn set_leading_and_trailing_size(&mut self, leading_size: usize, trailing_size: usize) {
650 self.region_size = (leading_size + trailing_size + self.value_size as usize) as u8;
651 self.value_offset = leading_size as u8;
652 }
653
654 fn typ(&self) -> OffsetType {
655 self.typ
656 }
657
658 fn flags(&self) -> u8 {
659 self.flags
660 }
661
662 fn region_size(&self) -> usize {
663 self.region_size as usize
664 }
665
666 fn value_size(&self) -> usize {
667 self.value_size as usize
668 }
669
670 fn value_offset(&self) -> usize {
671 self.value_offset as usize
672 }
673
674 fn imm_bit_count(&self) -> usize {
675 self.imm_bit_count as usize
676 }
677
678 fn imm_bit_shift(&self) -> usize {
679 self.imm_bit_shift as usize
680 }
681
682 fn imm_discard_lsb(&self) -> usize {
683 self.imm_discard_lsb as usize
684 }
685}
686
687pub(crate) const fn lsb_mask<T>(n: u32) -> u64 {
688 if size_of::<T>() < size_of::<u64>() {
689 (1 << n) - 1
690 } else {
691 if n != 0 {
692 (!0u64).wrapping_shr((size_of::<T>() as u32 * 8) - n)
693 } else {
694 0
695 }
696 }
697}
698
699pub(crate) const fn cond_code_to_opcode_field(cond: u32) -> u32 {
700 (cond.wrapping_sub(2)) & 0xf
701}
702
703pub(crate) const fn is_byte_mask_imm(imm: u64) -> bool {
704 let mask = 0x0101010101010101 & u64::MAX;
705 imm == (imm & mask) * 255
706}
707
708pub(crate) const fn encode_imm64_byte_mask_to_imm8(imm: u64) -> u32 {
709 (((imm >> (7 - 0)) & 0b00000011) | ((imm >> (23 - 2)) & 0b00001100) | ((imm >> (39 - 4)) & 0b00110000) | ((imm >> (55 - 6)) & 0b11000000)) as u32
713}
714
715macro_rules! is_fp_imm8_generic {
716 ($t: ty: $val: expr, $num_b_bits: expr, $num_cdefgh_bits: expr, $num_zero_bits: expr) => {{
717 let all_bs_mask = lsb_mask::<u32>($num_b_bits);
718 let b0_pattern = 1u32 << ($num_b_bits - 1);
719 let b1_pattern = all_bs_mask as u32 ^ b0_pattern;
720
721 let imm_z = $val & lsb_mask::<$t>($num_zero_bits as _) as $t;
722 let imm_b = ($val >> ($num_zero_bits + $num_cdefgh_bits)) as u32 & all_bs_mask as u32;
723 imm_z == 0 && (imm_b == b0_pattern || imm_b == b1_pattern)
724 }};
725}
726
727pub const fn is_fp16_imm8(val: u32) -> bool {
728 is_fp_imm8_generic!(u32: val, 3, 6, 6)
729}
730
731pub const fn is_fp32_imm8(val: u32) -> bool {
732 is_fp_imm8_generic!(u32: val, 6, 6, 19)
733}
734
735pub const fn is_fp64_imm8(val: u64) -> bool {
736 is_fp_imm8_generic!(u64: val, 9, 6, 48)
737}
738
739macro_rules! encode_fp_to_imm8_generic {
740 ($t: ty: $val: expr, $num_b_bits: expr, $num_cdefgh_bits: expr, $num_zero_bits: expr) => {{
741 let bits = ($val >> $num_zero_bits) as u32;
742 ((bits >> ($num_b_bits + $num_cdefgh_bits - 7)) & 0x80) | (bits & 0x7f)
743 }};
744}
745
746pub const fn encode_fp64_to_imm8(val: u64) -> u32 {
747 encode_fp_to_imm8_generic!(u64: val, 9, 6, 48)
748}
749
750pub(crate) fn pick_fp_opcode(
751 reg: Vec,
752 s_op: u32,
753 s_hf: u32,
754 v_op: u32,
755 v_hf: u32,
756 sz_out: &mut u32,
757) -> Option<Opc> {
758 const QBIT_INDEX: usize = 30;
759
760 struct EncodeFpOpcodeBits {
761 size_mask: u32,
762 mask: [u32; 3],
763 }
764
765 static SZ_BITS_TABLE: [EncodeFpOpcodeBits; 6] = [
766 EncodeFpOpcodeBits {
767 size_mask: (1 << 2) | (1 << 1),
768 mask: [0, 0, 1 << 22],
769 },
770 EncodeFpOpcodeBits {
771 size_mask: (1 << 2) | (1 << 1) | (1 << 0),
772 mask: [0, 0, 0],
773 },
774 EncodeFpOpcodeBits {
775 size_mask: (1 << 2) | (1 << 1) | (1 << 0),
776 mask: [1 << 23 | 1 << 22, 0, 1 << 22],
777 },
778 EncodeFpOpcodeBits {
779 size_mask: (1 << 2) | (1 << 1) | (1 << 0),
780 mask: [(1 << 22) | (1 << 20) | (1 << 19), 0, 0],
781 },
782 EncodeFpOpcodeBits {
783 size_mask: (1 << 2) | (1 << 1) | (1 << 0),
784 mask: [1 << 22 | (1 << 21) | (1 << 15) | (1 << 14), 0, 1 << 22],
785 },
786 EncodeFpOpcodeBits {
787 size_mask: (1 << 2) | (1 << 1) | (1 << 0),
788 mask: [1 << 23, 0, 1 << 22],
789 },
790 ];
791
792 let mut op = Opc(0);
793 if !reg.has_element_type() {
794 let sz = (reg.typ() as u32).wrapping_sub(RegType::Vec16 as u32);
796 if sz > 2 || !bit_test32(SZ_BITS_TABLE[s_hf as usize].size_mask, sz) {
797 return None;
798 }
799
800 op.reset(SZ_BITS_TABLE[s_hf as usize].mask[sz as usize] ^ s_op);
801 *sz_out = sz;
802
803 return (s_op != 0).then_some(op);
804 } else {
805 let q = (reg.typ() as u32).wrapping_sub(RegType::Vec64 as u32);
807 let sz = (reg.element_type() as u32).wrapping_sub(VecElementType::H as u32);
808
809 if q > 1 || sz > 2 || !bit_test32(SZ_BITS_TABLE[v_hf as usize].size_mask, sz) {
810 return None;
811 }
812
813 op.reset(SZ_BITS_TABLE[v_hf as usize].mask[sz as usize] ^ (v_op | (q << QBIT_INDEX)));
814 *sz_out = sz;
815 return (v_op != 0).then_some(op);
816 }
817}
818
819pub(crate) const fn bit_test32(value: u32, n: u32) -> bool {
820 n < 32 && value & (1 << n) != 0
821}
822
823pub(crate) struct SizeOpTable {
824 pub(crate) array: [SizeOp; ((RegType::Vec128 as usize - RegType::Vec8 as usize + 1) + 1) * 40],
825}
826
827impl SizeOpTable {
828 const fn len() -> usize {
829 ((RegType::Vec128 as usize - RegType::Vec8 as usize + 1) + 1) * 40
830 }
831 pub(crate) const fn bin() -> Self {
832 let mut i = 0;
833 let mut array = [SizeOp::new(SizeOp::K_INVALID); Self::len()];
834 while i < Self::len() {
835 array[i] = Self::bin_at(i);
836 i += 1;
837 }
838 Self { array }
839 }
840
841 pub(crate) const fn any() -> Self {
842 let mut i = 0;
843 let mut array = [SizeOp::new(SizeOp::K_INVALID); Self::len()];
844 while i < Self::len() {
845 array[i] = Self::any_at(i);
846 i += 1;
847 }
848 Self { array }
849 }
850
851 const fn bin_at(x: usize) -> SizeOp {
852 if x == (((RegType::Vec64 as usize - RegType::Vec8 as usize) << 3)
853 | VecElementType::None as usize)
854 {
855 SizeOp::new(SizeOp::K00)
856 } else if x
857 == (((RegType::Vec128 as usize - RegType::Vec8 as usize) << 3)
858 | VecElementType::None as usize)
859 {
860 SizeOp::new(SizeOp::K00_Q)
861 } else if x
862 == (((RegType::Vec64 as usize - RegType::Vec8 as usize) << 3)
863 | VecElementType::B as usize)
864 {
865 SizeOp::new(SizeOp::K00)
866 } else if x
867 == (((RegType::Vec128 as usize - RegType::Vec8 as usize) << 3)
868 | VecElementType::B as usize)
869 {
870 SizeOp::new(SizeOp::K00_Q)
871 } else {
872 SizeOp::new(SizeOp::K_INVALID)
873 }
874 }
875
876 const fn any_at(x: usize) -> SizeOp {
877 if x == (((RegType::Vec8 as usize - RegType::Vec8 as usize) << 3)
878 | VecElementType::None as usize)
879 {
880 SizeOp::new(SizeOp::K00_S)
881 } else if x
882 == (((RegType::Vec16 as usize - RegType::Vec8 as usize) << 3)
883 | VecElementType::None as usize)
884 {
885 SizeOp::new(SizeOp::K01_S)
886 } else if x
887 == (((RegType::Vec32 as usize - RegType::Vec8 as usize) << 3)
888 | VecElementType::None as usize)
889 {
890 SizeOp::new(SizeOp::K10_S)
891 } else if x
892 == (((RegType::Vec64 as usize - RegType::Vec8 as usize) << 3)
893 | VecElementType::None as usize)
894 {
895 SizeOp::new(SizeOp::K11_S)
896 } else if x
897 == (((RegType::Vec64 as usize - RegType::Vec8 as usize) << 3)
898 | VecElementType::B as usize)
899 {
900 SizeOp::new(SizeOp::K00)
901 } else if x
902 == (((RegType::Vec128 as usize - RegType::Vec8 as usize) << 3)
903 | VecElementType::B as usize)
904 {
905 SizeOp::new(SizeOp::K00_Q)
906 } else if x
907 == (((RegType::Vec64 as usize - RegType::Vec8 as usize) << 3)
908 | VecElementType::H as usize)
909 {
910 SizeOp::new(SizeOp::K01)
911 } else if x
912 == (((RegType::Vec128 as usize - RegType::Vec8 as usize) << 3)
913 | VecElementType::H as usize)
914 {
915 SizeOp::new(SizeOp::K01_Q)
916 } else if x
917 == (((RegType::Vec64 as usize - RegType::Vec8 as usize) << 3)
918 | VecElementType::S as usize)
919 {
920 SizeOp::new(SizeOp::K10)
921 } else if x
922 == (((RegType::Vec128 as usize - RegType::Vec8 as usize) << 3)
923 | VecElementType::S as usize)
924 {
925 SizeOp::new(SizeOp::K10_Q)
926 } else if x
927 == (((RegType::Vec64 as usize - RegType::Vec8 as usize) << 3)
928 | VecElementType::D as usize)
929 {
930 SizeOp::new(SizeOp::K11_S)
931 } else if x
932 == (((RegType::Vec128 as usize - RegType::Vec8 as usize) << 3)
933 | VecElementType::D as usize)
934 {
935 SizeOp::new(SizeOp::K11_Q)
936 } else {
937 SizeOp::new(SizeOp::K_INVALID)
938 }
939 }
940}
941
942#[derive(Copy, Clone, PartialEq, Eq, Debug)]
943#[repr(transparent)]
944pub(crate) struct SizeOp(u8);
945
946impl SizeOp {
947 pub const fn new(val: u8) -> Self {
948 Self(val)
949 }
950
951 pub(crate) const K128_BIT_SHIFT: u8 = 0;
952 pub(crate) const K_SCALAR_SHIFT: u8 = 1;
953 pub(crate) const K_SIZE_SHIFT: u8 = 2;
954
955 pub(crate) const K_Q: u8 = 1u8 << Self::K128_BIT_SHIFT;
956 pub(crate) const K_S: u8 = 1u8 << Self::K_SCALAR_SHIFT;
957
958 pub(crate) const K00: u8 = 0 << Self::K_SIZE_SHIFT;
959 pub(crate) const K01: u8 = 1 << Self::K_SIZE_SHIFT;
960 pub(crate) const K10: u8 = 2 << Self::K_SIZE_SHIFT;
961 pub(crate) const K11: u8 = 3 << Self::K_SIZE_SHIFT;
962
963 pub(crate) const K00_Q: u8 = Self::K00 | Self::K_Q;
964 pub(crate) const K01_Q: u8 = Self::K01 | Self::K_Q;
965 pub(crate) const K10_Q: u8 = Self::K10 | Self::K_Q;
966 pub(crate) const K11_Q: u8 = Self::K11 | Self::K_Q;
967
968 pub(crate) const K00_S: u8 = Self::K00 | Self::K_S;
969 pub(crate) const K01_S: u8 = Self::K01 | Self::K_S;
970 pub(crate) const K10_S: u8 = Self::K10 | Self::K_S;
971 pub(crate) const K11_S: u8 = Self::K11 | Self::K_S;
972
973 pub(crate) const K_INVALID: u8 = 0xFF;
974
975 pub(crate) const K_SZ_Q: u8 = (0x3u8 << Self::K_SIZE_SHIFT) | Self::K_Q;
976 pub(crate) const K_SZ_S: u8 = (0x3u8 << Self::K_SIZE_SHIFT) | Self::K_S;
977 pub(crate) const K_SZ_QS: u8 = (0x3u8 << Self::K_SIZE_SHIFT) | Self::K_Q | Self::K_S;
978
979 pub(crate) const fn is_valid(self) -> bool {
980 self.0 != Self::K_INVALID
981 }
982
983 pub(crate) const fn make_invalid(&mut self) {
984 self.0 = Self::K_INVALID;
985 }
986
987 pub(crate) const fn q(&self) -> u32 {
988 (self.0 >> Self::K128_BIT_SHIFT) as u32 & 1
989 }
990
991 pub(crate) const fn qs(&self) -> u32 {
992 (((self.0 >> Self::K128_BIT_SHIFT) as u32) | ((self.0 >> Self::K_SCALAR_SHIFT) as u32)) & 1
993 }
994
995 pub(crate) const fn scalar(&self) -> u32 {
996 (self.0 >> Self::K_SCALAR_SHIFT) as u32 & 1
997 }
998
999 pub(crate) const fn size(&self) -> u32 {
1000 (self.0 >> Self::K_SIZE_SHIFT) as u32 & 0x3
1001 }
1002
1003 pub(crate) const fn decrement_size(&mut self) {
1004 self.0 = (self.0 as u32 - (1u32 << Self::K_SIZE_SHIFT)) as u8;
1005 }
1006}
1007
1008#[derive(Copy, Clone, Debug)]
1009pub(crate) struct SizeOpMap {
1010 pub(crate) table_id: u8,
1011 pub(crate) size_op_mask: u8,
1012 pub(crate) accept_mask: u16,
1013}
1014
1015pub(crate) const fn significant_simd_op<'a>(
1016 o0: &'a Operand,
1017 o1: &'a Operand,
1018 inst_flags: u32,
1019) -> &'a Operand {
1020 if (inst_flags & InstFlag::Long as u32) == 0 {
1021 o0
1022 } else {
1023 o1
1024 }
1025}
1026
1027pub(crate) fn match_signature2(o0: &Operand, o1: &Operand, inst_flags: u32) -> bool {
1032 if inst_flags & (InstFlag::Long as u32 | InstFlag::Narrow as u32) == 0 {
1033 o0.signature() == o1.signature()
1034 } else {
1035 true
1036 }
1037}
1038
1039pub(crate) fn match_signature3(o0: &Operand, o1: &Operand, o2: &Operand, inst_flags: u32) -> bool {
1041 match_signature2(o0, o1, inst_flags) && o1.signature() == o2.signature()
1042}
1043
1044pub(crate) fn match_signature4(
1046 o0: &Operand,
1047 o1: &Operand,
1048 o2: &Operand,
1049 o3: &Operand,
1050 inst_flags: u32,
1051) -> bool {
1052 match_signature2(o0, o1, inst_flags)
1053 && o1.signature() == o2.signature()
1054 && o2.signature() == o3.signature()
1055}
1056
1057pub(crate) const fn element_type_to_size_op(
1058 vec_op_type: u32,
1059 reg_type: RegType,
1060 element_type: VecElementType,
1061) -> SizeOp {
1062 let map = &SIZE_OP_MAP[vec_op_type as usize];
1063 let table = &SIZE_OP_TABLE[map.table_id as usize];
1064
1065 let a = (reg_type as usize).wrapping_sub(RegType::Vec8 as usize);
1068 let b = RegType::Vec128 as usize - RegType::Vec8 as usize;
1069
1070 let clamped = if a < b + 1 { a } else { b + 1 };
1071 let index = (clamped << 3) | (element_type as usize);
1072 let op = table.array[index];
1073 let mut modified_op = SizeOp::new(op.0 & map.size_op_mask);
1074
1075 if !bit_test32(map.accept_mask as u32, op.0 as u32) {
1076 modified_op.make_invalid();
1077 }
1078
1079 modified_op
1080}
1081
1082pub(crate) struct LMHImm {
1083 pub(crate) lm: u32,
1084 pub(crate) h: u32,
1085 pub(crate) max_rm_id: u32,
1086}
1087
1088pub(crate) fn encode_lmh(size_field: u32, element_index: u32, out: &mut LMHImm) -> bool {
1089 if size_field != 1 && size_field != 2 {
1090 return false;
1091 }
1092
1093 let h_shift = 3u32.saturating_sub(size_field);
1094 let lm_shift = size_field.saturating_sub(1u32);
1095 let max_element_index = 15u32 >> size_field;
1096
1097 out.h = element_index >> h_shift;
1098 out.lm = (element_index << lm_shift) & 0x3u32;
1099 out.max_rm_id = (8u32 << size_field).saturating_sub(1);
1100
1101 element_index <= max_element_index
1102}