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