cranelift_codegen/isa/s390x/inst/
emit.rs

1//! S390x ISA: binary code emission.
2
3use crate::ir::{self, LibCall, MemFlags, TrapCode};
4use crate::isa::s390x::inst::*;
5use crate::isa::s390x::settings as s390x_settings;
6use cranelift_control::ControlPlane;
7
8/// Debug macro for testing that a regpair is valid: that the high register is even, and the low
9/// register is one higher than the high register.
10macro_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
41/// Type(s) of memory instructions available for mem_finalize.
42pub struct MemInstType {
43    /// True if 12-bit unsigned displacement is supported.
44    pub have_d12: bool,
45    /// True if 20-bit signed displacement is supported.
46    pub have_d20: bool,
47    /// True if PC-relative addressing is supported (memory access).
48    pub have_pcrel: bool,
49    /// True if PC-relative addressing is supported (load address).
50    pub have_unaligned_pcrel: bool,
51    /// True if an index register is supported.
52    pub have_index: bool,
53}
54
55/// Memory addressing mode finalization: convert "special" modes (e.g.,
56/// generic arbitrary stack offset) into real addressing modes, possibly by
57/// emitting some helper instructions that come immediately before the use
58/// of this amode.
59pub 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    // Resolve virtual addressing modes.
67    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                    // The offset must be smaller than the stack frame size,
117                    // which the ABI code limits to 128 MB.
118                    unreachable!();
119                }
120                MemArg::reg_plus_reg(base, tmp.to_reg(), mem.get_flags())
121            }
122        }
123        _ => mem.clone(),
124    };
125
126    // If this addressing mode cannot be handled by the instruction, use load-address.
127    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    // Convert 12-bit displacement to 20-bit if required.
146    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
418//=============================================================================
419// Instructions and subcomponents: emission
420
421fn 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
470/// E-type instructions.
471///
472///   15
473///   opcode
474///        0
475///
476fn 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
486/// RIa-type instructions.
487///
488///   31      23 19      15
489///   opcode1 r1 opcode2 i2
490///        24 20      16  0
491///
492fn 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
504/// RIb-type instructions.
505///
506///   31      23 19      15
507///   opcode1 r1 opcode2 ri2
508///        24 20      16   0
509///
510fn 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
523/// RIc-type instructions.
524///
525///   31      23 19      15
526///   opcode1 m1 opcode2 ri2
527///        24 20      16   0
528///
529fn 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
542/// RIEa-type instructions.
543///
544///   47      39 35 31 15 11 7
545///   opcode1 r1 -- i2 m3 -- opcode2
546///        40 36 32 16 12 8       0
547///
548fn 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
563/// RIEd-type instructions.
564///
565///   47      39 35 31 15 7
566///   opcode1 r1 r3 i2 -- opcode2
567///        40 36 32 16  8       0
568///
569fn 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
583/// RIEf-type instructions.
584///
585///   47      39 35 31 23 15 7
586///   opcode1 r1 r2 i3 i4 i5 opcode2
587///        40 36 32 24 16  8       0
588///
589fn 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
605/// RIEg-type instructions.
606///
607///   47      39 35 31 15 7
608///   opcode1 r1 m3 i2 -- opcode2
609///        40 36 32 16  8       0
610///
611fn 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
625/// RILa-type instructions.
626///
627///   47      39 35      31
628///   opcode1 r1 opcode2 i2
629///        40 36      32  0
630///
631fn 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
643/// RILb-type instructions.
644///
645///   47      39 35      31
646///   opcode1 r1 opcode2 ri2
647///        40 36      32   0
648///
649fn 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
662/// RILc-type instructions.
663///
664///   47      39 35      31
665///   opcode1 m1 opcode2 i2
666///        40 36      32  0
667///
668fn 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
681/// RR-type instructions.
682///
683///   15     7  3
684///   opcode r1 r2
685///        8  4  0
686///
687fn 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
698/// RRD-type instructions.
699///
700///   31     15 11 7  3
701///   opcode r1 -- r3 r2
702///       16 12  8 4  0
703///
704fn 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
719/// RRE-type instructions.
720///
721///   31     15 7  3
722///   opcode -- r1 r2
723///       16  8  4  0
724///
725fn 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
738/// RRFa/b-type instructions.
739///
740///   31     15 11 7  3
741///   opcode r3 m4 r1 r2
742///       16 12  8  4  0
743///
744fn 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
760/// RRFc/d/e-type instructions.
761///
762///   31     15 11 7  3
763///   opcode m3 m4 r1 r2
764///       16 12  8  4  0
765///
766fn 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
782/// RS-type instructions.
783///
784///   31     23 19 15 11
785///   opcode r1 r3 b2 d2
786///       24 20 16 12  0
787///
788fn 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
804/// RSY-type instructions.
805///
806///   47      39 35 31 27  15  7
807///   opcode1 r1 r3 b2 dl2 dh2 opcode2
808///        40 36 32 28  16   8       0
809///
810fn 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
830/// RX-type instructions.
831///
832///   31     23 19 15 11
833///   opcode r1 x2 b2 d2
834///       24 20 16 12  0
835///
836fn 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
852/// RXY-type instructions.
853///
854///   47      39 35 31 27  15  7
855///   opcode1 r1 x2 b2 dl2 dh2 opcode2
856///        40 36 32 28  16   8       0
857///
858fn 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
878/// SI-type instructions.
879///
880///   31     23 15 11
881///   opcode i2 b1 d1
882///       24 16 12  0
883///
884fn 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
898/// SIL-type instructions.
899///
900///   47     31 27 15
901///   opcode b1 d1 i2
902///       32 28 16  0
903///
904fn 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
920/// SIY-type instructions.
921///
922///   47      39 31 27  15  7
923///   opcode1 i2 b1 dl1 dh1 opcode2
924///        40 32 28  16   8       0
925///
926fn 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
944/// VRIa-type instructions.
945///
946///   47      39 35 31 15 11  7
947///   opcode1 v1 -  i2 m3 rxb opcode2
948///        40 36 32 16 12   8       0
949///
950fn 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
966/// VRIb-type instructions.
967///
968///   47      39 35 31 23 15 11  7
969///   opcode1 v1 -  i2 i3 m4 rxb opcode2
970///        40 36 32 24 16 12   8       0
971///
972fn 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
989/// VRIc-type instructions.
990///
991///   47      39 35 31 15 11  7
992///   opcode1 v1 v3 i2 m4 rxb opcode2
993///        40 36 32 16 12   8       0
994///
995fn 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
1012/// VRRa-type instructions.
1013///
1014///   47      39 35 31 23 19 15 11  7
1015///   opcode1 v1 v2 -  m5 m3 m2 rxb opcode2
1016///        40 36 32 24 20 16 12   8       0
1017///
1018fn 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
1038/// VRRb-type instructions.
1039///
1040///   47      39 35 31 27 23 19 15 11  7
1041///   opcode1 v1 v2 v3 -  m5 -  m4 rxb opcode2
1042///        40 36 32 28 24 20 16 12   8       0
1043///
1044fn 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
1064/// VRRc-type instructions.
1065///
1066///   47      39 35 31 27 23 19 15 11  7
1067///   opcode1 v1 v2 v3 -  m6 m5 m4 rxb opcode2
1068///        40 36 32 28 24 20 16 12   8       0
1069///
1070fn 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
1091/// VRRe-type instructions.
1092///
1093///   47      39 35 31 27 23 19 15 11  7
1094///   opcode1 v1 v2 v3 m6 -  m5 v4 rxb opcode2
1095///        40 36 32 28 24 20 16 12   8       0
1096///
1097fn 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
1118/// VRRf-type instructions.
1119///
1120///   47      39 35 31 27 11  7
1121///   opcode1 v1 r2 r3 -  rxb opcode2
1122///        40 36 32 28 12   8       0
1123///
1124fn 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
1141/// VRSa-type instructions.
1142///
1143///   47      39 35 31 27 15 11  7
1144///   opcode1 v1 v3 b2 d2 m4 rxb opcode2
1145///        40 36 32 28 16 12   8       0
1146///
1147fn 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
1168/// VRSb-type instructions.
1169///
1170///   47      39 35 31 27 15 11  7
1171///   opcode1 v1 r3 b2 d2 m4 rxb opcode2
1172///        40 36 32 28 16 12   8       0
1173///
1174fn 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
1195/// VRSc-type instructions.
1196///
1197///   47      39 35 31 27 15 11  7
1198///   opcode1 r1 v3 b2 d2 m4 rxb opcode2
1199///        40 36 32 28 16 12   8       0
1200///
1201fn 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
1222/// VRX-type instructions.
1223///
1224///   47      39 35 31 27 15 11  7
1225///   opcode1 v1 x2 b2 d2 m3 rxb opcode2
1226///        40 36 32 28 16 12   8       0
1227///
1228fn 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
1249/// Emit encoding to sink.
1250fn put(sink: &mut MachBuffer<Inst>, enc: &[u8]) {
1251    for byte in enc {
1252        sink.put1(*byte);
1253    }
1254}
1255
1256/// Emit encoding to sink, adding a trap on the last byte.
1257fn 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/// State carried between emissions of a sequence of instructions.
1267#[derive(Default, Clone, Debug)]
1268pub struct EmitState {
1269    /// Offset from the actual SP to the "nominal SP".  The latter is defined
1270    /// as the value the stack pointer has after the prolog.  This offset is
1271    /// normally always zero, except during a call sequence using the tail-call
1272    /// ABI, between the AllocateArgs and the actual call instruction.
1273    pub(crate) nominal_sp_offset: u32,
1274
1275    /// The user stack map for the upcoming instruction, as provided to
1276    /// `pre_safepoint()`.
1277    user_stack_map: Option<ir::UserStackMap>,
1278
1279    /// Only used during fuzz-testing. Otherwise, it is a zero-sized struct and
1280    /// optimized away at compiletime. See [cranelift_control].
1281    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
1323/// Constant state used during function compilation.
1324pub 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        // Verify that we can emit this Inst in the current ISA
1355        let matches_isa_flags = |iset_requirement: &InstructionSet| -> bool {
1356            match iset_requirement {
1357                // Baseline ISA is z14
1358                InstructionSet::Base => true,
1359                // Miscellaneous-Instruction-Extensions Facility 2 (z15)
1360                InstructionSet::MIE2 => emit_info.isa_flags.has_mie2(),
1361                // Vector-Enhancements Facility 2 (z15)
1362                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        // N.B.: we *must* not exceed the "worst-case size" used to compute
1373        // where to insert islands, except when islands are explicitly triggered
1374        // (with an `EmitIsland`). We check this in debug builds. This is `mut`
1375        // to allow disabling the check for `JTSequence`, which is always
1376        // emitted following an `EmitIsland`.
1377        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),        // ARK
1383                    ALUOp::Add64 => (0xb9e8, true),        // AGRK
1384                    ALUOp::AddLogical32 => (0xb9fa, true), // ALRK
1385                    ALUOp::AddLogical64 => (0xb9ea, true), // ALGRK
1386                    ALUOp::Sub32 => (0xb9f9, true),        // SRK
1387                    ALUOp::Sub64 => (0xb9e9, true),        // SGRK
1388                    ALUOp::SubLogical32 => (0xb9fb, true), // SLRK
1389                    ALUOp::SubLogical64 => (0xb9eb, true), // SLGRK
1390                    ALUOp::Mul32 => (0xb9fd, true),        // MSRKC
1391                    ALUOp::Mul64 => (0xb9ed, true),        // MSGRKC
1392                    ALUOp::And32 => (0xb9f4, true),        // NRK
1393                    ALUOp::And64 => (0xb9e4, true),        // NGRK
1394                    ALUOp::Orr32 => (0xb9f6, true),        // ORK
1395                    ALUOp::Orr64 => (0xb9e6, true),        // OGRK
1396                    ALUOp::Xor32 => (0xb9f7, true),        // XRK
1397                    ALUOp::Xor64 => (0xb9e7, true),        // XGRK
1398                    ALUOp::NotAnd32 => (0xb974, false),    // NNRK
1399                    ALUOp::NotAnd64 => (0xb964, false),    // NNGRK
1400                    ALUOp::NotOrr32 => (0xb976, false),    // NORK
1401                    ALUOp::NotOrr64 => (0xb966, false),    // NOGRK
1402                    ALUOp::NotXor32 => (0xb977, false),    // NXRK
1403                    ALUOp::NotXor64 => (0xb967, false),    // NXGRK
1404                    ALUOp::AndNot32 => (0xb9f5, false),    // NCRK
1405                    ALUOp::AndNot64 => (0xb9e5, false),    // NCGRK
1406                    ALUOp::OrrNot32 => (0xb975, false),    // OCRK
1407                    ALUOp::OrrNot64 => (0xb965, false),    // OCGRK
1408                    _ => 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, // AHIK
1439                        ALUOp::Add64 => 0xecd9, // AGHIK
1440                        _ => 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),              // AR
1450                    ALUOp::Add64 => (0xb908, true),             // AGR
1451                    ALUOp::Add64Ext32 => (0xb918, true),        // AGFR
1452                    ALUOp::AddLogical32 => (0x1e, false),       // ALR
1453                    ALUOp::AddLogical64 => (0xb90a, true),      // ALGR
1454                    ALUOp::AddLogical64Ext32 => (0xb91a, true), // ALGFR
1455                    ALUOp::Sub32 => (0x1b, false),              // SR
1456                    ALUOp::Sub64 => (0xb909, true),             // SGR
1457                    ALUOp::Sub64Ext32 => (0xb919, true),        // SGFR
1458                    ALUOp::SubLogical32 => (0x1f, false),       // SLR
1459                    ALUOp::SubLogical64 => (0xb90b, true),      // SLGR
1460                    ALUOp::SubLogical64Ext32 => (0xb91b, true), // SLGFR
1461                    ALUOp::Mul32 => (0xb252, true),             // MSR
1462                    ALUOp::Mul64 => (0xb90c, true),             // MSGR
1463                    ALUOp::Mul64Ext32 => (0xb91c, true),        // MSGFR
1464                    ALUOp::And32 => (0x14, false),              // NR
1465                    ALUOp::And64 => (0xb980, true),             // NGR
1466                    ALUOp::Orr32 => (0x16, false),              // OR
1467                    ALUOp::Orr64 => (0xb981, true),             // OGR
1468                    ALUOp::Xor32 => (0x17, false),              // XR
1469                    ALUOp::Xor64 => (0xb982, true),             // XGR
1470                    _ => 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)),        // A(Y)
1489                    ALUOp::Add32Ext16 => (Some(0x4a), Some(0xe37a)),   // AH(Y)
1490                    ALUOp::Add64 => (None, Some(0xe308)),              // AG
1491                    ALUOp::Add64Ext16 => (None, Some(0xe338)),         // AGH
1492                    ALUOp::Add64Ext32 => (None, Some(0xe318)),         // AGF
1493                    ALUOp::AddLogical32 => (Some(0x5e), Some(0xe35e)), // AL(Y)
1494                    ALUOp::AddLogical64 => (None, Some(0xe30a)),       // ALG
1495                    ALUOp::AddLogical64Ext32 => (None, Some(0xe31a)),  // ALGF
1496                    ALUOp::Sub32 => (Some(0x5b), Some(0xe35b)),        // S(Y)
1497                    ALUOp::Sub32Ext16 => (Some(0x4b), Some(0xe37b)),   // SH(Y)
1498                    ALUOp::Sub64 => (None, Some(0xe309)),              // SG
1499                    ALUOp::Sub64Ext16 => (None, Some(0xe339)),         // SGH
1500                    ALUOp::Sub64Ext32 => (None, Some(0xe319)),         // SGF
1501                    ALUOp::SubLogical32 => (Some(0x5f), Some(0xe35f)), // SL(Y)
1502                    ALUOp::SubLogical64 => (None, Some(0xe30b)),       // SLG
1503                    ALUOp::SubLogical64Ext32 => (None, Some(0xe31b)),  // SLGF
1504                    ALUOp::Mul32 => (Some(0x71), Some(0xe351)),        // MS(Y)
1505                    ALUOp::Mul32Ext16 => (Some(0x4c), Some(0xe37c)),   // MH(Y)
1506                    ALUOp::Mul64 => (None, Some(0xe30c)),              // MSG
1507                    ALUOp::Mul64Ext16 => (None, Some(0xe33c)),         // MSH
1508                    ALUOp::Mul64Ext32 => (None, Some(0xe31c)),         // MSGF
1509                    ALUOp::And32 => (Some(0x54), Some(0xe354)),        // N(Y)
1510                    ALUOp::And64 => (None, Some(0xe380)),              // NG
1511                    ALUOp::Orr32 => (Some(0x56), Some(0xe356)),        // O(Y)
1512                    ALUOp::Orr64 => (None, Some(0xe381)),              // OG
1513                    ALUOp::Xor32 => (Some(0x57), Some(0xe357)),        // X(Y)
1514                    ALUOp::Xor64 => (None, Some(0xe382)),              // XG
1515                    _ => 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, // AHI
1532                    ALUOp::Add64 => 0xa7b, // AGHI
1533                    ALUOp::Mul32 => 0xa7c, // MHI
1534                    ALUOp::Mul64 => 0xa7d, // MGHI
1535                    _ => 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, // AFI
1549                    ALUOp::Add64 => 0xc28, // AGFI
1550                    ALUOp::Mul32 => 0xc21, // MSFI
1551                    ALUOp::Mul64 => 0xc20, // MSGFI
1552                    _ => 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, // ALFI
1566                    ALUOp::AddLogical64 => 0xc2a, // ALGFI
1567                    ALUOp::SubLogical32 => 0xc25, // SLFI
1568                    ALUOp::SubLogical64 => 0xc24, // SLGFI
1569                    _ => 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, // NILL
1583                    (ALUOp::And32, 1) => 0xa56, // NILH
1584                    (ALUOp::And64, 0) => 0xa57, // NILL
1585                    (ALUOp::And64, 1) => 0xa56, // NILH
1586                    (ALUOp::And64, 2) => 0xa55, // NIHL
1587                    (ALUOp::And64, 3) => 0xa54, // NIHL
1588                    (ALUOp::Orr32, 0) => 0xa5b, // OILL
1589                    (ALUOp::Orr32, 1) => 0xa5a, // OILH
1590                    (ALUOp::Orr64, 0) => 0xa5b, // OILL
1591                    (ALUOp::Orr64, 1) => 0xa5a, // OILH
1592                    (ALUOp::Orr64, 2) => 0xa59, // OIHL
1593                    (ALUOp::Orr64, 3) => 0xa58, // OIHH
1594                    _ => 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, // NILF
1608                    (ALUOp::And64, 0) => 0xc0b, // NILF
1609                    (ALUOp::And64, 1) => 0xc0a, // NIHF
1610                    (ALUOp::Orr32, 0) => 0xc0d, // OILF
1611                    (ALUOp::Orr64, 0) => 0xc0d, // OILF
1612                    (ALUOp::Orr64, 1) => 0xc0c, // OILF
1613                    (ALUOp::Xor32, 0) => 0xc07, // XILF
1614                    (ALUOp::Xor64, 0) => 0xc07, // XILF
1615                    (ALUOp::Xor64, 1) => 0xc06, // XILH
1616                    _ => 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; // MGRK
1627                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; // MLGR
1636                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; // DSGFR
1645                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; // DSGR
1655                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; // DLR
1668                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; // DLGR
1681                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; // FLOGR
1690                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, // RLL
1702                    ShiftOp::RotL64 => 0xeb1c, // RLLG
1703                    ShiftOp::LShL32 => 0xebdf, // SLLK  (SLL ?)
1704                    ShiftOp::LShL64 => 0xeb0d, // SLLG
1705                    ShiftOp::LShR32 => 0xebde, // SRLK  (SRL ?)
1706                    ShiftOp::LShR64 => 0xeb0c, // SRLG
1707                    ShiftOp::AShR32 => 0xebdc, // SRAK  (SRA ?)
1708                    ShiftOp::AShR64 => 0xeb0a, // SRAG
1709                };
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, // RISBGN
1729                    RxSBGOp::And => 0xec54,    // RNSBG
1730                    RxSBGOp::Or => 0xec56,     // ROSBG
1731                    RxSBGOp::Xor => 0xec57,    // RXSBG
1732                };
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, // RNSBG
1756                    RxSBGOp::Or => 0xec56,  // ROSBG
1757                    RxSBGOp::Xor => 0xec57, // RXSBG
1758                    _ => 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; // LPR
1777                        put(sink, &enc_rr(opcode, rd.to_reg(), rn));
1778                    }
1779                    UnaryOp::Abs64 => {
1780                        let opcode = 0xb900; // LPGR
1781                        put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1782                    }
1783                    UnaryOp::Abs64Ext32 => {
1784                        let opcode = 0xb910; // LPGFR
1785                        put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1786                    }
1787                    UnaryOp::Neg32 => {
1788                        let opcode = 0x13; // LCR
1789                        put(sink, &enc_rr(opcode, rd.to_reg(), rn));
1790                    }
1791                    UnaryOp::Neg64 => {
1792                        let opcode = 0xb903; // LCGR
1793                        put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1794                    }
1795                    UnaryOp::Neg64Ext32 => {
1796                        let opcode = 0xb913; // LCGFR
1797                        put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1798                    }
1799                    UnaryOp::PopcntByte => {
1800                        let opcode = 0xb9e1; // POPCNT
1801                        put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rn, 0, 0));
1802                    }
1803                    UnaryOp::PopcntReg => {
1804                        let opcode = 0xb9e1; // POPCNT
1805                        put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rn, 8, 0));
1806                    }
1807                    UnaryOp::BSwap32 => {
1808                        let opcode = 0xb91f; // LRVR
1809                        put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1810                    }
1811                    UnaryOp::BSwap64 => {
1812                        let opcode = 0xb90f; // LRVRG
1813                        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,      // LBR
1827                    (_, 1, 64) => 0xb906,      // LGBR
1828                    (false, 8, 32) => 0xb994,  // LLCR
1829                    (false, 8, 64) => 0xb984,  // LLGCR
1830                    (true, 8, 32) => 0xb926,   // LBR
1831                    (true, 8, 64) => 0xb906,   // LGBR
1832                    (false, 16, 32) => 0xb995, // LLHR
1833                    (false, 16, 64) => 0xb985, // LLGHR
1834                    (true, 16, 32) => 0xb927,  // LHR
1835                    (true, 16, 64) => 0xb907,  // LGHR
1836                    (false, 32, 64) => 0xb916, // LLGFR
1837                    (true, 32, 64) => 0xb914,  // LGFR
1838                    _ => 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),       // CR
1848                    CmpOp::CmpS64 => (0xb920, true),      // CGR
1849                    CmpOp::CmpS64Ext32 => (0xb930, true), // CGFR
1850                    CmpOp::CmpL32 => (0x15, false),       // CLR
1851                    CmpOp::CmpL64 => (0xb921, true),      // CLGR
1852                    CmpOp::CmpL64Ext32 => (0xb931, true), // CLGFR
1853                    _ => 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)), // C(Y), CRL
1866                    CmpOp::CmpS32Ext16 => (Some(0x49), Some(0xe379), Some(0xc65)), // CH(Y), CHRL
1867                    CmpOp::CmpS64 => (None, Some(0xe320), Some(0xc68)),       // CG, CGRL
1868                    CmpOp::CmpS64Ext16 => (None, Some(0xe334), Some(0xc64)),  // CGH, CGHRL
1869                    CmpOp::CmpS64Ext32 => (None, Some(0xe330), Some(0xc6c)),  // CGF, CGFRL
1870                    CmpOp::CmpL32 => (Some(0x55), Some(0xe355), Some(0xc6f)), // CL(Y), CLRL
1871                    CmpOp::CmpL32Ext16 => (None, None, Some(0xc67)),          // CLHRL
1872                    CmpOp::CmpL64 => (None, Some(0xe321), Some(0xc6a)),       // CLG, CLGRL
1873                    CmpOp::CmpL64Ext16 => (None, None, Some(0xc66)),          // CLGHRL
1874                    CmpOp::CmpL64Ext32 => (None, Some(0xe331), Some(0xc6e)),  // CLGF, CLGFRL
1875                };
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, // CHI
1883                    CmpOp::CmpS64 => 0xa7f, // CGHI
1884                    _ => 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, // CFI
1891                    CmpOp::CmpS64 => 0xc2c, // CGFI
1892                    _ => 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, // CLFI
1899                    CmpOp::CmpL64 => 0xc2e, // CLGFI
1900                    _ => 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, // CRT
1913                    CmpOp::CmpS64 => 0xb960, // CGRT
1914                    CmpOp::CmpL32 => 0xb973, // CLRT
1915                    CmpOp::CmpL64 => 0xb961, // CLGRT
1916                    _ => 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, // CIT
1933                    CmpOp::CmpS64 => 0xec70, // CGIT
1934                    _ => 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, // CLFIT
1951                    CmpOp::CmpL64 => 0xec71, // CLGIT
1952                    _ => 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,        // LAA
1967                    ALUOp::Add64 => 0xebe8,        // LAAG
1968                    ALUOp::AddLogical32 => 0xebfa, // LAAL
1969                    ALUOp::AddLogical64 => 0xebea, // LAALG
1970                    ALUOp::And32 => 0xebf4,        // LAN
1971                    ALUOp::And64 => 0xebe4,        // LANG
1972                    ALUOp::Orr32 => 0xebf6,        // LAO
1973                    ALUOp::Orr64 => 0xebe6,        // LAOG
1974                    ALUOp::Xor32 => 0xebf7,        // LAX
1975                    ALUOp::Xor64 => 0xebe7,        // LAXG
1976                    _ => 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                // This sequence is *one* instruction in the vcode, and is expanded only here at
1994                // emission time, because it requires branching to internal labels.
1995                let loop_label = sink.get_label();
1996                let done_label = sink.get_label();
1997
1998                // Emit label at the start of the loop.
1999                sink.bind_label(loop_label, &mut state.ctrl_plane);
2000
2001                for inst in (&body).into_iter() {
2002                    match &inst {
2003                        // Replace a CondBreak with a branch to done_label.
2004                        &Inst::CondBreak { cond } => {
2005                            let opcode = 0xc04; // BCRL
2006                            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; // BCRL
2018                sink.use_label_at_offset(sink.cur_offset(), loop_label, LabelUse::BranchRIL);
2019                put(sink, &enc_ril_c(opcode, cond.bits(), 0));
2020
2021                // Emit label at the end of the loop.
2022                sink.bind_label(done_label, &mut state.ctrl_plane);
2023            }
2024            &Inst::CondBreak { .. } => unreachable!(), // Only valid inside a Loop.
2025            &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)), // CS(Y)
2042                    &Inst::AtomicCas64 { .. } => (None, Some(0xeb30)),       // CSG
2043                    _ => 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)), // L(Y), LRL
2074                    &Inst::Load32ZExt8 { .. } => (None, Some(0xe394), None),         // LLC
2075                    &Inst::Load32SExt8 { .. } => (None, Some(0xe376), None),         // LB
2076                    &Inst::Load32ZExt16 { .. } => (None, Some(0xe395), Some(0xc42)), // LLH, LLHRL
2077                    &Inst::Load32SExt16 { .. } => (Some(0x48), Some(0xe378), Some(0xc45)), // LH(Y), LHRL
2078                    &Inst::Load64 { .. } => (None, Some(0xe304), Some(0xc48)), // LG, LGRL
2079                    &Inst::Load64ZExt8 { .. } => (None, Some(0xe390), None),   // LLGC
2080                    &Inst::Load64SExt8 { .. } => (None, Some(0xe377), None),   // LGB
2081                    &Inst::Load64ZExt16 { .. } => (None, Some(0xe391), Some(0xc46)), // LLGH, LLGHRL
2082                    &Inst::Load64SExt16 { .. } => (None, Some(0xe315), Some(0xc44)), // LGH, LGHRL
2083                    &Inst::Load64ZExt32 { .. } => (None, Some(0xe316), Some(0xc4e)), // LLGF, LLGFRL
2084                    &Inst::Load64SExt32 { .. } => (None, Some(0xe314), Some(0xc4c)), // LGF, LGFRL
2085                    &Inst::LoadRev16 { .. } => (None, Some(0xe31f), None),     // LRVH
2086                    &Inst::LoadRev32 { .. } => (None, Some(0xe31e), None),     // LRV
2087                    &Inst::LoadRev64 { .. } => (None, Some(0xe30f), None),     // LRVG
2088                    _ => 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), // STC(Y)
2107                    &Inst::Store16 { .. } => (Some(0x40), Some(0xe370), Some(0xc47)), // STH(Y), STHRL
2108                    &Inst::Store32 { .. } => (Some(0x50), Some(0xe350), Some(0xc4f)), // ST(Y), STRL
2109                    &Inst::Store64 { .. } => (None, Some(0xe324), Some(0xc4b)),       // STG, STGRL
2110                    &Inst::StoreRev16 { .. } => (None, Some(0xe33f), None),           // STRVH
2111                    &Inst::StoreRev32 { .. } => (None, Some(0xe33e), None),           // STRV
2112                    &Inst::StoreRev64 { .. } => (None, Some(0xe32f), None),           // STRVG
2113                    _ => 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; // MVI
2123                let opcode_siy = 0xeb52; // MVIY
2124                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,       // MVHHI
2135                    &Inst::StoreImm32SExt16 { .. } => 0xe54c, // MVHI
2136                    &Inst::StoreImm64SExt16 { .. } => 0xe548, // MVGHI
2137                    _ => 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; // LMG
2146                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; // STMG
2164                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); // LA
2181                let opcode_rxy = Some(0xe371); // LAY
2182                let opcode_ril = Some(0xc00); // LARL
2183                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; // LGR
2191                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; // LR
2198                put(sink, &enc_rr(opcode, rd.to_reg(), rm));
2199            }
2200            &Inst::Mov32Imm { rd, imm } => {
2201                let opcode = 0xc09; // IILF
2202                put(sink, &enc_ril_a(opcode, rd.to_reg(), imm));
2203            }
2204            &Inst::Mov32SImm16 { rd, imm } => {
2205                let opcode = 0xa78; // LHI
2206                put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16));
2207            }
2208            &Inst::Mov64SImm16 { rd, imm } => {
2209                let opcode = 0xa79; // LGHI
2210                put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16));
2211            }
2212            &Inst::Mov64SImm32 { rd, imm } => {
2213                let opcode = 0xc01; // LGFI
2214                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; // LOCR
2220                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; // LOCGR
2226                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; // LOCHI
2232                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; // LOCGHI
2241                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, // LLILL
2249                    1 => 0xa5e, // LLILH
2250                    2 => 0xa5d, // LLIHL
2251                    3 => 0xa5c, // LLIHH
2252                    _ => 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, // LLILF
2259                    1 => 0xc0e, // LLIHF
2260                    _ => 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, // IILL
2269                    1 => 0xa52, // IILH
2270                    2 => 0xa51, // IIHL
2271                    3 => 0xa50, // IIHH
2272                    _ => 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, // IILF
2281                    1 => 0xc08, // IIHF
2282                    _ => unreachable!(),
2283                };
2284                put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits));
2285            }
2286            &Inst::LoadAR { rd, ar } => {
2287                let opcode = 0xb24f; // EAR
2288                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; // EAR
2295                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; // BRAS
2302                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; // LER
2320                    put(sink, &enc_rr(opcode, rd.to_reg(), rn));
2321                } else {
2322                    let opcode = 0xe756; // VLR
2323                    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; // LDR
2329                    put(sink, &enc_rr(opcode, rd.to_reg(), rn));
2330                } else {
2331                    let opcode = 0xe756; // VLR
2332                    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; // BCR
2340                    put(sink, &enc_ri_c(opcode, cond.invert().bits(), 4 + 2));
2341                    let opcode = 0x38; // LER
2342                    put(sink, &enc_rr(opcode, rd.to_reg(), rm));
2343                } else {
2344                    let opcode = 0xa74; // BCR
2345                    put(sink, &enc_ri_c(opcode, cond.invert().bits(), 4 + 6));
2346                    let opcode = 0xe756; // VLR
2347                    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; // BCR
2355                    put(sink, &enc_ri_c(opcode, cond.invert().bits(), 4 + 2));
2356                    let opcode = 0x28; // LDR
2357                    put(sink, &enc_rr(opcode, rd.to_reg(), rm));
2358                } else {
2359                    let opcode = 0xa74; // BCR
2360                    put(sink, &enc_ri_c(opcode, cond.invert().bits(), 4 + 6));
2361                    let opcode = 0xe756; // VLR
2362                    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; // BRAS
2367                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; // BRAS
2380                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)), // WFPSO, LPEBR
2394                    FPUOp1::Abs64 => (0xe7cc, 3, 8, 2, Some(0xb310)), // WFPSO, LPDBR
2395                    FPUOp1::Abs32x4 => (0xe7cc, 2, 0, 2, None),       // VFPSO
2396                    FPUOp1::Abs64x2 => (0xe7cc, 3, 0, 2, None),       // VFPSO
2397                    FPUOp1::Neg32 => (0xe7cc, 2, 8, 0, Some(0xb303)), // WFPSO, LCEBR
2398                    FPUOp1::Neg64 => (0xe7cc, 3, 8, 0, Some(0xb313)), // WFPSO, LCDBR
2399                    FPUOp1::Neg32x4 => (0xe7cc, 2, 0, 0, None),       // VFPSO
2400                    FPUOp1::Neg64x2 => (0xe7cc, 3, 0, 0, None),       // VFPSO
2401                    FPUOp1::NegAbs32 => (0xe7cc, 2, 8, 1, Some(0xb301)), // WFPSO, LNEBR
2402                    FPUOp1::NegAbs64 => (0xe7cc, 3, 8, 1, Some(0xb311)), // WFPSO, LNDBR
2403                    FPUOp1::NegAbs32x4 => (0xe7cc, 2, 0, 1, None),    // VFPSO
2404                    FPUOp1::NegAbs64x2 => (0xe7cc, 3, 0, 1, None),    // VFPSO
2405                    FPUOp1::Sqrt32 => (0xe7ce, 2, 8, 0, Some(0xb314)), // WFSQ, SQEBR
2406                    FPUOp1::Sqrt64 => (0xe7ce, 3, 8, 0, Some(0xb315)), // WFSQ, SQDBR
2407                    FPUOp1::Sqrt32x4 => (0xe7ce, 2, 0, 0, None),      // VFSQ
2408                    FPUOp1::Sqrt64x2 => (0xe7ce, 3, 0, 0, None),      // VFSQ
2409                    FPUOp1::Cvt32To64 => (0xe7c4, 2, 8, 0, Some(0xb304)), // WFLL, LDEBR
2410                    FPUOp1::Cvt32x4To64x2 => (0xe7c4, 2, 0, 0, None), // VFLL
2411                };
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)), // WFA, AEBR
2421                    FPUOp2::Add64 => (0xe7e3, 3, 8, 0, Some(0xb31a)), // WFA, ADBR
2422                    FPUOp2::Add32x4 => (0xe7e3, 2, 0, 0, None),       // VFA
2423                    FPUOp2::Add64x2 => (0xe7e3, 3, 0, 0, None),       // VFA
2424                    FPUOp2::Sub32 => (0xe7e2, 2, 8, 0, Some(0xb30b)), // WFS, SEBR
2425                    FPUOp2::Sub64 => (0xe7e2, 3, 8, 0, Some(0xb31b)), // WFS, SDBR
2426                    FPUOp2::Sub32x4 => (0xe7e2, 2, 0, 0, None),       // VFS
2427                    FPUOp2::Sub64x2 => (0xe7e2, 3, 0, 0, None),       // VFS
2428                    FPUOp2::Mul32 => (0xe7e7, 2, 8, 0, Some(0xb317)), // WFM, MEEBR
2429                    FPUOp2::Mul64 => (0xe7e7, 3, 8, 0, Some(0xb31c)), // WFM, MDBR
2430                    FPUOp2::Mul32x4 => (0xe7e7, 2, 0, 0, None),       // VFM
2431                    FPUOp2::Mul64x2 => (0xe7e7, 3, 0, 0, None),       // VFM
2432                    FPUOp2::Div32 => (0xe7e5, 2, 8, 0, Some(0xb30d)), // WFD, DEBR
2433                    FPUOp2::Div64 => (0xe7e5, 3, 8, 0, Some(0xb31d)), // WFD, DDBR
2434                    FPUOp2::Div32x4 => (0xe7e5, 2, 0, 0, None),       // VFD
2435                    FPUOp2::Div64x2 => (0xe7e5, 3, 0, 0, None),       // VFD
2436                    FPUOp2::Max32 => (0xe7ef, 2, 8, 1, None),         // WFMAX
2437                    FPUOp2::Max64 => (0xe7ef, 3, 8, 1, None),         // WFMAX
2438                    FPUOp2::Max32x4 => (0xe7ef, 2, 0, 1, None),       // VFMAX
2439                    FPUOp2::Max64x2 => (0xe7ef, 3, 0, 1, None),       // VFMAX
2440                    FPUOp2::Min32 => (0xe7ee, 2, 8, 1, None),         // WFMIN
2441                    FPUOp2::Min64 => (0xe7ee, 3, 8, 1, None),         // WFMIN
2442                    FPUOp2::Min32x4 => (0xe7ee, 2, 0, 1, None),       // VFMIN
2443                    FPUOp2::Min64x2 => (0xe7ee, 3, 0, 1, None),       // VFMIN
2444                    FPUOp2::MaxPseudo32 => (0xe7ef, 2, 8, 3, None),   // WFMAX
2445                    FPUOp2::MaxPseudo64 => (0xe7ef, 3, 8, 3, None),   // WFMAX
2446                    FPUOp2::MaxPseudo32x4 => (0xe7ef, 2, 0, 3, None), // VFMAX
2447                    FPUOp2::MaxPseudo64x2 => (0xe7ef, 3, 0, 3, None), // VFMAX
2448                    FPUOp2::MinPseudo32 => (0xe7ee, 2, 8, 3, None),   // WFMIN
2449                    FPUOp2::MinPseudo64 => (0xe7ee, 3, 8, 3, None),   // WFMIN
2450                    FPUOp2::MinPseudo32x4 => (0xe7ee, 2, 0, 3, None), // VFMIN
2451                    FPUOp2::MinPseudo64x2 => (0xe7ee, 3, 0, 3, None), // VFMIN
2452                };
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)), // WFMA, MAEBR
2469                    FPUOp3::MAdd64 => (0xe78f, 8, 3, Some(0xb31e)), // WFMA, MADBR
2470                    FPUOp3::MAdd32x4 => (0xe78f, 0, 2, None),       // VFMA
2471                    FPUOp3::MAdd64x2 => (0xe78f, 0, 3, None),       // VFMA
2472                    FPUOp3::MSub32 => (0xe78e, 8, 2, Some(0xb30f)), // WFMS, MSEBR
2473                    FPUOp3::MSub64 => (0xe78e, 8, 3, Some(0xb31f)), // WFMS, MSDBR
2474                    FPUOp3::MSub32x4 => (0xe78e, 0, 2, None),       // VFMS
2475                    FPUOp3::MSub64x2 => (0xe78e, 0, 3, None),       // VFMS
2476                };
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)), // WFLR, LEDBR(A)
2495                    FpuRoundOp::Cvt64x2To32x4 => (0xe7c5, 3, 0, None),     // VFLR
2496                    FpuRoundOp::Round32 => (0xe7c7, 2, 8, Some(0xb357)),   // WFI, FIEBR
2497                    FpuRoundOp::Round64 => (0xe7c7, 3, 8, Some(0xb35f)),   // WFI, FIDBR
2498                    FpuRoundOp::Round32x4 => (0xe7c7, 2, 0, None),         // VFI
2499                    FpuRoundOp::Round64x2 => (0xe7c7, 3, 0, None),         // VFI
2500                    FpuRoundOp::ToSInt32 => (0xe7c2, 2, 8, None),          // WCSFP
2501                    FpuRoundOp::ToSInt64 => (0xe7c2, 3, 8, None),          // WCSFP
2502                    FpuRoundOp::ToUInt32 => (0xe7c0, 2, 8, None),          // WCLFP
2503                    FpuRoundOp::ToUInt64 => (0xe7c0, 3, 8, None),          // WCLFP
2504                    FpuRoundOp::ToSInt32x4 => (0xe7c2, 2, 0, None),        // VCSFP
2505                    FpuRoundOp::ToSInt64x2 => (0xe7c2, 3, 0, None),        // VCSFP
2506                    FpuRoundOp::ToUInt32x4 => (0xe7c0, 2, 0, None),        // VCLFP
2507                    FpuRoundOp::ToUInt64x2 => (0xe7c0, 3, 0, None),        // VCLFP
2508                    FpuRoundOp::FromSInt32 => (0xe7c3, 2, 8, None),        // WCFPS
2509                    FpuRoundOp::FromSInt64 => (0xe7c3, 3, 8, None),        // WCFPS
2510                    FpuRoundOp::FromUInt32 => (0xe7c1, 2, 8, None),        // WCFPL
2511                    FpuRoundOp::FromUInt64 => (0xe7c1, 3, 8, None),        // WCFPL
2512                    FpuRoundOp::FromSInt32x4 => (0xe7c3, 2, 0, None),      // VCFPS
2513                    FpuRoundOp::FromSInt64x2 => (0xe7c3, 3, 0, None),      // VCFPS
2514                    FpuRoundOp::FromUInt32x4 => (0xe7c1, 2, 0, None),      // VCFPL
2515                    FpuRoundOp::FromUInt64x2 => (0xe7c1, 3, 0, None),      // VCFPL
2516                };
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; // CEBR
2529                    put(sink, &enc_rre(opcode, rn, rm));
2530                } else {
2531                    let opcode = 0xe7cb; // WFC
2532                    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; // CDBR
2538                    put(sink, &enc_rre(opcode, rn, rm));
2539                } else {
2540                    let opcode = 0xe7cb; // WFC
2541                    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),       // VAB
2548                    VecBinaryOp::Add16x8 => (0xe7f3, 1),       // VAH
2549                    VecBinaryOp::Add32x4 => (0xe7f3, 2),       // VAF
2550                    VecBinaryOp::Add64x2 => (0xe7f3, 3),       // VAG
2551                    VecBinaryOp::Add128 => (0xe7f3, 4),        // VAQ
2552                    VecBinaryOp::Sub8x16 => (0xe7f7, 0),       // VSB
2553                    VecBinaryOp::Sub16x8 => (0xe7f7, 1),       // VSH
2554                    VecBinaryOp::Sub32x4 => (0xe7f7, 2),       // VSF
2555                    VecBinaryOp::Sub64x2 => (0xe7f7, 3),       // VSG
2556                    VecBinaryOp::Sub128 => (0xe7f7, 4),        // VSQ
2557                    VecBinaryOp::Mul8x16 => (0xe7a2, 0),       // VMLB
2558                    VecBinaryOp::Mul16x8 => (0xe7a2, 1),       // VMLHW
2559                    VecBinaryOp::Mul32x4 => (0xe7a2, 2),       // VMLF
2560                    VecBinaryOp::UMulHi8x16 => (0xe7a1, 0),    // VMLHB
2561                    VecBinaryOp::UMulHi16x8 => (0xe7a1, 1),    // VMLHH
2562                    VecBinaryOp::UMulHi32x4 => (0xe7a1, 2),    // VMLHF
2563                    VecBinaryOp::SMulHi8x16 => (0xe7a3, 0),    // VMHB
2564                    VecBinaryOp::SMulHi16x8 => (0xe7a3, 1),    // VMHH
2565                    VecBinaryOp::SMulHi32x4 => (0xe7a3, 2),    // VMHF
2566                    VecBinaryOp::UMulEven8x16 => (0xe7a4, 0),  // VMLEB
2567                    VecBinaryOp::UMulEven16x8 => (0xe7a4, 1),  // VMLEH
2568                    VecBinaryOp::UMulEven32x4 => (0xe7a4, 2),  // VMLEF
2569                    VecBinaryOp::SMulEven8x16 => (0xe7a6, 0),  // VMEB
2570                    VecBinaryOp::SMulEven16x8 => (0xe7a6, 1),  // VMEH
2571                    VecBinaryOp::SMulEven32x4 => (0xe7a6, 2),  // VMEF
2572                    VecBinaryOp::UMulOdd8x16 => (0xe7a5, 0),   // VMLOB
2573                    VecBinaryOp::UMulOdd16x8 => (0xe7a5, 1),   // VMLOH
2574                    VecBinaryOp::UMulOdd32x4 => (0xe7a5, 2),   // VMLOF
2575                    VecBinaryOp::SMulOdd8x16 => (0xe7a7, 0),   // VMOB
2576                    VecBinaryOp::SMulOdd16x8 => (0xe7a7, 1),   // VMOH
2577                    VecBinaryOp::SMulOdd32x4 => (0xe7a7, 2),   // VMOF
2578                    VecBinaryOp::UMax8x16 => (0xe7fd, 0),      // VMXLB
2579                    VecBinaryOp::UMax16x8 => (0xe7fd, 1),      // VMXLH
2580                    VecBinaryOp::UMax32x4 => (0xe7fd, 2),      // VMXLF
2581                    VecBinaryOp::UMax64x2 => (0xe7fd, 3),      // VMXLG
2582                    VecBinaryOp::SMax8x16 => (0xe7ff, 0),      // VMXB
2583                    VecBinaryOp::SMax16x8 => (0xe7ff, 1),      // VMXH
2584                    VecBinaryOp::SMax32x4 => (0xe7ff, 2),      // VMXF
2585                    VecBinaryOp::SMax64x2 => (0xe7ff, 3),      // VMXG
2586                    VecBinaryOp::UMin8x16 => (0xe7fc, 0),      // VMNLB
2587                    VecBinaryOp::UMin16x8 => (0xe7fc, 1),      // VMNLH
2588                    VecBinaryOp::UMin32x4 => (0xe7fc, 2),      // VMNLF
2589                    VecBinaryOp::UMin64x2 => (0xe7fc, 3),      // VMNLG
2590                    VecBinaryOp::SMin8x16 => (0xe7fe, 0),      // VMNB
2591                    VecBinaryOp::SMin16x8 => (0xe7fe, 1),      // VMNH
2592                    VecBinaryOp::SMin32x4 => (0xe7fe, 2),      // VMNF
2593                    VecBinaryOp::SMin64x2 => (0xe7fe, 3),      // VMNG
2594                    VecBinaryOp::UAvg8x16 => (0xe7f0, 0),      // VAVGLB
2595                    VecBinaryOp::UAvg16x8 => (0xe7f0, 1),      // VAVGLH
2596                    VecBinaryOp::UAvg32x4 => (0xe7f0, 2),      // VAVGLF
2597                    VecBinaryOp::UAvg64x2 => (0xe7f0, 3),      // VAVGLG
2598                    VecBinaryOp::SAvg8x16 => (0xe7f2, 0),      // VAVGB
2599                    VecBinaryOp::SAvg16x8 => (0xe7f2, 1),      // VAVGH
2600                    VecBinaryOp::SAvg32x4 => (0xe7f2, 2),      // VAVGF
2601                    VecBinaryOp::SAvg64x2 => (0xe7f2, 3),      // VAVGG
2602                    VecBinaryOp::And128 => (0xe768, 0),        // VN
2603                    VecBinaryOp::Orr128 => (0xe76a, 0),        // VO
2604                    VecBinaryOp::Xor128 => (0xe76d, 0),        // VX
2605                    VecBinaryOp::NotAnd128 => (0xe76e, 0),     // VNN
2606                    VecBinaryOp::NotOrr128 => (0xe76b, 0),     // VNO
2607                    VecBinaryOp::NotXor128 => (0xe76c, 0),     // VNX
2608                    VecBinaryOp::AndNot128 => (0xe769, 0),     // VNC
2609                    VecBinaryOp::OrrNot128 => (0xe76f, 0),     // VOC
2610                    VecBinaryOp::BitPermute128 => (0xe785, 0), // VBPERM
2611                    VecBinaryOp::LShLByByte128 => (0xe775, 0), // VSLB
2612                    VecBinaryOp::LShRByByte128 => (0xe77d, 0), // VSRLB
2613                    VecBinaryOp::AShRByByte128 => (0xe77f, 0), // VSRAB
2614                    VecBinaryOp::LShLByBit128 => (0xe774, 0),  // VSL
2615                    VecBinaryOp::LShRByBit128 => (0xe77c, 0),  // VSRL
2616                    VecBinaryOp::AShRByBit128 => (0xe77e, 0),  // VSRA
2617                    VecBinaryOp::Pack16x8 => (0xe794, 1),      // VPKH
2618                    VecBinaryOp::Pack32x4 => (0xe794, 2),      // VPKF
2619                    VecBinaryOp::Pack64x2 => (0xe794, 3),      // VPKG
2620                    VecBinaryOp::PackUSat16x8 => (0xe795, 1),  // VPKLSH
2621                    VecBinaryOp::PackUSat32x4 => (0xe795, 2),  // VPKLSF
2622                    VecBinaryOp::PackUSat64x2 => (0xe795, 3),  // VPKLSG
2623                    VecBinaryOp::PackSSat16x8 => (0xe797, 1),  // VPKSH
2624                    VecBinaryOp::PackSSat32x4 => (0xe797, 2),  // VPKSF
2625                    VecBinaryOp::PackSSat64x2 => (0xe797, 3),  // VPKSG
2626                    VecBinaryOp::MergeLow8x16 => (0xe760, 0),  // VMRLB
2627                    VecBinaryOp::MergeLow16x8 => (0xe760, 1),  // VMRLH
2628                    VecBinaryOp::MergeLow32x4 => (0xe760, 2),  // VMRLF
2629                    VecBinaryOp::MergeLow64x2 => (0xe760, 3),  // VMRLG
2630                    VecBinaryOp::MergeHigh8x16 => (0xe761, 0), // VMRHB
2631                    VecBinaryOp::MergeHigh16x8 => (0xe761, 1), // VMRHH
2632                    VecBinaryOp::MergeHigh32x4 => (0xe761, 2), // VMRHF
2633                    VecBinaryOp::MergeHigh64x2 => (0xe761, 3), // VMRHG
2634                };
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),         // VLPB
2641                    VecUnaryOp::Abs16x8 => (0xe7df, 1),         // VLPH
2642                    VecUnaryOp::Abs32x4 => (0xe7df, 2),         // VLPF
2643                    VecUnaryOp::Abs64x2 => (0xe7df, 3),         // VLPG
2644                    VecUnaryOp::Neg8x16 => (0xe7de, 0),         // VLCB
2645                    VecUnaryOp::Neg16x8 => (0xe7de, 1),         // VLCH
2646                    VecUnaryOp::Neg32x4 => (0xe7de, 2),         // VLCF
2647                    VecUnaryOp::Neg64x2 => (0xe7de, 3),         // VLCG
2648                    VecUnaryOp::Popcnt8x16 => (0xe750, 0),      // VPOPCTB
2649                    VecUnaryOp::Popcnt16x8 => (0xe750, 1),      // VPOPCTH
2650                    VecUnaryOp::Popcnt32x4 => (0xe750, 2),      // VPOPCTF
2651                    VecUnaryOp::Popcnt64x2 => (0xe750, 3),      // VPOPCTG
2652                    VecUnaryOp::Clz8x16 => (0xe753, 0),         // VCLZB
2653                    VecUnaryOp::Clz16x8 => (0xe753, 1),         // VCLZH
2654                    VecUnaryOp::Clz32x4 => (0xe753, 2),         // VCLZF
2655                    VecUnaryOp::Clz64x2 => (0xe753, 3),         // VCLZG
2656                    VecUnaryOp::Ctz8x16 => (0xe752, 0),         // VCTZB
2657                    VecUnaryOp::Ctz16x8 => (0xe752, 1),         // VCTZH
2658                    VecUnaryOp::Ctz32x4 => (0xe752, 2),         // VCTZF
2659                    VecUnaryOp::Ctz64x2 => (0xe752, 3),         // VCTZG
2660                    VecUnaryOp::UnpackULow8x16 => (0xe7d4, 0),  // VUPLLB
2661                    VecUnaryOp::UnpackULow16x8 => (0xe7d4, 1),  // VUPLLH
2662                    VecUnaryOp::UnpackULow32x4 => (0xe7d4, 2),  // VUPLLF
2663                    VecUnaryOp::UnpackUHigh8x16 => (0xe7d5, 0), // VUPLHB
2664                    VecUnaryOp::UnpackUHigh16x8 => (0xe7d5, 1), // VUPLHH
2665                    VecUnaryOp::UnpackUHigh32x4 => (0xe7d5, 2), // VUPLHF
2666                    VecUnaryOp::UnpackSLow8x16 => (0xe7d6, 0),  // VUPLB
2667                    VecUnaryOp::UnpackSLow16x8 => (0xe7d6, 1),  // VUPLH
2668                    VecUnaryOp::UnpackSLow32x4 => (0xe7d6, 2),  // VUPLF
2669                    VecUnaryOp::UnpackSHigh8x16 => (0xe7d7, 0), // VUPHB
2670                    VecUnaryOp::UnpackSHigh16x8 => (0xe7d7, 1), // VUPHH
2671                    VecUnaryOp::UnpackSHigh32x4 => (0xe7d7, 2), // VUPHF
2672                };
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), // VERLLB
2685                    VecShiftOp::RotL16x8 => (0xe733, 1), // VERLLH
2686                    VecShiftOp::RotL32x4 => (0xe733, 2), // VERLLF
2687                    VecShiftOp::RotL64x2 => (0xe733, 3), // VERLLG
2688                    VecShiftOp::LShL8x16 => (0xe730, 0), // VESLB
2689                    VecShiftOp::LShL16x8 => (0xe730, 1), // VESLH
2690                    VecShiftOp::LShL32x4 => (0xe730, 2), // VESLF
2691                    VecShiftOp::LShL64x2 => (0xe730, 3), // VESLG
2692                    VecShiftOp::LShR8x16 => (0xe738, 0), // VESRLB
2693                    VecShiftOp::LShR16x8 => (0xe738, 1), // VESRLH
2694                    VecShiftOp::LShR32x4 => (0xe738, 2), // VESRLF
2695                    VecShiftOp::LShR64x2 => (0xe738, 3), // VESRLG
2696                    VecShiftOp::AShR8x16 => (0xe73a, 0), // VESRAB
2697                    VecShiftOp::AShR16x8 => (0xe73a, 1), // VESRAH
2698                    VecShiftOp::AShR32x4 => (0xe73a, 2), // VESRAF
2699                    VecShiftOp::AShR64x2 => (0xe73a, 3), // VESRAG
2700                };
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; // VSEL
2708                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; // VPERM
2712                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; // VPDI
2724                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),  // VCEQB
2729                    VecIntCmpOp::CmpEq16x8 => (0xe7f8, 1),  // VCEQH
2730                    VecIntCmpOp::CmpEq32x4 => (0xe7f8, 2),  // VCEQF
2731                    VecIntCmpOp::CmpEq64x2 => (0xe7f8, 3),  // VCEQG
2732                    VecIntCmpOp::SCmpHi8x16 => (0xe7fb, 0), // VCHB
2733                    VecIntCmpOp::SCmpHi16x8 => (0xe7fb, 1), // VCHH
2734                    VecIntCmpOp::SCmpHi32x4 => (0xe7fb, 2), // VCHG
2735                    VecIntCmpOp::SCmpHi64x2 => (0xe7fb, 3), // VCHG
2736                    VecIntCmpOp::UCmpHi8x16 => (0xe7f9, 0), // VCHLB
2737                    VecIntCmpOp::UCmpHi16x8 => (0xe7f9, 1), // VCHLH
2738                    VecIntCmpOp::UCmpHi32x4 => (0xe7f9, 2), // VCHLG
2739                    VecIntCmpOp::UCmpHi64x2 => (0xe7f9, 3), // VCHLG
2740                };
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),   // VFCESB
2752                    VecFloatCmpOp::CmpEq64x2 => (0xe7e8, 3),   // VFCEDB
2753                    VecFloatCmpOp::CmpHi32x4 => (0xe7eb, 2),   // VFCHSB
2754                    VecFloatCmpOp::CmpHi64x2 => (0xe7eb, 3),   // VFCHDB
2755                    VecFloatCmpOp::CmpHiEq32x4 => (0xe7ea, 2), // VFCHESB
2756                    VecFloatCmpOp::CmpHiEq64x2 => (0xe7ea, 3), // VFCHEDB
2757                };
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                // Synthetic instruction to compare 128-bit values.
2768                // Sets CC 1 if rn > rm, sets a different CC otherwise.
2769
2770                // Use VECTOR ELEMENT COMPARE to compare the high parts.
2771                // Swap the inputs to get:
2772                //    CC 1 if high(rn) > high(rm)
2773                //    CC 2 if high(rn) < high(rm)
2774                //    CC 0 if high(rn) == high(rm)
2775                let (opcode, m3) = match self {
2776                    &Inst::VecInt128SCmpHi { .. } => (0xe7db, 3), // VECG
2777                    &Inst::VecInt128UCmpHi { .. } => (0xe7d9, 3), // VECLG
2778                    _ => unreachable!(),
2779                };
2780                put(sink, &enc_vrr_a(opcode, rm, rn, m3, 0, 0));
2781
2782                // If CC != 0, we'd done, so jump over the next instruction.
2783                let opcode = 0xa74; // BCR
2784                put(sink, &enc_ri_c(opcode, 7, 4 + 6));
2785
2786                // Otherwise, use VECTOR COMPARE HIGH LOGICAL.
2787                // Since we already know the high parts are equal, the CC
2788                // result will only depend on the low parts:
2789                //     CC 1 if low(rn) > low(rm)
2790                //     CC 3 if low(rn) <= low(rm)
2791                let inst = Inst::VecIntCmpS {
2792                    op: VecIntCmpOp::UCmpHi64x2,
2793                    // N.B.: This is the first write to tmp, and it happens
2794                    // after all uses of rn and rm.  If this were to ever
2795                    // change, tmp would have to become an early-def.
2796                    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),          // VL
2815                    &Inst::VecLoadRev { .. } => (0xe606, 4),       // VLBRQ
2816                    &Inst::VecLoadByte16Rev { .. } => (0xe606, 1), // VLBRH
2817                    &Inst::VecLoadByte32Rev { .. } => (0xe606, 2), // VLBRF
2818                    &Inst::VecLoadByte64Rev { .. } => (0xe606, 3), // VLBRG
2819                    &Inst::VecLoadElt16Rev { .. } => (0xe607, 1),  // VLERH
2820                    &Inst::VecLoadElt32Rev { .. } => (0xe607, 2),  // VLERF
2821                    &Inst::VecLoadElt64Rev { .. } => (0xe607, 3),  // VLERG
2822                    _ => 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),          // VST
2838                    &Inst::VecStoreRev { .. } => (0xe60e, 4),       // VSTBRQ
2839                    &Inst::VecStoreByte16Rev { .. } => (0xe60e, 1), // VSTBRH
2840                    &Inst::VecStoreByte32Rev { .. } => (0xe60e, 2), // VSTBRF
2841                    &Inst::VecStoreByte64Rev { .. } => (0xe60e, 3), // VSTBRG
2842                    &Inst::VecStoreElt16Rev { .. } => (0xe60f, 1),  // VSTERH
2843                    &Inst::VecStoreElt32Rev { .. } => (0xe60f, 2),  // VSTERF
2844                    &Inst::VecStoreElt64Rev { .. } => (0xe60f, 3),  // VSTERG
2845                    _ => 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), // VLREPB
2855                    (&Inst::VecLoadReplicate { .. }, 16) => (0xe705, 1), // VLREPH
2856                    (&Inst::VecLoadReplicate { .. }, 32) => (0xe705, 2), // VLREPF
2857                    (&Inst::VecLoadReplicate { .. }, 64) => (0xe705, 3), // VLREPG
2858                    (&Inst::VecLoadReplicateRev { .. }, 16) => (0xe605, 1), // VLREPBRH
2859                    (&Inst::VecLoadReplicateRev { .. }, 32) => (0xe605, 2), // VLREPBRF
2860                    (&Inst::VecLoadReplicateRev { .. }, 64) => (0xe605, 3), // VLREPBRG
2861                    _ => 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; // VLR
2868                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; // BCR
2874                put(sink, &enc_ri_c(opcode, cond.invert().bits(), 4 + 6));
2875                let opcode = 0xe756; // VLR
2876                put(sink, &enc_vrr_a(opcode, rd.to_reg(), rm, 0, 0, 0));
2877            }
2878            &Inst::MovToVec128 { rd, rn, rm } => {
2879                let opcode = 0xe762; // VLVGP
2880                put(sink, &enc_vrr_f(opcode, rd.to_reg(), rn, rm));
2881            }
2882            &Inst::VecLoadConst { rd, const_data } => {
2883                let opcode = 0xa75; // BRAS
2884                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; // BRAS
2901                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; // VGBM
2915                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),  // VGMB
2925                    16 => (0xe746, 1), // VGMH
2926                    32 => (0xe746, 2), // VGMF
2927                    64 => (0xe746, 3), // VGMG
2928                    _ => 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),  // VREPIB
2938                    16 => (0xe745, 1), // VREPIH
2939                    32 => (0xe745, 2), // VREPIF
2940                    64 => (0xe745, 3), // VREPIG
2941                    _ => 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,     // VLEB
2964                    (&Inst::VecLoadLane { .. }, 16) => 0xe701,    // VLEH
2965                    (&Inst::VecLoadLane { .. }, 32) => 0xe703,    // VLEF
2966                    (&Inst::VecLoadLane { .. }, 64) => 0xe702,    // VLEG
2967                    (&Inst::VecLoadLaneRev { .. }, 16) => 0xe601, // VLEBRH
2968                    (&Inst::VecLoadLaneRev { .. }, 32) => 0xe603, // VLEBRF
2969                    (&Inst::VecLoadLaneRev { .. }, 64) => 0xe602, // VLEBRG
2970                    _ => 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), // VLEB
3001                    (&Inst::VecLoadLaneUndef { .. }, 16) => (0xe701, None, None), // VLEH
3002                    (&Inst::VecLoadLaneUndef { .. }, 32) => (0xe703, Some(0x78), Some(0xed64)), // VLEF, LE(Y)
3003                    (&Inst::VecLoadLaneUndef { .. }, 64) => (0xe702, Some(0x68), Some(0xed65)), // VLEG, LD(Y)
3004                    (&Inst::VecLoadLaneRevUndef { .. }, 16) => (0xe601, None, None), // VLEBRH
3005                    (&Inst::VecLoadLaneRevUndef { .. }, 32) => (0xe603, None, None), // VLEBRF
3006                    (&Inst::VecLoadLaneRevUndef { .. }, 64) => (0xe602, None, None), // VLEBRG
3007                    _ => 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), // VSTEB
3044                    (&Inst::VecStoreLane { .. }, 16) => (0xe709, None, None), // VSTEH
3045                    (&Inst::VecStoreLane { .. }, 32) => (0xe70b, Some(0x70), Some(0xed66)), // VSTEF, STE(Y)
3046                    (&Inst::VecStoreLane { .. }, 64) => (0xe70a, Some(0x60), Some(0xed67)), // VSTEG, STD(Y)
3047                    (&Inst::VecStoreLaneRev { .. }, 16) => (0xe609, None, None), // VSTEBRH
3048                    (&Inst::VecStoreLaneRev { .. }, 32) => (0xe60b, None, None), // VSTEBRF
3049                    (&Inst::VecStoreLaneRev { .. }, 64) => (0xe60a, None, None), // VSTEBRG
3050                    _ => 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),  // VLVGB
3082                    16 => (0xe722, 1), // VLVGH
3083                    32 => (0xe722, 2), // VLVGF
3084                    64 => (0xe722, 3), // VLVGG
3085                    _ => 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),          // VLVGB
3101                    16 => (0xe722, 1, None),         // VLVGH
3102                    32 => (0xe722, 2, None),         // VLVGF
3103                    64 => (0xe722, 3, Some(0xb3c1)), // VLVGG, LDGR
3104                    _ => 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),          // VLGVB
3128                    16 => (0xe721, 1, None),         // VLGVH
3129                    32 => (0xe721, 2, None),         // VLGVF
3130                    64 => (0xe721, 3, Some(0xb3cd)), // VLGVG, LGDR
3131                    _ => 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,  // VLEIB
3153                    16 => 0xe741, // LEIVH
3154                    32 => 0xe743, // VLEIF
3155                    64 => 0xe742, // VLEIG
3156                    _ => 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),  // VREPB
3171                    16 => (0xe74d, 1), // VREPH
3172                    32 => (0xe74d, 2), // VREPF
3173                    64 => (0xe74d, 3), // VREPG
3174                    _ => 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; // BRASL
3203
3204                // Add relocation for target function.  This has to be done *before*
3205                // the S390xTlsGdCall relocation if any, to ensure linker relaxation
3206                // works correctly.
3207                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; // BASR
3227                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; // BCRL
3242                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; // BCR
3258                put(sink, &enc_rr(opcode, gpr(15), rn));
3259                sink.add_call_site();
3260            }
3261            &Inst::ElfTlsGetOffset { ref symbol, .. } => {
3262                let opcode = 0xc05; // BRASL
3263
3264                // Add relocation for target function. This has to be done
3265                // *before* the S390xTlsGdCall, to ensure linker relaxation
3266                // works correctly.
3267                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; // BCR
3282                put(sink, &enc_rr(opcode, gpr(15), link));
3283            }
3284            &Inst::Jump { dest } => {
3285                let off = sink.cur_offset();
3286                // Indicate that the jump uses a label, if so, so that a fixup can occur later.
3287                sink.use_label_at_offset(off, dest, LabelUse::BranchRIL);
3288                sink.add_uncond_branch(off, off + 6, dest);
3289                // Emit the jump itself.
3290                let opcode = 0xc04; // BCRL
3291                put(sink, &enc_ril_c(opcode, 15, 0));
3292            }
3293            &Inst::IndirectBr { rn, .. } => {
3294                let opcode = 0x07; // BCR
3295                put(sink, &enc_rr(opcode, gpr(15), rn));
3296            }
3297            &Inst::CondBr {
3298                taken,
3299                not_taken,
3300                cond,
3301            } => {
3302                let opcode = 0xc04; // BCRL
3303
3304                // Conditional part first.
3305                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                // Unconditional part next.
3312                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                // We implement a TrapIf as a conditional branch into the middle
3329                // of the branch (BRCL) instruction itself - those middle two bytes
3330                // are zero, which matches the trap instruction itself.
3331                let opcode = 0xc04; // BCRL
3332                let enc = &enc_ril_c(opcode, cond.bits(), 2);
3333                debug_assert!(enc.len() == 6 && enc[2] == 0 && enc[3] == 0);
3334                // The trap must be placed on the last byte of the embedded trap
3335                // instruction, so we need to emit the encoding in two parts.
3336                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                // This sequence is *one* instruction in the vcode, and is expanded only here at
3348                // emission time, because we cannot allow the regalloc to insert spills/reloads in
3349                // the middle; we depend on hardcoded PC-rel addressing below.
3350
3351                // Branch to the default target if the given default condition is true.
3352                let opcode = 0xc04; // BCRL
3353                sink.use_label_at_offset(sink.cur_offset(), default, LabelUse::BranchRIL);
3354                put(sink, &enc_ril_c(opcode, default_cond.bits(), 0));
3355
3356                // Set temp register to address of jump table.
3357                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                // Set temp to target address by adding the value of the jump table entry.
3367                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                // Branch to computed address. (`targets` here is only used for successor queries
3376                // and is not needed for emission.)
3377                let inst = Inst::IndirectBr {
3378                    rn: rtmp.to_reg(),
3379                    targets: vec![],
3380                };
3381                inst.emit(sink, emit_info, state);
3382
3383                // Emit jump table (table of 32-bit offsets).
3384                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                // Lowering produces an EmitIsland before using a JTSequence, so we can safely
3394                // disable the worst-case-size check in this case.
3395                start_off = sink.cur_offset();
3396            }
3397
3398            Inst::StackProbeLoop {
3399                probe_count,
3400                guard_size,
3401            } => {
3402                // Emit the loop start label
3403                let loop_start = sink.get_label();
3404                sink.bind_label(loop_start, state.ctrl_plane_mut());
3405
3406                // aghi %r15, -GUARD_SIZE
3407                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                // mvi 0(%r15), 0
3416                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                // brct PROBE_COUNT, LOOP_START
3423                let opcode = 0xa76; // BRCT
3424                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}