1use crate::ir::{self, LibCall, MemFlags, TrapCode};
4use crate::isa::s390x::inst::*;
5use crate::isa::s390x::settings as s390x_settings;
6use cranelift_control::ControlPlane;
7
8macro_rules! debug_assert_valid_regpair {
11 ($hi:expr, $lo:expr) => {
12 if cfg!(debug_assertions) {
13 match ($hi.to_real_reg(), $lo.to_real_reg()) {
14 (Some(hi), Some(lo)) => {
15 assert!(
16 hi.hw_enc() % 2 == 0,
17 "High register is not even: {}",
18 show_reg($hi)
19 );
20 assert_eq!(
21 hi.hw_enc() + 1,
22 lo.hw_enc(),
23 "Low register is not valid: {}, {}",
24 show_reg($hi),
25 show_reg($lo)
26 );
27 }
28
29 _ => {
30 panic!(
31 "Expected real registers for {} {}",
32 show_reg($hi),
33 show_reg($lo)
34 );
35 }
36 }
37 }
38 };
39}
40
41pub struct MemInstType {
43 pub have_d12: bool,
45 pub have_d20: bool,
47 pub have_pcrel: bool,
49 pub have_unaligned_pcrel: bool,
51 pub have_index: bool,
53}
54
55pub fn mem_finalize(
60 mem: &MemArg,
61 state: &EmitState,
62 mi: MemInstType,
63) -> (SmallVec<[Inst; 4]>, MemArg) {
64 let mut insts = SmallVec::new();
65
66 let mem = match mem {
68 &MemArg::RegOffset { off, .. }
69 | &MemArg::InitialSPOffset { off }
70 | &MemArg::NominalSPOffset { off }
71 | &MemArg::SlotOffset { off } => {
72 let base = match mem {
73 &MemArg::RegOffset { reg, .. } => reg,
74 &MemArg::InitialSPOffset { .. }
75 | &MemArg::NominalSPOffset { .. }
76 | &MemArg::SlotOffset { .. } => stack_reg(),
77 _ => unreachable!(),
78 };
79 let adj = match mem {
80 &MemArg::InitialSPOffset { .. } => i64::from(
81 state.frame_layout().clobber_size
82 + state.frame_layout().fixed_frame_storage_size
83 + state.frame_layout().outgoing_args_size
84 + state.nominal_sp_offset,
85 ),
86 &MemArg::SlotOffset { .. } => {
87 i64::from(state.frame_layout().outgoing_args_size + state.nominal_sp_offset)
88 }
89 &MemArg::NominalSPOffset { .. } => i64::from(state.nominal_sp_offset),
90 _ => 0,
91 };
92 let off = off + adj;
93
94 if let Some(disp) = UImm12::maybe_from_u64(off as u64) {
95 MemArg::BXD12 {
96 base,
97 index: zero_reg(),
98 disp,
99 flags: mem.get_flags(),
100 }
101 } else if let Some(disp) = SImm20::maybe_from_i64(off) {
102 MemArg::BXD20 {
103 base,
104 index: zero_reg(),
105 disp,
106 flags: mem.get_flags(),
107 }
108 } else {
109 let tmp = writable_spilltmp_reg();
110 assert!(base != tmp.to_reg());
111 if let Ok(imm) = i16::try_from(off) {
112 insts.push(Inst::Mov64SImm16 { rd: tmp, imm });
113 } else if let Ok(imm) = i32::try_from(off) {
114 insts.push(Inst::Mov64SImm32 { rd: tmp, imm });
115 } else {
116 unreachable!();
119 }
120 MemArg::reg_plus_reg(base, tmp.to_reg(), mem.get_flags())
121 }
122 }
123 _ => mem.clone(),
124 };
125
126 let need_load_address = match &mem {
128 &MemArg::Label { .. } | &MemArg::Symbol { .. } if !mi.have_pcrel => true,
129 &MemArg::Symbol { flags, .. } if !mi.have_unaligned_pcrel && !flags.aligned() => true,
130 &MemArg::BXD20 { .. } if !mi.have_d20 => true,
131 &MemArg::BXD12 { index, .. } | &MemArg::BXD20 { index, .. } if !mi.have_index => {
132 index != zero_reg()
133 }
134 _ => false,
135 };
136 let mem = if need_load_address {
137 let flags = mem.get_flags();
138 let tmp = writable_spilltmp_reg();
139 insts.push(Inst::LoadAddr { rd: tmp, mem });
140 MemArg::reg(tmp.to_reg(), flags)
141 } else {
142 mem
143 };
144
145 let mem = match &mem {
147 &MemArg::BXD12 {
148 base,
149 index,
150 disp,
151 flags,
152 } if !mi.have_d12 => {
153 assert!(mi.have_d20);
154 MemArg::BXD20 {
155 base,
156 index,
157 disp: SImm20::from_uimm12(disp),
158 flags,
159 }
160 }
161 _ => mem,
162 };
163
164 (insts, mem)
165}
166
167pub fn mem_emit(
168 rd: Reg,
169 mem: &MemArg,
170 opcode_rx: Option<u16>,
171 opcode_rxy: Option<u16>,
172 opcode_ril: Option<u16>,
173 add_trap: bool,
174 sink: &mut MachBuffer<Inst>,
175 emit_info: &EmitInfo,
176 state: &mut EmitState,
177) {
178 let (mem_insts, mem) = mem_finalize(
179 mem,
180 state,
181 MemInstType {
182 have_d12: opcode_rx.is_some(),
183 have_d20: opcode_rxy.is_some(),
184 have_pcrel: opcode_ril.is_some(),
185 have_unaligned_pcrel: opcode_ril.is_some() && !add_trap,
186 have_index: true,
187 },
188 );
189 for inst in mem_insts.into_iter() {
190 inst.emit(sink, emit_info, state);
191 }
192
193 if add_trap {
194 if let Some(trap_code) = mem.get_flags().trap_code() {
195 sink.add_trap(trap_code);
196 }
197 }
198
199 match &mem {
200 &MemArg::BXD12 {
201 base, index, disp, ..
202 } => {
203 put(
204 sink,
205 &enc_rx(opcode_rx.unwrap(), rd, base, index, disp.bits()),
206 );
207 }
208 &MemArg::BXD20 {
209 base, index, disp, ..
210 } => {
211 put(
212 sink,
213 &enc_rxy(opcode_rxy.unwrap(), rd, base, index, disp.bits()),
214 );
215 }
216 &MemArg::Label { target } => {
217 sink.use_label_at_offset(sink.cur_offset(), target, LabelUse::BranchRIL);
218 put(sink, &enc_ril_b(opcode_ril.unwrap(), rd, 0));
219 }
220 &MemArg::Symbol {
221 ref name, offset, ..
222 } => {
223 let reloc_offset = sink.cur_offset() + 2;
224 sink.add_reloc_at_offset(
225 reloc_offset,
226 Reloc::S390xPCRel32Dbl,
227 &**name,
228 (offset + 2).into(),
229 );
230 put(sink, &enc_ril_b(opcode_ril.unwrap(), rd, 0));
231 }
232 _ => unreachable!(),
233 }
234}
235
236pub fn mem_rs_emit(
237 rd: Reg,
238 rn: Reg,
239 mem: &MemArg,
240 opcode_rs: Option<u16>,
241 opcode_rsy: Option<u16>,
242 add_trap: bool,
243 sink: &mut MachBuffer<Inst>,
244 emit_info: &EmitInfo,
245 state: &mut EmitState,
246) {
247 let (mem_insts, mem) = mem_finalize(
248 mem,
249 state,
250 MemInstType {
251 have_d12: opcode_rs.is_some(),
252 have_d20: opcode_rsy.is_some(),
253 have_pcrel: false,
254 have_unaligned_pcrel: false,
255 have_index: false,
256 },
257 );
258 for inst in mem_insts.into_iter() {
259 inst.emit(sink, emit_info, state);
260 }
261
262 if add_trap {
263 if let Some(trap_code) = mem.get_flags().trap_code() {
264 sink.add_trap(trap_code);
265 }
266 }
267
268 match &mem {
269 &MemArg::BXD12 {
270 base, index, disp, ..
271 } => {
272 assert!(index == zero_reg());
273 put(sink, &enc_rs(opcode_rs.unwrap(), rd, rn, base, disp.bits()));
274 }
275 &MemArg::BXD20 {
276 base, index, disp, ..
277 } => {
278 assert!(index == zero_reg());
279 put(
280 sink,
281 &enc_rsy(opcode_rsy.unwrap(), rd, rn, base, disp.bits()),
282 );
283 }
284 _ => unreachable!(),
285 }
286}
287
288pub fn mem_imm8_emit(
289 imm: u8,
290 mem: &MemArg,
291 opcode_si: u16,
292 opcode_siy: u16,
293 add_trap: bool,
294 sink: &mut MachBuffer<Inst>,
295 emit_info: &EmitInfo,
296 state: &mut EmitState,
297) {
298 let (mem_insts, mem) = mem_finalize(
299 mem,
300 state,
301 MemInstType {
302 have_d12: true,
303 have_d20: true,
304 have_pcrel: false,
305 have_unaligned_pcrel: false,
306 have_index: false,
307 },
308 );
309 for inst in mem_insts.into_iter() {
310 inst.emit(sink, emit_info, state);
311 }
312
313 if add_trap {
314 if let Some(trap_code) = mem.get_flags().trap_code() {
315 sink.add_trap(trap_code);
316 }
317 }
318
319 match &mem {
320 &MemArg::BXD12 {
321 base, index, disp, ..
322 } => {
323 assert!(index == zero_reg());
324 put(sink, &enc_si(opcode_si, base, disp.bits(), imm));
325 }
326 &MemArg::BXD20 {
327 base, index, disp, ..
328 } => {
329 assert!(index == zero_reg());
330 put(sink, &enc_siy(opcode_siy, base, disp.bits(), imm));
331 }
332 _ => unreachable!(),
333 }
334}
335
336pub fn mem_imm16_emit(
337 imm: i16,
338 mem: &MemArg,
339 opcode_sil: u16,
340 add_trap: bool,
341 sink: &mut MachBuffer<Inst>,
342 emit_info: &EmitInfo,
343 state: &mut EmitState,
344) {
345 let (mem_insts, mem) = mem_finalize(
346 mem,
347 state,
348 MemInstType {
349 have_d12: true,
350 have_d20: false,
351 have_pcrel: false,
352 have_unaligned_pcrel: false,
353 have_index: false,
354 },
355 );
356 for inst in mem_insts.into_iter() {
357 inst.emit(sink, emit_info, state);
358 }
359
360 if add_trap {
361 if let Some(trap_code) = mem.get_flags().trap_code() {
362 sink.add_trap(trap_code);
363 }
364 }
365
366 match &mem {
367 &MemArg::BXD12 {
368 base, index, disp, ..
369 } => {
370 assert!(index == zero_reg());
371 put(sink, &enc_sil(opcode_sil, base, disp.bits(), imm));
372 }
373 _ => unreachable!(),
374 }
375}
376
377pub fn mem_vrx_emit(
378 rd: Reg,
379 mem: &MemArg,
380 opcode: u16,
381 m3: u8,
382 add_trap: bool,
383 sink: &mut MachBuffer<Inst>,
384 emit_info: &EmitInfo,
385 state: &mut EmitState,
386) {
387 let (mem_insts, mem) = mem_finalize(
388 mem,
389 state,
390 MemInstType {
391 have_d12: true,
392 have_d20: false,
393 have_pcrel: false,
394 have_unaligned_pcrel: false,
395 have_index: true,
396 },
397 );
398 for inst in mem_insts.into_iter() {
399 inst.emit(sink, emit_info, state);
400 }
401
402 if add_trap {
403 if let Some(trap_code) = mem.get_flags().trap_code() {
404 sink.add_trap(trap_code);
405 }
406 }
407
408 match &mem {
409 &MemArg::BXD12 {
410 base, index, disp, ..
411 } => {
412 put(sink, &enc_vrx(opcode, rd, base, index, disp.bits(), m3));
413 }
414 _ => unreachable!(),
415 }
416}
417
418fn machreg_to_gpr(m: Reg) -> u8 {
422 assert_eq!(m.class(), RegClass::Int);
423 u8::try_from(m.to_real_reg().unwrap().hw_enc()).unwrap()
424}
425
426fn machreg_to_vr(m: Reg) -> u8 {
427 assert_eq!(m.class(), RegClass::Float);
428 u8::try_from(m.to_real_reg().unwrap().hw_enc()).unwrap()
429}
430
431fn machreg_to_fpr(m: Reg) -> u8 {
432 assert!(is_fpr(m));
433 u8::try_from(m.to_real_reg().unwrap().hw_enc()).unwrap()
434}
435
436fn machreg_to_gpr_or_fpr(m: Reg) -> u8 {
437 let reg = u8::try_from(m.to_real_reg().unwrap().hw_enc()).unwrap();
438 assert!(reg < 16);
439 reg
440}
441
442fn rxb(v1: Option<Reg>, v2: Option<Reg>, v3: Option<Reg>, v4: Option<Reg>) -> u8 {
443 let mut rxb = 0;
444
445 let is_high_vr = |reg| -> bool {
446 if let Some(reg) = reg {
447 if !is_fpr(reg) {
448 return true;
449 }
450 }
451 false
452 };
453
454 if is_high_vr(v1) {
455 rxb = rxb | 8;
456 }
457 if is_high_vr(v2) {
458 rxb = rxb | 4;
459 }
460 if is_high_vr(v3) {
461 rxb = rxb | 2;
462 }
463 if is_high_vr(v4) {
464 rxb = rxb | 1;
465 }
466
467 rxb
468}
469
470fn enc_e(opcode: u16) -> [u8; 2] {
477 let mut enc: [u8; 2] = [0; 2];
478 let opcode1 = ((opcode >> 8) & 0xff) as u8;
479 let opcode2 = (opcode & 0xff) as u8;
480
481 enc[0] = opcode1;
482 enc[1] = opcode2;
483 enc
484}
485
486fn enc_ri_a(opcode: u16, r1: Reg, i2: u16) -> [u8; 4] {
493 let mut enc: [u8; 4] = [0; 4];
494 let opcode1 = ((opcode >> 4) & 0xff) as u8;
495 let opcode2 = (opcode & 0xf) as u8;
496 let r1 = machreg_to_gpr(r1) & 0x0f;
497
498 enc[0] = opcode1;
499 enc[1] = r1 << 4 | opcode2;
500 enc[2..].copy_from_slice(&i2.to_be_bytes());
501 enc
502}
503
504fn enc_ri_b(opcode: u16, r1: Reg, ri2: i32) -> [u8; 4] {
511 let mut enc: [u8; 4] = [0; 4];
512 let opcode1 = ((opcode >> 4) & 0xff) as u8;
513 let opcode2 = (opcode & 0xf) as u8;
514 let r1 = machreg_to_gpr(r1) & 0x0f;
515 let ri2 = ((ri2 >> 1) & 0xffff) as u16;
516
517 enc[0] = opcode1;
518 enc[1] = r1 << 4 | opcode2;
519 enc[2..].copy_from_slice(&ri2.to_be_bytes());
520 enc
521}
522
523fn enc_ri_c(opcode: u16, m1: u8, ri2: i32) -> [u8; 4] {
530 let mut enc: [u8; 4] = [0; 4];
531 let opcode1 = ((opcode >> 4) & 0xff) as u8;
532 let opcode2 = (opcode & 0xf) as u8;
533 let m1 = m1 & 0x0f;
534 let ri2 = ((ri2 >> 1) & 0xffff) as u16;
535
536 enc[0] = opcode1;
537 enc[1] = m1 << 4 | opcode2;
538 enc[2..].copy_from_slice(&ri2.to_be_bytes());
539 enc
540}
541
542fn enc_rie_a(opcode: u16, r1: Reg, i2: u16, m3: u8) -> [u8; 6] {
549 let mut enc: [u8; 6] = [0; 6];
550 let opcode1 = ((opcode >> 8) & 0xff) as u8;
551 let opcode2 = (opcode & 0xff) as u8;
552 let r1 = machreg_to_gpr(r1) & 0x0f;
553 let m3 = m3 & 0x0f;
554
555 enc[0] = opcode1;
556 enc[1] = r1 << 4;
557 enc[2..4].copy_from_slice(&i2.to_be_bytes());
558 enc[4] = m3 << 4;
559 enc[5] = opcode2;
560 enc
561}
562
563fn enc_rie_d(opcode: u16, r1: Reg, r3: Reg, i2: u16) -> [u8; 6] {
570 let mut enc: [u8; 6] = [0; 6];
571 let opcode1 = ((opcode >> 8) & 0xff) as u8;
572 let opcode2 = (opcode & 0xff) as u8;
573 let r1 = machreg_to_gpr(r1) & 0x0f;
574 let r3 = machreg_to_gpr(r3) & 0x0f;
575
576 enc[0] = opcode1;
577 enc[1] = r1 << 4 | r3;
578 enc[2..4].copy_from_slice(&i2.to_be_bytes());
579 enc[5] = opcode2;
580 enc
581}
582
583fn enc_rie_f(opcode: u16, r1: Reg, r2: Reg, i3: u8, i4: u8, i5: u8) -> [u8; 6] {
590 let mut enc: [u8; 6] = [0; 6];
591 let opcode1 = ((opcode >> 8) & 0xff) as u8;
592 let opcode2 = (opcode & 0xff) as u8;
593 let r1 = machreg_to_gpr(r1) & 0x0f;
594 let r2 = machreg_to_gpr(r2) & 0x0f;
595
596 enc[0] = opcode1;
597 enc[1] = r1 << 4 | r2;
598 enc[2] = i3;
599 enc[3] = i4;
600 enc[4] = i5;
601 enc[5] = opcode2;
602 enc
603}
604
605fn enc_rie_g(opcode: u16, r1: Reg, i2: u16, m3: u8) -> [u8; 6] {
612 let mut enc: [u8; 6] = [0; 6];
613 let opcode1 = ((opcode >> 8) & 0xff) as u8;
614 let opcode2 = (opcode & 0xff) as u8;
615 let r1 = machreg_to_gpr(r1) & 0x0f;
616 let m3 = m3 & 0x0f;
617
618 enc[0] = opcode1;
619 enc[1] = r1 << 4 | m3;
620 enc[2..4].copy_from_slice(&i2.to_be_bytes());
621 enc[5] = opcode2;
622 enc
623}
624
625fn enc_ril_a(opcode: u16, r1: Reg, i2: u32) -> [u8; 6] {
632 let mut enc: [u8; 6] = [0; 6];
633 let opcode1 = ((opcode >> 4) & 0xff) as u8;
634 let opcode2 = (opcode & 0xf) as u8;
635 let r1 = machreg_to_gpr(r1) & 0x0f;
636
637 enc[0] = opcode1;
638 enc[1] = r1 << 4 | opcode2;
639 enc[2..].copy_from_slice(&i2.to_be_bytes());
640 enc
641}
642
643fn enc_ril_b(opcode: u16, r1: Reg, ri2: u32) -> [u8; 6] {
650 let mut enc: [u8; 6] = [0; 6];
651 let opcode1 = ((opcode >> 4) & 0xff) as u8;
652 let opcode2 = (opcode & 0xf) as u8;
653 let r1 = machreg_to_gpr(r1) & 0x0f;
654 let ri2 = ri2 >> 1;
655
656 enc[0] = opcode1;
657 enc[1] = r1 << 4 | opcode2;
658 enc[2..].copy_from_slice(&ri2.to_be_bytes());
659 enc
660}
661
662fn enc_ril_c(opcode: u16, m1: u8, ri2: u32) -> [u8; 6] {
669 let mut enc: [u8; 6] = [0; 6];
670 let opcode1 = ((opcode >> 4) & 0xff) as u8;
671 let opcode2 = (opcode & 0xf) as u8;
672 let m1 = m1 & 0x0f;
673 let ri2 = ri2 >> 1;
674
675 enc[0] = opcode1;
676 enc[1] = m1 << 4 | opcode2;
677 enc[2..].copy_from_slice(&ri2.to_be_bytes());
678 enc
679}
680
681fn enc_rr(opcode: u16, r1: Reg, r2: Reg) -> [u8; 2] {
688 let mut enc: [u8; 2] = [0; 2];
689 let opcode = (opcode & 0xff) as u8;
690 let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;
691 let r2 = machreg_to_gpr_or_fpr(r2) & 0x0f;
692
693 enc[0] = opcode;
694 enc[1] = r1 << 4 | r2;
695 enc
696}
697
698fn enc_rrd(opcode: u16, r1: Reg, r2: Reg, r3: Reg) -> [u8; 4] {
705 let mut enc: [u8; 4] = [0; 4];
706 let opcode1 = ((opcode >> 8) & 0xff) as u8;
707 let opcode2 = (opcode & 0xff) as u8;
708 let r1 = machreg_to_fpr(r1) & 0x0f;
709 let r2 = machreg_to_fpr(r2) & 0x0f;
710 let r3 = machreg_to_fpr(r3) & 0x0f;
711
712 enc[0] = opcode1;
713 enc[1] = opcode2;
714 enc[2] = r1 << 4;
715 enc[3] = r3 << 4 | r2;
716 enc
717}
718
719fn enc_rre(opcode: u16, r1: Reg, r2: Reg) -> [u8; 4] {
726 let mut enc: [u8; 4] = [0; 4];
727 let opcode1 = ((opcode >> 8) & 0xff) as u8;
728 let opcode2 = (opcode & 0xff) as u8;
729 let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;
730 let r2 = machreg_to_gpr_or_fpr(r2) & 0x0f;
731
732 enc[0] = opcode1;
733 enc[1] = opcode2;
734 enc[3] = r1 << 4 | r2;
735 enc
736}
737
738fn enc_rrf_ab(opcode: u16, r1: Reg, r2: Reg, r3: Reg, m4: u8) -> [u8; 4] {
745 let mut enc: [u8; 4] = [0; 4];
746 let opcode1 = ((opcode >> 8) & 0xff) as u8;
747 let opcode2 = (opcode & 0xff) as u8;
748 let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;
749 let r2 = machreg_to_gpr_or_fpr(r2) & 0x0f;
750 let r3 = machreg_to_gpr_or_fpr(r3) & 0x0f;
751 let m4 = m4 & 0x0f;
752
753 enc[0] = opcode1;
754 enc[1] = opcode2;
755 enc[2] = r3 << 4 | m4;
756 enc[3] = r1 << 4 | r2;
757 enc
758}
759
760fn enc_rrf_cde(opcode: u16, r1: Reg, r2: Reg, m3: u8, m4: u8) -> [u8; 4] {
767 let mut enc: [u8; 4] = [0; 4];
768 let opcode1 = ((opcode >> 8) & 0xff) as u8;
769 let opcode2 = (opcode & 0xff) as u8;
770 let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;
771 let r2 = machreg_to_gpr_or_fpr(r2) & 0x0f;
772 let m3 = m3 & 0x0f;
773 let m4 = m4 & 0x0f;
774
775 enc[0] = opcode1;
776 enc[1] = opcode2;
777 enc[2] = m3 << 4 | m4;
778 enc[3] = r1 << 4 | r2;
779 enc
780}
781
782fn enc_rs(opcode: u16, r1: Reg, r3: Reg, b2: Reg, d2: u32) -> [u8; 4] {
789 let opcode = (opcode & 0xff) as u8;
790 let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;
791 let r3 = machreg_to_gpr_or_fpr(r3) & 0x0f;
792 let b2 = machreg_to_gpr(b2) & 0x0f;
793 let d2_lo = (d2 & 0xff) as u8;
794 let d2_hi = ((d2 >> 8) & 0x0f) as u8;
795
796 let mut enc: [u8; 4] = [0; 4];
797 enc[0] = opcode;
798 enc[1] = r1 << 4 | r3;
799 enc[2] = b2 << 4 | d2_hi;
800 enc[3] = d2_lo;
801 enc
802}
803
804fn enc_rsy(opcode: u16, r1: Reg, r3: Reg, b2: Reg, d2: u32) -> [u8; 6] {
811 let opcode1 = ((opcode >> 8) & 0xff) as u8;
812 let opcode2 = (opcode & 0xff) as u8;
813 let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;
814 let r3 = machreg_to_gpr_or_fpr(r3) & 0x0f;
815 let b2 = machreg_to_gpr(b2) & 0x0f;
816 let dl2_lo = (d2 & 0xff) as u8;
817 let dl2_hi = ((d2 >> 8) & 0x0f) as u8;
818 let dh2 = ((d2 >> 12) & 0xff) as u8;
819
820 let mut enc: [u8; 6] = [0; 6];
821 enc[0] = opcode1;
822 enc[1] = r1 << 4 | r3;
823 enc[2] = b2 << 4 | dl2_hi;
824 enc[3] = dl2_lo;
825 enc[4] = dh2;
826 enc[5] = opcode2;
827 enc
828}
829
830fn enc_rx(opcode: u16, r1: Reg, b2: Reg, x2: Reg, d2: u32) -> [u8; 4] {
837 let opcode = (opcode & 0xff) as u8;
838 let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;
839 let b2 = machreg_to_gpr(b2) & 0x0f;
840 let x2 = machreg_to_gpr(x2) & 0x0f;
841 let d2_lo = (d2 & 0xff) as u8;
842 let d2_hi = ((d2 >> 8) & 0x0f) as u8;
843
844 let mut enc: [u8; 4] = [0; 4];
845 enc[0] = opcode;
846 enc[1] = r1 << 4 | x2;
847 enc[2] = b2 << 4 | d2_hi;
848 enc[3] = d2_lo;
849 enc
850}
851
852fn enc_rxy(opcode: u16, r1: Reg, b2: Reg, x2: Reg, d2: u32) -> [u8; 6] {
859 let opcode1 = ((opcode >> 8) & 0xff) as u8;
860 let opcode2 = (opcode & 0xff) as u8;
861 let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;
862 let b2 = machreg_to_gpr(b2) & 0x0f;
863 let x2 = machreg_to_gpr(x2) & 0x0f;
864 let dl2_lo = (d2 & 0xff) as u8;
865 let dl2_hi = ((d2 >> 8) & 0x0f) as u8;
866 let dh2 = ((d2 >> 12) & 0xff) as u8;
867
868 let mut enc: [u8; 6] = [0; 6];
869 enc[0] = opcode1;
870 enc[1] = r1 << 4 | x2;
871 enc[2] = b2 << 4 | dl2_hi;
872 enc[3] = dl2_lo;
873 enc[4] = dh2;
874 enc[5] = opcode2;
875 enc
876}
877
878fn enc_si(opcode: u16, b1: Reg, d1: u32, i2: u8) -> [u8; 4] {
885 let opcode = (opcode & 0xff) as u8;
886 let b1 = machreg_to_gpr(b1) & 0x0f;
887 let d1_lo = (d1 & 0xff) as u8;
888 let d1_hi = ((d1 >> 8) & 0x0f) as u8;
889
890 let mut enc: [u8; 4] = [0; 4];
891 enc[0] = opcode;
892 enc[1] = i2;
893 enc[2] = b1 << 4 | d1_hi;
894 enc[3] = d1_lo;
895 enc
896}
897
898fn enc_sil(opcode: u16, b1: Reg, d1: u32, i2: i16) -> [u8; 6] {
905 let opcode1 = ((opcode >> 8) & 0xff) as u8;
906 let opcode2 = (opcode & 0xff) as u8;
907 let b1 = machreg_to_gpr(b1) & 0x0f;
908 let d1_lo = (d1 & 0xff) as u8;
909 let d1_hi = ((d1 >> 8) & 0x0f) as u8;
910
911 let mut enc: [u8; 6] = [0; 6];
912 enc[0] = opcode1;
913 enc[1] = opcode2;
914 enc[2] = b1 << 4 | d1_hi;
915 enc[3] = d1_lo;
916 enc[4..].copy_from_slice(&i2.to_be_bytes());
917 enc
918}
919
920fn enc_siy(opcode: u16, b1: Reg, d1: u32, i2: u8) -> [u8; 6] {
927 let opcode1 = ((opcode >> 8) & 0xff) as u8;
928 let opcode2 = (opcode & 0xff) as u8;
929 let b1 = machreg_to_gpr(b1) & 0x0f;
930 let dl1_lo = (d1 & 0xff) as u8;
931 let dl1_hi = ((d1 >> 8) & 0x0f) as u8;
932 let dh1 = ((d1 >> 12) & 0xff) as u8;
933
934 let mut enc: [u8; 6] = [0; 6];
935 enc[0] = opcode1;
936 enc[1] = i2;
937 enc[2] = b1 << 4 | dl1_hi;
938 enc[3] = dl1_lo;
939 enc[4] = dh1;
940 enc[5] = opcode2;
941 enc
942}
943
944fn enc_vri_a(opcode: u16, v1: Reg, i2: u16, m3: u8) -> [u8; 6] {
951 let opcode1 = ((opcode >> 8) & 0xff) as u8;
952 let opcode2 = (opcode & 0xff) as u8;
953 let rxb = rxb(Some(v1), None, None, None);
954 let v1 = machreg_to_vr(v1) & 0x0f;
955 let m3 = m3 & 0x0f;
956
957 let mut enc: [u8; 6] = [0; 6];
958 enc[0] = opcode1;
959 enc[1] = v1 << 4;
960 enc[2..4].copy_from_slice(&i2.to_be_bytes());
961 enc[4] = m3 << 4 | rxb;
962 enc[5] = opcode2;
963 enc
964}
965
966fn enc_vri_b(opcode: u16, v1: Reg, i2: u8, i3: u8, m4: u8) -> [u8; 6] {
973 let opcode1 = ((opcode >> 8) & 0xff) as u8;
974 let opcode2 = (opcode & 0xff) as u8;
975 let rxb = rxb(Some(v1), None, None, None);
976 let v1 = machreg_to_vr(v1) & 0x0f;
977 let m4 = m4 & 0x0f;
978
979 let mut enc: [u8; 6] = [0; 6];
980 enc[0] = opcode1;
981 enc[1] = v1 << 4;
982 enc[2] = i2;
983 enc[3] = i3;
984 enc[4] = m4 << 4 | rxb;
985 enc[5] = opcode2;
986 enc
987}
988
989fn enc_vri_c(opcode: u16, v1: Reg, i2: u16, v3: Reg, m4: u8) -> [u8; 6] {
996 let opcode1 = ((opcode >> 8) & 0xff) as u8;
997 let opcode2 = (opcode & 0xff) as u8;
998 let rxb = rxb(Some(v1), Some(v3), None, None);
999 let v1 = machreg_to_vr(v1) & 0x0f;
1000 let v3 = machreg_to_vr(v3) & 0x0f;
1001 let m4 = m4 & 0x0f;
1002
1003 let mut enc: [u8; 6] = [0; 6];
1004 enc[0] = opcode1;
1005 enc[1] = v1 << 4 | v3;
1006 enc[2..4].copy_from_slice(&i2.to_be_bytes());
1007 enc[4] = m4 << 4 | rxb;
1008 enc[5] = opcode2;
1009 enc
1010}
1011
1012fn enc_vrr_a(opcode: u16, v1: Reg, v2: Reg, m3: u8, m4: u8, m5: u8) -> [u8; 6] {
1019 let opcode1 = ((opcode >> 8) & 0xff) as u8;
1020 let opcode2 = (opcode & 0xff) as u8;
1021 let rxb = rxb(Some(v1), Some(v2), None, None);
1022 let v1 = machreg_to_vr(v1) & 0x0f;
1023 let v2 = machreg_to_vr(v2) & 0x0f;
1024 let m3 = m3 & 0x0f;
1025 let m4 = m4 & 0x0f;
1026 let m5 = m5 & 0x0f;
1027
1028 let mut enc: [u8; 6] = [0; 6];
1029 enc[0] = opcode1;
1030 enc[1] = v1 << 4 | v2;
1031 enc[2] = 0;
1032 enc[3] = m5 << 4 | m4;
1033 enc[4] = m3 << 4 | rxb;
1034 enc[5] = opcode2;
1035 enc
1036}
1037
1038fn enc_vrr_b(opcode: u16, v1: Reg, v2: Reg, v3: Reg, m4: u8, m5: u8) -> [u8; 6] {
1045 let opcode1 = ((opcode >> 8) & 0xff) as u8;
1046 let opcode2 = (opcode & 0xff) as u8;
1047 let rxb = rxb(Some(v1), Some(v2), Some(v3), None);
1048 let v1 = machreg_to_vr(v1) & 0x0f;
1049 let v2 = machreg_to_vr(v2) & 0x0f;
1050 let v3 = machreg_to_vr(v3) & 0x0f;
1051 let m4 = m4 & 0x0f;
1052 let m5 = m5 & 0x0f;
1053
1054 let mut enc: [u8; 6] = [0; 6];
1055 enc[0] = opcode1;
1056 enc[1] = v1 << 4 | v2;
1057 enc[2] = v3 << 4;
1058 enc[3] = m5 << 4;
1059 enc[4] = m4 << 4 | rxb;
1060 enc[5] = opcode2;
1061 enc
1062}
1063
1064fn enc_vrr_c(opcode: u16, v1: Reg, v2: Reg, v3: Reg, m4: u8, m5: u8, m6: u8) -> [u8; 6] {
1071 let opcode1 = ((opcode >> 8) & 0xff) as u8;
1072 let opcode2 = (opcode & 0xff) as u8;
1073 let rxb = rxb(Some(v1), Some(v2), Some(v3), None);
1074 let v1 = machreg_to_vr(v1) & 0x0f;
1075 let v2 = machreg_to_vr(v2) & 0x0f;
1076 let v3 = machreg_to_vr(v3) & 0x0f;
1077 let m4 = m4 & 0x0f;
1078 let m5 = m5 & 0x0f;
1079 let m6 = m6 & 0x0f;
1080
1081 let mut enc: [u8; 6] = [0; 6];
1082 enc[0] = opcode1;
1083 enc[1] = v1 << 4 | v2;
1084 enc[2] = v3 << 4;
1085 enc[3] = m6 << 4 | m5;
1086 enc[4] = m4 << 4 | rxb;
1087 enc[5] = opcode2;
1088 enc
1089}
1090
1091fn enc_vrr_e(opcode: u16, v1: Reg, v2: Reg, v3: Reg, v4: Reg, m5: u8, m6: u8) -> [u8; 6] {
1098 let opcode1 = ((opcode >> 8) & 0xff) as u8;
1099 let opcode2 = (opcode & 0xff) as u8;
1100 let rxb = rxb(Some(v1), Some(v2), Some(v3), Some(v4));
1101 let v1 = machreg_to_vr(v1) & 0x0f;
1102 let v2 = machreg_to_vr(v2) & 0x0f;
1103 let v3 = machreg_to_vr(v3) & 0x0f;
1104 let v4 = machreg_to_vr(v4) & 0x0f;
1105 let m5 = m5 & 0x0f;
1106 let m6 = m6 & 0x0f;
1107
1108 let mut enc: [u8; 6] = [0; 6];
1109 enc[0] = opcode1;
1110 enc[1] = v1 << 4 | v2;
1111 enc[2] = v3 << 4 | m6;
1112 enc[3] = m5;
1113 enc[4] = v4 << 4 | rxb;
1114 enc[5] = opcode2;
1115 enc
1116}
1117
1118fn enc_vrr_f(opcode: u16, v1: Reg, r2: Reg, r3: Reg) -> [u8; 6] {
1125 let opcode1 = ((opcode >> 8) & 0xff) as u8;
1126 let opcode2 = (opcode & 0xff) as u8;
1127 let rxb = rxb(Some(v1), None, None, None);
1128 let v1 = machreg_to_vr(v1) & 0x0f;
1129 let r2 = machreg_to_gpr(r2) & 0x0f;
1130 let r3 = machreg_to_gpr(r3) & 0x0f;
1131
1132 let mut enc: [u8; 6] = [0; 6];
1133 enc[0] = opcode1;
1134 enc[1] = v1 << 4 | r2;
1135 enc[2] = r3 << 4;
1136 enc[4] = rxb;
1137 enc[5] = opcode2;
1138 enc
1139}
1140
1141fn enc_vrs_a(opcode: u16, v1: Reg, b2: Reg, d2: u32, v3: Reg, m4: u8) -> [u8; 6] {
1148 let opcode1 = ((opcode >> 8) & 0xff) as u8;
1149 let opcode2 = (opcode & 0xff) as u8;
1150 let rxb = rxb(Some(v1), Some(v3), None, None);
1151 let v1 = machreg_to_vr(v1) & 0x0f;
1152 let b2 = machreg_to_gpr(b2) & 0x0f;
1153 let v3 = machreg_to_vr(v3) & 0x0f;
1154 let d2_lo = (d2 & 0xff) as u8;
1155 let d2_hi = ((d2 >> 8) & 0x0f) as u8;
1156 let m4 = m4 & 0x0f;
1157
1158 let mut enc: [u8; 6] = [0; 6];
1159 enc[0] = opcode1;
1160 enc[1] = v1 << 4 | v3;
1161 enc[2] = b2 << 4 | d2_hi;
1162 enc[3] = d2_lo;
1163 enc[4] = m4 << 4 | rxb;
1164 enc[5] = opcode2;
1165 enc
1166}
1167
1168fn enc_vrs_b(opcode: u16, v1: Reg, b2: Reg, d2: u32, r3: Reg, m4: u8) -> [u8; 6] {
1175 let opcode1 = ((opcode >> 8) & 0xff) as u8;
1176 let opcode2 = (opcode & 0xff) as u8;
1177 let rxb = rxb(Some(v1), None, None, None);
1178 let v1 = machreg_to_vr(v1) & 0x0f;
1179 let b2 = machreg_to_gpr(b2) & 0x0f;
1180 let r3 = machreg_to_gpr(r3) & 0x0f;
1181 let d2_lo = (d2 & 0xff) as u8;
1182 let d2_hi = ((d2 >> 8) & 0x0f) as u8;
1183 let m4 = m4 & 0x0f;
1184
1185 let mut enc: [u8; 6] = [0; 6];
1186 enc[0] = opcode1;
1187 enc[1] = v1 << 4 | r3;
1188 enc[2] = b2 << 4 | d2_hi;
1189 enc[3] = d2_lo;
1190 enc[4] = m4 << 4 | rxb;
1191 enc[5] = opcode2;
1192 enc
1193}
1194
1195fn enc_vrs_c(opcode: u16, r1: Reg, b2: Reg, d2: u32, v3: Reg, m4: u8) -> [u8; 6] {
1202 let opcode1 = ((opcode >> 8) & 0xff) as u8;
1203 let opcode2 = (opcode & 0xff) as u8;
1204 let rxb = rxb(None, Some(v3), None, None);
1205 let r1 = machreg_to_gpr(r1) & 0x0f;
1206 let b2 = machreg_to_gpr(b2) & 0x0f;
1207 let v3 = machreg_to_vr(v3) & 0x0f;
1208 let d2_lo = (d2 & 0xff) as u8;
1209 let d2_hi = ((d2 >> 8) & 0x0f) as u8;
1210 let m4 = m4 & 0x0f;
1211
1212 let mut enc: [u8; 6] = [0; 6];
1213 enc[0] = opcode1;
1214 enc[1] = r1 << 4 | v3;
1215 enc[2] = b2 << 4 | d2_hi;
1216 enc[3] = d2_lo;
1217 enc[4] = m4 << 4 | rxb;
1218 enc[5] = opcode2;
1219 enc
1220}
1221
1222fn enc_vrx(opcode: u16, v1: Reg, b2: Reg, x2: Reg, d2: u32, m3: u8) -> [u8; 6] {
1229 let opcode1 = ((opcode >> 8) & 0xff) as u8;
1230 let opcode2 = (opcode & 0xff) as u8;
1231 let rxb = rxb(Some(v1), None, None, None);
1232 let v1 = machreg_to_vr(v1) & 0x0f;
1233 let b2 = machreg_to_gpr(b2) & 0x0f;
1234 let x2 = machreg_to_gpr(x2) & 0x0f;
1235 let d2_lo = (d2 & 0xff) as u8;
1236 let d2_hi = ((d2 >> 8) & 0x0f) as u8;
1237 let m3 = m3 & 0x0f;
1238
1239 let mut enc: [u8; 6] = [0; 6];
1240 enc[0] = opcode1;
1241 enc[1] = v1 << 4 | x2;
1242 enc[2] = b2 << 4 | d2_hi;
1243 enc[3] = d2_lo;
1244 enc[4] = m3 << 4 | rxb;
1245 enc[5] = opcode2;
1246 enc
1247}
1248
1249fn put(sink: &mut MachBuffer<Inst>, enc: &[u8]) {
1251 for byte in enc {
1252 sink.put1(*byte);
1253 }
1254}
1255
1256fn put_with_trap(sink: &mut MachBuffer<Inst>, enc: &[u8], trap_code: TrapCode) {
1258 let len = enc.len();
1259 for i in 0..len - 1 {
1260 sink.put1(enc[i]);
1261 }
1262 sink.add_trap(trap_code);
1263 sink.put1(enc[len - 1]);
1264}
1265
1266#[derive(Default, Clone, Debug)]
1268pub struct EmitState {
1269 pub(crate) nominal_sp_offset: u32,
1274
1275 user_stack_map: Option<ir::UserStackMap>,
1278
1279 ctrl_plane: ControlPlane,
1282
1283 frame_layout: FrameLayout,
1284}
1285
1286impl MachInstEmitState<Inst> for EmitState {
1287 fn new(abi: &Callee<S390xMachineDeps>, ctrl_plane: ControlPlane) -> Self {
1288 EmitState {
1289 nominal_sp_offset: 0,
1290 user_stack_map: None,
1291 ctrl_plane,
1292 frame_layout: abi.frame_layout().clone(),
1293 }
1294 }
1295
1296 fn pre_safepoint(&mut self, user_stack_map: Option<ir::UserStackMap>) {
1297 self.user_stack_map = user_stack_map;
1298 }
1299
1300 fn ctrl_plane_mut(&mut self) -> &mut ControlPlane {
1301 &mut self.ctrl_plane
1302 }
1303
1304 fn take_ctrl_plane(self) -> ControlPlane {
1305 self.ctrl_plane
1306 }
1307
1308 fn frame_layout(&self) -> &FrameLayout {
1309 &self.frame_layout
1310 }
1311}
1312
1313impl EmitState {
1314 fn take_stack_map(&mut self) -> Option<ir::UserStackMap> {
1315 self.user_stack_map.take()
1316 }
1317
1318 fn clear_post_insn(&mut self) {
1319 self.user_stack_map = None;
1320 }
1321}
1322
1323pub struct EmitInfo {
1325 isa_flags: s390x_settings::Flags,
1326}
1327
1328impl EmitInfo {
1329 pub(crate) fn new(isa_flags: s390x_settings::Flags) -> Self {
1330 Self { isa_flags }
1331 }
1332}
1333
1334impl MachInstEmit for Inst {
1335 type State = EmitState;
1336 type Info = EmitInfo;
1337
1338 fn emit(&self, sink: &mut MachBuffer<Inst>, emit_info: &Self::Info, state: &mut EmitState) {
1339 self.emit_with_alloc_consumer(sink, emit_info, state)
1340 }
1341
1342 fn pretty_print_inst(&self, state: &mut EmitState) -> String {
1343 self.print_with_state(state)
1344 }
1345}
1346
1347impl Inst {
1348 fn emit_with_alloc_consumer(
1349 &self,
1350 sink: &mut MachBuffer<Inst>,
1351 emit_info: &EmitInfo,
1352 state: &mut EmitState,
1353 ) {
1354 let matches_isa_flags = |iset_requirement: &InstructionSet| -> bool {
1356 match iset_requirement {
1357 InstructionSet::Base => true,
1359 InstructionSet::MIE2 => emit_info.isa_flags.has_mie2(),
1361 InstructionSet::VXRS_EXT2 => emit_info.isa_flags.has_vxrs_ext2(),
1363 }
1364 };
1365 let isa_requirements = self.available_in_isa();
1366 if !matches_isa_flags(&isa_requirements) {
1367 panic!(
1368 "Cannot emit inst '{self:?}' for target; failed to match ISA requirements: {isa_requirements:?}"
1369 )
1370 }
1371
1372 let mut start_off = sink.cur_offset();
1378
1379 match self {
1380 &Inst::AluRRR { alu_op, rd, rn, rm } => {
1381 let (opcode, have_rr) = match alu_op {
1382 ALUOp::Add32 => (0xb9f8, true), ALUOp::Add64 => (0xb9e8, true), ALUOp::AddLogical32 => (0xb9fa, true), ALUOp::AddLogical64 => (0xb9ea, true), ALUOp::Sub32 => (0xb9f9, true), ALUOp::Sub64 => (0xb9e9, true), ALUOp::SubLogical32 => (0xb9fb, true), ALUOp::SubLogical64 => (0xb9eb, true), ALUOp::Mul32 => (0xb9fd, true), ALUOp::Mul64 => (0xb9ed, true), ALUOp::And32 => (0xb9f4, true), ALUOp::And64 => (0xb9e4, true), ALUOp::Orr32 => (0xb9f6, true), ALUOp::Orr64 => (0xb9e6, true), ALUOp::Xor32 => (0xb9f7, true), ALUOp::Xor64 => (0xb9e7, true), ALUOp::NotAnd32 => (0xb974, false), ALUOp::NotAnd64 => (0xb964, false), ALUOp::NotOrr32 => (0xb976, false), ALUOp::NotOrr64 => (0xb966, false), ALUOp::NotXor32 => (0xb977, false), ALUOp::NotXor64 => (0xb967, false), ALUOp::AndNot32 => (0xb9f5, false), ALUOp::AndNot64 => (0xb9e5, false), ALUOp::OrrNot32 => (0xb975, false), ALUOp::OrrNot64 => (0xb965, false), _ => unreachable!(),
1409 };
1410 if have_rr && rd.to_reg() == rn {
1411 let inst = Inst::AluRR {
1412 alu_op,
1413 rd,
1414 ri: rn,
1415 rm,
1416 };
1417 inst.emit(sink, emit_info, state);
1418 } else {
1419 put(sink, &enc_rrf_ab(opcode, rd.to_reg(), rn, rm, 0));
1420 }
1421 }
1422 &Inst::AluRRSImm16 {
1423 alu_op,
1424 rd,
1425 rn,
1426 imm,
1427 } => {
1428 if rd.to_reg() == rn {
1429 let inst = Inst::AluRSImm16 {
1430 alu_op,
1431 rd,
1432 ri: rn,
1433 imm,
1434 };
1435 inst.emit(sink, emit_info, state);
1436 } else {
1437 let opcode = match alu_op {
1438 ALUOp::Add32 => 0xecd8, ALUOp::Add64 => 0xecd9, _ => unreachable!(),
1441 };
1442 put(sink, &enc_rie_d(opcode, rd.to_reg(), rn, imm as u16));
1443 }
1444 }
1445 &Inst::AluRR { alu_op, rd, ri, rm } => {
1446 debug_assert_eq!(rd.to_reg(), ri);
1447
1448 let (opcode, is_rre) = match alu_op {
1449 ALUOp::Add32 => (0x1a, false), ALUOp::Add64 => (0xb908, true), ALUOp::Add64Ext32 => (0xb918, true), ALUOp::AddLogical32 => (0x1e, false), ALUOp::AddLogical64 => (0xb90a, true), ALUOp::AddLogical64Ext32 => (0xb91a, true), ALUOp::Sub32 => (0x1b, false), ALUOp::Sub64 => (0xb909, true), ALUOp::Sub64Ext32 => (0xb919, true), ALUOp::SubLogical32 => (0x1f, false), ALUOp::SubLogical64 => (0xb90b, true), ALUOp::SubLogical64Ext32 => (0xb91b, true), ALUOp::Mul32 => (0xb252, true), ALUOp::Mul64 => (0xb90c, true), ALUOp::Mul64Ext32 => (0xb91c, true), ALUOp::And32 => (0x14, false), ALUOp::And64 => (0xb980, true), ALUOp::Orr32 => (0x16, false), ALUOp::Orr64 => (0xb981, true), ALUOp::Xor32 => (0x17, false), ALUOp::Xor64 => (0xb982, true), _ => unreachable!(),
1471 };
1472 if is_rre {
1473 put(sink, &enc_rre(opcode, rd.to_reg(), rm));
1474 } else {
1475 put(sink, &enc_rr(opcode, rd.to_reg(), rm));
1476 }
1477 }
1478 &Inst::AluRX {
1479 alu_op,
1480 rd,
1481 ri,
1482 ref mem,
1483 } => {
1484 debug_assert_eq!(rd.to_reg(), ri);
1485 let mem = mem.clone();
1486
1487 let (opcode_rx, opcode_rxy) = match alu_op {
1488 ALUOp::Add32 => (Some(0x5a), Some(0xe35a)), ALUOp::Add32Ext16 => (Some(0x4a), Some(0xe37a)), ALUOp::Add64 => (None, Some(0xe308)), ALUOp::Add64Ext16 => (None, Some(0xe338)), ALUOp::Add64Ext32 => (None, Some(0xe318)), ALUOp::AddLogical32 => (Some(0x5e), Some(0xe35e)), ALUOp::AddLogical64 => (None, Some(0xe30a)), ALUOp::AddLogical64Ext32 => (None, Some(0xe31a)), ALUOp::Sub32 => (Some(0x5b), Some(0xe35b)), ALUOp::Sub32Ext16 => (Some(0x4b), Some(0xe37b)), ALUOp::Sub64 => (None, Some(0xe309)), ALUOp::Sub64Ext16 => (None, Some(0xe339)), ALUOp::Sub64Ext32 => (None, Some(0xe319)), ALUOp::SubLogical32 => (Some(0x5f), Some(0xe35f)), ALUOp::SubLogical64 => (None, Some(0xe30b)), ALUOp::SubLogical64Ext32 => (None, Some(0xe31b)), ALUOp::Mul32 => (Some(0x71), Some(0xe351)), ALUOp::Mul32Ext16 => (Some(0x4c), Some(0xe37c)), ALUOp::Mul64 => (None, Some(0xe30c)), ALUOp::Mul64Ext16 => (None, Some(0xe33c)), ALUOp::Mul64Ext32 => (None, Some(0xe31c)), ALUOp::And32 => (Some(0x54), Some(0xe354)), ALUOp::And64 => (None, Some(0xe380)), ALUOp::Orr32 => (Some(0x56), Some(0xe356)), ALUOp::Orr64 => (None, Some(0xe381)), ALUOp::Xor32 => (Some(0x57), Some(0xe357)), ALUOp::Xor64 => (None, Some(0xe382)), _ => unreachable!(),
1516 };
1517 let rd = rd.to_reg();
1518 mem_emit(
1519 rd, &mem, opcode_rx, opcode_rxy, None, true, sink, emit_info, state,
1520 );
1521 }
1522 &Inst::AluRSImm16 {
1523 alu_op,
1524 rd,
1525 ri,
1526 imm,
1527 } => {
1528 debug_assert_eq!(rd.to_reg(), ri);
1529
1530 let opcode = match alu_op {
1531 ALUOp::Add32 => 0xa7a, ALUOp::Add64 => 0xa7b, ALUOp::Mul32 => 0xa7c, ALUOp::Mul64 => 0xa7d, _ => unreachable!(),
1536 };
1537 put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16));
1538 }
1539 &Inst::AluRSImm32 {
1540 alu_op,
1541 rd,
1542 ri,
1543 imm,
1544 } => {
1545 debug_assert_eq!(rd.to_reg(), ri);
1546
1547 let opcode = match alu_op {
1548 ALUOp::Add32 => 0xc29, ALUOp::Add64 => 0xc28, ALUOp::Mul32 => 0xc21, ALUOp::Mul64 => 0xc20, _ => unreachable!(),
1553 };
1554 put(sink, &enc_ril_a(opcode, rd.to_reg(), imm as u32));
1555 }
1556 &Inst::AluRUImm32 {
1557 alu_op,
1558 rd,
1559 ri,
1560 imm,
1561 } => {
1562 debug_assert_eq!(rd.to_reg(), ri);
1563
1564 let opcode = match alu_op {
1565 ALUOp::AddLogical32 => 0xc2b, ALUOp::AddLogical64 => 0xc2a, ALUOp::SubLogical32 => 0xc25, ALUOp::SubLogical64 => 0xc24, _ => unreachable!(),
1570 };
1571 put(sink, &enc_ril_a(opcode, rd.to_reg(), imm));
1572 }
1573 &Inst::AluRUImm16Shifted {
1574 alu_op,
1575 rd,
1576 ri,
1577 imm,
1578 } => {
1579 debug_assert_eq!(rd.to_reg(), ri);
1580
1581 let opcode = match (alu_op, imm.shift) {
1582 (ALUOp::And32, 0) => 0xa57, (ALUOp::And32, 1) => 0xa56, (ALUOp::And64, 0) => 0xa57, (ALUOp::And64, 1) => 0xa56, (ALUOp::And64, 2) => 0xa55, (ALUOp::And64, 3) => 0xa54, (ALUOp::Orr32, 0) => 0xa5b, (ALUOp::Orr32, 1) => 0xa5a, (ALUOp::Orr64, 0) => 0xa5b, (ALUOp::Orr64, 1) => 0xa5a, (ALUOp::Orr64, 2) => 0xa59, (ALUOp::Orr64, 3) => 0xa58, _ => unreachable!(),
1595 };
1596 put(sink, &enc_ri_a(opcode, rd.to_reg(), imm.bits));
1597 }
1598 &Inst::AluRUImm32Shifted {
1599 alu_op,
1600 rd,
1601 ri,
1602 imm,
1603 } => {
1604 debug_assert_eq!(rd.to_reg(), ri);
1605
1606 let opcode = match (alu_op, imm.shift) {
1607 (ALUOp::And32, 0) => 0xc0b, (ALUOp::And64, 0) => 0xc0b, (ALUOp::And64, 1) => 0xc0a, (ALUOp::Orr32, 0) => 0xc0d, (ALUOp::Orr64, 0) => 0xc0d, (ALUOp::Orr64, 1) => 0xc0c, (ALUOp::Xor32, 0) => 0xc07, (ALUOp::Xor64, 0) => 0xc07, (ALUOp::Xor64, 1) => 0xc06, _ => unreachable!(),
1617 };
1618 put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits));
1619 }
1620
1621 &Inst::SMulWide { rd, rn, rm } => {
1622 let rd1 = rd.hi;
1623 let rd2 = rd.lo;
1624 debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1625
1626 let opcode = 0xb9ec; put(sink, &enc_rrf_ab(opcode, rd1.to_reg(), rn, rm, 0));
1628 }
1629 &Inst::UMulWide { rd, ri, rn } => {
1630 let rd1 = rd.hi;
1631 let rd2 = rd.lo;
1632 debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1633 debug_assert_eq!(rd2.to_reg(), ri);
1634
1635 let opcode = 0xb986; put(sink, &enc_rre(opcode, rd1.to_reg(), rn));
1637 }
1638 &Inst::SDivMod32 { rd, ri, rn } => {
1639 let rd1 = rd.hi;
1640 let rd2 = rd.lo;
1641 debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1642 debug_assert_eq!(rd2.to_reg(), ri);
1643
1644 let opcode = 0xb91d; let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;
1646 put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);
1647 }
1648 &Inst::SDivMod64 { rd, ri, rn } => {
1649 let rd1 = rd.hi;
1650 let rd2 = rd.lo;
1651 debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1652 debug_assert_eq!(rd2.to_reg(), ri);
1653
1654 let opcode = 0xb90d; let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;
1656 put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);
1657 }
1658 &Inst::UDivMod32 { rd, ri, rn } => {
1659 let rd1 = rd.hi;
1660 let rd2 = rd.lo;
1661 debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1662 let ri1 = ri.hi;
1663 let ri2 = ri.lo;
1664 debug_assert_eq!(rd1.to_reg(), ri1);
1665 debug_assert_eq!(rd2.to_reg(), ri2);
1666
1667 let opcode = 0xb997; let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;
1669 put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);
1670 }
1671 &Inst::UDivMod64 { rd, ri, rn } => {
1672 let rd1 = rd.hi;
1673 let rd2 = rd.lo;
1674 debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1675 let ri1 = ri.hi;
1676 let ri2 = ri.lo;
1677 debug_assert_eq!(rd1.to_reg(), ri1);
1678 debug_assert_eq!(rd2.to_reg(), ri2);
1679
1680 let opcode = 0xb987; let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;
1682 put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);
1683 }
1684 &Inst::Flogr { rd, rn } => {
1685 let rd1 = rd.hi;
1686 let rd2 = rd.lo;
1687 debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1688
1689 let opcode = 0xb983; put(sink, &enc_rre(opcode, rd1.to_reg(), rn));
1691 }
1692
1693 &Inst::ShiftRR {
1694 shift_op,
1695 rd,
1696 rn,
1697 shift_imm,
1698 shift_reg,
1699 } => {
1700 let opcode = match shift_op {
1701 ShiftOp::RotL32 => 0xeb1d, ShiftOp::RotL64 => 0xeb1c, ShiftOp::LShL32 => 0xebdf, ShiftOp::LShL64 => 0xeb0d, ShiftOp::LShR32 => 0xebde, ShiftOp::LShR64 => 0xeb0c, ShiftOp::AShR32 => 0xebdc, ShiftOp::AShR64 => 0xeb0a, };
1710 put(
1711 sink,
1712 &enc_rsy(opcode, rd.to_reg(), rn, shift_reg, shift_imm.into()),
1713 );
1714 }
1715
1716 &Inst::RxSBG {
1717 op,
1718 rd,
1719 ri,
1720 rn,
1721 start_bit,
1722 end_bit,
1723 rotate_amt,
1724 } => {
1725 debug_assert_eq!(rd.to_reg(), ri);
1726
1727 let opcode = match op {
1728 RxSBGOp::Insert => 0xec59, RxSBGOp::And => 0xec54, RxSBGOp::Or => 0xec56, RxSBGOp::Xor => 0xec57, };
1733 put(
1734 sink,
1735 &enc_rie_f(
1736 opcode,
1737 rd.to_reg(),
1738 rn,
1739 start_bit,
1740 end_bit,
1741 (rotate_amt as u8) & 63,
1742 ),
1743 );
1744 }
1745
1746 &Inst::RxSBGTest {
1747 op,
1748 rd,
1749 rn,
1750 start_bit,
1751 end_bit,
1752 rotate_amt,
1753 } => {
1754 let opcode = match op {
1755 RxSBGOp::And => 0xec54, RxSBGOp::Or => 0xec56, RxSBGOp::Xor => 0xec57, _ => unreachable!(),
1759 };
1760 put(
1761 sink,
1762 &enc_rie_f(
1763 opcode,
1764 rd,
1765 rn,
1766 start_bit | 0x80,
1767 end_bit,
1768 (rotate_amt as u8) & 63,
1769 ),
1770 );
1771 }
1772
1773 &Inst::UnaryRR { op, rd, rn } => {
1774 match op {
1775 UnaryOp::Abs32 => {
1776 let opcode = 0x10; put(sink, &enc_rr(opcode, rd.to_reg(), rn));
1778 }
1779 UnaryOp::Abs64 => {
1780 let opcode = 0xb900; put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1782 }
1783 UnaryOp::Abs64Ext32 => {
1784 let opcode = 0xb910; put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1786 }
1787 UnaryOp::Neg32 => {
1788 let opcode = 0x13; put(sink, &enc_rr(opcode, rd.to_reg(), rn));
1790 }
1791 UnaryOp::Neg64 => {
1792 let opcode = 0xb903; put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1794 }
1795 UnaryOp::Neg64Ext32 => {
1796 let opcode = 0xb913; put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1798 }
1799 UnaryOp::PopcntByte => {
1800 let opcode = 0xb9e1; put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rn, 0, 0));
1802 }
1803 UnaryOp::PopcntReg => {
1804 let opcode = 0xb9e1; put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rn, 8, 0));
1806 }
1807 UnaryOp::BSwap32 => {
1808 let opcode = 0xb91f; put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1810 }
1811 UnaryOp::BSwap64 => {
1812 let opcode = 0xb90f; put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1814 }
1815 }
1816 }
1817
1818 &Inst::Extend {
1819 rd,
1820 rn,
1821 signed,
1822 from_bits,
1823 to_bits,
1824 } => {
1825 let opcode = match (signed, from_bits, to_bits) {
1826 (_, 1, 32) => 0xb926, (_, 1, 64) => 0xb906, (false, 8, 32) => 0xb994, (false, 8, 64) => 0xb984, (true, 8, 32) => 0xb926, (true, 8, 64) => 0xb906, (false, 16, 32) => 0xb995, (false, 16, 64) => 0xb985, (true, 16, 32) => 0xb927, (true, 16, 64) => 0xb907, (false, 32, 64) => 0xb916, (true, 32, 64) => 0xb914, _ => panic!(
1839 "Unsupported extend combination: signed = {signed}, from_bits = {from_bits}, to_bits = {to_bits}"
1840 ),
1841 };
1842 put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1843 }
1844
1845 &Inst::CmpRR { op, rn, rm } => {
1846 let (opcode, is_rre) = match op {
1847 CmpOp::CmpS32 => (0x19, false), CmpOp::CmpS64 => (0xb920, true), CmpOp::CmpS64Ext32 => (0xb930, true), CmpOp::CmpL32 => (0x15, false), CmpOp::CmpL64 => (0xb921, true), CmpOp::CmpL64Ext32 => (0xb931, true), _ => unreachable!(),
1854 };
1855 if is_rre {
1856 put(sink, &enc_rre(opcode, rn, rm));
1857 } else {
1858 put(sink, &enc_rr(opcode, rn, rm));
1859 }
1860 }
1861 &Inst::CmpRX { op, rn, ref mem } => {
1862 let mem = mem.clone();
1863
1864 let (opcode_rx, opcode_rxy, opcode_ril) = match op {
1865 CmpOp::CmpS32 => (Some(0x59), Some(0xe359), Some(0xc6d)), CmpOp::CmpS32Ext16 => (Some(0x49), Some(0xe379), Some(0xc65)), CmpOp::CmpS64 => (None, Some(0xe320), Some(0xc68)), CmpOp::CmpS64Ext16 => (None, Some(0xe334), Some(0xc64)), CmpOp::CmpS64Ext32 => (None, Some(0xe330), Some(0xc6c)), CmpOp::CmpL32 => (Some(0x55), Some(0xe355), Some(0xc6f)), CmpOp::CmpL32Ext16 => (None, None, Some(0xc67)), CmpOp::CmpL64 => (None, Some(0xe321), Some(0xc6a)), CmpOp::CmpL64Ext16 => (None, None, Some(0xc66)), CmpOp::CmpL64Ext32 => (None, Some(0xe331), Some(0xc6e)), };
1876 mem_emit(
1877 rn, &mem, opcode_rx, opcode_rxy, opcode_ril, true, sink, emit_info, state,
1878 );
1879 }
1880 &Inst::CmpRSImm16 { op, rn, imm } => {
1881 let opcode = match op {
1882 CmpOp::CmpS32 => 0xa7e, CmpOp::CmpS64 => 0xa7f, _ => unreachable!(),
1885 };
1886 put(sink, &enc_ri_a(opcode, rn, imm as u16));
1887 }
1888 &Inst::CmpRSImm32 { op, rn, imm } => {
1889 let opcode = match op {
1890 CmpOp::CmpS32 => 0xc2d, CmpOp::CmpS64 => 0xc2c, _ => unreachable!(),
1893 };
1894 put(sink, &enc_ril_a(opcode, rn, imm as u32));
1895 }
1896 &Inst::CmpRUImm32 { op, rn, imm } => {
1897 let opcode = match op {
1898 CmpOp::CmpL32 => 0xc2f, CmpOp::CmpL64 => 0xc2e, _ => unreachable!(),
1901 };
1902 put(sink, &enc_ril_a(opcode, rn, imm));
1903 }
1904 &Inst::CmpTrapRR {
1905 op,
1906 rn,
1907 rm,
1908 cond,
1909 trap_code,
1910 } => {
1911 let opcode = match op {
1912 CmpOp::CmpS32 => 0xb972, CmpOp::CmpS64 => 0xb960, CmpOp::CmpL32 => 0xb973, CmpOp::CmpL64 => 0xb961, _ => unreachable!(),
1917 };
1918 put_with_trap(
1919 sink,
1920 &enc_rrf_cde(opcode, rn, rm, cond.bits(), 0),
1921 trap_code,
1922 );
1923 }
1924 &Inst::CmpTrapRSImm16 {
1925 op,
1926 rn,
1927 imm,
1928 cond,
1929 trap_code,
1930 } => {
1931 let opcode = match op {
1932 CmpOp::CmpS32 => 0xec72, CmpOp::CmpS64 => 0xec70, _ => unreachable!(),
1935 };
1936 put_with_trap(
1937 sink,
1938 &enc_rie_a(opcode, rn, imm as u16, cond.bits()),
1939 trap_code,
1940 );
1941 }
1942 &Inst::CmpTrapRUImm16 {
1943 op,
1944 rn,
1945 imm,
1946 cond,
1947 trap_code,
1948 } => {
1949 let opcode = match op {
1950 CmpOp::CmpL32 => 0xec73, CmpOp::CmpL64 => 0xec71, _ => unreachable!(),
1953 };
1954 put_with_trap(sink, &enc_rie_a(opcode, rn, imm, cond.bits()), trap_code);
1955 }
1956
1957 &Inst::AtomicRmw {
1958 alu_op,
1959 rd,
1960 rn,
1961 ref mem,
1962 } => {
1963 let mem = mem.clone();
1964
1965 let opcode = match alu_op {
1966 ALUOp::Add32 => 0xebf8, ALUOp::Add64 => 0xebe8, ALUOp::AddLogical32 => 0xebfa, ALUOp::AddLogical64 => 0xebea, ALUOp::And32 => 0xebf4, ALUOp::And64 => 0xebe4, ALUOp::Orr32 => 0xebf6, ALUOp::Orr64 => 0xebe6, ALUOp::Xor32 => 0xebf7, ALUOp::Xor64 => 0xebe7, _ => unreachable!(),
1977 };
1978
1979 let rd = rd.to_reg();
1980 mem_rs_emit(
1981 rd,
1982 rn,
1983 &mem,
1984 None,
1985 Some(opcode),
1986 true,
1987 sink,
1988 emit_info,
1989 state,
1990 );
1991 }
1992 &Inst::Loop { ref body, cond } => {
1993 let loop_label = sink.get_label();
1996 let done_label = sink.get_label();
1997
1998 sink.bind_label(loop_label, &mut state.ctrl_plane);
2000
2001 for inst in (&body).into_iter() {
2002 match &inst {
2003 &Inst::CondBreak { cond } => {
2005 let opcode = 0xc04; sink.use_label_at_offset(
2007 sink.cur_offset(),
2008 done_label,
2009 LabelUse::BranchRIL,
2010 );
2011 put(sink, &enc_ril_c(opcode, cond.bits(), 0));
2012 }
2013 _ => inst.emit_with_alloc_consumer(sink, emit_info, state),
2014 };
2015 }
2016
2017 let opcode = 0xc04; sink.use_label_at_offset(sink.cur_offset(), loop_label, LabelUse::BranchRIL);
2019 put(sink, &enc_ril_c(opcode, cond.bits(), 0));
2020
2021 sink.bind_label(done_label, &mut state.ctrl_plane);
2023 }
2024 &Inst::CondBreak { .. } => unreachable!(), &Inst::AtomicCas32 {
2026 rd,
2027 ri,
2028 rn,
2029 ref mem,
2030 }
2031 | &Inst::AtomicCas64 {
2032 rd,
2033 ri,
2034 rn,
2035 ref mem,
2036 } => {
2037 debug_assert_eq!(rd.to_reg(), ri);
2038 let mem = mem.clone();
2039
2040 let (opcode_rs, opcode_rsy) = match self {
2041 &Inst::AtomicCas32 { .. } => (Some(0xba), Some(0xeb14)), &Inst::AtomicCas64 { .. } => (None, Some(0xeb30)), _ => unreachable!(),
2044 };
2045
2046 let rd = rd.to_reg();
2047 mem_rs_emit(
2048 rd, rn, &mem, opcode_rs, opcode_rsy, true, sink, emit_info, state,
2049 );
2050 }
2051 &Inst::Fence => {
2052 put(sink, &enc_e(0x07e0));
2053 }
2054
2055 &Inst::Load32 { rd, ref mem }
2056 | &Inst::Load32ZExt8 { rd, ref mem }
2057 | &Inst::Load32SExt8 { rd, ref mem }
2058 | &Inst::Load32ZExt16 { rd, ref mem }
2059 | &Inst::Load32SExt16 { rd, ref mem }
2060 | &Inst::Load64 { rd, ref mem }
2061 | &Inst::Load64ZExt8 { rd, ref mem }
2062 | &Inst::Load64SExt8 { rd, ref mem }
2063 | &Inst::Load64ZExt16 { rd, ref mem }
2064 | &Inst::Load64SExt16 { rd, ref mem }
2065 | &Inst::Load64ZExt32 { rd, ref mem }
2066 | &Inst::Load64SExt32 { rd, ref mem }
2067 | &Inst::LoadRev16 { rd, ref mem }
2068 | &Inst::LoadRev32 { rd, ref mem }
2069 | &Inst::LoadRev64 { rd, ref mem } => {
2070 let mem = mem.clone();
2071
2072 let (opcode_rx, opcode_rxy, opcode_ril) = match self {
2073 &Inst::Load32 { .. } => (Some(0x58), Some(0xe358), Some(0xc4d)), &Inst::Load32ZExt8 { .. } => (None, Some(0xe394), None), &Inst::Load32SExt8 { .. } => (None, Some(0xe376), None), &Inst::Load32ZExt16 { .. } => (None, Some(0xe395), Some(0xc42)), &Inst::Load32SExt16 { .. } => (Some(0x48), Some(0xe378), Some(0xc45)), &Inst::Load64 { .. } => (None, Some(0xe304), Some(0xc48)), &Inst::Load64ZExt8 { .. } => (None, Some(0xe390), None), &Inst::Load64SExt8 { .. } => (None, Some(0xe377), None), &Inst::Load64ZExt16 { .. } => (None, Some(0xe391), Some(0xc46)), &Inst::Load64SExt16 { .. } => (None, Some(0xe315), Some(0xc44)), &Inst::Load64ZExt32 { .. } => (None, Some(0xe316), Some(0xc4e)), &Inst::Load64SExt32 { .. } => (None, Some(0xe314), Some(0xc4c)), &Inst::LoadRev16 { .. } => (None, Some(0xe31f), None), &Inst::LoadRev32 { .. } => (None, Some(0xe31e), None), &Inst::LoadRev64 { .. } => (None, Some(0xe30f), None), _ => unreachable!(),
2089 };
2090 let rd = rd.to_reg();
2091 mem_emit(
2092 rd, &mem, opcode_rx, opcode_rxy, opcode_ril, true, sink, emit_info, state,
2093 );
2094 }
2095
2096 &Inst::Store8 { rd, ref mem }
2097 | &Inst::Store16 { rd, ref mem }
2098 | &Inst::Store32 { rd, ref mem }
2099 | &Inst::Store64 { rd, ref mem }
2100 | &Inst::StoreRev16 { rd, ref mem }
2101 | &Inst::StoreRev32 { rd, ref mem }
2102 | &Inst::StoreRev64 { rd, ref mem } => {
2103 let mem = mem.clone();
2104
2105 let (opcode_rx, opcode_rxy, opcode_ril) = match self {
2106 &Inst::Store8 { .. } => (Some(0x42), Some(0xe372), None), &Inst::Store16 { .. } => (Some(0x40), Some(0xe370), Some(0xc47)), &Inst::Store32 { .. } => (Some(0x50), Some(0xe350), Some(0xc4f)), &Inst::Store64 { .. } => (None, Some(0xe324), Some(0xc4b)), &Inst::StoreRev16 { .. } => (None, Some(0xe33f), None), &Inst::StoreRev32 { .. } => (None, Some(0xe33e), None), &Inst::StoreRev64 { .. } => (None, Some(0xe32f), None), _ => unreachable!(),
2114 };
2115 mem_emit(
2116 rd, &mem, opcode_rx, opcode_rxy, opcode_ril, true, sink, emit_info, state,
2117 );
2118 }
2119 &Inst::StoreImm8 { imm, ref mem } => {
2120 let mem = mem.clone();
2121
2122 let opcode_si = 0x92; let opcode_siy = 0xeb52; mem_imm8_emit(
2125 imm, &mem, opcode_si, opcode_siy, true, sink, emit_info, state,
2126 );
2127 }
2128 &Inst::StoreImm16 { imm, ref mem }
2129 | &Inst::StoreImm32SExt16 { imm, ref mem }
2130 | &Inst::StoreImm64SExt16 { imm, ref mem } => {
2131 let mem = mem.clone();
2132
2133 let opcode = match self {
2134 &Inst::StoreImm16 { .. } => 0xe544, &Inst::StoreImm32SExt16 { .. } => 0xe54c, &Inst::StoreImm64SExt16 { .. } => 0xe548, _ => unreachable!(),
2138 };
2139 mem_imm16_emit(imm, &mem, opcode, true, sink, emit_info, state);
2140 }
2141
2142 &Inst::LoadMultiple64 { rt, rt2, ref mem } => {
2143 let mem = mem.clone();
2144
2145 let opcode = 0xeb04; let rt = rt.to_reg();
2147 let rt2 = rt2.to_reg();
2148 mem_rs_emit(
2149 rt,
2150 rt2,
2151 &mem,
2152 None,
2153 Some(opcode),
2154 true,
2155 sink,
2156 emit_info,
2157 state,
2158 );
2159 }
2160 &Inst::StoreMultiple64 { rt, rt2, ref mem } => {
2161 let mem = mem.clone();
2162
2163 let opcode = 0xeb24; mem_rs_emit(
2165 rt,
2166 rt2,
2167 &mem,
2168 None,
2169 Some(opcode),
2170 true,
2171 sink,
2172 emit_info,
2173 state,
2174 );
2175 }
2176
2177 &Inst::LoadAddr { rd, ref mem } => {
2178 let mem = mem.clone();
2179
2180 let opcode_rx = Some(0x41); let opcode_rxy = Some(0xe371); let opcode_ril = Some(0xc00); let rd = rd.to_reg();
2184 mem_emit(
2185 rd, &mem, opcode_rx, opcode_rxy, opcode_ril, false, sink, emit_info, state,
2186 );
2187 }
2188
2189 &Inst::Mov64 { rd, rm } => {
2190 let opcode = 0xb904; put(sink, &enc_rre(opcode, rd.to_reg(), rm));
2192 }
2193 &Inst::MovPReg { rd, rm } => {
2194 Inst::Mov64 { rd, rm: rm.into() }.emit(sink, emit_info, state);
2195 }
2196 &Inst::Mov32 { rd, rm } => {
2197 let opcode = 0x18; put(sink, &enc_rr(opcode, rd.to_reg(), rm));
2199 }
2200 &Inst::Mov32Imm { rd, imm } => {
2201 let opcode = 0xc09; put(sink, &enc_ril_a(opcode, rd.to_reg(), imm));
2203 }
2204 &Inst::Mov32SImm16 { rd, imm } => {
2205 let opcode = 0xa78; put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16));
2207 }
2208 &Inst::Mov64SImm16 { rd, imm } => {
2209 let opcode = 0xa79; put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16));
2211 }
2212 &Inst::Mov64SImm32 { rd, imm } => {
2213 let opcode = 0xc01; put(sink, &enc_ril_a(opcode, rd.to_reg(), imm as u32));
2215 }
2216 &Inst::CMov32 { rd, cond, ri, rm } => {
2217 debug_assert_eq!(rd.to_reg(), ri);
2218
2219 let opcode = 0xb9f2; put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rm, cond.bits(), 0));
2221 }
2222 &Inst::CMov64 { rd, cond, ri, rm } => {
2223 debug_assert_eq!(rd.to_reg(), ri);
2224
2225 let opcode = 0xb9e2; put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rm, cond.bits(), 0));
2227 }
2228 &Inst::CMov32SImm16 { rd, cond, ri, imm } => {
2229 debug_assert_eq!(rd.to_reg(), ri);
2230
2231 let opcode = 0xec42; put(
2233 sink,
2234 &enc_rie_g(opcode, rd.to_reg(), imm as u16, cond.bits()),
2235 );
2236 }
2237 &Inst::CMov64SImm16 { rd, cond, ri, imm } => {
2238 debug_assert_eq!(rd.to_reg(), ri);
2239
2240 let opcode = 0xec46; put(
2242 sink,
2243 &enc_rie_g(opcode, rd.to_reg(), imm as u16, cond.bits()),
2244 );
2245 }
2246 &Inst::Mov64UImm16Shifted { rd, imm } => {
2247 let opcode = match imm.shift {
2248 0 => 0xa5f, 1 => 0xa5e, 2 => 0xa5d, 3 => 0xa5c, _ => unreachable!(),
2253 };
2254 put(sink, &enc_ri_a(opcode, rd.to_reg(), imm.bits));
2255 }
2256 &Inst::Mov64UImm32Shifted { rd, imm } => {
2257 let opcode = match imm.shift {
2258 0 => 0xc0f, 1 => 0xc0e, _ => unreachable!(),
2261 };
2262 put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits));
2263 }
2264 &Inst::Insert64UImm16Shifted { rd, ri, imm } => {
2265 debug_assert_eq!(rd.to_reg(), ri);
2266
2267 let opcode = match imm.shift {
2268 0 => 0xa53, 1 => 0xa52, 2 => 0xa51, 3 => 0xa50, _ => unreachable!(),
2273 };
2274 put(sink, &enc_ri_a(opcode, rd.to_reg(), imm.bits));
2275 }
2276 &Inst::Insert64UImm32Shifted { rd, ri, imm } => {
2277 debug_assert_eq!(rd.to_reg(), ri);
2278
2279 let opcode = match imm.shift {
2280 0 => 0xc09, 1 => 0xc08, _ => unreachable!(),
2283 };
2284 put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits));
2285 }
2286 &Inst::LoadAR { rd, ar } => {
2287 let opcode = 0xb24f; put(sink, &enc_rre(opcode, rd.to_reg(), gpr(ar)));
2289 }
2290
2291 &Inst::InsertAR { rd, ri, ar } => {
2292 debug_assert_eq!(rd.to_reg(), ri);
2293
2294 let opcode = 0xb24f; put(sink, &enc_rre(opcode, rd.to_reg(), gpr(ar)));
2296 }
2297 &Inst::LoadSymbolReloc {
2298 rd,
2299 ref symbol_reloc,
2300 } => {
2301 let opcode = 0xa75; let reg = writable_spilltmp_reg().to_reg();
2303 put(sink, &enc_ri_b(opcode, reg, 12));
2304 let (reloc, name, offset) = match &**symbol_reloc {
2305 SymbolReloc::Absolute { name, offset } => (Reloc::Abs8, name, *offset),
2306 SymbolReloc::TlsGd { name } => (Reloc::S390xTlsGd64, name, 0),
2307 };
2308 sink.add_reloc(reloc, name, offset);
2309 sink.put8(0);
2310 let inst = Inst::Load64 {
2311 rd,
2312 mem: MemArg::reg(reg, MemFlags::trusted()),
2313 };
2314 inst.emit(sink, emit_info, state);
2315 }
2316
2317 &Inst::FpuMove32 { rd, rn } => {
2318 if is_fpr(rd.to_reg()) && is_fpr(rn) {
2319 let opcode = 0x38; put(sink, &enc_rr(opcode, rd.to_reg(), rn));
2321 } else {
2322 let opcode = 0xe756; put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, 0, 0, 0));
2324 }
2325 }
2326 &Inst::FpuMove64 { rd, rn } => {
2327 if is_fpr(rd.to_reg()) && is_fpr(rn) {
2328 let opcode = 0x28; put(sink, &enc_rr(opcode, rd.to_reg(), rn));
2330 } else {
2331 let opcode = 0xe756; put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, 0, 0, 0));
2333 }
2334 }
2335 &Inst::FpuCMov32 { rd, cond, ri, rm } => {
2336 debug_assert_eq!(rd.to_reg(), ri);
2337
2338 if is_fpr(rd.to_reg()) && is_fpr(rm) {
2339 let opcode = 0xa74; put(sink, &enc_ri_c(opcode, cond.invert().bits(), 4 + 2));
2341 let opcode = 0x38; put(sink, &enc_rr(opcode, rd.to_reg(), rm));
2343 } else {
2344 let opcode = 0xa74; put(sink, &enc_ri_c(opcode, cond.invert().bits(), 4 + 6));
2346 let opcode = 0xe756; put(sink, &enc_vrr_a(opcode, rd.to_reg(), rm, 0, 0, 0));
2348 }
2349 }
2350 &Inst::FpuCMov64 { rd, cond, ri, rm } => {
2351 debug_assert_eq!(rd.to_reg(), ri);
2352
2353 if is_fpr(rd.to_reg()) && is_fpr(rm) {
2354 let opcode = 0xa74; put(sink, &enc_ri_c(opcode, cond.invert().bits(), 4 + 2));
2356 let opcode = 0x28; put(sink, &enc_rr(opcode, rd.to_reg(), rm));
2358 } else {
2359 let opcode = 0xa74; put(sink, &enc_ri_c(opcode, cond.invert().bits(), 4 + 6));
2361 let opcode = 0xe756; put(sink, &enc_vrr_a(opcode, rd.to_reg(), rm, 0, 0, 0));
2363 }
2364 }
2365 &Inst::LoadFpuConst32 { rd, const_data } => {
2366 let opcode = 0xa75; let reg = writable_spilltmp_reg().to_reg();
2368 put(sink, &enc_ri_b(opcode, reg, 8));
2369 sink.put4(const_data.swap_bytes());
2370 let inst = Inst::VecLoadLaneUndef {
2371 size: 32,
2372 rd,
2373 mem: MemArg::reg(reg, MemFlags::trusted()),
2374 lane_imm: 0,
2375 };
2376 inst.emit(sink, emit_info, state);
2377 }
2378 &Inst::LoadFpuConst64 { rd, const_data } => {
2379 let opcode = 0xa75; let reg = writable_spilltmp_reg().to_reg();
2381 put(sink, &enc_ri_b(opcode, reg, 12));
2382 sink.put8(const_data.swap_bytes());
2383 let inst = Inst::VecLoadLaneUndef {
2384 size: 64,
2385 rd,
2386 mem: MemArg::reg(reg, MemFlags::trusted()),
2387 lane_imm: 0,
2388 };
2389 inst.emit(sink, emit_info, state);
2390 }
2391 &Inst::FpuRR { fpu_op, rd, rn } => {
2392 let (opcode, m3, m4, m5, opcode_fpr) = match fpu_op {
2393 FPUOp1::Abs32 => (0xe7cc, 2, 8, 2, Some(0xb300)), FPUOp1::Abs64 => (0xe7cc, 3, 8, 2, Some(0xb310)), FPUOp1::Abs32x4 => (0xe7cc, 2, 0, 2, None), FPUOp1::Abs64x2 => (0xe7cc, 3, 0, 2, None), FPUOp1::Neg32 => (0xe7cc, 2, 8, 0, Some(0xb303)), FPUOp1::Neg64 => (0xe7cc, 3, 8, 0, Some(0xb313)), FPUOp1::Neg32x4 => (0xe7cc, 2, 0, 0, None), FPUOp1::Neg64x2 => (0xe7cc, 3, 0, 0, None), FPUOp1::NegAbs32 => (0xe7cc, 2, 8, 1, Some(0xb301)), FPUOp1::NegAbs64 => (0xe7cc, 3, 8, 1, Some(0xb311)), FPUOp1::NegAbs32x4 => (0xe7cc, 2, 0, 1, None), FPUOp1::NegAbs64x2 => (0xe7cc, 3, 0, 1, None), FPUOp1::Sqrt32 => (0xe7ce, 2, 8, 0, Some(0xb314)), FPUOp1::Sqrt64 => (0xe7ce, 3, 8, 0, Some(0xb315)), FPUOp1::Sqrt32x4 => (0xe7ce, 2, 0, 0, None), FPUOp1::Sqrt64x2 => (0xe7ce, 3, 0, 0, None), FPUOp1::Cvt32To64 => (0xe7c4, 2, 8, 0, Some(0xb304)), FPUOp1::Cvt32x4To64x2 => (0xe7c4, 2, 0, 0, None), };
2412 if m4 == 8 && is_fpr(rd.to_reg()) && is_fpr(rn) {
2413 put(sink, &enc_rre(opcode_fpr.unwrap(), rd.to_reg(), rn));
2414 } else {
2415 put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, m3, m4, m5));
2416 }
2417 }
2418 &Inst::FpuRRR { fpu_op, rd, rn, rm } => {
2419 let (opcode, m4, m5, m6, opcode_fpr) = match fpu_op {
2420 FPUOp2::Add32 => (0xe7e3, 2, 8, 0, Some(0xb30a)), FPUOp2::Add64 => (0xe7e3, 3, 8, 0, Some(0xb31a)), FPUOp2::Add32x4 => (0xe7e3, 2, 0, 0, None), FPUOp2::Add64x2 => (0xe7e3, 3, 0, 0, None), FPUOp2::Sub32 => (0xe7e2, 2, 8, 0, Some(0xb30b)), FPUOp2::Sub64 => (0xe7e2, 3, 8, 0, Some(0xb31b)), FPUOp2::Sub32x4 => (0xe7e2, 2, 0, 0, None), FPUOp2::Sub64x2 => (0xe7e2, 3, 0, 0, None), FPUOp2::Mul32 => (0xe7e7, 2, 8, 0, Some(0xb317)), FPUOp2::Mul64 => (0xe7e7, 3, 8, 0, Some(0xb31c)), FPUOp2::Mul32x4 => (0xe7e7, 2, 0, 0, None), FPUOp2::Mul64x2 => (0xe7e7, 3, 0, 0, None), FPUOp2::Div32 => (0xe7e5, 2, 8, 0, Some(0xb30d)), FPUOp2::Div64 => (0xe7e5, 3, 8, 0, Some(0xb31d)), FPUOp2::Div32x4 => (0xe7e5, 2, 0, 0, None), FPUOp2::Div64x2 => (0xe7e5, 3, 0, 0, None), FPUOp2::Max32 => (0xe7ef, 2, 8, 1, None), FPUOp2::Max64 => (0xe7ef, 3, 8, 1, None), FPUOp2::Max32x4 => (0xe7ef, 2, 0, 1, None), FPUOp2::Max64x2 => (0xe7ef, 3, 0, 1, None), FPUOp2::Min32 => (0xe7ee, 2, 8, 1, None), FPUOp2::Min64 => (0xe7ee, 3, 8, 1, None), FPUOp2::Min32x4 => (0xe7ee, 2, 0, 1, None), FPUOp2::Min64x2 => (0xe7ee, 3, 0, 1, None), FPUOp2::MaxPseudo32 => (0xe7ef, 2, 8, 3, None), FPUOp2::MaxPseudo64 => (0xe7ef, 3, 8, 3, None), FPUOp2::MaxPseudo32x4 => (0xe7ef, 2, 0, 3, None), FPUOp2::MaxPseudo64x2 => (0xe7ef, 3, 0, 3, None), FPUOp2::MinPseudo32 => (0xe7ee, 2, 8, 3, None), FPUOp2::MinPseudo64 => (0xe7ee, 3, 8, 3, None), FPUOp2::MinPseudo32x4 => (0xe7ee, 2, 0, 3, None), FPUOp2::MinPseudo64x2 => (0xe7ee, 3, 0, 3, None), };
2453 if m5 == 8 && opcode_fpr.is_some() && rd.to_reg() == rn && is_fpr(rn) && is_fpr(rm)
2454 {
2455 put(sink, &enc_rre(opcode_fpr.unwrap(), rd.to_reg(), rm));
2456 } else {
2457 put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, m5, m6));
2458 }
2459 }
2460 &Inst::FpuRRRR {
2461 fpu_op,
2462 rd,
2463 rn,
2464 rm,
2465 ra,
2466 } => {
2467 let (opcode, m5, m6, opcode_fpr) = match fpu_op {
2468 FPUOp3::MAdd32 => (0xe78f, 8, 2, Some(0xb30e)), FPUOp3::MAdd64 => (0xe78f, 8, 3, Some(0xb31e)), FPUOp3::MAdd32x4 => (0xe78f, 0, 2, None), FPUOp3::MAdd64x2 => (0xe78f, 0, 3, None), FPUOp3::MSub32 => (0xe78e, 8, 2, Some(0xb30f)), FPUOp3::MSub64 => (0xe78e, 8, 3, Some(0xb31f)), FPUOp3::MSub32x4 => (0xe78e, 0, 2, None), FPUOp3::MSub64x2 => (0xe78e, 0, 3, None), };
2477 if m5 == 8 && rd.to_reg() == ra && is_fpr(rn) && is_fpr(rm) && is_fpr(ra) {
2478 put(sink, &enc_rrd(opcode_fpr.unwrap(), rd.to_reg(), rm, rn));
2479 } else {
2480 put(sink, &enc_vrr_e(opcode, rd.to_reg(), rn, rm, ra, m5, m6));
2481 }
2482 }
2483 &Inst::FpuRound { op, mode, rd, rn } => {
2484 let mode = match mode {
2485 FpuRoundMode::Current => 0,
2486 FpuRoundMode::ToNearest => 1,
2487 FpuRoundMode::ShorterPrecision => 3,
2488 FpuRoundMode::ToNearestTiesToEven => 4,
2489 FpuRoundMode::ToZero => 5,
2490 FpuRoundMode::ToPosInfinity => 6,
2491 FpuRoundMode::ToNegInfinity => 7,
2492 };
2493 let (opcode, m3, m4, opcode_fpr) = match op {
2494 FpuRoundOp::Cvt64To32 => (0xe7c5, 3, 8, Some(0xb344)), FpuRoundOp::Cvt64x2To32x4 => (0xe7c5, 3, 0, None), FpuRoundOp::Round32 => (0xe7c7, 2, 8, Some(0xb357)), FpuRoundOp::Round64 => (0xe7c7, 3, 8, Some(0xb35f)), FpuRoundOp::Round32x4 => (0xe7c7, 2, 0, None), FpuRoundOp::Round64x2 => (0xe7c7, 3, 0, None), FpuRoundOp::ToSInt32 => (0xe7c2, 2, 8, None), FpuRoundOp::ToSInt64 => (0xe7c2, 3, 8, None), FpuRoundOp::ToUInt32 => (0xe7c0, 2, 8, None), FpuRoundOp::ToUInt64 => (0xe7c0, 3, 8, None), FpuRoundOp::ToSInt32x4 => (0xe7c2, 2, 0, None), FpuRoundOp::ToSInt64x2 => (0xe7c2, 3, 0, None), FpuRoundOp::ToUInt32x4 => (0xe7c0, 2, 0, None), FpuRoundOp::ToUInt64x2 => (0xe7c0, 3, 0, None), FpuRoundOp::FromSInt32 => (0xe7c3, 2, 8, None), FpuRoundOp::FromSInt64 => (0xe7c3, 3, 8, None), FpuRoundOp::FromUInt32 => (0xe7c1, 2, 8, None), FpuRoundOp::FromUInt64 => (0xe7c1, 3, 8, None), FpuRoundOp::FromSInt32x4 => (0xe7c3, 2, 0, None), FpuRoundOp::FromSInt64x2 => (0xe7c3, 3, 0, None), FpuRoundOp::FromUInt32x4 => (0xe7c1, 2, 0, None), FpuRoundOp::FromUInt64x2 => (0xe7c1, 3, 0, None), };
2517 if m4 == 8 && opcode_fpr.is_some() && is_fpr(rd.to_reg()) && is_fpr(rn) {
2518 put(
2519 sink,
2520 &enc_rrf_cde(opcode_fpr.unwrap(), rd.to_reg(), rn, mode, 0),
2521 );
2522 } else {
2523 put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, m3, m4, mode));
2524 }
2525 }
2526 &Inst::FpuCmp32 { rn, rm } => {
2527 if is_fpr(rn) && is_fpr(rm) {
2528 let opcode = 0xb309; put(sink, &enc_rre(opcode, rn, rm));
2530 } else {
2531 let opcode = 0xe7cb; put(sink, &enc_vrr_a(opcode, rn, rm, 2, 0, 0));
2533 }
2534 }
2535 &Inst::FpuCmp64 { rn, rm } => {
2536 if is_fpr(rn) && is_fpr(rm) {
2537 let opcode = 0xb319; put(sink, &enc_rre(opcode, rn, rm));
2539 } else {
2540 let opcode = 0xe7cb; put(sink, &enc_vrr_a(opcode, rn, rm, 3, 0, 0));
2542 }
2543 }
2544
2545 &Inst::VecRRR { op, rd, rn, rm } => {
2546 let (opcode, m4) = match op {
2547 VecBinaryOp::Add8x16 => (0xe7f3, 0), VecBinaryOp::Add16x8 => (0xe7f3, 1), VecBinaryOp::Add32x4 => (0xe7f3, 2), VecBinaryOp::Add64x2 => (0xe7f3, 3), VecBinaryOp::Add128 => (0xe7f3, 4), VecBinaryOp::Sub8x16 => (0xe7f7, 0), VecBinaryOp::Sub16x8 => (0xe7f7, 1), VecBinaryOp::Sub32x4 => (0xe7f7, 2), VecBinaryOp::Sub64x2 => (0xe7f7, 3), VecBinaryOp::Sub128 => (0xe7f7, 4), VecBinaryOp::Mul8x16 => (0xe7a2, 0), VecBinaryOp::Mul16x8 => (0xe7a2, 1), VecBinaryOp::Mul32x4 => (0xe7a2, 2), VecBinaryOp::UMulHi8x16 => (0xe7a1, 0), VecBinaryOp::UMulHi16x8 => (0xe7a1, 1), VecBinaryOp::UMulHi32x4 => (0xe7a1, 2), VecBinaryOp::SMulHi8x16 => (0xe7a3, 0), VecBinaryOp::SMulHi16x8 => (0xe7a3, 1), VecBinaryOp::SMulHi32x4 => (0xe7a3, 2), VecBinaryOp::UMulEven8x16 => (0xe7a4, 0), VecBinaryOp::UMulEven16x8 => (0xe7a4, 1), VecBinaryOp::UMulEven32x4 => (0xe7a4, 2), VecBinaryOp::SMulEven8x16 => (0xe7a6, 0), VecBinaryOp::SMulEven16x8 => (0xe7a6, 1), VecBinaryOp::SMulEven32x4 => (0xe7a6, 2), VecBinaryOp::UMulOdd8x16 => (0xe7a5, 0), VecBinaryOp::UMulOdd16x8 => (0xe7a5, 1), VecBinaryOp::UMulOdd32x4 => (0xe7a5, 2), VecBinaryOp::SMulOdd8x16 => (0xe7a7, 0), VecBinaryOp::SMulOdd16x8 => (0xe7a7, 1), VecBinaryOp::SMulOdd32x4 => (0xe7a7, 2), VecBinaryOp::UMax8x16 => (0xe7fd, 0), VecBinaryOp::UMax16x8 => (0xe7fd, 1), VecBinaryOp::UMax32x4 => (0xe7fd, 2), VecBinaryOp::UMax64x2 => (0xe7fd, 3), VecBinaryOp::SMax8x16 => (0xe7ff, 0), VecBinaryOp::SMax16x8 => (0xe7ff, 1), VecBinaryOp::SMax32x4 => (0xe7ff, 2), VecBinaryOp::SMax64x2 => (0xe7ff, 3), VecBinaryOp::UMin8x16 => (0xe7fc, 0), VecBinaryOp::UMin16x8 => (0xe7fc, 1), VecBinaryOp::UMin32x4 => (0xe7fc, 2), VecBinaryOp::UMin64x2 => (0xe7fc, 3), VecBinaryOp::SMin8x16 => (0xe7fe, 0), VecBinaryOp::SMin16x8 => (0xe7fe, 1), VecBinaryOp::SMin32x4 => (0xe7fe, 2), VecBinaryOp::SMin64x2 => (0xe7fe, 3), VecBinaryOp::UAvg8x16 => (0xe7f0, 0), VecBinaryOp::UAvg16x8 => (0xe7f0, 1), VecBinaryOp::UAvg32x4 => (0xe7f0, 2), VecBinaryOp::UAvg64x2 => (0xe7f0, 3), VecBinaryOp::SAvg8x16 => (0xe7f2, 0), VecBinaryOp::SAvg16x8 => (0xe7f2, 1), VecBinaryOp::SAvg32x4 => (0xe7f2, 2), VecBinaryOp::SAvg64x2 => (0xe7f2, 3), VecBinaryOp::And128 => (0xe768, 0), VecBinaryOp::Orr128 => (0xe76a, 0), VecBinaryOp::Xor128 => (0xe76d, 0), VecBinaryOp::NotAnd128 => (0xe76e, 0), VecBinaryOp::NotOrr128 => (0xe76b, 0), VecBinaryOp::NotXor128 => (0xe76c, 0), VecBinaryOp::AndNot128 => (0xe769, 0), VecBinaryOp::OrrNot128 => (0xe76f, 0), VecBinaryOp::BitPermute128 => (0xe785, 0), VecBinaryOp::LShLByByte128 => (0xe775, 0), VecBinaryOp::LShRByByte128 => (0xe77d, 0), VecBinaryOp::AShRByByte128 => (0xe77f, 0), VecBinaryOp::LShLByBit128 => (0xe774, 0), VecBinaryOp::LShRByBit128 => (0xe77c, 0), VecBinaryOp::AShRByBit128 => (0xe77e, 0), VecBinaryOp::Pack16x8 => (0xe794, 1), VecBinaryOp::Pack32x4 => (0xe794, 2), VecBinaryOp::Pack64x2 => (0xe794, 3), VecBinaryOp::PackUSat16x8 => (0xe795, 1), VecBinaryOp::PackUSat32x4 => (0xe795, 2), VecBinaryOp::PackUSat64x2 => (0xe795, 3), VecBinaryOp::PackSSat16x8 => (0xe797, 1), VecBinaryOp::PackSSat32x4 => (0xe797, 2), VecBinaryOp::PackSSat64x2 => (0xe797, 3), VecBinaryOp::MergeLow8x16 => (0xe760, 0), VecBinaryOp::MergeLow16x8 => (0xe760, 1), VecBinaryOp::MergeLow32x4 => (0xe760, 2), VecBinaryOp::MergeLow64x2 => (0xe760, 3), VecBinaryOp::MergeHigh8x16 => (0xe761, 0), VecBinaryOp::MergeHigh16x8 => (0xe761, 1), VecBinaryOp::MergeHigh32x4 => (0xe761, 2), VecBinaryOp::MergeHigh64x2 => (0xe761, 3), };
2635
2636 put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, 0, 0));
2637 }
2638 &Inst::VecRR { op, rd, rn } => {
2639 let (opcode, m3) = match op {
2640 VecUnaryOp::Abs8x16 => (0xe7df, 0), VecUnaryOp::Abs16x8 => (0xe7df, 1), VecUnaryOp::Abs32x4 => (0xe7df, 2), VecUnaryOp::Abs64x2 => (0xe7df, 3), VecUnaryOp::Neg8x16 => (0xe7de, 0), VecUnaryOp::Neg16x8 => (0xe7de, 1), VecUnaryOp::Neg32x4 => (0xe7de, 2), VecUnaryOp::Neg64x2 => (0xe7de, 3), VecUnaryOp::Popcnt8x16 => (0xe750, 0), VecUnaryOp::Popcnt16x8 => (0xe750, 1), VecUnaryOp::Popcnt32x4 => (0xe750, 2), VecUnaryOp::Popcnt64x2 => (0xe750, 3), VecUnaryOp::Clz8x16 => (0xe753, 0), VecUnaryOp::Clz16x8 => (0xe753, 1), VecUnaryOp::Clz32x4 => (0xe753, 2), VecUnaryOp::Clz64x2 => (0xe753, 3), VecUnaryOp::Ctz8x16 => (0xe752, 0), VecUnaryOp::Ctz16x8 => (0xe752, 1), VecUnaryOp::Ctz32x4 => (0xe752, 2), VecUnaryOp::Ctz64x2 => (0xe752, 3), VecUnaryOp::UnpackULow8x16 => (0xe7d4, 0), VecUnaryOp::UnpackULow16x8 => (0xe7d4, 1), VecUnaryOp::UnpackULow32x4 => (0xe7d4, 2), VecUnaryOp::UnpackUHigh8x16 => (0xe7d5, 0), VecUnaryOp::UnpackUHigh16x8 => (0xe7d5, 1), VecUnaryOp::UnpackUHigh32x4 => (0xe7d5, 2), VecUnaryOp::UnpackSLow8x16 => (0xe7d6, 0), VecUnaryOp::UnpackSLow16x8 => (0xe7d6, 1), VecUnaryOp::UnpackSLow32x4 => (0xe7d6, 2), VecUnaryOp::UnpackSHigh8x16 => (0xe7d7, 0), VecUnaryOp::UnpackSHigh16x8 => (0xe7d7, 1), VecUnaryOp::UnpackSHigh32x4 => (0xe7d7, 2), };
2673
2674 put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, m3, 0, 0));
2675 }
2676 &Inst::VecShiftRR {
2677 shift_op,
2678 rd,
2679 rn,
2680 shift_imm,
2681 shift_reg,
2682 } => {
2683 let (opcode, m4) = match shift_op {
2684 VecShiftOp::RotL8x16 => (0xe733, 0), VecShiftOp::RotL16x8 => (0xe733, 1), VecShiftOp::RotL32x4 => (0xe733, 2), VecShiftOp::RotL64x2 => (0xe733, 3), VecShiftOp::LShL8x16 => (0xe730, 0), VecShiftOp::LShL16x8 => (0xe730, 1), VecShiftOp::LShL32x4 => (0xe730, 2), VecShiftOp::LShL64x2 => (0xe730, 3), VecShiftOp::LShR8x16 => (0xe738, 0), VecShiftOp::LShR16x8 => (0xe738, 1), VecShiftOp::LShR32x4 => (0xe738, 2), VecShiftOp::LShR64x2 => (0xe738, 3), VecShiftOp::AShR8x16 => (0xe73a, 0), VecShiftOp::AShR16x8 => (0xe73a, 1), VecShiftOp::AShR32x4 => (0xe73a, 2), VecShiftOp::AShR64x2 => (0xe73a, 3), };
2701 put(
2702 sink,
2703 &enc_vrs_a(opcode, rd.to_reg(), shift_reg, shift_imm.into(), rn, m4),
2704 );
2705 }
2706 &Inst::VecSelect { rd, rn, rm, ra } => {
2707 let opcode = 0xe78d; put(sink, &enc_vrr_e(opcode, rd.to_reg(), rn, rm, ra, 0, 0));
2709 }
2710 &Inst::VecPermute { rd, rn, rm, ra } => {
2711 let opcode = 0xe78c; put(sink, &enc_vrr_e(opcode, rd.to_reg(), rn, rm, ra, 0, 0));
2713 }
2714 &Inst::VecPermuteDWImm {
2715 rd,
2716 rn,
2717 rm,
2718 idx1,
2719 idx2,
2720 } => {
2721 let m4 = (idx1 & 1) * 4 + (idx2 & 1);
2722
2723 let opcode = 0xe784; put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, 0, 0));
2725 }
2726 &Inst::VecIntCmp { op, rd, rn, rm } | &Inst::VecIntCmpS { op, rd, rn, rm } => {
2727 let (opcode, m4) = match op {
2728 VecIntCmpOp::CmpEq8x16 => (0xe7f8, 0), VecIntCmpOp::CmpEq16x8 => (0xe7f8, 1), VecIntCmpOp::CmpEq32x4 => (0xe7f8, 2), VecIntCmpOp::CmpEq64x2 => (0xe7f8, 3), VecIntCmpOp::SCmpHi8x16 => (0xe7fb, 0), VecIntCmpOp::SCmpHi16x8 => (0xe7fb, 1), VecIntCmpOp::SCmpHi32x4 => (0xe7fb, 2), VecIntCmpOp::SCmpHi64x2 => (0xe7fb, 3), VecIntCmpOp::UCmpHi8x16 => (0xe7f9, 0), VecIntCmpOp::UCmpHi16x8 => (0xe7f9, 1), VecIntCmpOp::UCmpHi32x4 => (0xe7f9, 2), VecIntCmpOp::UCmpHi64x2 => (0xe7f9, 3), };
2741 let m5 = match self {
2742 &Inst::VecIntCmp { .. } => 0,
2743 &Inst::VecIntCmpS { .. } => 1,
2744 _ => unreachable!(),
2745 };
2746
2747 put(sink, &enc_vrr_b(opcode, rd.to_reg(), rn, rm, m4, m5));
2748 }
2749 &Inst::VecFloatCmp { op, rd, rn, rm } | &Inst::VecFloatCmpS { op, rd, rn, rm } => {
2750 let (opcode, m4) = match op {
2751 VecFloatCmpOp::CmpEq32x4 => (0xe7e8, 2), VecFloatCmpOp::CmpEq64x2 => (0xe7e8, 3), VecFloatCmpOp::CmpHi32x4 => (0xe7eb, 2), VecFloatCmpOp::CmpHi64x2 => (0xe7eb, 3), VecFloatCmpOp::CmpHiEq32x4 => (0xe7ea, 2), VecFloatCmpOp::CmpHiEq64x2 => (0xe7ea, 3), };
2758 let m6 = match self {
2759 &Inst::VecFloatCmp { .. } => 0,
2760 &Inst::VecFloatCmpS { .. } => 1,
2761 _ => unreachable!(),
2762 };
2763
2764 put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, 0, m6));
2765 }
2766 &Inst::VecInt128SCmpHi { tmp, rn, rm } | &Inst::VecInt128UCmpHi { tmp, rn, rm } => {
2767 let (opcode, m3) = match self {
2776 &Inst::VecInt128SCmpHi { .. } => (0xe7db, 3), &Inst::VecInt128UCmpHi { .. } => (0xe7d9, 3), _ => unreachable!(),
2779 };
2780 put(sink, &enc_vrr_a(opcode, rm, rn, m3, 0, 0));
2781
2782 let opcode = 0xa74; put(sink, &enc_ri_c(opcode, 7, 4 + 6));
2785
2786 let inst = Inst::VecIntCmpS {
2792 op: VecIntCmpOp::UCmpHi64x2,
2793 rd: tmp,
2797 rn,
2798 rm,
2799 };
2800 inst.emit(sink, emit_info, state);
2801 }
2802
2803 &Inst::VecLoad { rd, ref mem }
2804 | &Inst::VecLoadRev { rd, ref mem }
2805 | &Inst::VecLoadByte16Rev { rd, ref mem }
2806 | &Inst::VecLoadByte32Rev { rd, ref mem }
2807 | &Inst::VecLoadByte64Rev { rd, ref mem }
2808 | &Inst::VecLoadElt16Rev { rd, ref mem }
2809 | &Inst::VecLoadElt32Rev { rd, ref mem }
2810 | &Inst::VecLoadElt64Rev { rd, ref mem } => {
2811 let mem = mem.clone();
2812
2813 let (opcode, m3) = match self {
2814 &Inst::VecLoad { .. } => (0xe706, 0), &Inst::VecLoadRev { .. } => (0xe606, 4), &Inst::VecLoadByte16Rev { .. } => (0xe606, 1), &Inst::VecLoadByte32Rev { .. } => (0xe606, 2), &Inst::VecLoadByte64Rev { .. } => (0xe606, 3), &Inst::VecLoadElt16Rev { .. } => (0xe607, 1), &Inst::VecLoadElt32Rev { .. } => (0xe607, 2), &Inst::VecLoadElt64Rev { .. } => (0xe607, 3), _ => unreachable!(),
2823 };
2824 mem_vrx_emit(rd.to_reg(), &mem, opcode, m3, true, sink, emit_info, state);
2825 }
2826 &Inst::VecStore { rd, ref mem }
2827 | &Inst::VecStoreRev { rd, ref mem }
2828 | &Inst::VecStoreByte16Rev { rd, ref mem }
2829 | &Inst::VecStoreByte32Rev { rd, ref mem }
2830 | &Inst::VecStoreByte64Rev { rd, ref mem }
2831 | &Inst::VecStoreElt16Rev { rd, ref mem }
2832 | &Inst::VecStoreElt32Rev { rd, ref mem }
2833 | &Inst::VecStoreElt64Rev { rd, ref mem } => {
2834 let mem = mem.clone();
2835
2836 let (opcode, m3) = match self {
2837 &Inst::VecStore { .. } => (0xe70e, 0), &Inst::VecStoreRev { .. } => (0xe60e, 4), &Inst::VecStoreByte16Rev { .. } => (0xe60e, 1), &Inst::VecStoreByte32Rev { .. } => (0xe60e, 2), &Inst::VecStoreByte64Rev { .. } => (0xe60e, 3), &Inst::VecStoreElt16Rev { .. } => (0xe60f, 1), &Inst::VecStoreElt32Rev { .. } => (0xe60f, 2), &Inst::VecStoreElt64Rev { .. } => (0xe60f, 3), _ => unreachable!(),
2846 };
2847 mem_vrx_emit(rd, &mem, opcode, m3, true, sink, emit_info, state);
2848 }
2849 &Inst::VecLoadReplicate { size, rd, ref mem }
2850 | &Inst::VecLoadReplicateRev { size, rd, ref mem } => {
2851 let mem = mem.clone();
2852
2853 let (opcode, m3) = match (self, size) {
2854 (&Inst::VecLoadReplicate { .. }, 8) => (0xe705, 0), (&Inst::VecLoadReplicate { .. }, 16) => (0xe705, 1), (&Inst::VecLoadReplicate { .. }, 32) => (0xe705, 2), (&Inst::VecLoadReplicate { .. }, 64) => (0xe705, 3), (&Inst::VecLoadReplicateRev { .. }, 16) => (0xe605, 1), (&Inst::VecLoadReplicateRev { .. }, 32) => (0xe605, 2), (&Inst::VecLoadReplicateRev { .. }, 64) => (0xe605, 3), _ => unreachable!(),
2862 };
2863 mem_vrx_emit(rd.to_reg(), &mem, opcode, m3, true, sink, emit_info, state);
2864 }
2865
2866 &Inst::VecMov { rd, rn } => {
2867 let opcode = 0xe756; put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, 0, 0, 0));
2869 }
2870 &Inst::VecCMov { rd, cond, ri, rm } => {
2871 debug_assert_eq!(rd.to_reg(), ri);
2872
2873 let opcode = 0xa74; put(sink, &enc_ri_c(opcode, cond.invert().bits(), 4 + 6));
2875 let opcode = 0xe756; put(sink, &enc_vrr_a(opcode, rd.to_reg(), rm, 0, 0, 0));
2877 }
2878 &Inst::MovToVec128 { rd, rn, rm } => {
2879 let opcode = 0xe762; put(sink, &enc_vrr_f(opcode, rd.to_reg(), rn, rm));
2881 }
2882 &Inst::VecLoadConst { rd, const_data } => {
2883 let opcode = 0xa75; let reg = writable_spilltmp_reg().to_reg();
2885 put(sink, &enc_ri_b(opcode, reg, 20));
2886 for i in const_data.to_be_bytes().iter() {
2887 sink.put1(*i);
2888 }
2889 let inst = Inst::VecLoad {
2890 rd,
2891 mem: MemArg::reg(reg, MemFlags::trusted()),
2892 };
2893 inst.emit(sink, emit_info, state);
2894 }
2895 &Inst::VecLoadConstReplicate {
2896 size,
2897 rd,
2898 const_data,
2899 } => {
2900 let opcode = 0xa75; let reg = writable_spilltmp_reg().to_reg();
2902 put(sink, &enc_ri_b(opcode, reg, (4 + size / 8) as i32));
2903 for i in 0..size / 8 {
2904 sink.put1((const_data >> (size - 8 - 8 * i)) as u8);
2905 }
2906 let inst = Inst::VecLoadReplicate {
2907 size,
2908 rd,
2909 mem: MemArg::reg(reg, MemFlags::trusted()),
2910 };
2911 inst.emit(sink, emit_info, state);
2912 }
2913 &Inst::VecImmByteMask { rd, mask } => {
2914 let opcode = 0xe744; put(sink, &enc_vri_a(opcode, rd.to_reg(), mask, 0));
2916 }
2917 &Inst::VecImmBitMask {
2918 size,
2919 rd,
2920 start_bit,
2921 end_bit,
2922 } => {
2923 let (opcode, m4) = match size {
2924 8 => (0xe746, 0), 16 => (0xe746, 1), 32 => (0xe746, 2), 64 => (0xe746, 3), _ => unreachable!(),
2929 };
2930 put(
2931 sink,
2932 &enc_vri_b(opcode, rd.to_reg(), start_bit, end_bit, m4),
2933 );
2934 }
2935 &Inst::VecImmReplicate { size, rd, imm } => {
2936 let (opcode, m3) = match size {
2937 8 => (0xe745, 0), 16 => (0xe745, 1), 32 => (0xe745, 2), 64 => (0xe745, 3), _ => unreachable!(),
2942 };
2943 put(sink, &enc_vri_a(opcode, rd.to_reg(), imm as u16, m3));
2944 }
2945 &Inst::VecLoadLane {
2946 size,
2947 rd,
2948 ri,
2949 ref mem,
2950 lane_imm,
2951 }
2952 | &Inst::VecLoadLaneRev {
2953 size,
2954 rd,
2955 ri,
2956 ref mem,
2957 lane_imm,
2958 } => {
2959 debug_assert_eq!(rd.to_reg(), ri);
2960 let mem = mem.clone();
2961
2962 let opcode_vrx = match (self, size) {
2963 (&Inst::VecLoadLane { .. }, 8) => 0xe700, (&Inst::VecLoadLane { .. }, 16) => 0xe701, (&Inst::VecLoadLane { .. }, 32) => 0xe703, (&Inst::VecLoadLane { .. }, 64) => 0xe702, (&Inst::VecLoadLaneRev { .. }, 16) => 0xe601, (&Inst::VecLoadLaneRev { .. }, 32) => 0xe603, (&Inst::VecLoadLaneRev { .. }, 64) => 0xe602, _ => unreachable!(),
2971 };
2972
2973 let rd = rd.to_reg();
2974 mem_vrx_emit(
2975 rd,
2976 &mem,
2977 opcode_vrx,
2978 lane_imm.into(),
2979 true,
2980 sink,
2981 emit_info,
2982 state,
2983 );
2984 }
2985 &Inst::VecLoadLaneUndef {
2986 size,
2987 rd,
2988 ref mem,
2989 lane_imm,
2990 }
2991 | &Inst::VecLoadLaneRevUndef {
2992 size,
2993 rd,
2994 ref mem,
2995 lane_imm,
2996 } => {
2997 let mem = mem.clone();
2998
2999 let (opcode_vrx, opcode_rx, opcode_rxy) = match (self, size) {
3000 (&Inst::VecLoadLaneUndef { .. }, 8) => (0xe700, None, None), (&Inst::VecLoadLaneUndef { .. }, 16) => (0xe701, None, None), (&Inst::VecLoadLaneUndef { .. }, 32) => (0xe703, Some(0x78), Some(0xed64)), (&Inst::VecLoadLaneUndef { .. }, 64) => (0xe702, Some(0x68), Some(0xed65)), (&Inst::VecLoadLaneRevUndef { .. }, 16) => (0xe601, None, None), (&Inst::VecLoadLaneRevUndef { .. }, 32) => (0xe603, None, None), (&Inst::VecLoadLaneRevUndef { .. }, 64) => (0xe602, None, None), _ => unreachable!(),
3008 };
3009
3010 let rd = rd.to_reg();
3011 if lane_imm == 0 && is_fpr(rd) && opcode_rx.is_some() {
3012 mem_emit(
3013 rd, &mem, opcode_rx, opcode_rxy, None, true, sink, emit_info, state,
3014 );
3015 } else {
3016 mem_vrx_emit(
3017 rd,
3018 &mem,
3019 opcode_vrx,
3020 lane_imm.into(),
3021 true,
3022 sink,
3023 emit_info,
3024 state,
3025 );
3026 }
3027 }
3028 &Inst::VecStoreLane {
3029 size,
3030 rd,
3031 ref mem,
3032 lane_imm,
3033 }
3034 | &Inst::VecStoreLaneRev {
3035 size,
3036 rd,
3037 ref mem,
3038 lane_imm,
3039 } => {
3040 let mem = mem.clone();
3041
3042 let (opcode_vrx, opcode_rx, opcode_rxy) = match (self, size) {
3043 (&Inst::VecStoreLane { .. }, 8) => (0xe708, None, None), (&Inst::VecStoreLane { .. }, 16) => (0xe709, None, None), (&Inst::VecStoreLane { .. }, 32) => (0xe70b, Some(0x70), Some(0xed66)), (&Inst::VecStoreLane { .. }, 64) => (0xe70a, Some(0x60), Some(0xed67)), (&Inst::VecStoreLaneRev { .. }, 16) => (0xe609, None, None), (&Inst::VecStoreLaneRev { .. }, 32) => (0xe60b, None, None), (&Inst::VecStoreLaneRev { .. }, 64) => (0xe60a, None, None), _ => unreachable!(),
3051 };
3052
3053 if lane_imm == 0 && is_fpr(rd) && opcode_rx.is_some() {
3054 mem_emit(
3055 rd, &mem, opcode_rx, opcode_rxy, None, true, sink, emit_info, state,
3056 );
3057 } else {
3058 mem_vrx_emit(
3059 rd,
3060 &mem,
3061 opcode_vrx,
3062 lane_imm.into(),
3063 true,
3064 sink,
3065 emit_info,
3066 state,
3067 );
3068 }
3069 }
3070 &Inst::VecInsertLane {
3071 size,
3072 rd,
3073 ri,
3074 rn,
3075 lane_imm,
3076 lane_reg,
3077 } => {
3078 debug_assert_eq!(rd.to_reg(), ri);
3079
3080 let (opcode_vrs, m4) = match size {
3081 8 => (0xe722, 0), 16 => (0xe722, 1), 32 => (0xe722, 2), 64 => (0xe722, 3), _ => unreachable!(),
3086 };
3087 put(
3088 sink,
3089 &enc_vrs_b(opcode_vrs, rd.to_reg(), lane_reg, lane_imm.into(), rn, m4),
3090 );
3091 }
3092 &Inst::VecInsertLaneUndef {
3093 size,
3094 rd,
3095 rn,
3096 lane_imm,
3097 lane_reg,
3098 } => {
3099 let (opcode_vrs, m4, opcode_rre) = match size {
3100 8 => (0xe722, 0, None), 16 => (0xe722, 1, None), 32 => (0xe722, 2, None), 64 => (0xe722, 3, Some(0xb3c1)), _ => unreachable!(),
3105 };
3106 if opcode_rre.is_some()
3107 && lane_imm == 0
3108 && lane_reg == zero_reg()
3109 && is_fpr(rd.to_reg())
3110 {
3111 put(sink, &enc_rre(opcode_rre.unwrap(), rd.to_reg(), rn));
3112 } else {
3113 put(
3114 sink,
3115 &enc_vrs_b(opcode_vrs, rd.to_reg(), lane_reg, lane_imm.into(), rn, m4),
3116 );
3117 }
3118 }
3119 &Inst::VecExtractLane {
3120 size,
3121 rd,
3122 rn,
3123 lane_imm,
3124 lane_reg,
3125 } => {
3126 let (opcode_vrs, m4, opcode_rre) = match size {
3127 8 => (0xe721, 0, None), 16 => (0xe721, 1, None), 32 => (0xe721, 2, None), 64 => (0xe721, 3, Some(0xb3cd)), _ => unreachable!(),
3132 };
3133 if opcode_rre.is_some() && lane_imm == 0 && lane_reg == zero_reg() && is_fpr(rn) {
3134 put(sink, &enc_rre(opcode_rre.unwrap(), rd.to_reg(), rn));
3135 } else {
3136 put(
3137 sink,
3138 &enc_vrs_c(opcode_vrs, rd.to_reg(), lane_reg, lane_imm.into(), rn, m4),
3139 );
3140 }
3141 }
3142 &Inst::VecInsertLaneImm {
3143 size,
3144 rd,
3145 ri,
3146 imm,
3147 lane_imm,
3148 } => {
3149 debug_assert_eq!(rd.to_reg(), ri);
3150
3151 let opcode = match size {
3152 8 => 0xe740, 16 => 0xe741, 32 => 0xe743, 64 => 0xe742, _ => unreachable!(),
3157 };
3158 put(
3159 sink,
3160 &enc_vri_a(opcode, rd.to_reg(), imm as u16, lane_imm.into()),
3161 );
3162 }
3163 &Inst::VecReplicateLane {
3164 size,
3165 rd,
3166 rn,
3167 lane_imm,
3168 } => {
3169 let (opcode, m4) = match size {
3170 8 => (0xe74d, 0), 16 => (0xe74d, 1), 32 => (0xe74d, 2), 64 => (0xe74d, 3), _ => unreachable!(),
3175 };
3176 put(
3177 sink,
3178 &enc_vri_c(opcode, rd.to_reg(), lane_imm.into(), rn, m4),
3179 );
3180 }
3181
3182 &Inst::AllocateArgs { size } => {
3183 let inst = if let Ok(size) = i16::try_from(size) {
3184 Inst::AluRSImm16 {
3185 alu_op: ALUOp::Add64,
3186 rd: writable_stack_reg(),
3187 ri: stack_reg(),
3188 imm: -size,
3189 }
3190 } else {
3191 Inst::AluRUImm32 {
3192 alu_op: ALUOp::SubLogical64,
3193 rd: writable_stack_reg(),
3194 ri: stack_reg(),
3195 imm: size,
3196 }
3197 };
3198 inst.emit(sink, emit_info, state);
3199 state.nominal_sp_offset += size;
3200 }
3201 &Inst::Call { link, ref info } => {
3202 let opcode = 0xc05; let offset = sink.cur_offset() + 2;
3208 sink.add_reloc_at_offset(offset, Reloc::S390xPLTRel32Dbl, &info.dest, 2);
3209
3210 if let Some(s) = state.take_stack_map() {
3211 let offset = sink.cur_offset() + 6;
3212 sink.push_user_stack_map(state, offset, s);
3213 }
3214
3215 put(sink, &enc_ril_b(opcode, link.to_reg(), 0));
3216 sink.add_call_site();
3217
3218 state.nominal_sp_offset -= info.callee_pop_size;
3219 }
3220 &Inst::CallInd { link, ref info } => {
3221 if let Some(s) = state.take_stack_map() {
3222 let offset = sink.cur_offset() + 2;
3223 sink.push_user_stack_map(state, offset, s);
3224 }
3225
3226 let opcode = 0x0d; put(sink, &enc_rr(opcode, link.to_reg(), info.dest));
3228 sink.add_call_site();
3229
3230 state.nominal_sp_offset -= info.callee_pop_size;
3231 }
3232 &Inst::ReturnCall { ref info } => {
3233 for inst in S390xMachineDeps::gen_tail_epilogue(
3234 state.frame_layout(),
3235 info.callee_pop_size,
3236 None,
3237 ) {
3238 inst.emit(sink, emit_info, state);
3239 }
3240
3241 let opcode = 0xc04; let offset = sink.cur_offset() + 2;
3243 sink.add_reloc_at_offset(offset, Reloc::S390xPLTRel32Dbl, &info.dest, 2);
3244 put(sink, &enc_ril_c(opcode, 15, 0));
3245 sink.add_call_site();
3246 }
3247 &Inst::ReturnCallInd { ref info } => {
3248 let mut rn = info.dest;
3249 for inst in S390xMachineDeps::gen_tail_epilogue(
3250 state.frame_layout(),
3251 info.callee_pop_size,
3252 Some(&mut rn),
3253 ) {
3254 inst.emit(sink, emit_info, state);
3255 }
3256
3257 let opcode = 0x07; put(sink, &enc_rr(opcode, gpr(15), rn));
3259 sink.add_call_site();
3260 }
3261 &Inst::ElfTlsGetOffset { ref symbol, .. } => {
3262 let opcode = 0xc05; let dest = ExternalName::LibCall(LibCall::ElfTlsGetOffset);
3268 let offset = sink.cur_offset() + 2;
3269 sink.add_reloc_at_offset(offset, Reloc::S390xPLTRel32Dbl, &dest, 2);
3270 match &**symbol {
3271 SymbolReloc::TlsGd { name } => sink.add_reloc(Reloc::S390xTlsGdCall, name, 0),
3272 _ => unreachable!(),
3273 }
3274
3275 put(sink, &enc_ril_b(opcode, gpr(14), 0));
3276 sink.add_call_site();
3277 }
3278 &Inst::Args { .. } => {}
3279 &Inst::Rets { .. } => {}
3280 &Inst::Ret { link } => {
3281 let opcode = 0x07; put(sink, &enc_rr(opcode, gpr(15), link));
3283 }
3284 &Inst::Jump { dest } => {
3285 let off = sink.cur_offset();
3286 sink.use_label_at_offset(off, dest, LabelUse::BranchRIL);
3288 sink.add_uncond_branch(off, off + 6, dest);
3289 let opcode = 0xc04; put(sink, &enc_ril_c(opcode, 15, 0));
3292 }
3293 &Inst::IndirectBr { rn, .. } => {
3294 let opcode = 0x07; put(sink, &enc_rr(opcode, gpr(15), rn));
3296 }
3297 &Inst::CondBr {
3298 taken,
3299 not_taken,
3300 cond,
3301 } => {
3302 let opcode = 0xc04; let cond_off = sink.cur_offset();
3306 sink.use_label_at_offset(cond_off, taken, LabelUse::BranchRIL);
3307 let inverted = &enc_ril_c(opcode, cond.invert().bits(), 0);
3308 sink.add_cond_branch(cond_off, cond_off + 6, taken, inverted);
3309 put(sink, &enc_ril_c(opcode, cond.bits(), 0));
3310
3311 let uncond_off = sink.cur_offset();
3313 sink.use_label_at_offset(uncond_off, not_taken, LabelUse::BranchRIL);
3314 sink.add_uncond_branch(uncond_off, uncond_off + 6, not_taken);
3315 put(sink, &enc_ril_c(opcode, 15, 0));
3316 }
3317 &Inst::Nop0 => {}
3318 &Inst::Nop2 => {
3319 put(sink, &enc_e(0x0707));
3320 }
3321 &Inst::Debugtrap => {
3322 put(sink, &enc_e(0x0001));
3323 }
3324 &Inst::Trap { trap_code } => {
3325 put_with_trap(sink, &enc_e(0x0000), trap_code);
3326 }
3327 &Inst::TrapIf { cond, trap_code } => {
3328 let opcode = 0xc04; let enc = &enc_ril_c(opcode, cond.bits(), 2);
3333 debug_assert!(enc.len() == 6 && enc[2] == 0 && enc[3] == 0);
3334 put_with_trap(sink, &enc[0..4], trap_code);
3337 put(sink, &enc[4..6]);
3338 }
3339 &Inst::JTSequence {
3340 ridx,
3341 default,
3342 default_cond,
3343 ref targets,
3344 } => {
3345 let table_label = sink.get_label();
3346
3347 let opcode = 0xc04; sink.use_label_at_offset(sink.cur_offset(), default, LabelUse::BranchRIL);
3354 put(sink, &enc_ril_c(opcode, default_cond.bits(), 0));
3355
3356 let rtmp = writable_spilltmp_reg();
3358 let inst = Inst::LoadAddr {
3359 rd: rtmp,
3360 mem: MemArg::Label {
3361 target: table_label,
3362 },
3363 };
3364 inst.emit(sink, emit_info, state);
3365
3366 let inst = Inst::AluRX {
3368 alu_op: ALUOp::Add64Ext32,
3369 rd: rtmp,
3370 ri: rtmp.to_reg(),
3371 mem: MemArg::reg_plus_reg(rtmp.to_reg(), ridx, MemFlags::trusted()),
3372 };
3373 inst.emit(sink, emit_info, state);
3374
3375 let inst = Inst::IndirectBr {
3378 rn: rtmp.to_reg(),
3379 targets: vec![],
3380 };
3381 inst.emit(sink, emit_info, state);
3382
3383 sink.bind_label(table_label, &mut state.ctrl_plane);
3385 let jt_off = sink.cur_offset();
3386 for &target in targets.iter() {
3387 let word_off = sink.cur_offset();
3388 let off_into_table = word_off - jt_off;
3389 sink.use_label_at_offset(word_off, target, LabelUse::PCRel32);
3390 sink.put4(off_into_table.swap_bytes());
3391 }
3392
3393 start_off = sink.cur_offset();
3396 }
3397
3398 Inst::StackProbeLoop {
3399 probe_count,
3400 guard_size,
3401 } => {
3402 let loop_start = sink.get_label();
3404 sink.bind_label(loop_start, state.ctrl_plane_mut());
3405
3406 let inst = Inst::AluRSImm16 {
3408 alu_op: ALUOp::Add64,
3409 rd: writable_stack_reg(),
3410 ri: stack_reg(),
3411 imm: -guard_size,
3412 };
3413 inst.emit(sink, emit_info, state);
3414
3415 let inst = Inst::StoreImm8 {
3417 imm: 0,
3418 mem: MemArg::reg(stack_reg(), MemFlags::trusted()),
3419 };
3420 inst.emit(sink, emit_info, state);
3421
3422 let opcode = 0xa76; sink.use_label_at_offset(sink.cur_offset(), loop_start, LabelUse::BranchRI);
3425 put(sink, &enc_ri_b(opcode, probe_count.to_reg(), 0));
3426 }
3427
3428 &Inst::Unwind { ref inst } => {
3429 sink.add_unwind(inst.clone());
3430 }
3431
3432 &Inst::DummyUse { .. } => {}
3433 }
3434
3435 let end_off = sink.cur_offset();
3436 debug_assert!((end_off - start_off) <= Inst::worst_case_size());
3437
3438 state.clear_post_insn();
3439 }
3440}