Path: blob/main/cranelift/codegen/src/isa/s390x/inst/emit.rs
1693 views
//! S390x ISA: binary code emission.12use crate::ir::{self, LibCall, MemFlags, TrapCode};3use crate::isa::CallConv;4use crate::isa::s390x::abi::REG_SAVE_AREA_SIZE;5use crate::isa::s390x::inst::*;6use crate::isa::s390x::settings as s390x_settings;7use cranelift_control::ControlPlane;89/// Debug macro for testing that a regpair is valid: that the high register is even, and the low10/// register is one higher than the high register.11macro_rules! debug_assert_valid_regpair {12($hi:expr, $lo:expr) => {13if cfg!(debug_assertions) {14match ($hi.to_real_reg(), $lo.to_real_reg()) {15(Some(hi), Some(lo)) => {16assert!(17hi.hw_enc() % 2 == 0,18"High register is not even: {}",19show_reg($hi)20);21assert_eq!(22hi.hw_enc() + 1,23lo.hw_enc(),24"Low register is not valid: {}, {}",25show_reg($hi),26show_reg($lo)27);28}2930_ => {31panic!(32"Expected real registers for {} {}",33show_reg($hi),34show_reg($lo)35);36}37}38}39};40}4142macro_rules! debug_assert_valid_fp_regpair {43($hi:expr, $lo:expr) => {44if cfg!(debug_assertions) {45match ($hi.to_real_reg(), $lo.to_real_reg()) {46(Some(hi), Some(lo)) => {47assert!(48hi.hw_enc() & 2 == 0,49"High register is not valid: {}",50show_reg($hi)51);52assert_eq!(53hi.hw_enc() + 2,54lo.hw_enc(),55"Low register is not valid: {}, {}",56show_reg($hi),57show_reg($lo)58);59}6061_ => {62panic!(63"Expected real registers for {} {}",64show_reg($hi),65show_reg($lo)66);67}68}69}70};71}7273const OPCODE_BRAS: u16 = 0xa75;74const OPCODE_BCR: u16 = 0xa74;75const OPCODE_LDR: u16 = 0x28;76const OPCODE_VLR: u16 = 0xe756;7778/// Type(s) of memory instructions available for mem_finalize.79pub struct MemInstType {80/// True if 12-bit unsigned displacement is supported.81pub have_d12: bool,82/// True if 20-bit signed displacement is supported.83pub have_d20: bool,84/// True if PC-relative addressing is supported (memory access).85pub have_pcrel: bool,86/// True if PC-relative addressing is supported (load address).87pub have_unaligned_pcrel: bool,88/// True if an index register is supported.89pub have_index: bool,90}9192/// Memory addressing mode finalization: convert "special" modes (e.g.,93/// generic arbitrary stack offset) into real addressing modes, possibly by94/// emitting some helper instructions that come immediately before the use95/// of this amode.96pub fn mem_finalize(97mem: &MemArg,98state: &EmitState,99mi: MemInstType,100) -> (SmallVec<[Inst; 4]>, MemArg) {101let mut insts = SmallVec::new();102103// Resolve virtual addressing modes.104let mem = match mem {105&MemArg::RegOffset { off, .. }106| &MemArg::InitialSPOffset { off }107| &MemArg::IncomingArgOffset { off }108| &MemArg::OutgoingArgOffset { off }109| &MemArg::SlotOffset { off }110| &MemArg::SpillOffset { off } => {111let base = match mem {112&MemArg::RegOffset { reg, .. } => reg,113&MemArg::InitialSPOffset { .. }114| &MemArg::IncomingArgOffset { .. }115| &MemArg::OutgoingArgOffset { .. }116| &MemArg::SlotOffset { .. }117| &MemArg::SpillOffset { .. } => stack_reg(),118_ => unreachable!(),119};120let adj = match mem {121&MemArg::IncomingArgOffset { .. } => i64::from(122state.incoming_args_size123+ REG_SAVE_AREA_SIZE124+ state.frame_layout().clobber_size125+ state.frame_layout().fixed_frame_storage_size126+ state.frame_layout().outgoing_args_size127+ state.nominal_sp_offset,128),129&MemArg::InitialSPOffset { .. } => i64::from(130state.frame_layout().clobber_size131+ state.frame_layout().fixed_frame_storage_size132+ state.frame_layout().outgoing_args_size133+ state.nominal_sp_offset,134),135&MemArg::SpillOffset { .. } => i64::from(136state.frame_layout().stackslots_size137+ state.frame_layout().outgoing_args_size138+ state.nominal_sp_offset,139),140&MemArg::SlotOffset { .. } => {141i64::from(state.frame_layout().outgoing_args_size + state.nominal_sp_offset)142}143&MemArg::OutgoingArgOffset { .. } => {144i64::from(REG_SAVE_AREA_SIZE) - i64::from(state.outgoing_sp_offset)145}146_ => 0,147};148let off = off + adj;149150if let Some(disp) = UImm12::maybe_from_u64(off as u64) {151MemArg::BXD12 {152base,153index: zero_reg(),154disp,155flags: mem.get_flags(),156}157} else if let Some(disp) = SImm20::maybe_from_i64(off) {158MemArg::BXD20 {159base,160index: zero_reg(),161disp,162flags: mem.get_flags(),163}164} else {165let tmp = writable_spilltmp_reg();166assert!(base != tmp.to_reg());167if let Ok(imm) = i16::try_from(off) {168insts.push(Inst::Mov64SImm16 { rd: tmp, imm });169} else if let Ok(imm) = i32::try_from(off) {170insts.push(Inst::Mov64SImm32 { rd: tmp, imm });171} else {172// The offset must be smaller than the stack frame size,173// which the ABI code limits to 128 MB.174unreachable!();175}176MemArg::reg_plus_reg(base, tmp.to_reg(), mem.get_flags())177}178}179_ => mem.clone(),180};181182// If this addressing mode cannot be handled by the instruction, use load-address.183let need_load_address = match &mem {184&MemArg::Label { .. } | &MemArg::Constant { .. } if !mi.have_pcrel => true,185&MemArg::Symbol { .. } if !mi.have_pcrel => true,186&MemArg::Symbol { flags, .. } if !mi.have_unaligned_pcrel && !flags.aligned() => true,187&MemArg::BXD20 { .. } if !mi.have_d20 => true,188&MemArg::BXD12 { index, .. } | &MemArg::BXD20 { index, .. } if !mi.have_index => {189index != zero_reg()190}191_ => false,192};193let mem = if need_load_address {194let flags = mem.get_flags();195let tmp = writable_spilltmp_reg();196insts.push(Inst::LoadAddr { rd: tmp, mem });197MemArg::reg(tmp.to_reg(), flags)198} else {199mem200};201202// Convert 12-bit displacement to 20-bit if required.203let mem = match &mem {204&MemArg::BXD12 {205base,206index,207disp,208flags,209} if !mi.have_d12 => {210assert!(mi.have_d20);211MemArg::BXD20 {212base,213index,214disp: SImm20::from_uimm12(disp),215flags,216}217}218_ => mem,219};220221(insts, mem)222}223224pub fn mem_emit(225rd: Reg,226mem: &MemArg,227opcode_rx: Option<u16>,228opcode_rxy: Option<u16>,229opcode_ril: Option<u16>,230add_trap: bool,231sink: &mut MachBuffer<Inst>,232emit_info: &EmitInfo,233state: &mut EmitState,234) {235let (mem_insts, mem) = mem_finalize(236mem,237state,238MemInstType {239have_d12: opcode_rx.is_some(),240have_d20: opcode_rxy.is_some(),241have_pcrel: opcode_ril.is_some(),242have_unaligned_pcrel: opcode_ril.is_some() && !add_trap,243have_index: true,244},245);246for inst in mem_insts.into_iter() {247inst.emit(sink, emit_info, state);248}249250if add_trap {251if let Some(trap_code) = mem.get_flags().trap_code() {252sink.add_trap(trap_code);253}254}255256match &mem {257&MemArg::BXD12 {258base, index, disp, ..259} => {260put(261sink,262&enc_rx(opcode_rx.unwrap(), rd, base, index, disp.bits()),263);264}265&MemArg::BXD20 {266base, index, disp, ..267} => {268put(269sink,270&enc_rxy(opcode_rxy.unwrap(), rd, base, index, disp.bits()),271);272}273&MemArg::Label { target } => {274sink.use_label_at_offset(sink.cur_offset(), target, LabelUse::BranchRIL);275put(sink, &enc_ril_b(opcode_ril.unwrap(), rd, 0));276}277&MemArg::Constant { constant } => {278let target = sink.get_label_for_constant(constant);279sink.use_label_at_offset(sink.cur_offset(), target, LabelUse::BranchRIL);280put(sink, &enc_ril_b(opcode_ril.unwrap(), rd, 0));281}282&MemArg::Symbol {283ref name, offset, ..284} => {285let reloc_offset = sink.cur_offset() + 2;286sink.add_reloc_at_offset(287reloc_offset,288Reloc::S390xPCRel32Dbl,289&**name,290(offset + 2).into(),291);292put(sink, &enc_ril_b(opcode_ril.unwrap(), rd, 0));293}294_ => unreachable!(),295}296}297298pub fn mem_rs_emit(299rd: Reg,300rn: Reg,301mem: &MemArg,302opcode_rs: Option<u16>,303opcode_rsy: Option<u16>,304add_trap: bool,305sink: &mut MachBuffer<Inst>,306emit_info: &EmitInfo,307state: &mut EmitState,308) {309let (mem_insts, mem) = mem_finalize(310mem,311state,312MemInstType {313have_d12: opcode_rs.is_some(),314have_d20: opcode_rsy.is_some(),315have_pcrel: false,316have_unaligned_pcrel: false,317have_index: false,318},319);320for inst in mem_insts.into_iter() {321inst.emit(sink, emit_info, state);322}323324if add_trap {325if let Some(trap_code) = mem.get_flags().trap_code() {326sink.add_trap(trap_code);327}328}329330match &mem {331&MemArg::BXD12 {332base, index, disp, ..333} => {334assert!(index == zero_reg());335put(sink, &enc_rs(opcode_rs.unwrap(), rd, rn, base, disp.bits()));336}337&MemArg::BXD20 {338base, index, disp, ..339} => {340assert!(index == zero_reg());341put(342sink,343&enc_rsy(opcode_rsy.unwrap(), rd, rn, base, disp.bits()),344);345}346_ => unreachable!(),347}348}349350pub fn mem_imm8_emit(351imm: u8,352mem: &MemArg,353opcode_si: u16,354opcode_siy: u16,355add_trap: bool,356sink: &mut MachBuffer<Inst>,357emit_info: &EmitInfo,358state: &mut EmitState,359) {360let (mem_insts, mem) = mem_finalize(361mem,362state,363MemInstType {364have_d12: true,365have_d20: true,366have_pcrel: false,367have_unaligned_pcrel: false,368have_index: false,369},370);371for inst in mem_insts.into_iter() {372inst.emit(sink, emit_info, state);373}374375if add_trap {376if let Some(trap_code) = mem.get_flags().trap_code() {377sink.add_trap(trap_code);378}379}380381match &mem {382&MemArg::BXD12 {383base, index, disp, ..384} => {385assert!(index == zero_reg());386put(sink, &enc_si(opcode_si, base, disp.bits(), imm));387}388&MemArg::BXD20 {389base, index, disp, ..390} => {391assert!(index == zero_reg());392put(sink, &enc_siy(opcode_siy, base, disp.bits(), imm));393}394_ => unreachable!(),395}396}397398pub fn mem_imm16_emit(399imm: i16,400mem: &MemArg,401opcode_sil: u16,402add_trap: bool,403sink: &mut MachBuffer<Inst>,404emit_info: &EmitInfo,405state: &mut EmitState,406) {407let (mem_insts, mem) = mem_finalize(408mem,409state,410MemInstType {411have_d12: true,412have_d20: false,413have_pcrel: false,414have_unaligned_pcrel: false,415have_index: false,416},417);418for inst in mem_insts.into_iter() {419inst.emit(sink, emit_info, state);420}421422if add_trap {423if let Some(trap_code) = mem.get_flags().trap_code() {424sink.add_trap(trap_code);425}426}427428match &mem {429&MemArg::BXD12 {430base, index, disp, ..431} => {432assert!(index == zero_reg());433put(sink, &enc_sil(opcode_sil, base, disp.bits(), imm));434}435_ => unreachable!(),436}437}438439pub fn mem_vrx_emit(440rd: Reg,441mem: &MemArg,442opcode: u16,443m3: u8,444add_trap: bool,445sink: &mut MachBuffer<Inst>,446emit_info: &EmitInfo,447state: &mut EmitState,448) {449let (mem_insts, mem) = mem_finalize(450mem,451state,452MemInstType {453have_d12: true,454have_d20: false,455have_pcrel: false,456have_unaligned_pcrel: false,457have_index: true,458},459);460for inst in mem_insts.into_iter() {461inst.emit(sink, emit_info, state);462}463464if add_trap {465if let Some(trap_code) = mem.get_flags().trap_code() {466sink.add_trap(trap_code);467}468}469470match &mem {471&MemArg::BXD12 {472base, index, disp, ..473} => {474put(sink, &enc_vrx(opcode, rd, base, index, disp.bits(), m3));475}476_ => unreachable!(),477}478}479480//=============================================================================481// Instructions and subcomponents: emission482483fn machreg_to_gpr(m: Reg) -> u8 {484assert_eq!(m.class(), RegClass::Int);485m.to_real_reg().unwrap().hw_enc()486}487488fn machreg_to_vr(m: Reg) -> u8 {489assert_eq!(m.class(), RegClass::Float);490m.to_real_reg().unwrap().hw_enc()491}492493fn machreg_to_fpr(m: Reg) -> u8 {494assert!(is_fpr(m));495m.to_real_reg().unwrap().hw_enc()496}497498fn machreg_to_gpr_or_fpr(m: Reg) -> u8 {499let reg = m.to_real_reg().unwrap().hw_enc();500assert!(reg < 16);501reg502}503504fn rxb(v1: Option<Reg>, v2: Option<Reg>, v3: Option<Reg>, v4: Option<Reg>) -> u8 {505let mut rxb = 0;506507let is_high_vr = |reg| -> bool {508if let Some(reg) = reg {509if !is_fpr(reg) {510return true;511}512}513false514};515516if is_high_vr(v1) {517rxb = rxb | 8;518}519if is_high_vr(v2) {520rxb = rxb | 4;521}522if is_high_vr(v3) {523rxb = rxb | 2;524}525if is_high_vr(v4) {526rxb = rxb | 1;527}528529rxb530}531532/// E-type instructions.533///534/// 15535/// opcode536/// 0537///538fn enc_e(opcode: u16) -> [u8; 2] {539let mut enc: [u8; 2] = [0; 2];540let opcode1 = ((opcode >> 8) & 0xff) as u8;541let opcode2 = (opcode & 0xff) as u8;542543enc[0] = opcode1;544enc[1] = opcode2;545enc546}547548/// RIa-type instructions.549///550/// 31 23 19 15551/// opcode1 r1 opcode2 i2552/// 24 20 16 0553///554fn enc_ri_a(opcode: u16, r1: Reg, i2: u16) -> [u8; 4] {555let mut enc: [u8; 4] = [0; 4];556let opcode1 = ((opcode >> 4) & 0xff) as u8;557let opcode2 = (opcode & 0xf) as u8;558let r1 = machreg_to_gpr(r1) & 0x0f;559560enc[0] = opcode1;561enc[1] = r1 << 4 | opcode2;562enc[2..].copy_from_slice(&i2.to_be_bytes());563enc564}565566/// RIb-type instructions.567///568/// 31 23 19 15569/// opcode1 r1 opcode2 ri2570/// 24 20 16 0571///572fn enc_ri_b(opcode: u16, r1: Reg, ri2: i32) -> [u8; 4] {573let mut enc: [u8; 4] = [0; 4];574let opcode1 = ((opcode >> 4) & 0xff) as u8;575let opcode2 = (opcode & 0xf) as u8;576let r1 = machreg_to_gpr(r1) & 0x0f;577let ri2 = ((ri2 >> 1) & 0xffff) as u16;578579enc[0] = opcode1;580enc[1] = r1 << 4 | opcode2;581enc[2..].copy_from_slice(&ri2.to_be_bytes());582enc583}584585/// RIc-type instructions.586///587/// 31 23 19 15588/// opcode1 m1 opcode2 ri2589/// 24 20 16 0590///591fn enc_ri_c(opcode: u16, m1: u8, ri2: i32) -> [u8; 4] {592let mut enc: [u8; 4] = [0; 4];593let opcode1 = ((opcode >> 4) & 0xff) as u8;594let opcode2 = (opcode & 0xf) as u8;595let m1 = m1 & 0x0f;596let ri2 = ((ri2 >> 1) & 0xffff) as u16;597598enc[0] = opcode1;599enc[1] = m1 << 4 | opcode2;600enc[2..].copy_from_slice(&ri2.to_be_bytes());601enc602}603604/// RIEa-type instructions.605///606/// 47 39 35 31 15 11 7607/// opcode1 r1 -- i2 m3 -- opcode2608/// 40 36 32 16 12 8 0609///610fn enc_rie_a(opcode: u16, r1: Reg, i2: u16, m3: u8) -> [u8; 6] {611let mut enc: [u8; 6] = [0; 6];612let opcode1 = ((opcode >> 8) & 0xff) as u8;613let opcode2 = (opcode & 0xff) as u8;614let r1 = machreg_to_gpr(r1) & 0x0f;615let m3 = m3 & 0x0f;616617enc[0] = opcode1;618enc[1] = r1 << 4;619enc[2..4].copy_from_slice(&i2.to_be_bytes());620enc[4] = m3 << 4;621enc[5] = opcode2;622enc623}624625/// RIEd-type instructions.626///627/// 47 39 35 31 15 7628/// opcode1 r1 r3 i2 -- opcode2629/// 40 36 32 16 8 0630///631fn enc_rie_d(opcode: u16, r1: Reg, r3: Reg, i2: u16) -> [u8; 6] {632let mut enc: [u8; 6] = [0; 6];633let opcode1 = ((opcode >> 8) & 0xff) as u8;634let opcode2 = (opcode & 0xff) as u8;635let r1 = machreg_to_gpr(r1) & 0x0f;636let r3 = machreg_to_gpr(r3) & 0x0f;637638enc[0] = opcode1;639enc[1] = r1 << 4 | r3;640enc[2..4].copy_from_slice(&i2.to_be_bytes());641enc[5] = opcode2;642enc643}644645/// RIEf-type instructions.646///647/// 47 39 35 31 23 15 7648/// opcode1 r1 r2 i3 i4 i5 opcode2649/// 40 36 32 24 16 8 0650///651fn enc_rie_f(opcode: u16, r1: Reg, r2: Reg, i3: u8, i4: u8, i5: u8) -> [u8; 6] {652let mut enc: [u8; 6] = [0; 6];653let opcode1 = ((opcode >> 8) & 0xff) as u8;654let opcode2 = (opcode & 0xff) as u8;655let r1 = machreg_to_gpr(r1) & 0x0f;656let r2 = machreg_to_gpr(r2) & 0x0f;657658enc[0] = opcode1;659enc[1] = r1 << 4 | r2;660enc[2] = i3;661enc[3] = i4;662enc[4] = i5;663enc[5] = opcode2;664enc665}666667/// RIEg-type instructions.668///669/// 47 39 35 31 15 7670/// opcode1 r1 m3 i2 -- opcode2671/// 40 36 32 16 8 0672///673fn enc_rie_g(opcode: u16, r1: Reg, i2: u16, m3: u8) -> [u8; 6] {674let mut enc: [u8; 6] = [0; 6];675let opcode1 = ((opcode >> 8) & 0xff) as u8;676let opcode2 = (opcode & 0xff) as u8;677let r1 = machreg_to_gpr(r1) & 0x0f;678let m3 = m3 & 0x0f;679680enc[0] = opcode1;681enc[1] = r1 << 4 | m3;682enc[2..4].copy_from_slice(&i2.to_be_bytes());683enc[5] = opcode2;684enc685}686687/// RILa-type instructions.688///689/// 47 39 35 31690/// opcode1 r1 opcode2 i2691/// 40 36 32 0692///693fn enc_ril_a(opcode: u16, r1: Reg, i2: u32) -> [u8; 6] {694let mut enc: [u8; 6] = [0; 6];695let opcode1 = ((opcode >> 4) & 0xff) as u8;696let opcode2 = (opcode & 0xf) as u8;697let r1 = machreg_to_gpr(r1) & 0x0f;698699enc[0] = opcode1;700enc[1] = r1 << 4 | opcode2;701enc[2..].copy_from_slice(&i2.to_be_bytes());702enc703}704705/// RILb-type instructions.706///707/// 47 39 35 31708/// opcode1 r1 opcode2 ri2709/// 40 36 32 0710///711fn enc_ril_b(opcode: u16, r1: Reg, ri2: u32) -> [u8; 6] {712let mut enc: [u8; 6] = [0; 6];713let opcode1 = ((opcode >> 4) & 0xff) as u8;714let opcode2 = (opcode & 0xf) as u8;715let r1 = machreg_to_gpr(r1) & 0x0f;716let ri2 = ri2 >> 1;717718enc[0] = opcode1;719enc[1] = r1 << 4 | opcode2;720enc[2..].copy_from_slice(&ri2.to_be_bytes());721enc722}723724/// RILc-type instructions.725///726/// 47 39 35 31727/// opcode1 m1 opcode2 i2728/// 40 36 32 0729///730fn enc_ril_c(opcode: u16, m1: u8, ri2: u32) -> [u8; 6] {731let mut enc: [u8; 6] = [0; 6];732let opcode1 = ((opcode >> 4) & 0xff) as u8;733let opcode2 = (opcode & 0xf) as u8;734let m1 = m1 & 0x0f;735let ri2 = ri2 >> 1;736737enc[0] = opcode1;738enc[1] = m1 << 4 | opcode2;739enc[2..].copy_from_slice(&ri2.to_be_bytes());740enc741}742743/// RR-type instructions.744///745/// 15 7 3746/// opcode r1 r2747/// 8 4 0748///749fn enc_rr(opcode: u16, r1: Reg, r2: Reg) -> [u8; 2] {750let mut enc: [u8; 2] = [0; 2];751let opcode = (opcode & 0xff) as u8;752let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;753let r2 = machreg_to_gpr_or_fpr(r2) & 0x0f;754755enc[0] = opcode;756enc[1] = r1 << 4 | r2;757enc758}759760/// RRD-type instructions.761///762/// 31 15 11 7 3763/// opcode r1 -- r3 r2764/// 16 12 8 4 0765///766fn enc_rrd(opcode: u16, r1: Reg, r2: Reg, r3: Reg) -> [u8; 4] {767let mut enc: [u8; 4] = [0; 4];768let opcode1 = ((opcode >> 8) & 0xff) as u8;769let opcode2 = (opcode & 0xff) as u8;770let r1 = machreg_to_fpr(r1) & 0x0f;771let r2 = machreg_to_fpr(r2) & 0x0f;772let r3 = machreg_to_fpr(r3) & 0x0f;773774enc[0] = opcode1;775enc[1] = opcode2;776enc[2] = r1 << 4;777enc[3] = r3 << 4 | r2;778enc779}780781/// RRE-type instructions.782///783/// 31 15 7 3784/// opcode -- r1 r2785/// 16 8 4 0786///787fn enc_rre(opcode: u16, r1: Reg, r2: Reg) -> [u8; 4] {788let mut enc: [u8; 4] = [0; 4];789let opcode1 = ((opcode >> 8) & 0xff) as u8;790let opcode2 = (opcode & 0xff) as u8;791let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;792let r2 = machreg_to_gpr_or_fpr(r2) & 0x0f;793794enc[0] = opcode1;795enc[1] = opcode2;796enc[3] = r1 << 4 | r2;797enc798}799800/// RRFa/b-type instructions.801///802/// 31 15 11 7 3803/// opcode r3 m4 r1 r2804/// 16 12 8 4 0805///806fn enc_rrf_ab(opcode: u16, r1: Reg, r2: Reg, r3: Reg, m4: u8) -> [u8; 4] {807let mut enc: [u8; 4] = [0; 4];808let opcode1 = ((opcode >> 8) & 0xff) as u8;809let opcode2 = (opcode & 0xff) as u8;810let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;811let r2 = machreg_to_gpr_or_fpr(r2) & 0x0f;812let r3 = machreg_to_gpr_or_fpr(r3) & 0x0f;813let m4 = m4 & 0x0f;814815enc[0] = opcode1;816enc[1] = opcode2;817enc[2] = r3 << 4 | m4;818enc[3] = r1 << 4 | r2;819enc820}821822/// RRFc/d/e-type instructions.823///824/// 31 15 11 7 3825/// opcode m3 m4 r1 r2826/// 16 12 8 4 0827///828fn enc_rrf_cde(opcode: u16, r1: Reg, r2: Reg, m3: u8, m4: u8) -> [u8; 4] {829let mut enc: [u8; 4] = [0; 4];830let opcode1 = ((opcode >> 8) & 0xff) as u8;831let opcode2 = (opcode & 0xff) as u8;832let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;833let r2 = machreg_to_gpr_or_fpr(r2) & 0x0f;834let m3 = m3 & 0x0f;835let m4 = m4 & 0x0f;836837enc[0] = opcode1;838enc[1] = opcode2;839enc[2] = m3 << 4 | m4;840enc[3] = r1 << 4 | r2;841enc842}843844/// RS-type instructions.845///846/// 31 23 19 15 11847/// opcode r1 r3 b2 d2848/// 24 20 16 12 0849///850fn enc_rs(opcode: u16, r1: Reg, r3: Reg, b2: Reg, d2: u32) -> [u8; 4] {851let opcode = (opcode & 0xff) as u8;852let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;853let r3 = machreg_to_gpr_or_fpr(r3) & 0x0f;854let b2 = machreg_to_gpr(b2) & 0x0f;855let d2_lo = (d2 & 0xff) as u8;856let d2_hi = ((d2 >> 8) & 0x0f) as u8;857858let mut enc: [u8; 4] = [0; 4];859enc[0] = opcode;860enc[1] = r1 << 4 | r3;861enc[2] = b2 << 4 | d2_hi;862enc[3] = d2_lo;863enc864}865866/// RSY-type instructions.867///868/// 47 39 35 31 27 15 7869/// opcode1 r1 r3 b2 dl2 dh2 opcode2870/// 40 36 32 28 16 8 0871///872fn enc_rsy(opcode: u16, r1: Reg, r3: Reg, b2: Reg, d2: u32) -> [u8; 6] {873let opcode1 = ((opcode >> 8) & 0xff) as u8;874let opcode2 = (opcode & 0xff) as u8;875let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;876let r3 = machreg_to_gpr_or_fpr(r3) & 0x0f;877let b2 = machreg_to_gpr(b2) & 0x0f;878let dl2_lo = (d2 & 0xff) as u8;879let dl2_hi = ((d2 >> 8) & 0x0f) as u8;880let dh2 = ((d2 >> 12) & 0xff) as u8;881882let mut enc: [u8; 6] = [0; 6];883enc[0] = opcode1;884enc[1] = r1 << 4 | r3;885enc[2] = b2 << 4 | dl2_hi;886enc[3] = dl2_lo;887enc[4] = dh2;888enc[5] = opcode2;889enc890}891892/// RX-type instructions.893///894/// 31 23 19 15 11895/// opcode r1 x2 b2 d2896/// 24 20 16 12 0897///898fn enc_rx(opcode: u16, r1: Reg, b2: Reg, x2: Reg, d2: u32) -> [u8; 4] {899let opcode = (opcode & 0xff) as u8;900let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;901let b2 = machreg_to_gpr(b2) & 0x0f;902let x2 = machreg_to_gpr(x2) & 0x0f;903let d2_lo = (d2 & 0xff) as u8;904let d2_hi = ((d2 >> 8) & 0x0f) as u8;905906let mut enc: [u8; 4] = [0; 4];907enc[0] = opcode;908enc[1] = r1 << 4 | x2;909enc[2] = b2 << 4 | d2_hi;910enc[3] = d2_lo;911enc912}913914/// RXY-type instructions.915///916/// 47 39 35 31 27 15 7917/// opcode1 r1 x2 b2 dl2 dh2 opcode2918/// 40 36 32 28 16 8 0919///920fn enc_rxy(opcode: u16, r1: Reg, b2: Reg, x2: Reg, d2: u32) -> [u8; 6] {921let opcode1 = ((opcode >> 8) & 0xff) as u8;922let opcode2 = (opcode & 0xff) as u8;923let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;924let b2 = machreg_to_gpr(b2) & 0x0f;925let x2 = machreg_to_gpr(x2) & 0x0f;926let dl2_lo = (d2 & 0xff) as u8;927let dl2_hi = ((d2 >> 8) & 0x0f) as u8;928let dh2 = ((d2 >> 12) & 0xff) as u8;929930let mut enc: [u8; 6] = [0; 6];931enc[0] = opcode1;932enc[1] = r1 << 4 | x2;933enc[2] = b2 << 4 | dl2_hi;934enc[3] = dl2_lo;935enc[4] = dh2;936enc[5] = opcode2;937enc938}939940/// SI-type instructions.941///942/// 31 23 15 11943/// opcode i2 b1 d1944/// 24 16 12 0945///946fn enc_si(opcode: u16, b1: Reg, d1: u32, i2: u8) -> [u8; 4] {947let opcode = (opcode & 0xff) as u8;948let b1 = machreg_to_gpr(b1) & 0x0f;949let d1_lo = (d1 & 0xff) as u8;950let d1_hi = ((d1 >> 8) & 0x0f) as u8;951952let mut enc: [u8; 4] = [0; 4];953enc[0] = opcode;954enc[1] = i2;955enc[2] = b1 << 4 | d1_hi;956enc[3] = d1_lo;957enc958}959960/// SIL-type instructions.961///962/// 47 31 27 15963/// opcode b1 d1 i2964/// 32 28 16 0965///966fn enc_sil(opcode: u16, b1: Reg, d1: u32, i2: i16) -> [u8; 6] {967let opcode1 = ((opcode >> 8) & 0xff) as u8;968let opcode2 = (opcode & 0xff) as u8;969let b1 = machreg_to_gpr(b1) & 0x0f;970let d1_lo = (d1 & 0xff) as u8;971let d1_hi = ((d1 >> 8) & 0x0f) as u8;972973let mut enc: [u8; 6] = [0; 6];974enc[0] = opcode1;975enc[1] = opcode2;976enc[2] = b1 << 4 | d1_hi;977enc[3] = d1_lo;978enc[4..].copy_from_slice(&i2.to_be_bytes());979enc980}981982/// SIY-type instructions.983///984/// 47 39 31 27 15 7985/// opcode1 i2 b1 dl1 dh1 opcode2986/// 40 32 28 16 8 0987///988fn enc_siy(opcode: u16, b1: Reg, d1: u32, i2: u8) -> [u8; 6] {989let opcode1 = ((opcode >> 8) & 0xff) as u8;990let opcode2 = (opcode & 0xff) as u8;991let b1 = machreg_to_gpr(b1) & 0x0f;992let dl1_lo = (d1 & 0xff) as u8;993let dl1_hi = ((d1 >> 8) & 0x0f) as u8;994let dh1 = ((d1 >> 12) & 0xff) as u8;995996let mut enc: [u8; 6] = [0; 6];997enc[0] = opcode1;998enc[1] = i2;999enc[2] = b1 << 4 | dl1_hi;1000enc[3] = dl1_lo;1001enc[4] = dh1;1002enc[5] = opcode2;1003enc1004}10051006/// VRIa-type instructions.1007///1008/// 47 39 35 31 15 11 71009/// opcode1 v1 - i2 m3 rxb opcode21010/// 40 36 32 16 12 8 01011///1012fn enc_vri_a(opcode: u16, v1: Reg, i2: u16, m3: u8) -> [u8; 6] {1013let opcode1 = ((opcode >> 8) & 0xff) as u8;1014let opcode2 = (opcode & 0xff) as u8;1015let rxb = rxb(Some(v1), None, None, None);1016let v1 = machreg_to_vr(v1) & 0x0f;1017let m3 = m3 & 0x0f;10181019let mut enc: [u8; 6] = [0; 6];1020enc[0] = opcode1;1021enc[1] = v1 << 4;1022enc[2..4].copy_from_slice(&i2.to_be_bytes());1023enc[4] = m3 << 4 | rxb;1024enc[5] = opcode2;1025enc1026}10271028/// VRIb-type instructions.1029///1030/// 47 39 35 31 23 15 11 71031/// opcode1 v1 - i2 i3 m4 rxb opcode21032/// 40 36 32 24 16 12 8 01033///1034fn enc_vri_b(opcode: u16, v1: Reg, i2: u8, i3: u8, m4: u8) -> [u8; 6] {1035let opcode1 = ((opcode >> 8) & 0xff) as u8;1036let opcode2 = (opcode & 0xff) as u8;1037let rxb = rxb(Some(v1), None, None, None);1038let v1 = machreg_to_vr(v1) & 0x0f;1039let m4 = m4 & 0x0f;10401041let mut enc: [u8; 6] = [0; 6];1042enc[0] = opcode1;1043enc[1] = v1 << 4;1044enc[2] = i2;1045enc[3] = i3;1046enc[4] = m4 << 4 | rxb;1047enc[5] = opcode2;1048enc1049}10501051/// VRIc-type instructions.1052///1053/// 47 39 35 31 15 11 71054/// opcode1 v1 v3 i2 m4 rxb opcode21055/// 40 36 32 16 12 8 01056///1057fn enc_vri_c(opcode: u16, v1: Reg, i2: u16, v3: Reg, m4: u8) -> [u8; 6] {1058let opcode1 = ((opcode >> 8) & 0xff) as u8;1059let opcode2 = (opcode & 0xff) as u8;1060let rxb = rxb(Some(v1), Some(v3), None, None);1061let v1 = machreg_to_vr(v1) & 0x0f;1062let v3 = machreg_to_vr(v3) & 0x0f;1063let m4 = m4 & 0x0f;10641065let mut enc: [u8; 6] = [0; 6];1066enc[0] = opcode1;1067enc[1] = v1 << 4 | v3;1068enc[2..4].copy_from_slice(&i2.to_be_bytes());1069enc[4] = m4 << 4 | rxb;1070enc[5] = opcode2;1071enc1072}10731074/// VRRa-type instructions.1075///1076/// 47 39 35 31 23 19 15 11 71077/// opcode1 v1 v2 - m5 m3 m2 rxb opcode21078/// 40 36 32 24 20 16 12 8 01079///1080fn enc_vrr_a(opcode: u16, v1: Reg, v2: Reg, m3: u8, m4: u8, m5: u8) -> [u8; 6] {1081let opcode1 = ((opcode >> 8) & 0xff) as u8;1082let opcode2 = (opcode & 0xff) as u8;1083let rxb = rxb(Some(v1), Some(v2), None, None);1084let v1 = machreg_to_vr(v1) & 0x0f;1085let v2 = machreg_to_vr(v2) & 0x0f;1086let m3 = m3 & 0x0f;1087let m4 = m4 & 0x0f;1088let m5 = m5 & 0x0f;10891090let mut enc: [u8; 6] = [0; 6];1091enc[0] = opcode1;1092enc[1] = v1 << 4 | v2;1093enc[2] = 0;1094enc[3] = m5 << 4 | m4;1095enc[4] = m3 << 4 | rxb;1096enc[5] = opcode2;1097enc1098}10991100/// VRRb-type instructions.1101///1102/// 47 39 35 31 27 23 19 15 11 71103/// opcode1 v1 v2 v3 - m5 - m4 rxb opcode21104/// 40 36 32 28 24 20 16 12 8 01105///1106fn enc_vrr_b(opcode: u16, v1: Reg, v2: Reg, v3: Reg, m4: u8, m5: u8) -> [u8; 6] {1107let opcode1 = ((opcode >> 8) & 0xff) as u8;1108let opcode2 = (opcode & 0xff) as u8;1109let rxb = rxb(Some(v1), Some(v2), Some(v3), None);1110let v1 = machreg_to_vr(v1) & 0x0f;1111let v2 = machreg_to_vr(v2) & 0x0f;1112let v3 = machreg_to_vr(v3) & 0x0f;1113let m4 = m4 & 0x0f;1114let m5 = m5 & 0x0f;11151116let mut enc: [u8; 6] = [0; 6];1117enc[0] = opcode1;1118enc[1] = v1 << 4 | v2;1119enc[2] = v3 << 4;1120enc[3] = m5 << 4;1121enc[4] = m4 << 4 | rxb;1122enc[5] = opcode2;1123enc1124}11251126/// VRRc-type instructions.1127///1128/// 47 39 35 31 27 23 19 15 11 71129/// opcode1 v1 v2 v3 - m6 m5 m4 rxb opcode21130/// 40 36 32 28 24 20 16 12 8 01131///1132fn enc_vrr_c(opcode: u16, v1: Reg, v2: Reg, v3: Reg, m4: u8, m5: u8, m6: u8) -> [u8; 6] {1133let opcode1 = ((opcode >> 8) & 0xff) as u8;1134let opcode2 = (opcode & 0xff) as u8;1135let rxb = rxb(Some(v1), Some(v2), Some(v3), None);1136let v1 = machreg_to_vr(v1) & 0x0f;1137let v2 = machreg_to_vr(v2) & 0x0f;1138let v3 = machreg_to_vr(v3) & 0x0f;1139let m4 = m4 & 0x0f;1140let m5 = m5 & 0x0f;1141let m6 = m6 & 0x0f;11421143let mut enc: [u8; 6] = [0; 6];1144enc[0] = opcode1;1145enc[1] = v1 << 4 | v2;1146enc[2] = v3 << 4;1147enc[3] = m6 << 4 | m5;1148enc[4] = m4 << 4 | rxb;1149enc[5] = opcode2;1150enc1151}11521153/// VRRe-type instructions.1154///1155/// 47 39 35 31 27 23 19 15 11 71156/// opcode1 v1 v2 v3 m6 - m5 v4 rxb opcode21157/// 40 36 32 28 24 20 16 12 8 01158///1159fn enc_vrr_e(opcode: u16, v1: Reg, v2: Reg, v3: Reg, v4: Reg, m5: u8, m6: u8) -> [u8; 6] {1160let opcode1 = ((opcode >> 8) & 0xff) as u8;1161let opcode2 = (opcode & 0xff) as u8;1162let rxb = rxb(Some(v1), Some(v2), Some(v3), Some(v4));1163let v1 = machreg_to_vr(v1) & 0x0f;1164let v2 = machreg_to_vr(v2) & 0x0f;1165let v3 = machreg_to_vr(v3) & 0x0f;1166let v4 = machreg_to_vr(v4) & 0x0f;1167let m5 = m5 & 0x0f;1168let m6 = m6 & 0x0f;11691170let mut enc: [u8; 6] = [0; 6];1171enc[0] = opcode1;1172enc[1] = v1 << 4 | v2;1173enc[2] = v3 << 4 | m6;1174enc[3] = m5;1175enc[4] = v4 << 4 | rxb;1176enc[5] = opcode2;1177enc1178}11791180/// VRRf-type instructions.1181///1182/// 47 39 35 31 27 11 71183/// opcode1 v1 r2 r3 - rxb opcode21184/// 40 36 32 28 12 8 01185///1186fn enc_vrr_f(opcode: u16, v1: Reg, r2: Reg, r3: Reg) -> [u8; 6] {1187let opcode1 = ((opcode >> 8) & 0xff) as u8;1188let opcode2 = (opcode & 0xff) as u8;1189let rxb = rxb(Some(v1), None, None, None);1190let v1 = machreg_to_vr(v1) & 0x0f;1191let r2 = machreg_to_gpr(r2) & 0x0f;1192let r3 = machreg_to_gpr(r3) & 0x0f;11931194let mut enc: [u8; 6] = [0; 6];1195enc[0] = opcode1;1196enc[1] = v1 << 4 | r2;1197enc[2] = r3 << 4;1198enc[4] = rxb;1199enc[5] = opcode2;1200enc1201}12021203/// VRSa-type instructions.1204///1205/// 47 39 35 31 27 15 11 71206/// opcode1 v1 v3 b2 d2 m4 rxb opcode21207/// 40 36 32 28 16 12 8 01208///1209fn enc_vrs_a(opcode: u16, v1: Reg, b2: Reg, d2: u32, v3: Reg, m4: u8) -> [u8; 6] {1210let opcode1 = ((opcode >> 8) & 0xff) as u8;1211let opcode2 = (opcode & 0xff) as u8;1212let rxb = rxb(Some(v1), Some(v3), None, None);1213let v1 = machreg_to_vr(v1) & 0x0f;1214let b2 = machreg_to_gpr(b2) & 0x0f;1215let v3 = machreg_to_vr(v3) & 0x0f;1216let d2_lo = (d2 & 0xff) as u8;1217let d2_hi = ((d2 >> 8) & 0x0f) as u8;1218let m4 = m4 & 0x0f;12191220let mut enc: [u8; 6] = [0; 6];1221enc[0] = opcode1;1222enc[1] = v1 << 4 | v3;1223enc[2] = b2 << 4 | d2_hi;1224enc[3] = d2_lo;1225enc[4] = m4 << 4 | rxb;1226enc[5] = opcode2;1227enc1228}12291230/// VRSb-type instructions.1231///1232/// 47 39 35 31 27 15 11 71233/// opcode1 v1 r3 b2 d2 m4 rxb opcode21234/// 40 36 32 28 16 12 8 01235///1236fn enc_vrs_b(opcode: u16, v1: Reg, b2: Reg, d2: u32, r3: Reg, m4: u8) -> [u8; 6] {1237let opcode1 = ((opcode >> 8) & 0xff) as u8;1238let opcode2 = (opcode & 0xff) as u8;1239let rxb = rxb(Some(v1), None, None, None);1240let v1 = machreg_to_vr(v1) & 0x0f;1241let b2 = machreg_to_gpr(b2) & 0x0f;1242let r3 = machreg_to_gpr(r3) & 0x0f;1243let d2_lo = (d2 & 0xff) as u8;1244let d2_hi = ((d2 >> 8) & 0x0f) as u8;1245let m4 = m4 & 0x0f;12461247let mut enc: [u8; 6] = [0; 6];1248enc[0] = opcode1;1249enc[1] = v1 << 4 | r3;1250enc[2] = b2 << 4 | d2_hi;1251enc[3] = d2_lo;1252enc[4] = m4 << 4 | rxb;1253enc[5] = opcode2;1254enc1255}12561257/// VRSc-type instructions.1258///1259/// 47 39 35 31 27 15 11 71260/// opcode1 r1 v3 b2 d2 m4 rxb opcode21261/// 40 36 32 28 16 12 8 01262///1263fn enc_vrs_c(opcode: u16, r1: Reg, b2: Reg, d2: u32, v3: Reg, m4: u8) -> [u8; 6] {1264let opcode1 = ((opcode >> 8) & 0xff) as u8;1265let opcode2 = (opcode & 0xff) as u8;1266let rxb = rxb(None, Some(v3), None, None);1267let r1 = machreg_to_gpr(r1) & 0x0f;1268let b2 = machreg_to_gpr(b2) & 0x0f;1269let v3 = machreg_to_vr(v3) & 0x0f;1270let d2_lo = (d2 & 0xff) as u8;1271let d2_hi = ((d2 >> 8) & 0x0f) as u8;1272let m4 = m4 & 0x0f;12731274let mut enc: [u8; 6] = [0; 6];1275enc[0] = opcode1;1276enc[1] = r1 << 4 | v3;1277enc[2] = b2 << 4 | d2_hi;1278enc[3] = d2_lo;1279enc[4] = m4 << 4 | rxb;1280enc[5] = opcode2;1281enc1282}12831284/// VRX-type instructions.1285///1286/// 47 39 35 31 27 15 11 71287/// opcode1 v1 x2 b2 d2 m3 rxb opcode21288/// 40 36 32 28 16 12 8 01289///1290fn enc_vrx(opcode: u16, v1: Reg, b2: Reg, x2: Reg, d2: u32, m3: u8) -> [u8; 6] {1291let opcode1 = ((opcode >> 8) & 0xff) as u8;1292let opcode2 = (opcode & 0xff) as u8;1293let rxb = rxb(Some(v1), None, None, None);1294let v1 = machreg_to_vr(v1) & 0x0f;1295let b2 = machreg_to_gpr(b2) & 0x0f;1296let x2 = machreg_to_gpr(x2) & 0x0f;1297let d2_lo = (d2 & 0xff) as u8;1298let d2_hi = ((d2 >> 8) & 0x0f) as u8;1299let m3 = m3 & 0x0f;13001301let mut enc: [u8; 6] = [0; 6];1302enc[0] = opcode1;1303enc[1] = v1 << 4 | x2;1304enc[2] = b2 << 4 | d2_hi;1305enc[3] = d2_lo;1306enc[4] = m3 << 4 | rxb;1307enc[5] = opcode2;1308enc1309}13101311/// Emit encoding to sink.1312fn put(sink: &mut MachBuffer<Inst>, enc: &[u8]) {1313for byte in enc {1314sink.put1(*byte);1315}1316}13171318/// Emit encoding to sink, adding a trap on the last byte.1319fn put_with_trap(sink: &mut MachBuffer<Inst>, enc: &[u8], trap_code: TrapCode) {1320let len = enc.len();1321for i in 0..len - 1 {1322sink.put1(enc[i]);1323}1324sink.add_trap(trap_code);1325sink.put1(enc[len - 1]);1326}13271328/// State carried between emissions of a sequence of instructions.1329#[derive(Default, Clone, Debug)]1330pub struct EmitState {1331/// Offset from the actual SP to the "nominal SP". The latter is defined1332/// as the value the stack pointer has after the prolog. This offset is1333/// normally always zero, except during a call sequence using the tail-call1334/// ABI, between the AllocateArgs and the actual call instruction.1335pub(crate) nominal_sp_offset: u32,13361337/// Offset from the actual SP to the SP during an outgoing function call.1338/// This is normally always zero, except during processing of the return1339/// argument handling after a call using the tail-call ABI has returned.1340pub(crate) outgoing_sp_offset: u32,13411342/// Size of the incoming argument area in the caller's frame. Always zero1343/// for functions using the tail-call ABI.1344pub(crate) incoming_args_size: u32,13451346/// The user stack map for the upcoming instruction, as provided to1347/// `pre_safepoint()`.1348user_stack_map: Option<ir::UserStackMap>,13491350/// Only used during fuzz-testing. Otherwise, it is a zero-sized struct and1351/// optimized away at compiletime. See [cranelift_control].1352ctrl_plane: ControlPlane,13531354frame_layout: FrameLayout,1355}13561357impl MachInstEmitState<Inst> for EmitState {1358fn new(abi: &Callee<S390xMachineDeps>, ctrl_plane: ControlPlane) -> Self {1359let incoming_args_size = if abi.call_conv() == CallConv::Tail {136001361} else {1362abi.frame_layout().incoming_args_size1363};1364EmitState {1365nominal_sp_offset: 0,1366outgoing_sp_offset: 0,1367incoming_args_size,1368user_stack_map: None,1369ctrl_plane,1370frame_layout: abi.frame_layout().clone(),1371}1372}13731374fn pre_safepoint(&mut self, user_stack_map: Option<ir::UserStackMap>) {1375self.user_stack_map = user_stack_map;1376}13771378fn ctrl_plane_mut(&mut self) -> &mut ControlPlane {1379&mut self.ctrl_plane1380}13811382fn take_ctrl_plane(self) -> ControlPlane {1383self.ctrl_plane1384}13851386fn frame_layout(&self) -> &FrameLayout {1387&self.frame_layout1388}1389}13901391impl EmitState {1392fn take_stack_map(&mut self) -> Option<ir::UserStackMap> {1393self.user_stack_map.take()1394}13951396fn clear_post_insn(&mut self) {1397self.user_stack_map = None;1398}1399}14001401/// Constant state used during function compilation.1402pub struct EmitInfo {1403isa_flags: s390x_settings::Flags,1404}14051406impl EmitInfo {1407pub(crate) fn new(isa_flags: s390x_settings::Flags) -> Self {1408Self { isa_flags }1409}1410}14111412impl MachInstEmit for Inst {1413type State = EmitState;1414type Info = EmitInfo;14151416fn emit(&self, sink: &mut MachBuffer<Inst>, emit_info: &Self::Info, state: &mut EmitState) {1417self.emit_with_alloc_consumer(sink, emit_info, state)1418}14191420fn pretty_print_inst(&self, state: &mut EmitState) -> String {1421self.print_with_state(state)1422}1423}14241425impl Inst {1426fn emit_with_alloc_consumer(1427&self,1428sink: &mut MachBuffer<Inst>,1429emit_info: &EmitInfo,1430state: &mut EmitState,1431) {1432// Verify that we can emit this Inst in the current ISA1433let matches_isa_flags = |iset_requirement: &InstructionSet| -> bool {1434match iset_requirement {1435// Baseline ISA is z141436InstructionSet::Base => true,1437// Miscellaneous-Instruction-Extensions Facility 3 (z15)1438InstructionSet::MIE3 => emit_info.isa_flags.has_mie3(),1439// Vector-Enhancements Facility 2 (z15)1440InstructionSet::VXRS_EXT2 => emit_info.isa_flags.has_vxrs_ext2(),1441}1442};1443let isa_requirements = self.available_in_isa();1444if !matches_isa_flags(&isa_requirements) {1445panic!(1446"Cannot emit inst '{self:?}' for target; failed to match ISA requirements: {isa_requirements:?}"1447)1448}14491450match self {1451&Inst::AluRRR { alu_op, rd, rn, rm } => {1452let (opcode, have_rr) = match alu_op {1453ALUOp::Add32 => (0xb9f8, true), // ARK1454ALUOp::Add64 => (0xb9e8, true), // AGRK1455ALUOp::AddLogical32 => (0xb9fa, true), // ALRK1456ALUOp::AddLogical64 => (0xb9ea, true), // ALGRK1457ALUOp::Sub32 => (0xb9f9, true), // SRK1458ALUOp::Sub64 => (0xb9e9, true), // SGRK1459ALUOp::SubLogical32 => (0xb9fb, true), // SLRK1460ALUOp::SubLogical64 => (0xb9eb, true), // SLGRK1461ALUOp::Mul32 => (0xb9fd, true), // MSRKC1462ALUOp::Mul64 => (0xb9ed, true), // MSGRKC1463ALUOp::And32 => (0xb9f4, true), // NRK1464ALUOp::And64 => (0xb9e4, true), // NGRK1465ALUOp::Orr32 => (0xb9f6, true), // ORK1466ALUOp::Orr64 => (0xb9e6, true), // OGRK1467ALUOp::Xor32 => (0xb9f7, true), // XRK1468ALUOp::Xor64 => (0xb9e7, true), // XGRK1469ALUOp::NotAnd32 => (0xb974, false), // NNRK1470ALUOp::NotAnd64 => (0xb964, false), // NNGRK1471ALUOp::NotOrr32 => (0xb976, false), // NORK1472ALUOp::NotOrr64 => (0xb966, false), // NOGRK1473ALUOp::NotXor32 => (0xb977, false), // NXRK1474ALUOp::NotXor64 => (0xb967, false), // NXGRK1475ALUOp::AndNot32 => (0xb9f5, false), // NCRK1476ALUOp::AndNot64 => (0xb9e5, false), // NCGRK1477ALUOp::OrrNot32 => (0xb975, false), // OCRK1478ALUOp::OrrNot64 => (0xb965, false), // OCGRK1479_ => unreachable!(),1480};1481if have_rr && rd.to_reg() == rn {1482let inst = Inst::AluRR {1483alu_op,1484rd,1485ri: rn,1486rm,1487};1488inst.emit(sink, emit_info, state);1489} else {1490put(sink, &enc_rrf_ab(opcode, rd.to_reg(), rn, rm, 0));1491}1492}1493&Inst::AluRRSImm16 {1494alu_op,1495rd,1496rn,1497imm,1498} => {1499if rd.to_reg() == rn {1500let inst = Inst::AluRSImm16 {1501alu_op,1502rd,1503ri: rn,1504imm,1505};1506inst.emit(sink, emit_info, state);1507} else {1508let opcode = match alu_op {1509ALUOp::Add32 => 0xecd8, // AHIK1510ALUOp::Add64 => 0xecd9, // AGHIK1511_ => unreachable!(),1512};1513put(sink, &enc_rie_d(opcode, rd.to_reg(), rn, imm as u16));1514}1515}1516&Inst::AluRR { alu_op, rd, ri, rm } => {1517debug_assert_eq!(rd.to_reg(), ri);15181519let (opcode, is_rre) = match alu_op {1520ALUOp::Add32 => (0x1a, false), // AR1521ALUOp::Add64 => (0xb908, true), // AGR1522ALUOp::Add64Ext32 => (0xb918, true), // AGFR1523ALUOp::AddLogical32 => (0x1e, false), // ALR1524ALUOp::AddLogical64 => (0xb90a, true), // ALGR1525ALUOp::AddLogical64Ext32 => (0xb91a, true), // ALGFR1526ALUOp::Sub32 => (0x1b, false), // SR1527ALUOp::Sub64 => (0xb909, true), // SGR1528ALUOp::Sub64Ext32 => (0xb919, true), // SGFR1529ALUOp::SubLogical32 => (0x1f, false), // SLR1530ALUOp::SubLogical64 => (0xb90b, true), // SLGR1531ALUOp::SubLogical64Ext32 => (0xb91b, true), // SLGFR1532ALUOp::Mul32 => (0xb252, true), // MSR1533ALUOp::Mul64 => (0xb90c, true), // MSGR1534ALUOp::Mul64Ext32 => (0xb91c, true), // MSGFR1535ALUOp::And32 => (0x14, false), // NR1536ALUOp::And64 => (0xb980, true), // NGR1537ALUOp::Orr32 => (0x16, false), // OR1538ALUOp::Orr64 => (0xb981, true), // OGR1539ALUOp::Xor32 => (0x17, false), // XR1540ALUOp::Xor64 => (0xb982, true), // XGR1541_ => unreachable!(),1542};1543if is_rre {1544put(sink, &enc_rre(opcode, rd.to_reg(), rm));1545} else {1546put(sink, &enc_rr(opcode, rd.to_reg(), rm));1547}1548}1549&Inst::AluRX {1550alu_op,1551rd,1552ri,1553ref mem,1554} => {1555debug_assert_eq!(rd.to_reg(), ri);1556let mem = mem.clone();15571558let (opcode_rx, opcode_rxy) = match alu_op {1559ALUOp::Add32 => (Some(0x5a), Some(0xe35a)), // A(Y)1560ALUOp::Add32Ext16 => (Some(0x4a), Some(0xe37a)), // AH(Y)1561ALUOp::Add64 => (None, Some(0xe308)), // AG1562ALUOp::Add64Ext16 => (None, Some(0xe338)), // AGH1563ALUOp::Add64Ext32 => (None, Some(0xe318)), // AGF1564ALUOp::AddLogical32 => (Some(0x5e), Some(0xe35e)), // AL(Y)1565ALUOp::AddLogical64 => (None, Some(0xe30a)), // ALG1566ALUOp::AddLogical64Ext32 => (None, Some(0xe31a)), // ALGF1567ALUOp::Sub32 => (Some(0x5b), Some(0xe35b)), // S(Y)1568ALUOp::Sub32Ext16 => (Some(0x4b), Some(0xe37b)), // SH(Y)1569ALUOp::Sub64 => (None, Some(0xe309)), // SG1570ALUOp::Sub64Ext16 => (None, Some(0xe339)), // SGH1571ALUOp::Sub64Ext32 => (None, Some(0xe319)), // SGF1572ALUOp::SubLogical32 => (Some(0x5f), Some(0xe35f)), // SL(Y)1573ALUOp::SubLogical64 => (None, Some(0xe30b)), // SLG1574ALUOp::SubLogical64Ext32 => (None, Some(0xe31b)), // SLGF1575ALUOp::Mul32 => (Some(0x71), Some(0xe351)), // MS(Y)1576ALUOp::Mul32Ext16 => (Some(0x4c), Some(0xe37c)), // MH(Y)1577ALUOp::Mul64 => (None, Some(0xe30c)), // MSG1578ALUOp::Mul64Ext16 => (None, Some(0xe33c)), // MSH1579ALUOp::Mul64Ext32 => (None, Some(0xe31c)), // MSGF1580ALUOp::And32 => (Some(0x54), Some(0xe354)), // N(Y)1581ALUOp::And64 => (None, Some(0xe380)), // NG1582ALUOp::Orr32 => (Some(0x56), Some(0xe356)), // O(Y)1583ALUOp::Orr64 => (None, Some(0xe381)), // OG1584ALUOp::Xor32 => (Some(0x57), Some(0xe357)), // X(Y)1585ALUOp::Xor64 => (None, Some(0xe382)), // XG1586_ => unreachable!(),1587};1588let rd = rd.to_reg();1589mem_emit(1590rd, &mem, opcode_rx, opcode_rxy, None, true, sink, emit_info, state,1591);1592}1593&Inst::AluRSImm16 {1594alu_op,1595rd,1596ri,1597imm,1598} => {1599debug_assert_eq!(rd.to_reg(), ri);16001601let opcode = match alu_op {1602ALUOp::Add32 => 0xa7a, // AHI1603ALUOp::Add64 => 0xa7b, // AGHI1604ALUOp::Mul32 => 0xa7c, // MHI1605ALUOp::Mul64 => 0xa7d, // MGHI1606_ => unreachable!(),1607};1608put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16));1609}1610&Inst::AluRSImm32 {1611alu_op,1612rd,1613ri,1614imm,1615} => {1616debug_assert_eq!(rd.to_reg(), ri);16171618let opcode = match alu_op {1619ALUOp::Add32 => 0xc29, // AFI1620ALUOp::Add64 => 0xc28, // AGFI1621ALUOp::Mul32 => 0xc21, // MSFI1622ALUOp::Mul64 => 0xc20, // MSGFI1623_ => unreachable!(),1624};1625put(sink, &enc_ril_a(opcode, rd.to_reg(), imm as u32));1626}1627&Inst::AluRUImm32 {1628alu_op,1629rd,1630ri,1631imm,1632} => {1633debug_assert_eq!(rd.to_reg(), ri);16341635let opcode = match alu_op {1636ALUOp::AddLogical32 => 0xc2b, // ALFI1637ALUOp::AddLogical64 => 0xc2a, // ALGFI1638ALUOp::SubLogical32 => 0xc25, // SLFI1639ALUOp::SubLogical64 => 0xc24, // SLGFI1640_ => unreachable!(),1641};1642put(sink, &enc_ril_a(opcode, rd.to_reg(), imm));1643}1644&Inst::AluRUImm16Shifted {1645alu_op,1646rd,1647ri,1648imm,1649} => {1650debug_assert_eq!(rd.to_reg(), ri);16511652let opcode = match (alu_op, imm.shift) {1653(ALUOp::And32, 0) => 0xa57, // NILL1654(ALUOp::And32, 1) => 0xa56, // NILH1655(ALUOp::And64, 0) => 0xa57, // NILL1656(ALUOp::And64, 1) => 0xa56, // NILH1657(ALUOp::And64, 2) => 0xa55, // NIHL1658(ALUOp::And64, 3) => 0xa54, // NIHL1659(ALUOp::Orr32, 0) => 0xa5b, // OILL1660(ALUOp::Orr32, 1) => 0xa5a, // OILH1661(ALUOp::Orr64, 0) => 0xa5b, // OILL1662(ALUOp::Orr64, 1) => 0xa5a, // OILH1663(ALUOp::Orr64, 2) => 0xa59, // OIHL1664(ALUOp::Orr64, 3) => 0xa58, // OIHH1665_ => unreachable!(),1666};1667put(sink, &enc_ri_a(opcode, rd.to_reg(), imm.bits));1668}1669&Inst::AluRUImm32Shifted {1670alu_op,1671rd,1672ri,1673imm,1674} => {1675debug_assert_eq!(rd.to_reg(), ri);16761677let opcode = match (alu_op, imm.shift) {1678(ALUOp::And32, 0) => 0xc0b, // NILF1679(ALUOp::And64, 0) => 0xc0b, // NILF1680(ALUOp::And64, 1) => 0xc0a, // NIHF1681(ALUOp::Orr32, 0) => 0xc0d, // OILF1682(ALUOp::Orr64, 0) => 0xc0d, // OILF1683(ALUOp::Orr64, 1) => 0xc0c, // OILF1684(ALUOp::Xor32, 0) => 0xc07, // XILF1685(ALUOp::Xor64, 0) => 0xc07, // XILF1686(ALUOp::Xor64, 1) => 0xc06, // XILH1687_ => unreachable!(),1688};1689put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits));1690}16911692&Inst::SMulWide { rd, rn, rm } => {1693let rd1 = rd.hi;1694let rd2 = rd.lo;1695debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());16961697let opcode = 0xb9ec; // MGRK1698put(sink, &enc_rrf_ab(opcode, rd1.to_reg(), rn, rm, 0));1699}1700&Inst::UMulWide { rd, ri, rn } => {1701let rd1 = rd.hi;1702let rd2 = rd.lo;1703debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());1704debug_assert_eq!(rd2.to_reg(), ri);17051706let opcode = 0xb986; // MLGR1707put(sink, &enc_rre(opcode, rd1.to_reg(), rn));1708}1709&Inst::SDivMod32 { rd, ri, rn } => {1710let rd1 = rd.hi;1711let rd2 = rd.lo;1712debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());1713debug_assert_eq!(rd2.to_reg(), ri);17141715let opcode = 0xb91d; // DSGFR1716let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;1717put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);1718}1719&Inst::SDivMod64 { rd, ri, rn } => {1720let rd1 = rd.hi;1721let rd2 = rd.lo;1722debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());1723debug_assert_eq!(rd2.to_reg(), ri);17241725let opcode = 0xb90d; // DSGR1726let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;1727put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);1728}1729&Inst::UDivMod32 { rd, ri, rn } => {1730let rd1 = rd.hi;1731let rd2 = rd.lo;1732debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());1733let ri1 = ri.hi;1734let ri2 = ri.lo;1735debug_assert_eq!(rd1.to_reg(), ri1);1736debug_assert_eq!(rd2.to_reg(), ri2);17371738let opcode = 0xb997; // DLR1739let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;1740put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);1741}1742&Inst::UDivMod64 { rd, ri, rn } => {1743let rd1 = rd.hi;1744let rd2 = rd.lo;1745debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());1746let ri1 = ri.hi;1747let ri2 = ri.lo;1748debug_assert_eq!(rd1.to_reg(), ri1);1749debug_assert_eq!(rd2.to_reg(), ri2);17501751let opcode = 0xb987; // DLGR1752let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;1753put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);1754}1755&Inst::Flogr { rd, rn } => {1756let rd1 = rd.hi;1757let rd2 = rd.lo;1758debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());17591760let opcode = 0xb983; // FLOGR1761put(sink, &enc_rre(opcode, rd1.to_reg(), rn));1762}17631764&Inst::ShiftRR {1765shift_op,1766rd,1767rn,1768shift_imm,1769shift_reg,1770} => {1771let opcode = match shift_op {1772ShiftOp::RotL32 => 0xeb1d, // RLL1773ShiftOp::RotL64 => 0xeb1c, // RLLG1774ShiftOp::LShL32 => 0xebdf, // SLLK (SLL ?)1775ShiftOp::LShL64 => 0xeb0d, // SLLG1776ShiftOp::LShR32 => 0xebde, // SRLK (SRL ?)1777ShiftOp::LShR64 => 0xeb0c, // SRLG1778ShiftOp::AShR32 => 0xebdc, // SRAK (SRA ?)1779ShiftOp::AShR64 => 0xeb0a, // SRAG1780};1781put(1782sink,1783&enc_rsy(opcode, rd.to_reg(), rn, shift_reg, shift_imm.into()),1784);1785}17861787&Inst::RxSBG {1788op,1789rd,1790ri,1791rn,1792start_bit,1793end_bit,1794rotate_amt,1795} => {1796debug_assert_eq!(rd.to_reg(), ri);17971798let opcode = match op {1799RxSBGOp::Insert => 0xec59, // RISBGN1800RxSBGOp::And => 0xec54, // RNSBG1801RxSBGOp::Or => 0xec56, // ROSBG1802RxSBGOp::Xor => 0xec57, // RXSBG1803};1804put(1805sink,1806&enc_rie_f(1807opcode,1808rd.to_reg(),1809rn,1810start_bit,1811end_bit,1812(rotate_amt as u8) & 63,1813),1814);1815}18161817&Inst::RxSBGTest {1818op,1819rd,1820rn,1821start_bit,1822end_bit,1823rotate_amt,1824} => {1825let opcode = match op {1826RxSBGOp::And => 0xec54, // RNSBG1827RxSBGOp::Or => 0xec56, // ROSBG1828RxSBGOp::Xor => 0xec57, // RXSBG1829_ => unreachable!(),1830};1831put(1832sink,1833&enc_rie_f(1834opcode,1835rd,1836rn,1837start_bit | 0x80,1838end_bit,1839(rotate_amt as u8) & 63,1840),1841);1842}18431844&Inst::UnaryRR { op, rd, rn } => {1845match op {1846UnaryOp::Abs32 => {1847let opcode = 0x10; // LPR1848put(sink, &enc_rr(opcode, rd.to_reg(), rn));1849}1850UnaryOp::Abs64 => {1851let opcode = 0xb900; // LPGR1852put(sink, &enc_rre(opcode, rd.to_reg(), rn));1853}1854UnaryOp::Abs64Ext32 => {1855let opcode = 0xb910; // LPGFR1856put(sink, &enc_rre(opcode, rd.to_reg(), rn));1857}1858UnaryOp::Neg32 => {1859let opcode = 0x13; // LCR1860put(sink, &enc_rr(opcode, rd.to_reg(), rn));1861}1862UnaryOp::Neg64 => {1863let opcode = 0xb903; // LCGR1864put(sink, &enc_rre(opcode, rd.to_reg(), rn));1865}1866UnaryOp::Neg64Ext32 => {1867let opcode = 0xb913; // LCGFR1868put(sink, &enc_rre(opcode, rd.to_reg(), rn));1869}1870UnaryOp::PopcntByte => {1871let opcode = 0xb9e1; // POPCNT1872put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rn, 0, 0));1873}1874UnaryOp::PopcntReg => {1875let opcode = 0xb9e1; // POPCNT1876put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rn, 8, 0));1877}1878UnaryOp::BSwap32 => {1879let opcode = 0xb91f; // LRVR1880put(sink, &enc_rre(opcode, rd.to_reg(), rn));1881}1882UnaryOp::BSwap64 => {1883let opcode = 0xb90f; // LRVRG1884put(sink, &enc_rre(opcode, rd.to_reg(), rn));1885}1886}1887}18881889&Inst::Extend {1890rd,1891rn,1892signed,1893from_bits,1894to_bits,1895} => {1896let opcode = match (signed, from_bits, to_bits) {1897(_, 1, 32) => 0xb926, // LBR1898(_, 1, 64) => 0xb906, // LGBR1899(false, 8, 32) => 0xb994, // LLCR1900(false, 8, 64) => 0xb984, // LLGCR1901(true, 8, 32) => 0xb926, // LBR1902(true, 8, 64) => 0xb906, // LGBR1903(false, 16, 32) => 0xb995, // LLHR1904(false, 16, 64) => 0xb985, // LLGHR1905(true, 16, 32) => 0xb927, // LHR1906(true, 16, 64) => 0xb907, // LGHR1907(false, 32, 64) => 0xb916, // LLGFR1908(true, 32, 64) => 0xb914, // LGFR1909_ => panic!(1910"Unsupported extend combination: signed = {signed}, from_bits = {from_bits}, to_bits = {to_bits}"1911),1912};1913put(sink, &enc_rre(opcode, rd.to_reg(), rn));1914}19151916&Inst::CmpRR { op, rn, rm } => {1917let (opcode, is_rre) = match op {1918CmpOp::CmpS32 => (0x19, false), // CR1919CmpOp::CmpS64 => (0xb920, true), // CGR1920CmpOp::CmpS64Ext32 => (0xb930, true), // CGFR1921CmpOp::CmpL32 => (0x15, false), // CLR1922CmpOp::CmpL64 => (0xb921, true), // CLGR1923CmpOp::CmpL64Ext32 => (0xb931, true), // CLGFR1924_ => unreachable!(),1925};1926if is_rre {1927put(sink, &enc_rre(opcode, rn, rm));1928} else {1929put(sink, &enc_rr(opcode, rn, rm));1930}1931}1932&Inst::CmpRX { op, rn, ref mem } => {1933let mem = mem.clone();19341935let (opcode_rx, opcode_rxy, opcode_ril) = match op {1936CmpOp::CmpS32 => (Some(0x59), Some(0xe359), Some(0xc6d)), // C(Y), CRL1937CmpOp::CmpS32Ext16 => (Some(0x49), Some(0xe379), Some(0xc65)), // CH(Y), CHRL1938CmpOp::CmpS64 => (None, Some(0xe320), Some(0xc68)), // CG, CGRL1939CmpOp::CmpS64Ext16 => (None, Some(0xe334), Some(0xc64)), // CGH, CGHRL1940CmpOp::CmpS64Ext32 => (None, Some(0xe330), Some(0xc6c)), // CGF, CGFRL1941CmpOp::CmpL32 => (Some(0x55), Some(0xe355), Some(0xc6f)), // CL(Y), CLRL1942CmpOp::CmpL32Ext16 => (None, None, Some(0xc67)), // CLHRL1943CmpOp::CmpL64 => (None, Some(0xe321), Some(0xc6a)), // CLG, CLGRL1944CmpOp::CmpL64Ext16 => (None, None, Some(0xc66)), // CLGHRL1945CmpOp::CmpL64Ext32 => (None, Some(0xe331), Some(0xc6e)), // CLGF, CLGFRL1946};1947mem_emit(1948rn, &mem, opcode_rx, opcode_rxy, opcode_ril, true, sink, emit_info, state,1949);1950}1951&Inst::CmpRSImm16 { op, rn, imm } => {1952let opcode = match op {1953CmpOp::CmpS32 => 0xa7e, // CHI1954CmpOp::CmpS64 => 0xa7f, // CGHI1955_ => unreachable!(),1956};1957put(sink, &enc_ri_a(opcode, rn, imm as u16));1958}1959&Inst::CmpRSImm32 { op, rn, imm } => {1960let opcode = match op {1961CmpOp::CmpS32 => 0xc2d, // CFI1962CmpOp::CmpS64 => 0xc2c, // CGFI1963_ => unreachable!(),1964};1965put(sink, &enc_ril_a(opcode, rn, imm as u32));1966}1967&Inst::CmpRUImm32 { op, rn, imm } => {1968let opcode = match op {1969CmpOp::CmpL32 => 0xc2f, // CLFI1970CmpOp::CmpL64 => 0xc2e, // CLGFI1971_ => unreachable!(),1972};1973put(sink, &enc_ril_a(opcode, rn, imm));1974}1975&Inst::CmpTrapRR {1976op,1977rn,1978rm,1979cond,1980trap_code,1981} => {1982let opcode = match op {1983CmpOp::CmpS32 => 0xb972, // CRT1984CmpOp::CmpS64 => 0xb960, // CGRT1985CmpOp::CmpL32 => 0xb973, // CLRT1986CmpOp::CmpL64 => 0xb961, // CLGRT1987_ => unreachable!(),1988};1989put_with_trap(1990sink,1991&enc_rrf_cde(opcode, rn, rm, cond.bits(), 0),1992trap_code,1993);1994}1995&Inst::CmpTrapRSImm16 {1996op,1997rn,1998imm,1999cond,2000trap_code,2001} => {2002let opcode = match op {2003CmpOp::CmpS32 => 0xec72, // CIT2004CmpOp::CmpS64 => 0xec70, // CGIT2005_ => unreachable!(),2006};2007put_with_trap(2008sink,2009&enc_rie_a(opcode, rn, imm as u16, cond.bits()),2010trap_code,2011);2012}2013&Inst::CmpTrapRUImm16 {2014op,2015rn,2016imm,2017cond,2018trap_code,2019} => {2020let opcode = match op {2021CmpOp::CmpL32 => 0xec73, // CLFIT2022CmpOp::CmpL64 => 0xec71, // CLGIT2023_ => unreachable!(),2024};2025put_with_trap(sink, &enc_rie_a(opcode, rn, imm, cond.bits()), trap_code);2026}20272028&Inst::AtomicRmw {2029alu_op,2030rd,2031rn,2032ref mem,2033} => {2034let mem = mem.clone();20352036let opcode = match alu_op {2037ALUOp::Add32 => 0xebf8, // LAA2038ALUOp::Add64 => 0xebe8, // LAAG2039ALUOp::AddLogical32 => 0xebfa, // LAAL2040ALUOp::AddLogical64 => 0xebea, // LAALG2041ALUOp::And32 => 0xebf4, // LAN2042ALUOp::And64 => 0xebe4, // LANG2043ALUOp::Orr32 => 0xebf6, // LAO2044ALUOp::Orr64 => 0xebe6, // LAOG2045ALUOp::Xor32 => 0xebf7, // LAX2046ALUOp::Xor64 => 0xebe7, // LAXG2047_ => unreachable!(),2048};20492050let rd = rd.to_reg();2051mem_rs_emit(2052rd,2053rn,2054&mem,2055None,2056Some(opcode),2057true,2058sink,2059emit_info,2060state,2061);2062}2063&Inst::Loop { ref body, cond } => {2064// This sequence is *one* instruction in the vcode, and is expanded only here at2065// emission time, because it requires branching to internal labels.2066let loop_label = sink.get_label();2067let done_label = sink.get_label();20682069// Emit label at the start of the loop.2070sink.bind_label(loop_label, &mut state.ctrl_plane);20712072for inst in (&body).into_iter() {2073match &inst {2074// Replace a CondBreak with a branch to done_label.2075&Inst::CondBreak { cond } => {2076let opcode = 0xc04; // BCRL2077sink.use_label_at_offset(2078sink.cur_offset(),2079done_label,2080LabelUse::BranchRIL,2081);2082put(sink, &enc_ril_c(opcode, cond.bits(), 0));2083}2084_ => inst.emit_with_alloc_consumer(sink, emit_info, state),2085};2086}20872088let opcode = 0xc04; // BCRL2089sink.use_label_at_offset(sink.cur_offset(), loop_label, LabelUse::BranchRIL);2090put(sink, &enc_ril_c(opcode, cond.bits(), 0));20912092// Emit label at the end of the loop.2093sink.bind_label(done_label, &mut state.ctrl_plane);2094}2095&Inst::CondBreak { .. } => unreachable!(), // Only valid inside a Loop.2096&Inst::AtomicCas32 {2097rd,2098ri,2099rn,2100ref mem,2101}2102| &Inst::AtomicCas64 {2103rd,2104ri,2105rn,2106ref mem,2107} => {2108debug_assert_eq!(rd.to_reg(), ri);2109let mem = mem.clone();21102111let (opcode_rs, opcode_rsy) = match self {2112&Inst::AtomicCas32 { .. } => (Some(0xba), Some(0xeb14)), // CS(Y)2113&Inst::AtomicCas64 { .. } => (None, Some(0xeb30)), // CSG2114_ => unreachable!(),2115};21162117let rd = rd.to_reg();2118mem_rs_emit(2119rd, rn, &mem, opcode_rs, opcode_rsy, true, sink, emit_info, state,2120);2121}2122&Inst::Fence => {2123put(sink, &enc_e(0x07e0));2124}21252126&Inst::Load32 { rd, ref mem }2127| &Inst::Load32ZExt8 { rd, ref mem }2128| &Inst::Load32SExt8 { rd, ref mem }2129| &Inst::Load32ZExt16 { rd, ref mem }2130| &Inst::Load32SExt16 { rd, ref mem }2131| &Inst::Load64 { rd, ref mem }2132| &Inst::Load64ZExt8 { rd, ref mem }2133| &Inst::Load64SExt8 { rd, ref mem }2134| &Inst::Load64ZExt16 { rd, ref mem }2135| &Inst::Load64SExt16 { rd, ref mem }2136| &Inst::Load64ZExt32 { rd, ref mem }2137| &Inst::Load64SExt32 { rd, ref mem }2138| &Inst::LoadRev16 { rd, ref mem }2139| &Inst::LoadRev32 { rd, ref mem }2140| &Inst::LoadRev64 { rd, ref mem } => {2141let mem = mem.clone();21422143let (opcode_rx, opcode_rxy, opcode_ril) = match self {2144&Inst::Load32 { .. } => (Some(0x58), Some(0xe358), Some(0xc4d)), // L(Y), LRL2145&Inst::Load32ZExt8 { .. } => (None, Some(0xe394), None), // LLC2146&Inst::Load32SExt8 { .. } => (None, Some(0xe376), None), // LB2147&Inst::Load32ZExt16 { .. } => (None, Some(0xe395), Some(0xc42)), // LLH, LLHRL2148&Inst::Load32SExt16 { .. } => (Some(0x48), Some(0xe378), Some(0xc45)), // LH(Y), LHRL2149&Inst::Load64 { .. } => (None, Some(0xe304), Some(0xc48)), // LG, LGRL2150&Inst::Load64ZExt8 { .. } => (None, Some(0xe390), None), // LLGC2151&Inst::Load64SExt8 { .. } => (None, Some(0xe377), None), // LGB2152&Inst::Load64ZExt16 { .. } => (None, Some(0xe391), Some(0xc46)), // LLGH, LLGHRL2153&Inst::Load64SExt16 { .. } => (None, Some(0xe315), Some(0xc44)), // LGH, LGHRL2154&Inst::Load64ZExt32 { .. } => (None, Some(0xe316), Some(0xc4e)), // LLGF, LLGFRL2155&Inst::Load64SExt32 { .. } => (None, Some(0xe314), Some(0xc4c)), // LGF, LGFRL2156&Inst::LoadRev16 { .. } => (None, Some(0xe31f), None), // LRVH2157&Inst::LoadRev32 { .. } => (None, Some(0xe31e), None), // LRV2158&Inst::LoadRev64 { .. } => (None, Some(0xe30f), None), // LRVG2159_ => unreachable!(),2160};2161let rd = rd.to_reg();2162mem_emit(2163rd, &mem, opcode_rx, opcode_rxy, opcode_ril, true, sink, emit_info, state,2164);2165}21662167&Inst::Store8 { rd, ref mem }2168| &Inst::Store16 { rd, ref mem }2169| &Inst::Store32 { rd, ref mem }2170| &Inst::Store64 { rd, ref mem }2171| &Inst::StoreRev16 { rd, ref mem }2172| &Inst::StoreRev32 { rd, ref mem }2173| &Inst::StoreRev64 { rd, ref mem } => {2174let mem = mem.clone();21752176let (opcode_rx, opcode_rxy, opcode_ril) = match self {2177&Inst::Store8 { .. } => (Some(0x42), Some(0xe372), None), // STC(Y)2178&Inst::Store16 { .. } => (Some(0x40), Some(0xe370), Some(0xc47)), // STH(Y), STHRL2179&Inst::Store32 { .. } => (Some(0x50), Some(0xe350), Some(0xc4f)), // ST(Y), STRL2180&Inst::Store64 { .. } => (None, Some(0xe324), Some(0xc4b)), // STG, STGRL2181&Inst::StoreRev16 { .. } => (None, Some(0xe33f), None), // STRVH2182&Inst::StoreRev32 { .. } => (None, Some(0xe33e), None), // STRV2183&Inst::StoreRev64 { .. } => (None, Some(0xe32f), None), // STRVG2184_ => unreachable!(),2185};2186mem_emit(2187rd, &mem, opcode_rx, opcode_rxy, opcode_ril, true, sink, emit_info, state,2188);2189}2190&Inst::StoreImm8 { imm, ref mem } => {2191let mem = mem.clone();21922193let opcode_si = 0x92; // MVI2194let opcode_siy = 0xeb52; // MVIY2195mem_imm8_emit(2196imm, &mem, opcode_si, opcode_siy, true, sink, emit_info, state,2197);2198}2199&Inst::StoreImm16 { imm, ref mem }2200| &Inst::StoreImm32SExt16 { imm, ref mem }2201| &Inst::StoreImm64SExt16 { imm, ref mem } => {2202let mem = mem.clone();22032204let opcode = match self {2205&Inst::StoreImm16 { .. } => 0xe544, // MVHHI2206&Inst::StoreImm32SExt16 { .. } => 0xe54c, // MVHI2207&Inst::StoreImm64SExt16 { .. } => 0xe548, // MVGHI2208_ => unreachable!(),2209};2210mem_imm16_emit(imm, &mem, opcode, true, sink, emit_info, state);2211}22122213&Inst::LoadMultiple64 { rt, rt2, ref mem } => {2214let mem = mem.clone();22152216let opcode = 0xeb04; // LMG2217let rt = rt.to_reg();2218let rt2 = rt2.to_reg();2219mem_rs_emit(2220rt,2221rt2,2222&mem,2223None,2224Some(opcode),2225true,2226sink,2227emit_info,2228state,2229);2230}2231&Inst::StoreMultiple64 { rt, rt2, ref mem } => {2232let mem = mem.clone();22332234let opcode = 0xeb24; // STMG2235mem_rs_emit(2236rt,2237rt2,2238&mem,2239None,2240Some(opcode),2241true,2242sink,2243emit_info,2244state,2245);2246}22472248&Inst::LoadAddr { rd, ref mem } => {2249let mem = mem.clone();22502251let opcode_rx = Some(0x41); // LA2252let opcode_rxy = Some(0xe371); // LAY2253let opcode_ril = Some(0xc00); // LARL2254let rd = rd.to_reg();2255mem_emit(2256rd, &mem, opcode_rx, opcode_rxy, opcode_ril, false, sink, emit_info, state,2257);2258}22592260&Inst::Mov64 { rd, rm } => {2261let opcode = 0xb904; // LGR2262put(sink, &enc_rre(opcode, rd.to_reg(), rm));2263}2264&Inst::MovPReg { rd, rm } => {2265Inst::Mov64 { rd, rm: rm.into() }.emit(sink, emit_info, state);2266}2267&Inst::Mov32 { rd, rm } => {2268let opcode = 0x18; // LR2269put(sink, &enc_rr(opcode, rd.to_reg(), rm));2270}2271&Inst::Mov32Imm { rd, imm } => {2272let opcode = 0xc09; // IILF2273put(sink, &enc_ril_a(opcode, rd.to_reg(), imm));2274}2275&Inst::Mov32SImm16 { rd, imm } => {2276let opcode = 0xa78; // LHI2277put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16));2278}2279&Inst::Mov64SImm16 { rd, imm } => {2280let opcode = 0xa79; // LGHI2281put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16));2282}2283&Inst::Mov64SImm32 { rd, imm } => {2284let opcode = 0xc01; // LGFI2285put(sink, &enc_ril_a(opcode, rd.to_reg(), imm as u32));2286}2287&Inst::CMov32 { rd, cond, ri, rm } => {2288debug_assert_eq!(rd.to_reg(), ri);22892290let opcode = 0xb9f2; // LOCR2291put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rm, cond.bits(), 0));2292}2293&Inst::CMov64 { rd, cond, ri, rm } => {2294debug_assert_eq!(rd.to_reg(), ri);22952296let opcode = 0xb9e2; // LOCGR2297put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rm, cond.bits(), 0));2298}2299&Inst::CMov32SImm16 { rd, cond, ri, imm } => {2300debug_assert_eq!(rd.to_reg(), ri);23012302let opcode = 0xec42; // LOCHI2303put(2304sink,2305&enc_rie_g(opcode, rd.to_reg(), imm as u16, cond.bits()),2306);2307}2308&Inst::CMov64SImm16 { rd, cond, ri, imm } => {2309debug_assert_eq!(rd.to_reg(), ri);23102311let opcode = 0xec46; // LOCGHI2312put(2313sink,2314&enc_rie_g(opcode, rd.to_reg(), imm as u16, cond.bits()),2315);2316}2317&Inst::Mov64UImm16Shifted { rd, imm } => {2318let opcode = match imm.shift {23190 => 0xa5f, // LLILL23201 => 0xa5e, // LLILH23212 => 0xa5d, // LLIHL23223 => 0xa5c, // LLIHH2323_ => unreachable!(),2324};2325put(sink, &enc_ri_a(opcode, rd.to_reg(), imm.bits));2326}2327&Inst::Mov64UImm32Shifted { rd, imm } => {2328let opcode = match imm.shift {23290 => 0xc0f, // LLILF23301 => 0xc0e, // LLIHF2331_ => unreachable!(),2332};2333put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits));2334}2335&Inst::Insert64UImm16Shifted { rd, ri, imm } => {2336debug_assert_eq!(rd.to_reg(), ri);23372338let opcode = match imm.shift {23390 => 0xa53, // IILL23401 => 0xa52, // IILH23412 => 0xa51, // IIHL23423 => 0xa50, // IIHH2343_ => unreachable!(),2344};2345put(sink, &enc_ri_a(opcode, rd.to_reg(), imm.bits));2346}2347&Inst::Insert64UImm32Shifted { rd, ri, imm } => {2348debug_assert_eq!(rd.to_reg(), ri);23492350let opcode = match imm.shift {23510 => 0xc09, // IILF23521 => 0xc08, // IIHF2353_ => unreachable!(),2354};2355put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits));2356}2357&Inst::LoadAR { rd, ar } => {2358let opcode = 0xb24f; // EAR2359put(sink, &enc_rre(opcode, rd.to_reg(), gpr(ar)));2360}23612362&Inst::InsertAR { rd, ri, ar } => {2363debug_assert_eq!(rd.to_reg(), ri);23642365let opcode = 0xb24f; // EAR2366put(sink, &enc_rre(opcode, rd.to_reg(), gpr(ar)));2367}2368&Inst::LoadSymbolReloc {2369rd,2370ref symbol_reloc,2371} => {2372let reg = writable_spilltmp_reg().to_reg();2373put(sink, &enc_ri_b(OPCODE_BRAS, reg, 12));2374let (reloc, name, offset) = match &**symbol_reloc {2375SymbolReloc::Absolute { name, offset } => (Reloc::Abs8, name, *offset),2376SymbolReloc::TlsGd { name } => (Reloc::S390xTlsGd64, name, 0),2377};2378sink.add_reloc(reloc, name, offset);2379sink.put8(0);2380let inst = Inst::Load64 {2381rd,2382mem: MemArg::reg(reg, MemFlags::trusted()),2383};2384inst.emit(sink, emit_info, state);2385}23862387&Inst::FpuMove32 { rd, rn } => {2388if is_fpr(rd.to_reg()) && is_fpr(rn) {2389let opcode = 0x38; // LER2390put(sink, &enc_rr(opcode, rd.to_reg(), rn));2391} else {2392put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rn, 0, 0, 0));2393}2394}2395&Inst::FpuMove64 { rd, rn } => {2396if is_fpr(rd.to_reg()) && is_fpr(rn) {2397put(sink, &enc_rr(OPCODE_LDR, rd.to_reg(), rn));2398} else {2399put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rn, 0, 0, 0));2400}2401}2402&Inst::FpuCMov32 { rd, cond, ri, rm } => {2403debug_assert_eq!(rd.to_reg(), ri);24042405if is_fpr(rd.to_reg()) && is_fpr(rm) {2406put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 2));2407let opcode = 0x38; // LER2408put(sink, &enc_rr(opcode, rd.to_reg(), rm));2409} else {2410put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 6));2411put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rm, 0, 0, 0));2412}2413}2414&Inst::FpuCMov64 { rd, cond, ri, rm } => {2415debug_assert_eq!(rd.to_reg(), ri);24162417if is_fpr(rd.to_reg()) && is_fpr(rm) {2418put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 2));2419put(sink, &enc_rr(OPCODE_LDR, rd.to_reg(), rm));2420} else {2421put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 6));2422put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rm, 0, 0, 0));2423}2424}2425&Inst::FpuRR { fpu_op, rd, rn } => {2426let (opcode, m3, m4, m5, opcode_fpr) = match fpu_op {2427FPUOp1::Abs32 => (0xe7cc, 2, 8, 2, Some(0xb300)), // WFPSO, LPEBR2428FPUOp1::Abs64 => (0xe7cc, 3, 8, 2, Some(0xb310)), // WFPSO, LPDBR2429FPUOp1::Abs128 => (0xe7cc, 4, 8, 2, None), // WFPSO2430FPUOp1::Abs32x4 => (0xe7cc, 2, 0, 2, None), // VFPSO2431FPUOp1::Abs64x2 => (0xe7cc, 3, 0, 2, None), // VFPSO2432FPUOp1::Neg32 => (0xe7cc, 2, 8, 0, Some(0xb303)), // WFPSO, LCEBR2433FPUOp1::Neg64 => (0xe7cc, 3, 8, 0, Some(0xb313)), // WFPSO, LCDBR2434FPUOp1::Neg128 => (0xe7cc, 4, 8, 0, None), // WFPSO2435FPUOp1::Neg32x4 => (0xe7cc, 2, 0, 0, None), // VFPSO2436FPUOp1::Neg64x2 => (0xe7cc, 3, 0, 0, None), // VFPSO2437FPUOp1::NegAbs32 => (0xe7cc, 2, 8, 1, Some(0xb301)), // WFPSO, LNEBR2438FPUOp1::NegAbs64 => (0xe7cc, 3, 8, 1, Some(0xb311)), // WFPSO, LNDBR2439FPUOp1::NegAbs128 => (0xe7cc, 4, 8, 1, None), // WFPSO2440FPUOp1::NegAbs32x4 => (0xe7cc, 2, 0, 1, None), // VFPSO2441FPUOp1::NegAbs64x2 => (0xe7cc, 3, 0, 1, None), // VFPSO2442FPUOp1::Sqrt32 => (0xe7ce, 2, 8, 0, Some(0xb314)), // WFSQ, SQEBR2443FPUOp1::Sqrt64 => (0xe7ce, 3, 8, 0, Some(0xb315)), // WFSQ, SQDBR2444FPUOp1::Sqrt128 => (0xe7ce, 4, 8, 0, None), // WFSQ2445FPUOp1::Sqrt32x4 => (0xe7ce, 2, 0, 0, None), // VFSQ2446FPUOp1::Sqrt64x2 => (0xe7ce, 3, 0, 0, None), // VFSQ2447FPUOp1::Cvt32To64 => (0xe7c4, 2, 8, 0, Some(0xb304)), // WFLL, LDEBR2448FPUOp1::Cvt32x4To64x2 => (0xe7c4, 2, 0, 0, None), // VFLL2449FPUOp1::Cvt64To128 => (0xe7c4, 3, 8, 0, None), // WFLL2450};2451if m4 == 8 && opcode_fpr.is_some() && is_fpr(rd.to_reg()) && is_fpr(rn) {2452put(sink, &enc_rre(opcode_fpr.unwrap(), rd.to_reg(), rn));2453} else {2454put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, m3, m4, m5));2455}2456}2457&Inst::FpuRRR { fpu_op, rd, rn, rm } => {2458let (opcode, m4, m5, m6, opcode_fpr) = match fpu_op {2459FPUOp2::Add32 => (0xe7e3, 2, 8, 0, Some(0xb30a)), // WFA, AEBR2460FPUOp2::Add64 => (0xe7e3, 3, 8, 0, Some(0xb31a)), // WFA, ADBR2461FPUOp2::Add128 => (0xe7e3, 4, 8, 0, None), // WFA2462FPUOp2::Add32x4 => (0xe7e3, 2, 0, 0, None), // VFA2463FPUOp2::Add64x2 => (0xe7e3, 3, 0, 0, None), // VFA2464FPUOp2::Sub32 => (0xe7e2, 2, 8, 0, Some(0xb30b)), // WFS, SEBR2465FPUOp2::Sub64 => (0xe7e2, 3, 8, 0, Some(0xb31b)), // WFS, SDBR2466FPUOp2::Sub128 => (0xe7e2, 4, 8, 0, None), // WFS2467FPUOp2::Sub32x4 => (0xe7e2, 2, 0, 0, None), // VFS2468FPUOp2::Sub64x2 => (0xe7e2, 3, 0, 0, None), // VFS2469FPUOp2::Mul32 => (0xe7e7, 2, 8, 0, Some(0xb317)), // WFM, MEEBR2470FPUOp2::Mul64 => (0xe7e7, 3, 8, 0, Some(0xb31c)), // WFM, MDBR2471FPUOp2::Mul128 => (0xe7e7, 4, 8, 0, None), // WFM2472FPUOp2::Mul32x4 => (0xe7e7, 2, 0, 0, None), // VFM2473FPUOp2::Mul64x2 => (0xe7e7, 3, 0, 0, None), // VFM2474FPUOp2::Div32 => (0xe7e5, 2, 8, 0, Some(0xb30d)), // WFD, DEBR2475FPUOp2::Div64 => (0xe7e5, 3, 8, 0, Some(0xb31d)), // WFD, DDBR2476FPUOp2::Div128 => (0xe7e5, 4, 8, 0, None), // WFD2477FPUOp2::Div32x4 => (0xe7e5, 2, 0, 0, None), // VFD2478FPUOp2::Div64x2 => (0xe7e5, 3, 0, 0, None), // VFD2479FPUOp2::Max32 => (0xe7ef, 2, 8, 1, None), // WFMAX2480FPUOp2::Max64 => (0xe7ef, 3, 8, 1, None), // WFMAX2481FPUOp2::Max128 => (0xe7ef, 4, 8, 1, None), // WFMAX2482FPUOp2::Max32x4 => (0xe7ef, 2, 0, 1, None), // VFMAX2483FPUOp2::Max64x2 => (0xe7ef, 3, 0, 1, None), // VFMAX2484FPUOp2::Min32 => (0xe7ee, 2, 8, 1, None), // WFMIN2485FPUOp2::Min64 => (0xe7ee, 3, 8, 1, None), // WFMIN2486FPUOp2::Min128 => (0xe7ee, 4, 8, 1, None), // WFMIN2487FPUOp2::Min32x4 => (0xe7ee, 2, 0, 1, None), // VFMIN2488FPUOp2::Min64x2 => (0xe7ee, 3, 0, 1, None), // VFMIN2489FPUOp2::MaxPseudo32 => (0xe7ef, 2, 8, 3, None), // WFMAX2490FPUOp2::MaxPseudo64 => (0xe7ef, 3, 8, 3, None), // WFMAX2491FPUOp2::MaxPseudo128 => (0xe7ef, 4, 8, 3, None), // WFMAX2492FPUOp2::MaxPseudo32x4 => (0xe7ef, 2, 0, 3, None), // VFMAX2493FPUOp2::MaxPseudo64x2 => (0xe7ef, 3, 0, 3, None), // VFMAX2494FPUOp2::MinPseudo32 => (0xe7ee, 2, 8, 3, None), // WFMIN2495FPUOp2::MinPseudo64 => (0xe7ee, 3, 8, 3, None), // WFMIN2496FPUOp2::MinPseudo128 => (0xe7ee, 4, 8, 3, None), // WFMIN2497FPUOp2::MinPseudo32x4 => (0xe7ee, 2, 0, 3, None), // VFMIN2498FPUOp2::MinPseudo64x2 => (0xe7ee, 3, 0, 3, None), // VFMIN2499};2500if m5 == 8 && opcode_fpr.is_some() && rd.to_reg() == rn && is_fpr(rn) && is_fpr(rm)2501{2502put(sink, &enc_rre(opcode_fpr.unwrap(), rd.to_reg(), rm));2503} else {2504put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, m5, m6));2505}2506}2507&Inst::FpuRRRR {2508fpu_op,2509rd,2510rn,2511rm,2512ra,2513} => {2514let (opcode, m5, m6, opcode_fpr) = match fpu_op {2515FPUOp3::MAdd32 => (0xe78f, 8, 2, Some(0xb30e)), // WFMA, MAEBR2516FPUOp3::MAdd64 => (0xe78f, 8, 3, Some(0xb31e)), // WFMA, MADBR2517FPUOp3::MAdd128 => (0xe78f, 8, 4, None), // WFMA2518FPUOp3::MAdd32x4 => (0xe78f, 0, 2, None), // VFMA2519FPUOp3::MAdd64x2 => (0xe78f, 0, 3, None), // VFMA2520FPUOp3::MSub32 => (0xe78e, 8, 2, Some(0xb30f)), // WFMS, MSEBR2521FPUOp3::MSub64 => (0xe78e, 8, 3, Some(0xb31f)), // WFMS, MSDBR2522FPUOp3::MSub128 => (0xe78e, 8, 4, None), // WFMS2523FPUOp3::MSub32x4 => (0xe78e, 0, 2, None), // VFMS2524FPUOp3::MSub64x2 => (0xe78e, 0, 3, None), // VFMS2525};2526if m5 == 82527&& opcode_fpr.is_some()2528&& rd.to_reg() == ra2529&& is_fpr(rn)2530&& is_fpr(rm)2531&& is_fpr(ra)2532{2533put(sink, &enc_rrd(opcode_fpr.unwrap(), rd.to_reg(), rm, rn));2534} else {2535put(sink, &enc_vrr_e(opcode, rd.to_reg(), rn, rm, ra, m5, m6));2536}2537}2538&Inst::FpuRound { op, mode, rd, rn } => {2539let mode = match mode {2540FpuRoundMode::Current => 0,2541FpuRoundMode::ToNearest => 1,2542FpuRoundMode::ShorterPrecision => 3,2543FpuRoundMode::ToNearestTiesToEven => 4,2544FpuRoundMode::ToZero => 5,2545FpuRoundMode::ToPosInfinity => 6,2546FpuRoundMode::ToNegInfinity => 7,2547};2548let (opcode, m3, m4, opcode_fpr) = match op {2549FpuRoundOp::Cvt64To32 => (0xe7c5, 3, 8, Some(0xb344)), // WFLR, LEDBR(A)2550FpuRoundOp::Cvt64x2To32x4 => (0xe7c5, 3, 0, None), // VFLR2551FpuRoundOp::Cvt128To64 => (0xe7c5, 4, 8, None), // WFLR2552FpuRoundOp::Round32 => (0xe7c7, 2, 8, Some(0xb357)), // WFI, FIEBR2553FpuRoundOp::Round64 => (0xe7c7, 3, 8, Some(0xb35f)), // WFI, FIDBR2554FpuRoundOp::Round128 => (0xe7c7, 4, 8, None), // WFI2555FpuRoundOp::Round32x4 => (0xe7c7, 2, 0, None), // VFI2556FpuRoundOp::Round64x2 => (0xe7c7, 3, 0, None), // VFI2557FpuRoundOp::ToSInt32 => (0xe7c2, 2, 8, None), // WCSFP2558FpuRoundOp::ToSInt64 => (0xe7c2, 3, 8, None), // WCSFP2559FpuRoundOp::ToUInt32 => (0xe7c0, 2, 8, None), // WCLFP2560FpuRoundOp::ToUInt64 => (0xe7c0, 3, 8, None), // WCLFP2561FpuRoundOp::ToSInt32x4 => (0xe7c2, 2, 0, None), // VCSFP2562FpuRoundOp::ToSInt64x2 => (0xe7c2, 3, 0, None), // VCSFP2563FpuRoundOp::ToUInt32x4 => (0xe7c0, 2, 0, None), // VCLFP2564FpuRoundOp::ToUInt64x2 => (0xe7c0, 3, 0, None), // VCLFP2565FpuRoundOp::FromSInt32 => (0xe7c3, 2, 8, None), // WCFPS2566FpuRoundOp::FromSInt64 => (0xe7c3, 3, 8, None), // WCFPS2567FpuRoundOp::FromUInt32 => (0xe7c1, 2, 8, None), // WCFPL2568FpuRoundOp::FromUInt64 => (0xe7c1, 3, 8, None), // WCFPL2569FpuRoundOp::FromSInt32x4 => (0xe7c3, 2, 0, None), // VCFPS2570FpuRoundOp::FromSInt64x2 => (0xe7c3, 3, 0, None), // VCFPS2571FpuRoundOp::FromUInt32x4 => (0xe7c1, 2, 0, None), // VCFPL2572FpuRoundOp::FromUInt64x2 => (0xe7c1, 3, 0, None), // VCFPL2573};2574if m4 == 8 && opcode_fpr.is_some() && is_fpr(rd.to_reg()) && is_fpr(rn) {2575put(2576sink,2577&enc_rrf_cde(opcode_fpr.unwrap(), rd.to_reg(), rn, mode, 0),2578);2579} else {2580put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, m3, m4, mode));2581}2582}2583&Inst::FpuConv128FromInt { op, mode, rd, rn } => {2584let rd1 = rd.hi;2585let rd2 = rd.lo;2586debug_assert_valid_fp_regpair!(rd1.to_reg(), rd2.to_reg());25872588let mode = match mode {2589FpuRoundMode::Current => 0,2590FpuRoundMode::ToNearest => 1,2591FpuRoundMode::ShorterPrecision => 3,2592FpuRoundMode::ToNearestTiesToEven => 4,2593FpuRoundMode::ToZero => 5,2594FpuRoundMode::ToPosInfinity => 6,2595FpuRoundMode::ToNegInfinity => 7,2596};2597let opcode = match op {2598FpuConv128Op::SInt32 => 0xb396, // CXFBRA2599FpuConv128Op::SInt64 => 0xb3a6, // CXGBRA2600FpuConv128Op::UInt32 => 0xb392, // CXLFBR2601FpuConv128Op::UInt64 => 0xb3a2, // CXLGBR2602};2603put(sink, &enc_rrf_cde(opcode, rd1.to_reg(), rn, mode, 0));2604}2605&Inst::FpuConv128ToInt { op, mode, rd, rn } => {2606let rn1 = rn.hi;2607let rn2 = rn.lo;2608debug_assert_valid_fp_regpair!(rn1, rn2);26092610let mode = match mode {2611FpuRoundMode::Current => 0,2612FpuRoundMode::ToNearest => 1,2613FpuRoundMode::ShorterPrecision => 3,2614FpuRoundMode::ToNearestTiesToEven => 4,2615FpuRoundMode::ToZero => 5,2616FpuRoundMode::ToPosInfinity => 6,2617FpuRoundMode::ToNegInfinity => 7,2618};2619let opcode = match op {2620FpuConv128Op::SInt32 => 0xb39a, // CFXBRA2621FpuConv128Op::SInt64 => 0xb3aa, // CGXBRA2622FpuConv128Op::UInt32 => 0xb39e, // CLFXBR2623FpuConv128Op::UInt64 => 0xb3ae, // CLGXBR2624};2625put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rn1, mode, 0));2626}2627&Inst::FpuCmp32 { rn, rm } => {2628if is_fpr(rn) && is_fpr(rm) {2629let opcode = 0xb309; // CEBR2630put(sink, &enc_rre(opcode, rn, rm));2631} else {2632let opcode = 0xe7cb; // WFC2633put(sink, &enc_vrr_a(opcode, rn, rm, 2, 0, 0));2634}2635}2636&Inst::FpuCmp64 { rn, rm } => {2637if is_fpr(rn) && is_fpr(rm) {2638let opcode = 0xb319; // CDBR2639put(sink, &enc_rre(opcode, rn, rm));2640} else {2641let opcode = 0xe7cb; // WFC2642put(sink, &enc_vrr_a(opcode, rn, rm, 3, 0, 0));2643}2644}2645&Inst::FpuCmp128 { rn, rm } => {2646let opcode = 0xe7cb; // WFC2647put(sink, &enc_vrr_a(opcode, rn, rm, 4, 0, 0));2648}26492650&Inst::VecRRR { op, rd, rn, rm } => {2651let (opcode, m4) = match op {2652VecBinaryOp::Add8x16 => (0xe7f3, 0), // VAB2653VecBinaryOp::Add16x8 => (0xe7f3, 1), // VAH2654VecBinaryOp::Add32x4 => (0xe7f3, 2), // VAF2655VecBinaryOp::Add64x2 => (0xe7f3, 3), // VAG2656VecBinaryOp::Add128 => (0xe7f3, 4), // VAQ2657VecBinaryOp::Sub8x16 => (0xe7f7, 0), // VSB2658VecBinaryOp::Sub16x8 => (0xe7f7, 1), // VSH2659VecBinaryOp::Sub32x4 => (0xe7f7, 2), // VSF2660VecBinaryOp::Sub64x2 => (0xe7f7, 3), // VSG2661VecBinaryOp::Sub128 => (0xe7f7, 4), // VSQ2662VecBinaryOp::Mul8x16 => (0xe7a2, 0), // VMLB2663VecBinaryOp::Mul16x8 => (0xe7a2, 1), // VMLHW2664VecBinaryOp::Mul32x4 => (0xe7a2, 2), // VMLF2665VecBinaryOp::UMulHi8x16 => (0xe7a1, 0), // VMLHB2666VecBinaryOp::UMulHi16x8 => (0xe7a1, 1), // VMLHH2667VecBinaryOp::UMulHi32x4 => (0xe7a1, 2), // VMLHF2668VecBinaryOp::SMulHi8x16 => (0xe7a3, 0), // VMHB2669VecBinaryOp::SMulHi16x8 => (0xe7a3, 1), // VMHH2670VecBinaryOp::SMulHi32x4 => (0xe7a3, 2), // VMHF2671VecBinaryOp::UMulEven8x16 => (0xe7a4, 0), // VMLEB2672VecBinaryOp::UMulEven16x8 => (0xe7a4, 1), // VMLEH2673VecBinaryOp::UMulEven32x4 => (0xe7a4, 2), // VMLEF2674VecBinaryOp::SMulEven8x16 => (0xe7a6, 0), // VMEB2675VecBinaryOp::SMulEven16x8 => (0xe7a6, 1), // VMEH2676VecBinaryOp::SMulEven32x4 => (0xe7a6, 2), // VMEF2677VecBinaryOp::UMulOdd8x16 => (0xe7a5, 0), // VMLOB2678VecBinaryOp::UMulOdd16x8 => (0xe7a5, 1), // VMLOH2679VecBinaryOp::UMulOdd32x4 => (0xe7a5, 2), // VMLOF2680VecBinaryOp::SMulOdd8x16 => (0xe7a7, 0), // VMOB2681VecBinaryOp::SMulOdd16x8 => (0xe7a7, 1), // VMOH2682VecBinaryOp::SMulOdd32x4 => (0xe7a7, 2), // VMOF2683VecBinaryOp::UMax8x16 => (0xe7fd, 0), // VMXLB2684VecBinaryOp::UMax16x8 => (0xe7fd, 1), // VMXLH2685VecBinaryOp::UMax32x4 => (0xe7fd, 2), // VMXLF2686VecBinaryOp::UMax64x2 => (0xe7fd, 3), // VMXLG2687VecBinaryOp::SMax8x16 => (0xe7ff, 0), // VMXB2688VecBinaryOp::SMax16x8 => (0xe7ff, 1), // VMXH2689VecBinaryOp::SMax32x4 => (0xe7ff, 2), // VMXF2690VecBinaryOp::SMax64x2 => (0xe7ff, 3), // VMXG2691VecBinaryOp::UMin8x16 => (0xe7fc, 0), // VMNLB2692VecBinaryOp::UMin16x8 => (0xe7fc, 1), // VMNLH2693VecBinaryOp::UMin32x4 => (0xe7fc, 2), // VMNLF2694VecBinaryOp::UMin64x2 => (0xe7fc, 3), // VMNLG2695VecBinaryOp::SMin8x16 => (0xe7fe, 0), // VMNB2696VecBinaryOp::SMin16x8 => (0xe7fe, 1), // VMNH2697VecBinaryOp::SMin32x4 => (0xe7fe, 2), // VMNF2698VecBinaryOp::SMin64x2 => (0xe7fe, 3), // VMNG2699VecBinaryOp::UAvg8x16 => (0xe7f0, 0), // VAVGLB2700VecBinaryOp::UAvg16x8 => (0xe7f0, 1), // VAVGLH2701VecBinaryOp::UAvg32x4 => (0xe7f0, 2), // VAVGLF2702VecBinaryOp::UAvg64x2 => (0xe7f0, 3), // VAVGLG2703VecBinaryOp::SAvg8x16 => (0xe7f2, 0), // VAVGB2704VecBinaryOp::SAvg16x8 => (0xe7f2, 1), // VAVGH2705VecBinaryOp::SAvg32x4 => (0xe7f2, 2), // VAVGF2706VecBinaryOp::SAvg64x2 => (0xe7f2, 3), // VAVGG2707VecBinaryOp::And128 => (0xe768, 0), // VN2708VecBinaryOp::Orr128 => (0xe76a, 0), // VO2709VecBinaryOp::Xor128 => (0xe76d, 0), // VX2710VecBinaryOp::NotAnd128 => (0xe76e, 0), // VNN2711VecBinaryOp::NotOrr128 => (0xe76b, 0), // VNO2712VecBinaryOp::NotXor128 => (0xe76c, 0), // VNX2713VecBinaryOp::AndNot128 => (0xe769, 0), // VNC2714VecBinaryOp::OrrNot128 => (0xe76f, 0), // VOC2715VecBinaryOp::BitPermute128 => (0xe785, 0), // VBPERM2716VecBinaryOp::LShLByByte128 => (0xe775, 0), // VSLB2717VecBinaryOp::LShRByByte128 => (0xe77d, 0), // VSRLB2718VecBinaryOp::AShRByByte128 => (0xe77f, 0), // VSRAB2719VecBinaryOp::LShLByBit128 => (0xe774, 0), // VSL2720VecBinaryOp::LShRByBit128 => (0xe77c, 0), // VSRL2721VecBinaryOp::AShRByBit128 => (0xe77e, 0), // VSRA2722VecBinaryOp::Pack16x8 => (0xe794, 1), // VPKH2723VecBinaryOp::Pack32x4 => (0xe794, 2), // VPKF2724VecBinaryOp::Pack64x2 => (0xe794, 3), // VPKG2725VecBinaryOp::PackUSat16x8 => (0xe795, 1), // VPKLSH2726VecBinaryOp::PackUSat32x4 => (0xe795, 2), // VPKLSF2727VecBinaryOp::PackUSat64x2 => (0xe795, 3), // VPKLSG2728VecBinaryOp::PackSSat16x8 => (0xe797, 1), // VPKSH2729VecBinaryOp::PackSSat32x4 => (0xe797, 2), // VPKSF2730VecBinaryOp::PackSSat64x2 => (0xe797, 3), // VPKSG2731VecBinaryOp::MergeLow8x16 => (0xe760, 0), // VMRLB2732VecBinaryOp::MergeLow16x8 => (0xe760, 1), // VMRLH2733VecBinaryOp::MergeLow32x4 => (0xe760, 2), // VMRLF2734VecBinaryOp::MergeLow64x2 => (0xe760, 3), // VMRLG2735VecBinaryOp::MergeHigh8x16 => (0xe761, 0), // VMRHB2736VecBinaryOp::MergeHigh16x8 => (0xe761, 1), // VMRHH2737VecBinaryOp::MergeHigh32x4 => (0xe761, 2), // VMRHF2738VecBinaryOp::MergeHigh64x2 => (0xe761, 3), // VMRHG2739};27402741put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, 0, 0));2742}2743&Inst::VecRR { op, rd, rn } => {2744let (opcode, m3) = match op {2745VecUnaryOp::Abs8x16 => (0xe7df, 0), // VLPB2746VecUnaryOp::Abs16x8 => (0xe7df, 1), // VLPH2747VecUnaryOp::Abs32x4 => (0xe7df, 2), // VLPF2748VecUnaryOp::Abs64x2 => (0xe7df, 3), // VLPG2749VecUnaryOp::Neg8x16 => (0xe7de, 0), // VLCB2750VecUnaryOp::Neg16x8 => (0xe7de, 1), // VLCH2751VecUnaryOp::Neg32x4 => (0xe7de, 2), // VLCF2752VecUnaryOp::Neg64x2 => (0xe7de, 3), // VLCG2753VecUnaryOp::Popcnt8x16 => (0xe750, 0), // VPOPCTB2754VecUnaryOp::Popcnt16x8 => (0xe750, 1), // VPOPCTH2755VecUnaryOp::Popcnt32x4 => (0xe750, 2), // VPOPCTF2756VecUnaryOp::Popcnt64x2 => (0xe750, 3), // VPOPCTG2757VecUnaryOp::Clz8x16 => (0xe753, 0), // VCLZB2758VecUnaryOp::Clz16x8 => (0xe753, 1), // VCLZH2759VecUnaryOp::Clz32x4 => (0xe753, 2), // VCLZF2760VecUnaryOp::Clz64x2 => (0xe753, 3), // VCLZG2761VecUnaryOp::Ctz8x16 => (0xe752, 0), // VCTZB2762VecUnaryOp::Ctz16x8 => (0xe752, 1), // VCTZH2763VecUnaryOp::Ctz32x4 => (0xe752, 2), // VCTZF2764VecUnaryOp::Ctz64x2 => (0xe752, 3), // VCTZG2765VecUnaryOp::UnpackULow8x16 => (0xe7d4, 0), // VUPLLB2766VecUnaryOp::UnpackULow16x8 => (0xe7d4, 1), // VUPLLH2767VecUnaryOp::UnpackULow32x4 => (0xe7d4, 2), // VUPLLF2768VecUnaryOp::UnpackUHigh8x16 => (0xe7d5, 0), // VUPLHB2769VecUnaryOp::UnpackUHigh16x8 => (0xe7d5, 1), // VUPLHH2770VecUnaryOp::UnpackUHigh32x4 => (0xe7d5, 2), // VUPLHF2771VecUnaryOp::UnpackSLow8x16 => (0xe7d6, 0), // VUPLB2772VecUnaryOp::UnpackSLow16x8 => (0xe7d6, 1), // VUPLH2773VecUnaryOp::UnpackSLow32x4 => (0xe7d6, 2), // VUPLF2774VecUnaryOp::UnpackSHigh8x16 => (0xe7d7, 0), // VUPHB2775VecUnaryOp::UnpackSHigh16x8 => (0xe7d7, 1), // VUPHH2776VecUnaryOp::UnpackSHigh32x4 => (0xe7d7, 2), // VUPHF2777};27782779put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, m3, 0, 0));2780}2781&Inst::VecShiftRR {2782shift_op,2783rd,2784rn,2785shift_imm,2786shift_reg,2787} => {2788let (opcode, m4) = match shift_op {2789VecShiftOp::RotL8x16 => (0xe733, 0), // VERLLB2790VecShiftOp::RotL16x8 => (0xe733, 1), // VERLLH2791VecShiftOp::RotL32x4 => (0xe733, 2), // VERLLF2792VecShiftOp::RotL64x2 => (0xe733, 3), // VERLLG2793VecShiftOp::LShL8x16 => (0xe730, 0), // VESLB2794VecShiftOp::LShL16x8 => (0xe730, 1), // VESLH2795VecShiftOp::LShL32x4 => (0xe730, 2), // VESLF2796VecShiftOp::LShL64x2 => (0xe730, 3), // VESLG2797VecShiftOp::LShR8x16 => (0xe738, 0), // VESRLB2798VecShiftOp::LShR16x8 => (0xe738, 1), // VESRLH2799VecShiftOp::LShR32x4 => (0xe738, 2), // VESRLF2800VecShiftOp::LShR64x2 => (0xe738, 3), // VESRLG2801VecShiftOp::AShR8x16 => (0xe73a, 0), // VESRAB2802VecShiftOp::AShR16x8 => (0xe73a, 1), // VESRAH2803VecShiftOp::AShR32x4 => (0xe73a, 2), // VESRAF2804VecShiftOp::AShR64x2 => (0xe73a, 3), // VESRAG2805};2806put(2807sink,2808&enc_vrs_a(opcode, rd.to_reg(), shift_reg, shift_imm.into(), rn, m4),2809);2810}2811&Inst::VecSelect { rd, rn, rm, ra } => {2812let opcode = 0xe78d; // VSEL2813put(sink, &enc_vrr_e(opcode, rd.to_reg(), rn, rm, ra, 0, 0));2814}2815&Inst::VecPermute { rd, rn, rm, ra } => {2816let opcode = 0xe78c; // VPERM2817put(sink, &enc_vrr_e(opcode, rd.to_reg(), rn, rm, ra, 0, 0));2818}2819&Inst::VecPermuteDWImm {2820rd,2821rn,2822rm,2823idx1,2824idx2,2825} => {2826let m4 = (idx1 & 1) * 4 + (idx2 & 1);28272828let opcode = 0xe784; // VPDI2829put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, 0, 0));2830}2831&Inst::VecIntCmp { op, rd, rn, rm } | &Inst::VecIntCmpS { op, rd, rn, rm } => {2832let (opcode, m4) = match op {2833VecIntCmpOp::CmpEq8x16 => (0xe7f8, 0), // VCEQB2834VecIntCmpOp::CmpEq16x8 => (0xe7f8, 1), // VCEQH2835VecIntCmpOp::CmpEq32x4 => (0xe7f8, 2), // VCEQF2836VecIntCmpOp::CmpEq64x2 => (0xe7f8, 3), // VCEQG2837VecIntCmpOp::SCmpHi8x16 => (0xe7fb, 0), // VCHB2838VecIntCmpOp::SCmpHi16x8 => (0xe7fb, 1), // VCHH2839VecIntCmpOp::SCmpHi32x4 => (0xe7fb, 2), // VCHG2840VecIntCmpOp::SCmpHi64x2 => (0xe7fb, 3), // VCHG2841VecIntCmpOp::UCmpHi8x16 => (0xe7f9, 0), // VCHLB2842VecIntCmpOp::UCmpHi16x8 => (0xe7f9, 1), // VCHLH2843VecIntCmpOp::UCmpHi32x4 => (0xe7f9, 2), // VCHLG2844VecIntCmpOp::UCmpHi64x2 => (0xe7f9, 3), // VCHLG2845};2846let m5 = match self {2847&Inst::VecIntCmp { .. } => 0,2848&Inst::VecIntCmpS { .. } => 1,2849_ => unreachable!(),2850};28512852put(sink, &enc_vrr_b(opcode, rd.to_reg(), rn, rm, m4, m5));2853}2854&Inst::VecFloatCmp { op, rd, rn, rm } | &Inst::VecFloatCmpS { op, rd, rn, rm } => {2855let (opcode, m4) = match op {2856VecFloatCmpOp::CmpEq32x4 => (0xe7e8, 2), // VFCESB2857VecFloatCmpOp::CmpEq64x2 => (0xe7e8, 3), // VFCEDB2858VecFloatCmpOp::CmpHi32x4 => (0xe7eb, 2), // VFCHSB2859VecFloatCmpOp::CmpHi64x2 => (0xe7eb, 3), // VFCHDB2860VecFloatCmpOp::CmpHiEq32x4 => (0xe7ea, 2), // VFCHESB2861VecFloatCmpOp::CmpHiEq64x2 => (0xe7ea, 3), // VFCHEDB2862};2863let m6 = match self {2864&Inst::VecFloatCmp { .. } => 0,2865&Inst::VecFloatCmpS { .. } => 1,2866_ => unreachable!(),2867};28682869put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, 0, m6));2870}2871&Inst::VecInt128SCmpHi { tmp, rn, rm } | &Inst::VecInt128UCmpHi { tmp, rn, rm } => {2872// Synthetic instruction to compare 128-bit values.2873// Sets CC 1 if rn > rm, sets a different CC otherwise.28742875// Use VECTOR ELEMENT COMPARE to compare the high parts.2876// Swap the inputs to get:2877// CC 1 if high(rn) > high(rm)2878// CC 2 if high(rn) < high(rm)2879// CC 0 if high(rn) == high(rm)2880let (opcode, m3) = match self {2881&Inst::VecInt128SCmpHi { .. } => (0xe7db, 3), // VECG2882&Inst::VecInt128UCmpHi { .. } => (0xe7d9, 3), // VECLG2883_ => unreachable!(),2884};2885put(sink, &enc_vrr_a(opcode, rm, rn, m3, 0, 0));28862887// If CC != 0, we'd done, so jump over the next instruction.2888put(sink, &enc_ri_c(OPCODE_BCR, 7, 4 + 6));28892890// Otherwise, use VECTOR COMPARE HIGH LOGICAL.2891// Since we already know the high parts are equal, the CC2892// result will only depend on the low parts:2893// CC 1 if low(rn) > low(rm)2894// CC 3 if low(rn) <= low(rm)2895let inst = Inst::VecIntCmpS {2896op: VecIntCmpOp::UCmpHi64x2,2897// N.B.: This is the first write to tmp, and it happens2898// after all uses of rn and rm. If this were to ever2899// change, tmp would have to become an early-def.2900rd: tmp,2901rn,2902rm,2903};2904inst.emit(sink, emit_info, state);2905}29062907&Inst::VecLoad { rd, ref mem }2908| &Inst::VecLoadRev { rd, ref mem }2909| &Inst::VecLoadByte16Rev { rd, ref mem }2910| &Inst::VecLoadByte32Rev { rd, ref mem }2911| &Inst::VecLoadByte64Rev { rd, ref mem }2912| &Inst::VecLoadElt16Rev { rd, ref mem }2913| &Inst::VecLoadElt32Rev { rd, ref mem }2914| &Inst::VecLoadElt64Rev { rd, ref mem } => {2915let mem = mem.clone();29162917let (opcode, m3) = match self {2918&Inst::VecLoad { .. } => (0xe706, 0), // VL2919&Inst::VecLoadRev { .. } => (0xe606, 4), // VLBRQ2920&Inst::VecLoadByte16Rev { .. } => (0xe606, 1), // VLBRH2921&Inst::VecLoadByte32Rev { .. } => (0xe606, 2), // VLBRF2922&Inst::VecLoadByte64Rev { .. } => (0xe606, 3), // VLBRG2923&Inst::VecLoadElt16Rev { .. } => (0xe607, 1), // VLERH2924&Inst::VecLoadElt32Rev { .. } => (0xe607, 2), // VLERF2925&Inst::VecLoadElt64Rev { .. } => (0xe607, 3), // VLERG2926_ => unreachable!(),2927};2928mem_vrx_emit(rd.to_reg(), &mem, opcode, m3, true, sink, emit_info, state);2929}2930&Inst::VecStore { rd, ref mem }2931| &Inst::VecStoreRev { rd, ref mem }2932| &Inst::VecStoreByte16Rev { rd, ref mem }2933| &Inst::VecStoreByte32Rev { rd, ref mem }2934| &Inst::VecStoreByte64Rev { rd, ref mem }2935| &Inst::VecStoreElt16Rev { rd, ref mem }2936| &Inst::VecStoreElt32Rev { rd, ref mem }2937| &Inst::VecStoreElt64Rev { rd, ref mem } => {2938let mem = mem.clone();29392940let (opcode, m3) = match self {2941&Inst::VecStore { .. } => (0xe70e, 0), // VST2942&Inst::VecStoreRev { .. } => (0xe60e, 4), // VSTBRQ2943&Inst::VecStoreByte16Rev { .. } => (0xe60e, 1), // VSTBRH2944&Inst::VecStoreByte32Rev { .. } => (0xe60e, 2), // VSTBRF2945&Inst::VecStoreByte64Rev { .. } => (0xe60e, 3), // VSTBRG2946&Inst::VecStoreElt16Rev { .. } => (0xe60f, 1), // VSTERH2947&Inst::VecStoreElt32Rev { .. } => (0xe60f, 2), // VSTERF2948&Inst::VecStoreElt64Rev { .. } => (0xe60f, 3), // VSTERG2949_ => unreachable!(),2950};2951mem_vrx_emit(rd, &mem, opcode, m3, true, sink, emit_info, state);2952}2953&Inst::VecLoadReplicate { size, rd, ref mem }2954| &Inst::VecLoadReplicateRev { size, rd, ref mem } => {2955let mem = mem.clone();29562957let (opcode, m3) = match (self, size) {2958(&Inst::VecLoadReplicate { .. }, 8) => (0xe705, 0), // VLREPB2959(&Inst::VecLoadReplicate { .. }, 16) => (0xe705, 1), // VLREPH2960(&Inst::VecLoadReplicate { .. }, 32) => (0xe705, 2), // VLREPF2961(&Inst::VecLoadReplicate { .. }, 64) => (0xe705, 3), // VLREPG2962(&Inst::VecLoadReplicateRev { .. }, 16) => (0xe605, 1), // VLREPBRH2963(&Inst::VecLoadReplicateRev { .. }, 32) => (0xe605, 2), // VLREPBRF2964(&Inst::VecLoadReplicateRev { .. }, 64) => (0xe605, 3), // VLREPBRG2965_ => unreachable!(),2966};2967mem_vrx_emit(rd.to_reg(), &mem, opcode, m3, true, sink, emit_info, state);2968}29692970&Inst::VecMov { rd, rn } => {2971put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rn, 0, 0, 0));2972}2973&Inst::VecCMov { rd, cond, ri, rm } => {2974debug_assert_eq!(rd.to_reg(), ri);29752976put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 6));2977put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rm, 0, 0, 0));2978}2979&Inst::MovToVec128 { rd, rn, rm } => {2980let opcode = 0xe762; // VLVGP2981put(sink, &enc_vrr_f(opcode, rd.to_reg(), rn, rm));2982}2983&Inst::VecImmByteMask { rd, mask } => {2984let opcode = 0xe744; // VGBM2985put(sink, &enc_vri_a(opcode, rd.to_reg(), mask, 0));2986}2987&Inst::VecImmBitMask {2988size,2989rd,2990start_bit,2991end_bit,2992} => {2993let (opcode, m4) = match size {29948 => (0xe746, 0), // VGMB299516 => (0xe746, 1), // VGMH299632 => (0xe746, 2), // VGMF299764 => (0xe746, 3), // VGMG2998_ => unreachable!(),2999};3000put(3001sink,3002&enc_vri_b(opcode, rd.to_reg(), start_bit, end_bit, m4),3003);3004}3005&Inst::VecImmReplicate { size, rd, imm } => {3006let (opcode, m3) = match size {30078 => (0xe745, 0), // VREPIB300816 => (0xe745, 1), // VREPIH300932 => (0xe745, 2), // VREPIF301064 => (0xe745, 3), // VREPIG3011_ => unreachable!(),3012};3013put(sink, &enc_vri_a(opcode, rd.to_reg(), imm as u16, m3));3014}3015&Inst::VecLoadLane {3016size,3017rd,3018ri,3019ref mem,3020lane_imm,3021}3022| &Inst::VecLoadLaneRev {3023size,3024rd,3025ri,3026ref mem,3027lane_imm,3028} => {3029debug_assert_eq!(rd.to_reg(), ri);3030let mem = mem.clone();30313032let opcode_vrx = match (self, size) {3033(&Inst::VecLoadLane { .. }, 8) => 0xe700, // VLEB3034(&Inst::VecLoadLane { .. }, 16) => 0xe701, // VLEH3035(&Inst::VecLoadLane { .. }, 32) => 0xe703, // VLEF3036(&Inst::VecLoadLane { .. }, 64) => 0xe702, // VLEG3037(&Inst::VecLoadLaneRev { .. }, 16) => 0xe601, // VLEBRH3038(&Inst::VecLoadLaneRev { .. }, 32) => 0xe603, // VLEBRF3039(&Inst::VecLoadLaneRev { .. }, 64) => 0xe602, // VLEBRG3040_ => unreachable!(),3041};30423043let rd = rd.to_reg();3044mem_vrx_emit(rd, &mem, opcode_vrx, lane_imm, true, sink, emit_info, state);3045}3046&Inst::VecLoadLaneUndef {3047size,3048rd,3049ref mem,3050lane_imm,3051}3052| &Inst::VecLoadLaneRevUndef {3053size,3054rd,3055ref mem,3056lane_imm,3057} => {3058let mem = mem.clone();30593060let (opcode_vrx, opcode_rx, opcode_rxy) = match (self, size) {3061(&Inst::VecLoadLaneUndef { .. }, 8) => (0xe700, None, None), // VLEB3062(&Inst::VecLoadLaneUndef { .. }, 16) => (0xe701, None, None), // VLEH3063(&Inst::VecLoadLaneUndef { .. }, 32) => (0xe703, Some(0x78), Some(0xed64)), // VLEF, LE(Y)3064(&Inst::VecLoadLaneUndef { .. }, 64) => (0xe702, Some(0x68), Some(0xed65)), // VLEG, LD(Y)3065(&Inst::VecLoadLaneRevUndef { .. }, 16) => (0xe601, None, None), // VLEBRH3066(&Inst::VecLoadLaneRevUndef { .. }, 32) => (0xe603, None, None), // VLEBRF3067(&Inst::VecLoadLaneRevUndef { .. }, 64) => (0xe602, None, None), // VLEBRG3068_ => unreachable!(),3069};30703071let rd = rd.to_reg();3072if lane_imm == 0 && is_fpr(rd) && opcode_rx.is_some() {3073mem_emit(3074rd, &mem, opcode_rx, opcode_rxy, None, true, sink, emit_info, state,3075);3076} else {3077mem_vrx_emit(rd, &mem, opcode_vrx, lane_imm, true, sink, emit_info, state);3078}3079}3080&Inst::VecStoreLane {3081size,3082rd,3083ref mem,3084lane_imm,3085}3086| &Inst::VecStoreLaneRev {3087size,3088rd,3089ref mem,3090lane_imm,3091} => {3092let mem = mem.clone();30933094let (opcode_vrx, opcode_rx, opcode_rxy) = match (self, size) {3095(&Inst::VecStoreLane { .. }, 8) => (0xe708, None, None), // VSTEB3096(&Inst::VecStoreLane { .. }, 16) => (0xe709, None, None), // VSTEH3097(&Inst::VecStoreLane { .. }, 32) => (0xe70b, Some(0x70), Some(0xed66)), // VSTEF, STE(Y)3098(&Inst::VecStoreLane { .. }, 64) => (0xe70a, Some(0x60), Some(0xed67)), // VSTEG, STD(Y)3099(&Inst::VecStoreLaneRev { .. }, 16) => (0xe609, None, None), // VSTEBRH3100(&Inst::VecStoreLaneRev { .. }, 32) => (0xe60b, None, None), // VSTEBRF3101(&Inst::VecStoreLaneRev { .. }, 64) => (0xe60a, None, None), // VSTEBRG3102_ => unreachable!(),3103};31043105if lane_imm == 0 && is_fpr(rd) && opcode_rx.is_some() {3106mem_emit(3107rd, &mem, opcode_rx, opcode_rxy, None, true, sink, emit_info, state,3108);3109} else {3110mem_vrx_emit(rd, &mem, opcode_vrx, lane_imm, true, sink, emit_info, state);3111}3112}3113&Inst::VecInsertLane {3114size,3115rd,3116ri,3117rn,3118lane_imm,3119lane_reg,3120} => {3121debug_assert_eq!(rd.to_reg(), ri);31223123let (opcode_vrs, m4) = match size {31248 => (0xe722, 0), // VLVGB312516 => (0xe722, 1), // VLVGH312632 => (0xe722, 2), // VLVGF312764 => (0xe722, 3), // VLVGG3128_ => unreachable!(),3129};3130put(3131sink,3132&enc_vrs_b(opcode_vrs, rd.to_reg(), lane_reg, lane_imm.into(), rn, m4),3133);3134}3135&Inst::VecInsertLaneUndef {3136size,3137rd,3138rn,3139lane_imm,3140lane_reg,3141} => {3142let (opcode_vrs, m4, opcode_rre) = match size {31438 => (0xe722, 0, None), // VLVGB314416 => (0xe722, 1, None), // VLVGH314532 => (0xe722, 2, None), // VLVGF314664 => (0xe722, 3, Some(0xb3c1)), // VLVGG, LDGR3147_ => unreachable!(),3148};3149if opcode_rre.is_some()3150&& lane_imm == 03151&& lane_reg == zero_reg()3152&& is_fpr(rd.to_reg())3153{3154put(sink, &enc_rre(opcode_rre.unwrap(), rd.to_reg(), rn));3155} else {3156put(3157sink,3158&enc_vrs_b(opcode_vrs, rd.to_reg(), lane_reg, lane_imm.into(), rn, m4),3159);3160}3161}3162&Inst::VecExtractLane {3163size,3164rd,3165rn,3166lane_imm,3167lane_reg,3168} => {3169let (opcode_vrs, m4, opcode_rre) = match size {31708 => (0xe721, 0, None), // VLGVB317116 => (0xe721, 1, None), // VLGVH317232 => (0xe721, 2, None), // VLGVF317364 => (0xe721, 3, Some(0xb3cd)), // VLGVG, LGDR3174_ => unreachable!(),3175};3176if opcode_rre.is_some() && lane_imm == 0 && lane_reg == zero_reg() && is_fpr(rn) {3177put(sink, &enc_rre(opcode_rre.unwrap(), rd.to_reg(), rn));3178} else {3179put(3180sink,3181&enc_vrs_c(opcode_vrs, rd.to_reg(), lane_reg, lane_imm.into(), rn, m4),3182);3183}3184}3185&Inst::VecInsertLaneImm {3186size,3187rd,3188ri,3189imm,3190lane_imm,3191} => {3192debug_assert_eq!(rd.to_reg(), ri);31933194let opcode = match size {31958 => 0xe740, // VLEIB319616 => 0xe741, // VLEIH319732 => 0xe743, // VLEIF319864 => 0xe742, // VLEIG3199_ => unreachable!(),3200};3201put(sink, &enc_vri_a(opcode, rd.to_reg(), imm as u16, lane_imm));3202}3203&Inst::VecInsertLaneImmUndef {3204size,3205rd,3206imm,3207lane_imm,3208} => {3209let opcode = match size {32108 => 0xe740, // VLEIB321116 => 0xe741, // VLEIH321232 => 0xe743, // VLEIF321364 => 0xe742, // VLEIG3214_ => unreachable!(),3215};3216put(sink, &enc_vri_a(opcode, rd.to_reg(), imm as u16, lane_imm));3217}3218&Inst::VecReplicateLane {3219size,3220rd,3221rn,3222lane_imm,3223} => {3224let (opcode, m4) = match size {32258 => (0xe74d, 0), // VREPB322616 => (0xe74d, 1), // VREPH322732 => (0xe74d, 2), // VREPF322864 => (0xe74d, 3), // VREPG3229_ => unreachable!(),3230};3231put(3232sink,3233&enc_vri_c(opcode, rd.to_reg(), lane_imm.into(), rn, m4),3234);3235}32363237&Inst::VecEltRev { lane_count, rd, rn } => {3238assert!(lane_count >= 2 && lane_count <= 16);3239let inst = Inst::VecPermuteDWImm {3240rd,3241rn,3242rm: rn,3243idx1: 1,3244idx2: 0,3245};3246inst.emit(sink, emit_info, state);3247if lane_count >= 4 {3248let inst = Inst::VecShiftRR {3249shift_op: VecShiftOp::RotL64x2,3250rd,3251rn: rd.to_reg(),3252shift_imm: 32,3253shift_reg: zero_reg(),3254};3255inst.emit(sink, emit_info, state);3256}3257if lane_count >= 8 {3258let inst = Inst::VecShiftRR {3259shift_op: VecShiftOp::RotL32x4,3260rd,3261rn: rd.to_reg(),3262shift_imm: 16,3263shift_reg: zero_reg(),3264};3265inst.emit(sink, emit_info, state);3266}3267if lane_count >= 16 {3268let inst = Inst::VecShiftRR {3269shift_op: VecShiftOp::RotL16x8,3270rd,3271rn: rd.to_reg(),3272shift_imm: 8,3273shift_reg: zero_reg(),3274};3275inst.emit(sink, emit_info, state);3276}3277}32783279&Inst::AllocateArgs { size } => {3280let inst = if let Ok(size) = i16::try_from(size) {3281Inst::AluRSImm16 {3282alu_op: ALUOp::Add64,3283rd: writable_stack_reg(),3284ri: stack_reg(),3285imm: -size,3286}3287} else {3288Inst::AluRUImm32 {3289alu_op: ALUOp::SubLogical64,3290rd: writable_stack_reg(),3291ri: stack_reg(),3292imm: size,3293}3294};3295inst.emit(sink, emit_info, state);3296assert_eq!(state.nominal_sp_offset, 0);3297state.nominal_sp_offset += size;3298}3299&Inst::Call { link, ref info } => {3300let enc: &[u8] = match &info.dest {3301CallInstDest::Direct { name } => {3302let offset = sink.cur_offset() + 2;3303sink.add_reloc_at_offset(offset, Reloc::S390xPLTRel32Dbl, name, 2);3304let opcode = 0xc05; // BRASL3305&enc_ril_b(opcode, link.to_reg(), 0)3306}3307CallInstDest::Indirect { reg } => {3308let opcode = 0x0d; // BASR3309&enc_rr(opcode, link.to_reg(), *reg)3310}3311};3312if let Some(s) = state.take_stack_map() {3313let offset = sink.cur_offset() + enc.len() as u32;3314sink.push_user_stack_map(state, offset, s);3315}3316put(sink, enc);33173318if let Some(try_call) = info.try_call_info.as_ref() {3319sink.add_try_call_site(3320Some(state.frame_layout.sp_to_fp()),3321try_call.exception_handlers(&state.frame_layout),3322);3323} else {3324sink.add_call_site();3325}33263327state.nominal_sp_offset -= info.callee_pop_size;3328assert_eq!(state.nominal_sp_offset, 0);33293330state.outgoing_sp_offset = info.callee_pop_size;3331for inst in S390xMachineDeps::gen_retval_loads(info) {3332inst.emit(sink, emit_info, state);3333}3334state.outgoing_sp_offset = 0;33353336// If this is a try-call, jump to the continuation3337// (normal-return) block.3338if let Some(try_call) = info.try_call_info.as_ref() {3339let jmp = Inst::Jump {3340dest: try_call.continuation,3341};3342jmp.emit(sink, emit_info, state);3343}3344}3345&Inst::ReturnCall { ref info } => {3346let (epilogue_insts, temp_dest) = S390xMachineDeps::gen_tail_epilogue(3347state.frame_layout(),3348info.callee_pop_size,3349&info.dest,3350);3351for inst in epilogue_insts {3352inst.emit(sink, emit_info, state);3353}33543355let enc: &[u8] = match &info.dest {3356CallInstDest::Direct { name } => {3357let offset = sink.cur_offset() + 2;3358sink.add_reloc_at_offset(offset, Reloc::S390xPLTRel32Dbl, name, 2);3359let opcode = 0xc04; // BCRL3360&enc_ril_c(opcode, 15, 0)3361}3362CallInstDest::Indirect { reg } => {3363let opcode = 0x07; // BCR3364&enc_rr(opcode, gpr(15), temp_dest.unwrap_or(*reg))3365}3366};3367put(sink, enc);3368sink.add_call_site();3369}3370&Inst::ElfTlsGetOffset { ref symbol, .. } => {3371let opcode = 0xc05; // BRASL33723373// Add relocation for target function. This has to be done3374// *before* the S390xTlsGdCall, to ensure linker relaxation3375// works correctly.3376let dest = ExternalName::LibCall(LibCall::ElfTlsGetOffset);3377let offset = sink.cur_offset() + 2;3378sink.add_reloc_at_offset(offset, Reloc::S390xPLTRel32Dbl, &dest, 2);3379match &**symbol {3380SymbolReloc::TlsGd { name } => sink.add_reloc(Reloc::S390xTlsGdCall, name, 0),3381_ => unreachable!(),3382}33833384put(sink, &enc_ril_b(opcode, gpr(14), 0));3385sink.add_call_site();3386}3387&Inst::Args { .. } => {}3388&Inst::Rets { .. } => {}3389&Inst::Ret { link } => {3390let opcode = 0x07; // BCR3391put(sink, &enc_rr(opcode, gpr(15), link));3392}3393&Inst::Jump { dest } => {3394let off = sink.cur_offset();3395// Indicate that the jump uses a label, if so, so that a fixup can occur later.3396sink.use_label_at_offset(off, dest, LabelUse::BranchRIL);3397sink.add_uncond_branch(off, off + 6, dest);3398// Emit the jump itself.3399let opcode = 0xc04; // BCRL3400put(sink, &enc_ril_c(opcode, 15, 0));3401}3402&Inst::IndirectBr { rn, .. } => {3403let opcode = 0x07; // BCR3404put(sink, &enc_rr(opcode, gpr(15), rn));3405}3406&Inst::CondBr {3407taken,3408not_taken,3409cond,3410} => {3411let opcode = 0xc04; // BCRL34123413// Conditional part first.3414let cond_off = sink.cur_offset();3415sink.use_label_at_offset(cond_off, taken, LabelUse::BranchRIL);3416let inverted = &enc_ril_c(opcode, cond.invert().bits(), 0);3417sink.add_cond_branch(cond_off, cond_off + 6, taken, inverted);3418put(sink, &enc_ril_c(opcode, cond.bits(), 0));34193420// Unconditional part next.3421let uncond_off = sink.cur_offset();3422sink.use_label_at_offset(uncond_off, not_taken, LabelUse::BranchRIL);3423sink.add_uncond_branch(uncond_off, uncond_off + 6, not_taken);3424put(sink, &enc_ril_c(opcode, 15, 0));3425}3426&Inst::Nop0 => {}3427&Inst::Nop2 => {3428put(sink, &enc_e(0x0707));3429}3430&Inst::Debugtrap => {3431put(sink, &enc_e(0x0001));3432}3433&Inst::Trap { trap_code } => {3434put_with_trap(sink, &enc_e(0x0000), trap_code);3435}3436&Inst::TrapIf { cond, trap_code } => {3437// We implement a TrapIf as a conditional branch into the middle3438// of the branch (BRCL) instruction itself - those middle two bytes3439// are zero, which matches the trap instruction itself.3440let opcode = 0xc04; // BCRL3441let enc = &enc_ril_c(opcode, cond.bits(), 2);3442debug_assert!(enc.len() == 6 && enc[2] == 0 && enc[3] == 0);3443// The trap must be placed on the last byte of the embedded trap3444// instruction, so we need to emit the encoding in two parts.3445put_with_trap(sink, &enc[0..4], trap_code);3446put(sink, &enc[4..6]);3447}3448&Inst::JTSequence {3449ridx,3450default,3451default_cond,3452ref targets,3453} => {3454let table_label = sink.get_label();34553456// This sequence is *one* instruction in the vcode, and is expanded only here at3457// emission time, because we cannot allow the regalloc to insert spills/reloads in3458// the middle; we depend on hardcoded PC-rel addressing below.34593460// Branch to the default target if the given default condition is true.3461let opcode = 0xc04; // BCRL3462sink.use_label_at_offset(sink.cur_offset(), default, LabelUse::BranchRIL);3463put(sink, &enc_ril_c(opcode, default_cond.bits(), 0));34643465// Set temp register to address of jump table.3466let rtmp = writable_spilltmp_reg();3467let inst = Inst::LoadAddr {3468rd: rtmp,3469mem: MemArg::Label {3470target: table_label,3471},3472};3473inst.emit(sink, emit_info, state);34743475// Set temp to target address by adding the value of the jump table entry.3476let inst = Inst::AluRX {3477alu_op: ALUOp::Add64Ext32,3478rd: rtmp,3479ri: rtmp.to_reg(),3480mem: MemArg::reg_plus_reg(rtmp.to_reg(), ridx, MemFlags::trusted()),3481};3482inst.emit(sink, emit_info, state);34833484// Branch to computed address. (`targets` here is only used for successor queries3485// and is not needed for emission.)3486let inst = Inst::IndirectBr {3487rn: rtmp.to_reg(),3488targets: vec![],3489};3490inst.emit(sink, emit_info, state);34913492// Emit jump table (table of 32-bit offsets).3493sink.bind_label(table_label, &mut state.ctrl_plane);3494let jt_off = sink.cur_offset();3495for &target in targets.iter() {3496let word_off = sink.cur_offset();3497let off_into_table = word_off - jt_off;3498sink.use_label_at_offset(word_off, target, LabelUse::PCRel32);3499sink.put4(off_into_table.swap_bytes());3500}3501}35023503Inst::StackProbeLoop {3504probe_count,3505guard_size,3506} => {3507// Emit the loop start label3508let loop_start = sink.get_label();3509sink.bind_label(loop_start, state.ctrl_plane_mut());35103511// aghi %r15, -GUARD_SIZE3512let inst = Inst::AluRSImm16 {3513alu_op: ALUOp::Add64,3514rd: writable_stack_reg(),3515ri: stack_reg(),3516imm: -guard_size,3517};3518inst.emit(sink, emit_info, state);35193520// mvi 0(%r15), 03521let inst = Inst::StoreImm8 {3522imm: 0,3523mem: MemArg::reg(stack_reg(), MemFlags::trusted()),3524};3525inst.emit(sink, emit_info, state);35263527// brct PROBE_COUNT, LOOP_START3528let opcode = 0xa76; // BRCT3529sink.use_label_at_offset(sink.cur_offset(), loop_start, LabelUse::BranchRI);3530put(sink, &enc_ri_b(opcode, probe_count.to_reg(), 0));3531}35323533&Inst::Unwind { ref inst } => {3534sink.add_unwind(inst.clone());3535}35363537&Inst::DummyUse { .. } => {}35383539&Inst::LabelAddress { dst, label } => {3540let inst = Inst::LoadAddr {3541rd: dst,3542mem: MemArg::Label { target: label },3543};3544inst.emit(sink, emit_info, state);3545}3546}35473548state.clear_post_insn();3549}3550}355135523553