Path: blob/main/cranelift/codegen/src/isa/s390x/inst/emit.rs
3101 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/// VRIk-type instructions.1075///1076/// 47 39 35 31 27 23 15 11 71077/// opcode1 v1 v2 v3 - i5 v4 rxb opcode21078/// 40 36 32 28 24 16 12 8 01079///1080fn enc_vri_k(opcode: u16, i5: u8, v1: Reg, v2: Reg, v3: Reg, v4: Reg) -> [u8; 6] {1081let opcode1 = ((opcode >> 8) & 0xff) as u8;1082let opcode2 = (opcode & 0xff) as u8;1083let rxb = rxb(Some(v1), Some(v2), Some(v3), Some(v4));1084let v1 = machreg_to_vr(v1) & 0x0f;1085let v2 = machreg_to_vr(v2) & 0x0f;1086let v3 = machreg_to_vr(v3) & 0x0f;1087let v4 = machreg_to_vr(v4) & 0x0f;10881089let mut enc: [u8; 6] = [0; 6];1090enc[0] = opcode1;1091enc[1] = v1 << 4 | v2;1092enc[2] = v3 << 4;1093enc[3] = i5;1094enc[4] = v4 << 4 | rxb;1095enc[5] = opcode2;1096enc1097}10981099/// VRRa-type instructions.1100///1101/// 47 39 35 31 23 19 15 11 71102/// opcode1 v1 v2 - m5 m3 m2 rxb opcode21103/// 40 36 32 24 20 16 12 8 01104///1105fn enc_vrr_a(opcode: u16, v1: Reg, v2: Reg, m3: u8, m4: u8, m5: u8) -> [u8; 6] {1106let opcode1 = ((opcode >> 8) & 0xff) as u8;1107let opcode2 = (opcode & 0xff) as u8;1108let rxb = rxb(Some(v1), Some(v2), None, None);1109let v1 = machreg_to_vr(v1) & 0x0f;1110let v2 = machreg_to_vr(v2) & 0x0f;1111let m3 = m3 & 0x0f;1112let m4 = m4 & 0x0f;1113let m5 = m5 & 0x0f;11141115let mut enc: [u8; 6] = [0; 6];1116enc[0] = opcode1;1117enc[1] = v1 << 4 | v2;1118enc[2] = 0;1119enc[3] = m5 << 4 | m4;1120enc[4] = m3 << 4 | rxb;1121enc[5] = opcode2;1122enc1123}11241125/// VRRb-type instructions.1126///1127/// 47 39 35 31 27 23 19 15 11 71128/// opcode1 v1 v2 v3 - m5 - m4 rxb opcode21129/// 40 36 32 28 24 20 16 12 8 01130///1131fn enc_vrr_b(opcode: u16, v1: Reg, v2: Reg, v3: Reg, m4: u8, m5: u8) -> [u8; 6] {1132let opcode1 = ((opcode >> 8) & 0xff) as u8;1133let opcode2 = (opcode & 0xff) as u8;1134let rxb = rxb(Some(v1), Some(v2), Some(v3), None);1135let v1 = machreg_to_vr(v1) & 0x0f;1136let v2 = machreg_to_vr(v2) & 0x0f;1137let v3 = machreg_to_vr(v3) & 0x0f;1138let m4 = m4 & 0x0f;1139let m5 = m5 & 0x0f;11401141let mut enc: [u8; 6] = [0; 6];1142enc[0] = opcode1;1143enc[1] = v1 << 4 | v2;1144enc[2] = v3 << 4;1145enc[3] = m5 << 4;1146enc[4] = m4 << 4 | rxb;1147enc[5] = opcode2;1148enc1149}11501151/// VRRc-type instructions.1152///1153/// 47 39 35 31 27 23 19 15 11 71154/// opcode1 v1 v2 v3 - m6 m5 m4 rxb opcode21155/// 40 36 32 28 24 20 16 12 8 01156///1157fn enc_vrr_c(opcode: u16, v1: Reg, v2: Reg, v3: Reg, m4: u8, m5: u8, m6: u8) -> [u8; 6] {1158let opcode1 = ((opcode >> 8) & 0xff) as u8;1159let opcode2 = (opcode & 0xff) as u8;1160let rxb = rxb(Some(v1), Some(v2), Some(v3), None);1161let v1 = machreg_to_vr(v1) & 0x0f;1162let v2 = machreg_to_vr(v2) & 0x0f;1163let v3 = machreg_to_vr(v3) & 0x0f;1164let m4 = m4 & 0x0f;1165let m5 = m5 & 0x0f;1166let m6 = m6 & 0x0f;11671168let mut enc: [u8; 6] = [0; 6];1169enc[0] = opcode1;1170enc[1] = v1 << 4 | v2;1171enc[2] = v3 << 4;1172enc[3] = m6 << 4 | m5;1173enc[4] = m4 << 4 | rxb;1174enc[5] = opcode2;1175enc1176}11771178/// VRRd-type instructions.1179///1180/// 47 39 35 31 27 23 19 15 11 71181/// opcode1 v1 v2 v3 m5 m6 - v4 rxb opcode21182/// 40 36 32 28 24 20 16 12 8 01183///1184fn enc_vrr_d(opcode: u16, v1: Reg, v2: Reg, v3: Reg, v4: Reg, m5: u8, m6: u8) -> [u8; 6] {1185let opcode1 = ((opcode >> 8) & 0xff) as u8;1186let opcode2 = (opcode & 0xff) as u8;1187let rxb = rxb(Some(v1), Some(v2), Some(v3), Some(v4));1188let v1 = machreg_to_vr(v1) & 0x0f;1189let v2 = machreg_to_vr(v2) & 0x0f;1190let v3 = machreg_to_vr(v3) & 0x0f;1191let v4 = machreg_to_vr(v4) & 0x0f;1192let m5 = m5 & 0x0f;1193let m6 = m6 & 0x0f;11941195let mut enc: [u8; 6] = [0; 6];1196enc[0] = opcode1;1197enc[1] = v1 << 4 | v2;1198enc[2] = v3 << 4 | m5;1199enc[3] = m6 << 4;1200enc[4] = v4 << 4 | rxb;1201enc[5] = opcode2;1202enc1203}12041205/// VRRe-type instructions.1206///1207/// 47 39 35 31 27 23 19 15 11 71208/// opcode1 v1 v2 v3 m6 - m5 v4 rxb opcode21209/// 40 36 32 28 24 20 16 12 8 01210///1211fn enc_vrr_e(opcode: u16, v1: Reg, v2: Reg, v3: Reg, v4: Reg, m5: u8, m6: u8) -> [u8; 6] {1212let opcode1 = ((opcode >> 8) & 0xff) as u8;1213let opcode2 = (opcode & 0xff) as u8;1214let rxb = rxb(Some(v1), Some(v2), Some(v3), Some(v4));1215let v1 = machreg_to_vr(v1) & 0x0f;1216let v2 = machreg_to_vr(v2) & 0x0f;1217let v3 = machreg_to_vr(v3) & 0x0f;1218let v4 = machreg_to_vr(v4) & 0x0f;1219let m5 = m5 & 0x0f;1220let m6 = m6 & 0x0f;12211222let mut enc: [u8; 6] = [0; 6];1223enc[0] = opcode1;1224enc[1] = v1 << 4 | v2;1225enc[2] = v3 << 4 | m6;1226enc[3] = m5;1227enc[4] = v4 << 4 | rxb;1228enc[5] = opcode2;1229enc1230}12311232/// VRRf-type instructions.1233///1234/// 47 39 35 31 27 11 71235/// opcode1 v1 r2 r3 - rxb opcode21236/// 40 36 32 28 12 8 01237///1238fn enc_vrr_f(opcode: u16, v1: Reg, r2: Reg, r3: Reg) -> [u8; 6] {1239let opcode1 = ((opcode >> 8) & 0xff) as u8;1240let opcode2 = (opcode & 0xff) as u8;1241let rxb = rxb(Some(v1), None, None, None);1242let v1 = machreg_to_vr(v1) & 0x0f;1243let r2 = machreg_to_gpr(r2) & 0x0f;1244let r3 = machreg_to_gpr(r3) & 0x0f;12451246let mut enc: [u8; 6] = [0; 6];1247enc[0] = opcode1;1248enc[1] = v1 << 4 | r2;1249enc[2] = r3 << 4;1250enc[4] = rxb;1251enc[5] = opcode2;1252enc1253}12541255/// VRSa-type instructions.1256///1257/// 47 39 35 31 27 15 11 71258/// opcode1 v1 v3 b2 d2 m4 rxb opcode21259/// 40 36 32 28 16 12 8 01260///1261fn enc_vrs_a(opcode: u16, v1: Reg, b2: Reg, d2: u32, v3: Reg, m4: u8) -> [u8; 6] {1262let opcode1 = ((opcode >> 8) & 0xff) as u8;1263let opcode2 = (opcode & 0xff) as u8;1264let rxb = rxb(Some(v1), Some(v3), None, None);1265let v1 = machreg_to_vr(v1) & 0x0f;1266let b2 = machreg_to_gpr(b2) & 0x0f;1267let v3 = machreg_to_vr(v3) & 0x0f;1268let d2_lo = (d2 & 0xff) as u8;1269let d2_hi = ((d2 >> 8) & 0x0f) as u8;1270let m4 = m4 & 0x0f;12711272let mut enc: [u8; 6] = [0; 6];1273enc[0] = opcode1;1274enc[1] = v1 << 4 | v3;1275enc[2] = b2 << 4 | d2_hi;1276enc[3] = d2_lo;1277enc[4] = m4 << 4 | rxb;1278enc[5] = opcode2;1279enc1280}12811282/// VRSb-type instructions.1283///1284/// 47 39 35 31 27 15 11 71285/// opcode1 v1 r3 b2 d2 m4 rxb opcode21286/// 40 36 32 28 16 12 8 01287///1288fn enc_vrs_b(opcode: u16, v1: Reg, b2: Reg, d2: u32, r3: Reg, m4: u8) -> [u8; 6] {1289let opcode1 = ((opcode >> 8) & 0xff) as u8;1290let opcode2 = (opcode & 0xff) as u8;1291let rxb = rxb(Some(v1), None, None, None);1292let v1 = machreg_to_vr(v1) & 0x0f;1293let b2 = machreg_to_gpr(b2) & 0x0f;1294let r3 = machreg_to_gpr(r3) & 0x0f;1295let d2_lo = (d2 & 0xff) as u8;1296let d2_hi = ((d2 >> 8) & 0x0f) as u8;1297let m4 = m4 & 0x0f;12981299let mut enc: [u8; 6] = [0; 6];1300enc[0] = opcode1;1301enc[1] = v1 << 4 | r3;1302enc[2] = b2 << 4 | d2_hi;1303enc[3] = d2_lo;1304enc[4] = m4 << 4 | rxb;1305enc[5] = opcode2;1306enc1307}13081309/// VRSc-type instructions.1310///1311/// 47 39 35 31 27 15 11 71312/// opcode1 r1 v3 b2 d2 m4 rxb opcode21313/// 40 36 32 28 16 12 8 01314///1315fn enc_vrs_c(opcode: u16, r1: Reg, b2: Reg, d2: u32, v3: Reg, m4: u8) -> [u8; 6] {1316let opcode1 = ((opcode >> 8) & 0xff) as u8;1317let opcode2 = (opcode & 0xff) as u8;1318let rxb = rxb(None, Some(v3), None, None);1319let r1 = machreg_to_gpr(r1) & 0x0f;1320let b2 = machreg_to_gpr(b2) & 0x0f;1321let v3 = machreg_to_vr(v3) & 0x0f;1322let d2_lo = (d2 & 0xff) as u8;1323let d2_hi = ((d2 >> 8) & 0x0f) as u8;1324let m4 = m4 & 0x0f;13251326let mut enc: [u8; 6] = [0; 6];1327enc[0] = opcode1;1328enc[1] = r1 << 4 | v3;1329enc[2] = b2 << 4 | d2_hi;1330enc[3] = d2_lo;1331enc[4] = m4 << 4 | rxb;1332enc[5] = opcode2;1333enc1334}13351336/// VRX-type instructions.1337///1338/// 47 39 35 31 27 15 11 71339/// opcode1 v1 x2 b2 d2 m3 rxb opcode21340/// 40 36 32 28 16 12 8 01341///1342fn enc_vrx(opcode: u16, v1: Reg, b2: Reg, x2: Reg, d2: u32, m3: u8) -> [u8; 6] {1343let opcode1 = ((opcode >> 8) & 0xff) as u8;1344let opcode2 = (opcode & 0xff) as u8;1345let rxb = rxb(Some(v1), None, None, None);1346let v1 = machreg_to_vr(v1) & 0x0f;1347let b2 = machreg_to_gpr(b2) & 0x0f;1348let x2 = machreg_to_gpr(x2) & 0x0f;1349let d2_lo = (d2 & 0xff) as u8;1350let d2_hi = ((d2 >> 8) & 0x0f) as u8;1351let m3 = m3 & 0x0f;13521353let mut enc: [u8; 6] = [0; 6];1354enc[0] = opcode1;1355enc[1] = v1 << 4 | x2;1356enc[2] = b2 << 4 | d2_hi;1357enc[3] = d2_lo;1358enc[4] = m3 << 4 | rxb;1359enc[5] = opcode2;1360enc1361}13621363/// Emit encoding to sink.1364fn put(sink: &mut MachBuffer<Inst>, enc: &[u8]) {1365for byte in enc {1366sink.put1(*byte);1367}1368}13691370/// Emit encoding to sink, adding a trap on the last byte.1371fn put_with_trap(sink: &mut MachBuffer<Inst>, enc: &[u8], trap_code: TrapCode) {1372let len = enc.len();1373for i in 0..len - 1 {1374sink.put1(enc[i]);1375}1376sink.add_trap(trap_code);1377sink.put1(enc[len - 1]);1378}13791380/// State carried between emissions of a sequence of instructions.1381#[derive(Default, Clone, Debug)]1382pub struct EmitState {1383/// Offset from the actual SP to the "nominal SP". The latter is defined1384/// as the value the stack pointer has after the prolog. This offset is1385/// normally always zero, except during a call sequence using the tail-call1386/// ABI, between the AllocateArgs and the actual call instruction.1387pub(crate) nominal_sp_offset: u32,13881389/// Offset from the actual SP to the SP during an outgoing function call.1390/// This is normally always zero, except during processing of the return1391/// argument handling after a call using the tail-call ABI has returned.1392pub(crate) outgoing_sp_offset: u32,13931394/// Size of the incoming argument area in the caller's frame. Always zero1395/// for functions using the tail-call ABI.1396pub(crate) incoming_args_size: u32,13971398/// The user stack map for the upcoming instruction, as provided to1399/// `pre_safepoint()`.1400user_stack_map: Option<ir::UserStackMap>,14011402/// Only used during fuzz-testing. Otherwise, it is a zero-sized struct and1403/// optimized away at compiletime. See [cranelift_control].1404ctrl_plane: ControlPlane,14051406frame_layout: FrameLayout,1407}14081409impl MachInstEmitState<Inst> for EmitState {1410fn new(abi: &Callee<S390xMachineDeps>, ctrl_plane: ControlPlane) -> Self {1411let incoming_args_size = if abi.call_conv() == CallConv::Tail {141201413} else {1414abi.frame_layout().incoming_args_size1415};1416EmitState {1417nominal_sp_offset: 0,1418outgoing_sp_offset: 0,1419incoming_args_size,1420user_stack_map: None,1421ctrl_plane,1422frame_layout: abi.frame_layout().clone(),1423}1424}14251426fn pre_safepoint(&mut self, user_stack_map: Option<ir::UserStackMap>) {1427self.user_stack_map = user_stack_map;1428}14291430fn ctrl_plane_mut(&mut self) -> &mut ControlPlane {1431&mut self.ctrl_plane1432}14331434fn take_ctrl_plane(self) -> ControlPlane {1435self.ctrl_plane1436}14371438fn frame_layout(&self) -> &FrameLayout {1439&self.frame_layout1440}1441}14421443impl EmitState {1444fn take_stack_map(&mut self) -> Option<ir::UserStackMap> {1445self.user_stack_map.take()1446}14471448fn clear_post_insn(&mut self) {1449self.user_stack_map = None;1450}1451}14521453/// Constant state used during function compilation.1454pub struct EmitInfo {1455isa_flags: s390x_settings::Flags,1456}14571458impl EmitInfo {1459pub(crate) fn new(isa_flags: s390x_settings::Flags) -> Self {1460Self { isa_flags }1461}1462}14631464impl MachInstEmit for Inst {1465type State = EmitState;1466type Info = EmitInfo;14671468fn emit(&self, sink: &mut MachBuffer<Inst>, emit_info: &Self::Info, state: &mut EmitState) {1469self.emit_with_alloc_consumer(sink, emit_info, state)1470}14711472fn pretty_print_inst(&self, state: &mut EmitState) -> String {1473self.print_with_state(state)1474}1475}14761477impl Inst {1478fn emit_with_alloc_consumer(1479&self,1480sink: &mut MachBuffer<Inst>,1481emit_info: &EmitInfo,1482state: &mut EmitState,1483) {1484// Verify that we can emit this Inst in the current ISA1485let matches_isa_flags = |iset_requirement: &InstructionSet| -> bool {1486match iset_requirement {1487// Baseline ISA is z141488InstructionSet::Base => true,1489// Miscellaneous-Instruction-Extensions Facility 3 (z15)1490InstructionSet::MIE3 => emit_info.isa_flags.has_mie3(),1491// Miscellaneous-Instruction-Extensions Facility 4 (z17)1492InstructionSet::MIE4 => emit_info.isa_flags.has_mie4(),1493// Vector-Enhancements Facility 2 (z15)1494InstructionSet::VXRS_EXT2 => emit_info.isa_flags.has_vxrs_ext2(),1495// Vector-Enhancements Facility 3 (z17)1496InstructionSet::VXRS_EXT3 => emit_info.isa_flags.has_vxrs_ext3(),1497}1498};1499let isa_requirements = self.available_in_isa();1500if !matches_isa_flags(&isa_requirements) {1501panic!(1502"Cannot emit inst '{self:?}' for target; failed to match ISA requirements: {isa_requirements:?}"1503)1504}15051506match self {1507&Inst::AluRRR { alu_op, rd, rn, rm } => {1508let (opcode, have_rr) = match alu_op {1509ALUOp::Add32 => (0xb9f8, true), // ARK1510ALUOp::Add64 => (0xb9e8, true), // AGRK1511ALUOp::AddLogical32 => (0xb9fa, true), // ALRK1512ALUOp::AddLogical64 => (0xb9ea, true), // ALGRK1513ALUOp::Sub32 => (0xb9f9, true), // SRK1514ALUOp::Sub64 => (0xb9e9, true), // SGRK1515ALUOp::SubLogical32 => (0xb9fb, true), // SLRK1516ALUOp::SubLogical64 => (0xb9eb, true), // SLGRK1517ALUOp::Mul32 => (0xb9fd, true), // MSRKC1518ALUOp::Mul64 => (0xb9ed, true), // MSGRKC1519ALUOp::And32 => (0xb9f4, true), // NRK1520ALUOp::And64 => (0xb9e4, true), // NGRK1521ALUOp::Orr32 => (0xb9f6, true), // ORK1522ALUOp::Orr64 => (0xb9e6, true), // OGRK1523ALUOp::Xor32 => (0xb9f7, true), // XRK1524ALUOp::Xor64 => (0xb9e7, true), // XGRK1525ALUOp::NotAnd32 => (0xb974, false), // NNRK1526ALUOp::NotAnd64 => (0xb964, false), // NNGRK1527ALUOp::NotOrr32 => (0xb976, false), // NORK1528ALUOp::NotOrr64 => (0xb966, false), // NOGRK1529ALUOp::NotXor32 => (0xb977, false), // NXRK1530ALUOp::NotXor64 => (0xb967, false), // NXGRK1531ALUOp::AndNot32 => (0xb9f5, false), // NCRK1532ALUOp::AndNot64 => (0xb9e5, false), // NCGRK1533ALUOp::OrrNot32 => (0xb975, false), // OCRK1534ALUOp::OrrNot64 => (0xb965, false), // OCGRK1535_ => unreachable!(),1536};1537if have_rr && rd.to_reg() == rn {1538let inst = Inst::AluRR {1539alu_op,1540rd,1541ri: rn,1542rm,1543};1544inst.emit(sink, emit_info, state);1545} else {1546put(sink, &enc_rrf_ab(opcode, rd.to_reg(), rn, rm, 0));1547}1548}1549&Inst::AluRRSImm16 {1550alu_op,1551rd,1552rn,1553imm,1554} => {1555if rd.to_reg() == rn {1556let inst = Inst::AluRSImm16 {1557alu_op,1558rd,1559ri: rn,1560imm,1561};1562inst.emit(sink, emit_info, state);1563} else {1564let opcode = match alu_op {1565ALUOp::Add32 => 0xecd8, // AHIK1566ALUOp::Add64 => 0xecd9, // AGHIK1567_ => unreachable!(),1568};1569put(sink, &enc_rie_d(opcode, rd.to_reg(), rn, imm as u16));1570}1571}1572&Inst::AluRR { alu_op, rd, ri, rm } => {1573debug_assert_eq!(rd.to_reg(), ri);15741575let (opcode, is_rre) = match alu_op {1576ALUOp::Add32 => (0x1a, false), // AR1577ALUOp::Add64 => (0xb908, true), // AGR1578ALUOp::Add64Ext32 => (0xb918, true), // AGFR1579ALUOp::AddLogical32 => (0x1e, false), // ALR1580ALUOp::AddLogical64 => (0xb90a, true), // ALGR1581ALUOp::AddLogical64Ext32 => (0xb91a, true), // ALGFR1582ALUOp::Sub32 => (0x1b, false), // SR1583ALUOp::Sub64 => (0xb909, true), // SGR1584ALUOp::Sub64Ext32 => (0xb919, true), // SGFR1585ALUOp::SubLogical32 => (0x1f, false), // SLR1586ALUOp::SubLogical64 => (0xb90b, true), // SLGR1587ALUOp::SubLogical64Ext32 => (0xb91b, true), // SLGFR1588ALUOp::Mul32 => (0xb252, true), // MSR1589ALUOp::Mul64 => (0xb90c, true), // MSGR1590ALUOp::Mul64Ext32 => (0xb91c, true), // MSGFR1591ALUOp::And32 => (0x14, false), // NR1592ALUOp::And64 => (0xb980, true), // NGR1593ALUOp::Orr32 => (0x16, false), // OR1594ALUOp::Orr64 => (0xb981, true), // OGR1595ALUOp::Xor32 => (0x17, false), // XR1596ALUOp::Xor64 => (0xb982, true), // XGR1597_ => unreachable!(),1598};1599if is_rre {1600put(sink, &enc_rre(opcode, rd.to_reg(), rm));1601} else {1602put(sink, &enc_rr(opcode, rd.to_reg(), rm));1603}1604}1605&Inst::AluRX {1606alu_op,1607rd,1608ri,1609ref mem,1610} => {1611debug_assert_eq!(rd.to_reg(), ri);1612let mem = mem.clone();16131614let (opcode_rx, opcode_rxy) = match alu_op {1615ALUOp::Add32 => (Some(0x5a), Some(0xe35a)), // A(Y)1616ALUOp::Add32Ext16 => (Some(0x4a), Some(0xe37a)), // AH(Y)1617ALUOp::Add64 => (None, Some(0xe308)), // AG1618ALUOp::Add64Ext16 => (None, Some(0xe338)), // AGH1619ALUOp::Add64Ext32 => (None, Some(0xe318)), // AGF1620ALUOp::AddLogical32 => (Some(0x5e), Some(0xe35e)), // AL(Y)1621ALUOp::AddLogical64 => (None, Some(0xe30a)), // ALG1622ALUOp::AddLogical64Ext32 => (None, Some(0xe31a)), // ALGF1623ALUOp::Sub32 => (Some(0x5b), Some(0xe35b)), // S(Y)1624ALUOp::Sub32Ext16 => (Some(0x4b), Some(0xe37b)), // SH(Y)1625ALUOp::Sub64 => (None, Some(0xe309)), // SG1626ALUOp::Sub64Ext16 => (None, Some(0xe339)), // SGH1627ALUOp::Sub64Ext32 => (None, Some(0xe319)), // SGF1628ALUOp::SubLogical32 => (Some(0x5f), Some(0xe35f)), // SL(Y)1629ALUOp::SubLogical64 => (None, Some(0xe30b)), // SLG1630ALUOp::SubLogical64Ext32 => (None, Some(0xe31b)), // SLGF1631ALUOp::Mul32 => (Some(0x71), Some(0xe351)), // MS(Y)1632ALUOp::Mul32Ext16 => (Some(0x4c), Some(0xe37c)), // MH(Y)1633ALUOp::Mul64 => (None, Some(0xe30c)), // MSG1634ALUOp::Mul64Ext16 => (None, Some(0xe33c)), // MSH1635ALUOp::Mul64Ext32 => (None, Some(0xe31c)), // MSGF1636ALUOp::And32 => (Some(0x54), Some(0xe354)), // N(Y)1637ALUOp::And64 => (None, Some(0xe380)), // NG1638ALUOp::Orr32 => (Some(0x56), Some(0xe356)), // O(Y)1639ALUOp::Orr64 => (None, Some(0xe381)), // OG1640ALUOp::Xor32 => (Some(0x57), Some(0xe357)), // X(Y)1641ALUOp::Xor64 => (None, Some(0xe382)), // XG1642_ => unreachable!(),1643};1644let rd = rd.to_reg();1645mem_emit(1646rd, &mem, opcode_rx, opcode_rxy, None, true, sink, emit_info, state,1647);1648}1649&Inst::AluRSImm16 {1650alu_op,1651rd,1652ri,1653imm,1654} => {1655debug_assert_eq!(rd.to_reg(), ri);16561657let opcode = match alu_op {1658ALUOp::Add32 => 0xa7a, // AHI1659ALUOp::Add64 => 0xa7b, // AGHI1660ALUOp::Mul32 => 0xa7c, // MHI1661ALUOp::Mul64 => 0xa7d, // MGHI1662_ => unreachable!(),1663};1664put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16));1665}1666&Inst::AluRSImm32 {1667alu_op,1668rd,1669ri,1670imm,1671} => {1672debug_assert_eq!(rd.to_reg(), ri);16731674let opcode = match alu_op {1675ALUOp::Add32 => 0xc29, // AFI1676ALUOp::Add64 => 0xc28, // AGFI1677ALUOp::Mul32 => 0xc21, // MSFI1678ALUOp::Mul64 => 0xc20, // MSGFI1679_ => unreachable!(),1680};1681put(sink, &enc_ril_a(opcode, rd.to_reg(), imm as u32));1682}1683&Inst::AluRUImm32 {1684alu_op,1685rd,1686ri,1687imm,1688} => {1689debug_assert_eq!(rd.to_reg(), ri);16901691let opcode = match alu_op {1692ALUOp::AddLogical32 => 0xc2b, // ALFI1693ALUOp::AddLogical64 => 0xc2a, // ALGFI1694ALUOp::SubLogical32 => 0xc25, // SLFI1695ALUOp::SubLogical64 => 0xc24, // SLGFI1696_ => unreachable!(),1697};1698put(sink, &enc_ril_a(opcode, rd.to_reg(), imm));1699}1700&Inst::AluRUImm16Shifted {1701alu_op,1702rd,1703ri,1704imm,1705} => {1706debug_assert_eq!(rd.to_reg(), ri);17071708let opcode = match (alu_op, imm.shift) {1709(ALUOp::And32, 0) => 0xa57, // NILL1710(ALUOp::And32, 1) => 0xa56, // NILH1711(ALUOp::And64, 0) => 0xa57, // NILL1712(ALUOp::And64, 1) => 0xa56, // NILH1713(ALUOp::And64, 2) => 0xa55, // NIHL1714(ALUOp::And64, 3) => 0xa54, // NIHL1715(ALUOp::Orr32, 0) => 0xa5b, // OILL1716(ALUOp::Orr32, 1) => 0xa5a, // OILH1717(ALUOp::Orr64, 0) => 0xa5b, // OILL1718(ALUOp::Orr64, 1) => 0xa5a, // OILH1719(ALUOp::Orr64, 2) => 0xa59, // OIHL1720(ALUOp::Orr64, 3) => 0xa58, // OIHH1721_ => unreachable!(),1722};1723put(sink, &enc_ri_a(opcode, rd.to_reg(), imm.bits));1724}1725&Inst::AluRUImm32Shifted {1726alu_op,1727rd,1728ri,1729imm,1730} => {1731debug_assert_eq!(rd.to_reg(), ri);17321733let opcode = match (alu_op, imm.shift) {1734(ALUOp::And32, 0) => 0xc0b, // NILF1735(ALUOp::And64, 0) => 0xc0b, // NILF1736(ALUOp::And64, 1) => 0xc0a, // NIHF1737(ALUOp::Orr32, 0) => 0xc0d, // OILF1738(ALUOp::Orr64, 0) => 0xc0d, // OILF1739(ALUOp::Orr64, 1) => 0xc0c, // OILF1740(ALUOp::Xor32, 0) => 0xc07, // XILF1741(ALUOp::Xor64, 0) => 0xc07, // XILF1742(ALUOp::Xor64, 1) => 0xc06, // XILH1743_ => unreachable!(),1744};1745put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits));1746}17471748&Inst::SMulWide { rd, rn, rm } => {1749let rd1 = rd.hi;1750let rd2 = rd.lo;1751debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());17521753let opcode = 0xb9ec; // MGRK1754put(sink, &enc_rrf_ab(opcode, rd1.to_reg(), rn, rm, 0));1755}1756&Inst::UMulWide { rd, ri, rn } => {1757let rd1 = rd.hi;1758let rd2 = rd.lo;1759debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());1760debug_assert_eq!(rd2.to_reg(), ri);17611762let opcode = 0xb986; // MLGR1763put(sink, &enc_rre(opcode, rd1.to_reg(), rn));1764}1765&Inst::SDivMod32 { rd, ri, rn } => {1766let rd1 = rd.hi;1767let rd2 = rd.lo;1768debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());1769debug_assert_eq!(rd2.to_reg(), ri);17701771let opcode = 0xb91d; // DSGFR1772let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;1773put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);1774}1775&Inst::SDivMod64 { rd, ri, rn } => {1776let rd1 = rd.hi;1777let rd2 = rd.lo;1778debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());1779debug_assert_eq!(rd2.to_reg(), ri);17801781let opcode = 0xb90d; // DSGR1782let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;1783put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);1784}1785&Inst::UDivMod32 { rd, ri, rn } => {1786let rd1 = rd.hi;1787let rd2 = rd.lo;1788debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());1789let ri1 = ri.hi;1790let ri2 = ri.lo;1791debug_assert_eq!(rd1.to_reg(), ri1);1792debug_assert_eq!(rd2.to_reg(), ri2);17931794let opcode = 0xb997; // DLR1795let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;1796put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);1797}1798&Inst::UDivMod64 { rd, ri, rn } => {1799let rd1 = rd.hi;1800let rd2 = rd.lo;1801debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());1802let ri1 = ri.hi;1803let ri2 = ri.lo;1804debug_assert_eq!(rd1.to_reg(), ri1);1805debug_assert_eq!(rd2.to_reg(), ri2);18061807let opcode = 0xb987; // DLGR1808let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;1809put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);1810}1811&Inst::Flogr { rd, rn } => {1812let rd1 = rd.hi;1813let rd2 = rd.lo;1814debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());18151816let opcode = 0xb983; // FLOGR1817put(sink, &enc_rre(opcode, rd1.to_reg(), rn));1818}18191820&Inst::ShiftRR {1821shift_op,1822rd,1823rn,1824shift_imm,1825shift_reg,1826} => {1827let opcode = match shift_op {1828ShiftOp::RotL32 => 0xeb1d, // RLL1829ShiftOp::RotL64 => 0xeb1c, // RLLG1830ShiftOp::LShL32 => 0xebdf, // SLLK (SLL ?)1831ShiftOp::LShL64 => 0xeb0d, // SLLG1832ShiftOp::LShR32 => 0xebde, // SRLK (SRL ?)1833ShiftOp::LShR64 => 0xeb0c, // SRLG1834ShiftOp::AShR32 => 0xebdc, // SRAK (SRA ?)1835ShiftOp::AShR64 => 0xeb0a, // SRAG1836};1837put(1838sink,1839&enc_rsy(opcode, rd.to_reg(), rn, shift_reg, shift_imm.into()),1840);1841}18421843&Inst::RxSBG {1844op,1845rd,1846ri,1847rn,1848start_bit,1849end_bit,1850rotate_amt,1851} => {1852debug_assert_eq!(rd.to_reg(), ri);18531854let opcode = match op {1855RxSBGOp::Insert => 0xec59, // RISBGN1856RxSBGOp::And => 0xec54, // RNSBG1857RxSBGOp::Or => 0xec56, // ROSBG1858RxSBGOp::Xor => 0xec57, // RXSBG1859};1860put(1861sink,1862&enc_rie_f(1863opcode,1864rd.to_reg(),1865rn,1866start_bit,1867end_bit,1868(rotate_amt as u8) & 63,1869),1870);1871}18721873&Inst::RxSBGTest {1874op,1875rd,1876rn,1877start_bit,1878end_bit,1879rotate_amt,1880} => {1881let opcode = match op {1882RxSBGOp::And => 0xec54, // RNSBG1883RxSBGOp::Or => 0xec56, // ROSBG1884RxSBGOp::Xor => 0xec57, // RXSBG1885_ => unreachable!(),1886};1887put(1888sink,1889&enc_rie_f(1890opcode,1891rd,1892rn,1893start_bit | 0x80,1894end_bit,1895(rotate_amt as u8) & 63,1896),1897);1898}18991900&Inst::UnaryRR { op, rd, rn } => {1901match op {1902UnaryOp::Abs32 => {1903let opcode = 0x10; // LPR1904put(sink, &enc_rr(opcode, rd.to_reg(), rn));1905}1906UnaryOp::Abs64 => {1907let opcode = 0xb900; // LPGR1908put(sink, &enc_rre(opcode, rd.to_reg(), rn));1909}1910UnaryOp::Abs64Ext32 => {1911let opcode = 0xb910; // LPGFR1912put(sink, &enc_rre(opcode, rd.to_reg(), rn));1913}1914UnaryOp::Neg32 => {1915let opcode = 0x13; // LCR1916put(sink, &enc_rr(opcode, rd.to_reg(), rn));1917}1918UnaryOp::Neg64 => {1919let opcode = 0xb903; // LCGR1920put(sink, &enc_rre(opcode, rd.to_reg(), rn));1921}1922UnaryOp::Neg64Ext32 => {1923let opcode = 0xb913; // LCGFR1924put(sink, &enc_rre(opcode, rd.to_reg(), rn));1925}1926UnaryOp::PopcntByte => {1927let opcode = 0xb9e1; // POPCNT1928put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rn, 0, 0));1929}1930UnaryOp::PopcntReg => {1931let opcode = 0xb9e1; // POPCNT1932put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rn, 8, 0));1933}1934UnaryOp::BSwap32 => {1935let opcode = 0xb91f; // LRVR1936put(sink, &enc_rre(opcode, rd.to_reg(), rn));1937}1938UnaryOp::BSwap64 => {1939let opcode = 0xb90f; // LRVRG1940put(sink, &enc_rre(opcode, rd.to_reg(), rn));1941}1942UnaryOp::Clz64 => {1943let opcode = 0xb968; // CLZG1944put(sink, &enc_rre(opcode, rd.to_reg(), rn));1945}1946UnaryOp::Ctz64 => {1947let opcode = 0xb969; // CTZG1948put(sink, &enc_rre(opcode, rd.to_reg(), rn));1949}1950}1951}19521953&Inst::Extend {1954rd,1955rn,1956signed,1957from_bits,1958to_bits,1959} => {1960let opcode = match (signed, from_bits, to_bits) {1961(_, 1, 32) => 0xb926, // LBR1962(_, 1, 64) => 0xb906, // LGBR1963(false, 8, 32) => 0xb994, // LLCR1964(false, 8, 64) => 0xb984, // LLGCR1965(true, 8, 32) => 0xb926, // LBR1966(true, 8, 64) => 0xb906, // LGBR1967(false, 16, 32) => 0xb995, // LLHR1968(false, 16, 64) => 0xb985, // LLGHR1969(true, 16, 32) => 0xb927, // LHR1970(true, 16, 64) => 0xb907, // LGHR1971(false, 32, 64) => 0xb916, // LLGFR1972(true, 32, 64) => 0xb914, // LGFR1973_ => panic!(1974"Unsupported extend combination: signed = {signed}, from_bits = {from_bits}, to_bits = {to_bits}"1975),1976};1977put(sink, &enc_rre(opcode, rd.to_reg(), rn));1978}19791980&Inst::CmpRR { op, rn, rm } => {1981let (opcode, is_rre) = match op {1982CmpOp::CmpS32 => (0x19, false), // CR1983CmpOp::CmpS64 => (0xb920, true), // CGR1984CmpOp::CmpS64Ext32 => (0xb930, true), // CGFR1985CmpOp::CmpL32 => (0x15, false), // CLR1986CmpOp::CmpL64 => (0xb921, true), // CLGR1987CmpOp::CmpL64Ext32 => (0xb931, true), // CLGFR1988_ => unreachable!(),1989};1990if is_rre {1991put(sink, &enc_rre(opcode, rn, rm));1992} else {1993put(sink, &enc_rr(opcode, rn, rm));1994}1995}1996&Inst::CmpRX { op, rn, ref mem } => {1997let mem = mem.clone();19981999let (opcode_rx, opcode_rxy, opcode_ril) = match op {2000CmpOp::CmpS32 => (Some(0x59), Some(0xe359), Some(0xc6d)), // C(Y), CRL2001CmpOp::CmpS32Ext16 => (Some(0x49), Some(0xe379), Some(0xc65)), // CH(Y), CHRL2002CmpOp::CmpS64 => (None, Some(0xe320), Some(0xc68)), // CG, CGRL2003CmpOp::CmpS64Ext16 => (None, Some(0xe334), Some(0xc64)), // CGH, CGHRL2004CmpOp::CmpS64Ext32 => (None, Some(0xe330), Some(0xc6c)), // CGF, CGFRL2005CmpOp::CmpL32 => (Some(0x55), Some(0xe355), Some(0xc6f)), // CL(Y), CLRL2006CmpOp::CmpL32Ext16 => (None, None, Some(0xc67)), // CLHRL2007CmpOp::CmpL64 => (None, Some(0xe321), Some(0xc6a)), // CLG, CLGRL2008CmpOp::CmpL64Ext16 => (None, None, Some(0xc66)), // CLGHRL2009CmpOp::CmpL64Ext32 => (None, Some(0xe331), Some(0xc6e)), // CLGF, CLGFRL2010};2011mem_emit(2012rn, &mem, opcode_rx, opcode_rxy, opcode_ril, true, sink, emit_info, state,2013);2014}2015&Inst::CmpRSImm16 { op, rn, imm } => {2016let opcode = match op {2017CmpOp::CmpS32 => 0xa7e, // CHI2018CmpOp::CmpS64 => 0xa7f, // CGHI2019_ => unreachable!(),2020};2021put(sink, &enc_ri_a(opcode, rn, imm as u16));2022}2023&Inst::CmpRSImm32 { op, rn, imm } => {2024let opcode = match op {2025CmpOp::CmpS32 => 0xc2d, // CFI2026CmpOp::CmpS64 => 0xc2c, // CGFI2027_ => unreachable!(),2028};2029put(sink, &enc_ril_a(opcode, rn, imm as u32));2030}2031&Inst::CmpRUImm32 { op, rn, imm } => {2032let opcode = match op {2033CmpOp::CmpL32 => 0xc2f, // CLFI2034CmpOp::CmpL64 => 0xc2e, // CLGFI2035_ => unreachable!(),2036};2037put(sink, &enc_ril_a(opcode, rn, imm));2038}2039&Inst::CmpTrapRR {2040op,2041rn,2042rm,2043cond,2044trap_code,2045} => {2046let opcode = match op {2047CmpOp::CmpS32 => 0xb972, // CRT2048CmpOp::CmpS64 => 0xb960, // CGRT2049CmpOp::CmpL32 => 0xb973, // CLRT2050CmpOp::CmpL64 => 0xb961, // CLGRT2051_ => unreachable!(),2052};2053put_with_trap(2054sink,2055&enc_rrf_cde(opcode, rn, rm, cond.bits(), 0),2056trap_code,2057);2058}2059&Inst::CmpTrapRSImm16 {2060op,2061rn,2062imm,2063cond,2064trap_code,2065} => {2066let opcode = match op {2067CmpOp::CmpS32 => 0xec72, // CIT2068CmpOp::CmpS64 => 0xec70, // CGIT2069_ => unreachable!(),2070};2071put_with_trap(2072sink,2073&enc_rie_a(opcode, rn, imm as u16, cond.bits()),2074trap_code,2075);2076}2077&Inst::CmpTrapRUImm16 {2078op,2079rn,2080imm,2081cond,2082trap_code,2083} => {2084let opcode = match op {2085CmpOp::CmpL32 => 0xec73, // CLFIT2086CmpOp::CmpL64 => 0xec71, // CLGIT2087_ => unreachable!(),2088};2089put_with_trap(sink, &enc_rie_a(opcode, rn, imm, cond.bits()), trap_code);2090}20912092&Inst::AtomicRmw {2093alu_op,2094rd,2095rn,2096ref mem,2097} => {2098let mem = mem.clone();20992100let opcode = match alu_op {2101ALUOp::Add32 => 0xebf8, // LAA2102ALUOp::Add64 => 0xebe8, // LAAG2103ALUOp::AddLogical32 => 0xebfa, // LAAL2104ALUOp::AddLogical64 => 0xebea, // LAALG2105ALUOp::And32 => 0xebf4, // LAN2106ALUOp::And64 => 0xebe4, // LANG2107ALUOp::Orr32 => 0xebf6, // LAO2108ALUOp::Orr64 => 0xebe6, // LAOG2109ALUOp::Xor32 => 0xebf7, // LAX2110ALUOp::Xor64 => 0xebe7, // LAXG2111_ => unreachable!(),2112};21132114let rd = rd.to_reg();2115mem_rs_emit(2116rd,2117rn,2118&mem,2119None,2120Some(opcode),2121true,2122sink,2123emit_info,2124state,2125);2126}2127&Inst::Loop { ref body, cond } => {2128// This sequence is *one* instruction in the vcode, and is expanded only here at2129// emission time, because it requires branching to internal labels.2130let loop_label = sink.get_label();2131let done_label = sink.get_label();21322133// Emit label at the start of the loop.2134sink.bind_label(loop_label, &mut state.ctrl_plane);21352136for inst in (&body).into_iter() {2137match &inst {2138// Replace a CondBreak with a branch to done_label.2139&Inst::CondBreak { cond } => {2140let opcode = 0xc04; // BCRL2141sink.use_label_at_offset(2142sink.cur_offset(),2143done_label,2144LabelUse::BranchRIL,2145);2146put(sink, &enc_ril_c(opcode, cond.bits(), 0));2147}2148_ => inst.emit_with_alloc_consumer(sink, emit_info, state),2149};2150}21512152let opcode = 0xc04; // BCRL2153sink.use_label_at_offset(sink.cur_offset(), loop_label, LabelUse::BranchRIL);2154put(sink, &enc_ril_c(opcode, cond.bits(), 0));21552156// Emit label at the end of the loop.2157sink.bind_label(done_label, &mut state.ctrl_plane);2158}2159&Inst::CondBreak { .. } => unreachable!(), // Only valid inside a Loop.2160&Inst::AtomicCas32 {2161rd,2162ri,2163rn,2164ref mem,2165}2166| &Inst::AtomicCas64 {2167rd,2168ri,2169rn,2170ref mem,2171} => {2172debug_assert_eq!(rd.to_reg(), ri);2173let mem = mem.clone();21742175let (opcode_rs, opcode_rsy) = match self {2176&Inst::AtomicCas32 { .. } => (Some(0xba), Some(0xeb14)), // CS(Y)2177&Inst::AtomicCas64 { .. } => (None, Some(0xeb30)), // CSG2178_ => unreachable!(),2179};21802181let rd = rd.to_reg();2182mem_rs_emit(2183rd, rn, &mem, opcode_rs, opcode_rsy, true, sink, emit_info, state,2184);2185}2186&Inst::Fence => {2187put(sink, &enc_e(0x07e0));2188}21892190&Inst::Load32 { rd, ref mem }2191| &Inst::Load32ZExt8 { rd, ref mem }2192| &Inst::Load32SExt8 { rd, ref mem }2193| &Inst::Load32ZExt16 { rd, ref mem }2194| &Inst::Load32SExt16 { rd, ref mem }2195| &Inst::Load64 { rd, ref mem }2196| &Inst::Load64ZExt8 { rd, ref mem }2197| &Inst::Load64SExt8 { rd, ref mem }2198| &Inst::Load64ZExt16 { rd, ref mem }2199| &Inst::Load64SExt16 { rd, ref mem }2200| &Inst::Load64ZExt32 { rd, ref mem }2201| &Inst::Load64SExt32 { rd, ref mem }2202| &Inst::LoadRev16 { rd, ref mem }2203| &Inst::LoadRev32 { rd, ref mem }2204| &Inst::LoadRev64 { rd, ref mem } => {2205let mem = mem.clone();22062207let (opcode_rx, opcode_rxy, opcode_ril) = match self {2208&Inst::Load32 { .. } => (Some(0x58), Some(0xe358), Some(0xc4d)), // L(Y), LRL2209&Inst::Load32ZExt8 { .. } => (None, Some(0xe394), None), // LLC2210&Inst::Load32SExt8 { .. } => (None, Some(0xe376), None), // LB2211&Inst::Load32ZExt16 { .. } => (None, Some(0xe395), Some(0xc42)), // LLH, LLHRL2212&Inst::Load32SExt16 { .. } => (Some(0x48), Some(0xe378), Some(0xc45)), // LH(Y), LHRL2213&Inst::Load64 { .. } => (None, Some(0xe304), Some(0xc48)), // LG, LGRL2214&Inst::Load64ZExt8 { .. } => (None, Some(0xe390), None), // LLGC2215&Inst::Load64SExt8 { .. } => (None, Some(0xe377), None), // LGB2216&Inst::Load64ZExt16 { .. } => (None, Some(0xe391), Some(0xc46)), // LLGH, LLGHRL2217&Inst::Load64SExt16 { .. } => (None, Some(0xe315), Some(0xc44)), // LGH, LGHRL2218&Inst::Load64ZExt32 { .. } => (None, Some(0xe316), Some(0xc4e)), // LLGF, LLGFRL2219&Inst::Load64SExt32 { .. } => (None, Some(0xe314), Some(0xc4c)), // LGF, LGFRL2220&Inst::LoadRev16 { .. } => (None, Some(0xe31f), None), // LRVH2221&Inst::LoadRev32 { .. } => (None, Some(0xe31e), None), // LRV2222&Inst::LoadRev64 { .. } => (None, Some(0xe30f), None), // LRVG2223_ => unreachable!(),2224};2225let rd = rd.to_reg();2226mem_emit(2227rd, &mem, opcode_rx, opcode_rxy, opcode_ril, true, sink, emit_info, state,2228);2229}22302231&Inst::Store8 { rd, ref mem }2232| &Inst::Store16 { rd, ref mem }2233| &Inst::Store32 { rd, ref mem }2234| &Inst::Store64 { rd, ref mem }2235| &Inst::StoreRev16 { rd, ref mem }2236| &Inst::StoreRev32 { rd, ref mem }2237| &Inst::StoreRev64 { rd, ref mem } => {2238let mem = mem.clone();22392240let (opcode_rx, opcode_rxy, opcode_ril) = match self {2241&Inst::Store8 { .. } => (Some(0x42), Some(0xe372), None), // STC(Y)2242&Inst::Store16 { .. } => (Some(0x40), Some(0xe370), Some(0xc47)), // STH(Y), STHRL2243&Inst::Store32 { .. } => (Some(0x50), Some(0xe350), Some(0xc4f)), // ST(Y), STRL2244&Inst::Store64 { .. } => (None, Some(0xe324), Some(0xc4b)), // STG, STGRL2245&Inst::StoreRev16 { .. } => (None, Some(0xe33f), None), // STRVH2246&Inst::StoreRev32 { .. } => (None, Some(0xe33e), None), // STRV2247&Inst::StoreRev64 { .. } => (None, Some(0xe32f), None), // STRVG2248_ => unreachable!(),2249};2250mem_emit(2251rd, &mem, opcode_rx, opcode_rxy, opcode_ril, true, sink, emit_info, state,2252);2253}2254&Inst::StoreImm8 { imm, ref mem } => {2255let mem = mem.clone();22562257let opcode_si = 0x92; // MVI2258let opcode_siy = 0xeb52; // MVIY2259mem_imm8_emit(2260imm, &mem, opcode_si, opcode_siy, true, sink, emit_info, state,2261);2262}2263&Inst::StoreImm16 { imm, ref mem }2264| &Inst::StoreImm32SExt16 { imm, ref mem }2265| &Inst::StoreImm64SExt16 { imm, ref mem } => {2266let mem = mem.clone();22672268let opcode = match self {2269&Inst::StoreImm16 { .. } => 0xe544, // MVHHI2270&Inst::StoreImm32SExt16 { .. } => 0xe54c, // MVHI2271&Inst::StoreImm64SExt16 { .. } => 0xe548, // MVGHI2272_ => unreachable!(),2273};2274mem_imm16_emit(imm, &mem, opcode, true, sink, emit_info, state);2275}22762277&Inst::LoadMultiple64 { rt, rt2, ref mem } => {2278let mem = mem.clone();22792280let opcode = 0xeb04; // LMG2281let rt = rt.to_reg();2282let rt2 = rt2.to_reg();2283mem_rs_emit(2284rt,2285rt2,2286&mem,2287None,2288Some(opcode),2289true,2290sink,2291emit_info,2292state,2293);2294}2295&Inst::StoreMultiple64 { rt, rt2, ref mem } => {2296let mem = mem.clone();22972298let opcode = 0xeb24; // STMG2299mem_rs_emit(2300rt,2301rt2,2302&mem,2303None,2304Some(opcode),2305true,2306sink,2307emit_info,2308state,2309);2310}23112312&Inst::LoadAddr { rd, ref mem } => {2313let mem = mem.clone();23142315let opcode_rx = Some(0x41); // LA2316let opcode_rxy = Some(0xe371); // LAY2317let opcode_ril = Some(0xc00); // LARL2318let rd = rd.to_reg();2319mem_emit(2320rd, &mem, opcode_rx, opcode_rxy, opcode_ril, false, sink, emit_info, state,2321);2322}23232324&Inst::Mov64 { rd, rm } => {2325let opcode = 0xb904; // LGR2326put(sink, &enc_rre(opcode, rd.to_reg(), rm));2327}2328&Inst::MovPReg { rd, rm } => {2329Inst::Mov64 { rd, rm: rm.into() }.emit(sink, emit_info, state);2330}2331&Inst::Mov32 { rd, rm } => {2332let opcode = 0x18; // LR2333put(sink, &enc_rr(opcode, rd.to_reg(), rm));2334}2335&Inst::Mov32Imm { rd, imm } => {2336let opcode = 0xc09; // IILF2337put(sink, &enc_ril_a(opcode, rd.to_reg(), imm));2338}2339&Inst::Mov32SImm16 { rd, imm } => {2340let opcode = 0xa78; // LHI2341put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16));2342}2343&Inst::Mov64SImm16 { rd, imm } => {2344let opcode = 0xa79; // LGHI2345put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16));2346}2347&Inst::Mov64SImm32 { rd, imm } => {2348let opcode = 0xc01; // LGFI2349put(sink, &enc_ril_a(opcode, rd.to_reg(), imm as u32));2350}2351&Inst::CMov32 { rd, cond, ri, rm } => {2352debug_assert_eq!(rd.to_reg(), ri);23532354let opcode = 0xb9f2; // LOCR2355put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rm, cond.bits(), 0));2356}2357&Inst::CMov64 { rd, cond, ri, rm } => {2358debug_assert_eq!(rd.to_reg(), ri);23592360let opcode = 0xb9e2; // LOCGR2361put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rm, cond.bits(), 0));2362}2363&Inst::CMov32SImm16 { rd, cond, ri, imm } => {2364debug_assert_eq!(rd.to_reg(), ri);23652366let opcode = 0xec42; // LOCHI2367put(2368sink,2369&enc_rie_g(opcode, rd.to_reg(), imm as u16, cond.bits()),2370);2371}2372&Inst::CMov64SImm16 { rd, cond, ri, imm } => {2373debug_assert_eq!(rd.to_reg(), ri);23742375let opcode = 0xec46; // LOCGHI2376put(2377sink,2378&enc_rie_g(opcode, rd.to_reg(), imm as u16, cond.bits()),2379);2380}2381&Inst::Mov64UImm16Shifted { rd, imm } => {2382let opcode = match imm.shift {23830 => 0xa5f, // LLILL23841 => 0xa5e, // LLILH23852 => 0xa5d, // LLIHL23863 => 0xa5c, // LLIHH2387_ => unreachable!(),2388};2389put(sink, &enc_ri_a(opcode, rd.to_reg(), imm.bits));2390}2391&Inst::Mov64UImm32Shifted { rd, imm } => {2392let opcode = match imm.shift {23930 => 0xc0f, // LLILF23941 => 0xc0e, // LLIHF2395_ => unreachable!(),2396};2397put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits));2398}2399&Inst::Insert64UImm16Shifted { rd, ri, imm } => {2400debug_assert_eq!(rd.to_reg(), ri);24012402let opcode = match imm.shift {24030 => 0xa53, // IILL24041 => 0xa52, // IILH24052 => 0xa51, // IIHL24063 => 0xa50, // IIHH2407_ => unreachable!(),2408};2409put(sink, &enc_ri_a(opcode, rd.to_reg(), imm.bits));2410}2411&Inst::Insert64UImm32Shifted { rd, ri, imm } => {2412debug_assert_eq!(rd.to_reg(), ri);24132414let opcode = match imm.shift {24150 => 0xc09, // IILF24161 => 0xc08, // IIHF2417_ => unreachable!(),2418};2419put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits));2420}2421&Inst::LoadAR { rd, ar } => {2422let opcode = 0xb24f; // EAR2423put(sink, &enc_rre(opcode, rd.to_reg(), gpr(ar)));2424}24252426&Inst::InsertAR { rd, ri, ar } => {2427debug_assert_eq!(rd.to_reg(), ri);24282429let opcode = 0xb24f; // EAR2430put(sink, &enc_rre(opcode, rd.to_reg(), gpr(ar)));2431}2432&Inst::LoadSymbolReloc {2433rd,2434ref symbol_reloc,2435} => {2436let reg = writable_spilltmp_reg().to_reg();2437put(sink, &enc_ri_b(OPCODE_BRAS, reg, 12));2438let (reloc, name, offset) = match &**symbol_reloc {2439SymbolReloc::Absolute { name, offset } => (Reloc::Abs8, name, *offset),2440SymbolReloc::TlsGd { name } => (Reloc::S390xTlsGd64, name, 0),2441};2442sink.add_reloc(reloc, name, offset);2443sink.put8(0);2444let inst = Inst::Load64 {2445rd,2446mem: MemArg::reg(reg, MemFlags::trusted()),2447};2448inst.emit(sink, emit_info, state);2449}24502451&Inst::FpuMove32 { rd, rn } => {2452if is_fpr(rd.to_reg()) && is_fpr(rn) {2453let opcode = 0x38; // LER2454put(sink, &enc_rr(opcode, rd.to_reg(), rn));2455} else {2456put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rn, 0, 0, 0));2457}2458}2459&Inst::FpuMove64 { rd, rn } => {2460if is_fpr(rd.to_reg()) && is_fpr(rn) {2461put(sink, &enc_rr(OPCODE_LDR, rd.to_reg(), rn));2462} else {2463put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rn, 0, 0, 0));2464}2465}2466&Inst::FpuCMov32 { rd, cond, ri, rm } => {2467debug_assert_eq!(rd.to_reg(), ri);24682469if is_fpr(rd.to_reg()) && is_fpr(rm) {2470put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 2));2471let opcode = 0x38; // LER2472put(sink, &enc_rr(opcode, rd.to_reg(), rm));2473} else {2474put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 6));2475put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rm, 0, 0, 0));2476}2477}2478&Inst::FpuCMov64 { rd, cond, ri, rm } => {2479debug_assert_eq!(rd.to_reg(), ri);24802481if is_fpr(rd.to_reg()) && is_fpr(rm) {2482put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 2));2483put(sink, &enc_rr(OPCODE_LDR, rd.to_reg(), rm));2484} else {2485put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 6));2486put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rm, 0, 0, 0));2487}2488}2489&Inst::FpuRR { fpu_op, rd, rn } => {2490let (opcode, m3, m4, m5, opcode_fpr) = match fpu_op {2491FPUOp1::Abs32 => (0xe7cc, 2, 8, 2, Some(0xb300)), // WFPSO, LPEBR2492FPUOp1::Abs64 => (0xe7cc, 3, 8, 2, Some(0xb310)), // WFPSO, LPDBR2493FPUOp1::Abs128 => (0xe7cc, 4, 8, 2, None), // WFPSO2494FPUOp1::Abs32x4 => (0xe7cc, 2, 0, 2, None), // VFPSO2495FPUOp1::Abs64x2 => (0xe7cc, 3, 0, 2, None), // VFPSO2496FPUOp1::Neg32 => (0xe7cc, 2, 8, 0, Some(0xb303)), // WFPSO, LCEBR2497FPUOp1::Neg64 => (0xe7cc, 3, 8, 0, Some(0xb313)), // WFPSO, LCDBR2498FPUOp1::Neg128 => (0xe7cc, 4, 8, 0, None), // WFPSO2499FPUOp1::Neg32x4 => (0xe7cc, 2, 0, 0, None), // VFPSO2500FPUOp1::Neg64x2 => (0xe7cc, 3, 0, 0, None), // VFPSO2501FPUOp1::NegAbs32 => (0xe7cc, 2, 8, 1, Some(0xb301)), // WFPSO, LNEBR2502FPUOp1::NegAbs64 => (0xe7cc, 3, 8, 1, Some(0xb311)), // WFPSO, LNDBR2503FPUOp1::NegAbs128 => (0xe7cc, 4, 8, 1, None), // WFPSO2504FPUOp1::NegAbs32x4 => (0xe7cc, 2, 0, 1, None), // VFPSO2505FPUOp1::NegAbs64x2 => (0xe7cc, 3, 0, 1, None), // VFPSO2506FPUOp1::Sqrt32 => (0xe7ce, 2, 8, 0, Some(0xb314)), // WFSQ, SQEBR2507FPUOp1::Sqrt64 => (0xe7ce, 3, 8, 0, Some(0xb315)), // WFSQ, SQDBR2508FPUOp1::Sqrt128 => (0xe7ce, 4, 8, 0, None), // WFSQ2509FPUOp1::Sqrt32x4 => (0xe7ce, 2, 0, 0, None), // VFSQ2510FPUOp1::Sqrt64x2 => (0xe7ce, 3, 0, 0, None), // VFSQ2511FPUOp1::Cvt32To64 => (0xe7c4, 2, 8, 0, Some(0xb304)), // WFLL, LDEBR2512FPUOp1::Cvt32x4To64x2 => (0xe7c4, 2, 0, 0, None), // VFLL2513FPUOp1::Cvt64To128 => (0xe7c4, 3, 8, 0, None), // WFLL2514};2515if m4 == 8 && opcode_fpr.is_some() && is_fpr(rd.to_reg()) && is_fpr(rn) {2516put(sink, &enc_rre(opcode_fpr.unwrap(), rd.to_reg(), rn));2517} else {2518put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, m3, m4, m5));2519}2520}2521&Inst::FpuRRR { fpu_op, rd, rn, rm } => {2522let (opcode, m4, m5, m6, opcode_fpr) = match fpu_op {2523FPUOp2::Add32 => (0xe7e3, 2, 8, 0, Some(0xb30a)), // WFA, AEBR2524FPUOp2::Add64 => (0xe7e3, 3, 8, 0, Some(0xb31a)), // WFA, ADBR2525FPUOp2::Add128 => (0xe7e3, 4, 8, 0, None), // WFA2526FPUOp2::Add32x4 => (0xe7e3, 2, 0, 0, None), // VFA2527FPUOp2::Add64x2 => (0xe7e3, 3, 0, 0, None), // VFA2528FPUOp2::Sub32 => (0xe7e2, 2, 8, 0, Some(0xb30b)), // WFS, SEBR2529FPUOp2::Sub64 => (0xe7e2, 3, 8, 0, Some(0xb31b)), // WFS, SDBR2530FPUOp2::Sub128 => (0xe7e2, 4, 8, 0, None), // WFS2531FPUOp2::Sub32x4 => (0xe7e2, 2, 0, 0, None), // VFS2532FPUOp2::Sub64x2 => (0xe7e2, 3, 0, 0, None), // VFS2533FPUOp2::Mul32 => (0xe7e7, 2, 8, 0, Some(0xb317)), // WFM, MEEBR2534FPUOp2::Mul64 => (0xe7e7, 3, 8, 0, Some(0xb31c)), // WFM, MDBR2535FPUOp2::Mul128 => (0xe7e7, 4, 8, 0, None), // WFM2536FPUOp2::Mul32x4 => (0xe7e7, 2, 0, 0, None), // VFM2537FPUOp2::Mul64x2 => (0xe7e7, 3, 0, 0, None), // VFM2538FPUOp2::Div32 => (0xe7e5, 2, 8, 0, Some(0xb30d)), // WFD, DEBR2539FPUOp2::Div64 => (0xe7e5, 3, 8, 0, Some(0xb31d)), // WFD, DDBR2540FPUOp2::Div128 => (0xe7e5, 4, 8, 0, None), // WFD2541FPUOp2::Div32x4 => (0xe7e5, 2, 0, 0, None), // VFD2542FPUOp2::Div64x2 => (0xe7e5, 3, 0, 0, None), // VFD2543FPUOp2::Max32 => (0xe7ef, 2, 8, 1, None), // WFMAX2544FPUOp2::Max64 => (0xe7ef, 3, 8, 1, None), // WFMAX2545FPUOp2::Max128 => (0xe7ef, 4, 8, 1, None), // WFMAX2546FPUOp2::Max32x4 => (0xe7ef, 2, 0, 1, None), // VFMAX2547FPUOp2::Max64x2 => (0xe7ef, 3, 0, 1, None), // VFMAX2548FPUOp2::Min32 => (0xe7ee, 2, 8, 1, None), // WFMIN2549FPUOp2::Min64 => (0xe7ee, 3, 8, 1, None), // WFMIN2550FPUOp2::Min128 => (0xe7ee, 4, 8, 1, None), // WFMIN2551FPUOp2::Min32x4 => (0xe7ee, 2, 0, 1, None), // VFMIN2552FPUOp2::Min64x2 => (0xe7ee, 3, 0, 1, None), // VFMIN2553FPUOp2::MaxPseudo32 => (0xe7ef, 2, 8, 3, None), // WFMAX2554FPUOp2::MaxPseudo64 => (0xe7ef, 3, 8, 3, None), // WFMAX2555FPUOp2::MaxPseudo128 => (0xe7ef, 4, 8, 3, None), // WFMAX2556FPUOp2::MaxPseudo32x4 => (0xe7ef, 2, 0, 3, None), // VFMAX2557FPUOp2::MaxPseudo64x2 => (0xe7ef, 3, 0, 3, None), // VFMAX2558FPUOp2::MinPseudo32 => (0xe7ee, 2, 8, 3, None), // WFMIN2559FPUOp2::MinPseudo64 => (0xe7ee, 3, 8, 3, None), // WFMIN2560FPUOp2::MinPseudo128 => (0xe7ee, 4, 8, 3, None), // WFMIN2561FPUOp2::MinPseudo32x4 => (0xe7ee, 2, 0, 3, None), // VFMIN2562FPUOp2::MinPseudo64x2 => (0xe7ee, 3, 0, 3, None), // VFMIN2563};2564if m5 == 8 && opcode_fpr.is_some() && rd.to_reg() == rn && is_fpr(rn) && is_fpr(rm)2565{2566put(sink, &enc_rre(opcode_fpr.unwrap(), rd.to_reg(), rm));2567} else {2568put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, m5, m6));2569}2570}2571&Inst::FpuRRRR {2572fpu_op,2573rd,2574rn,2575rm,2576ra,2577} => {2578let (opcode, m5, m6, opcode_fpr) = match fpu_op {2579FPUOp3::MAdd32 => (0xe78f, 8, 2, Some(0xb30e)), // WFMA, MAEBR2580FPUOp3::MAdd64 => (0xe78f, 8, 3, Some(0xb31e)), // WFMA, MADBR2581FPUOp3::MAdd128 => (0xe78f, 8, 4, None), // WFMA2582FPUOp3::MAdd32x4 => (0xe78f, 0, 2, None), // VFMA2583FPUOp3::MAdd64x2 => (0xe78f, 0, 3, None), // VFMA2584FPUOp3::MSub32 => (0xe78e, 8, 2, Some(0xb30f)), // WFMS, MSEBR2585FPUOp3::MSub64 => (0xe78e, 8, 3, Some(0xb31f)), // WFMS, MSDBR2586FPUOp3::MSub128 => (0xe78e, 8, 4, None), // WFMS2587FPUOp3::MSub32x4 => (0xe78e, 0, 2, None), // VFMS2588FPUOp3::MSub64x2 => (0xe78e, 0, 3, None), // VFMS2589};2590if m5 == 82591&& opcode_fpr.is_some()2592&& rd.to_reg() == ra2593&& is_fpr(rn)2594&& is_fpr(rm)2595&& is_fpr(ra)2596{2597put(sink, &enc_rrd(opcode_fpr.unwrap(), rd.to_reg(), rm, rn));2598} else {2599put(sink, &enc_vrr_e(opcode, rd.to_reg(), rn, rm, ra, m5, m6));2600}2601}2602&Inst::FpuRound { op, mode, rd, rn } => {2603let mode = match mode {2604FpuRoundMode::Current => 0,2605FpuRoundMode::ToNearest => 1,2606FpuRoundMode::ShorterPrecision => 3,2607FpuRoundMode::ToNearestTiesToEven => 4,2608FpuRoundMode::ToZero => 5,2609FpuRoundMode::ToPosInfinity => 6,2610FpuRoundMode::ToNegInfinity => 7,2611};2612let (opcode, m3, m4, opcode_fpr) = match op {2613FpuRoundOp::Cvt64To32 => (0xe7c5, 3, 8, Some(0xb344)), // WFLR, LEDBR(A)2614FpuRoundOp::Cvt64x2To32x4 => (0xe7c5, 3, 0, None), // VFLR2615FpuRoundOp::Cvt128To64 => (0xe7c5, 4, 8, None), // WFLR2616FpuRoundOp::Round32 => (0xe7c7, 2, 8, Some(0xb357)), // WFI, FIEBR2617FpuRoundOp::Round64 => (0xe7c7, 3, 8, Some(0xb35f)), // WFI, FIDBR2618FpuRoundOp::Round128 => (0xe7c7, 4, 8, None), // WFI2619FpuRoundOp::Round32x4 => (0xe7c7, 2, 0, None), // VFI2620FpuRoundOp::Round64x2 => (0xe7c7, 3, 0, None), // VFI2621FpuRoundOp::ToSInt32 => (0xe7c2, 2, 8, None), // WCSFP2622FpuRoundOp::ToSInt64 => (0xe7c2, 3, 8, None), // WCSFP2623FpuRoundOp::ToUInt32 => (0xe7c0, 2, 8, None), // WCLFP2624FpuRoundOp::ToUInt64 => (0xe7c0, 3, 8, None), // WCLFP2625FpuRoundOp::ToSInt32x4 => (0xe7c2, 2, 0, None), // VCSFP2626FpuRoundOp::ToSInt64x2 => (0xe7c2, 3, 0, None), // VCSFP2627FpuRoundOp::ToUInt32x4 => (0xe7c0, 2, 0, None), // VCLFP2628FpuRoundOp::ToUInt64x2 => (0xe7c0, 3, 0, None), // VCLFP2629FpuRoundOp::FromSInt32 => (0xe7c3, 2, 8, None), // WCFPS2630FpuRoundOp::FromSInt64 => (0xe7c3, 3, 8, None), // WCFPS2631FpuRoundOp::FromUInt32 => (0xe7c1, 2, 8, None), // WCFPL2632FpuRoundOp::FromUInt64 => (0xe7c1, 3, 8, None), // WCFPL2633FpuRoundOp::FromSInt32x4 => (0xe7c3, 2, 0, None), // VCFPS2634FpuRoundOp::FromSInt64x2 => (0xe7c3, 3, 0, None), // VCFPS2635FpuRoundOp::FromUInt32x4 => (0xe7c1, 2, 0, None), // VCFPL2636FpuRoundOp::FromUInt64x2 => (0xe7c1, 3, 0, None), // VCFPL2637};2638if m4 == 8 && opcode_fpr.is_some() && is_fpr(rd.to_reg()) && is_fpr(rn) {2639put(2640sink,2641&enc_rrf_cde(opcode_fpr.unwrap(), rd.to_reg(), rn, mode, 0),2642);2643} else {2644put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, m3, m4, mode));2645}2646}2647&Inst::FpuConv128FromInt { op, mode, rd, rn } => {2648let rd1 = rd.hi;2649let rd2 = rd.lo;2650debug_assert_valid_fp_regpair!(rd1.to_reg(), rd2.to_reg());26512652let mode = match mode {2653FpuRoundMode::Current => 0,2654FpuRoundMode::ToNearest => 1,2655FpuRoundMode::ShorterPrecision => 3,2656FpuRoundMode::ToNearestTiesToEven => 4,2657FpuRoundMode::ToZero => 5,2658FpuRoundMode::ToPosInfinity => 6,2659FpuRoundMode::ToNegInfinity => 7,2660};2661let opcode = match op {2662FpuConv128Op::SInt32 => 0xb396, // CXFBRA2663FpuConv128Op::SInt64 => 0xb3a6, // CXGBRA2664FpuConv128Op::UInt32 => 0xb392, // CXLFBR2665FpuConv128Op::UInt64 => 0xb3a2, // CXLGBR2666};2667put(sink, &enc_rrf_cde(opcode, rd1.to_reg(), rn, mode, 0));2668}2669&Inst::FpuConv128ToInt { op, mode, rd, rn } => {2670let rn1 = rn.hi;2671let rn2 = rn.lo;2672debug_assert_valid_fp_regpair!(rn1, rn2);26732674let mode = match mode {2675FpuRoundMode::Current => 0,2676FpuRoundMode::ToNearest => 1,2677FpuRoundMode::ShorterPrecision => 3,2678FpuRoundMode::ToNearestTiesToEven => 4,2679FpuRoundMode::ToZero => 5,2680FpuRoundMode::ToPosInfinity => 6,2681FpuRoundMode::ToNegInfinity => 7,2682};2683let opcode = match op {2684FpuConv128Op::SInt32 => 0xb39a, // CFXBRA2685FpuConv128Op::SInt64 => 0xb3aa, // CGXBRA2686FpuConv128Op::UInt32 => 0xb39e, // CLFXBR2687FpuConv128Op::UInt64 => 0xb3ae, // CLGXBR2688};2689put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rn1, mode, 0));2690}2691&Inst::FpuCmp32 { rn, rm } => {2692if is_fpr(rn) && is_fpr(rm) {2693let opcode = 0xb309; // CEBR2694put(sink, &enc_rre(opcode, rn, rm));2695} else {2696let opcode = 0xe7cb; // WFC2697put(sink, &enc_vrr_a(opcode, rn, rm, 2, 0, 0));2698}2699}2700&Inst::FpuCmp64 { rn, rm } => {2701if is_fpr(rn) && is_fpr(rm) {2702let opcode = 0xb319; // CDBR2703put(sink, &enc_rre(opcode, rn, rm));2704} else {2705let opcode = 0xe7cb; // WFC2706put(sink, &enc_vrr_a(opcode, rn, rm, 3, 0, 0));2707}2708}2709&Inst::FpuCmp128 { rn, rm } => {2710let opcode = 0xe7cb; // WFC2711put(sink, &enc_vrr_a(opcode, rn, rm, 4, 0, 0));2712}27132714&Inst::VecRRR { op, rd, rn, rm } => {2715let (opcode, m4) = match op {2716VecBinaryOp::Add8x16 => (0xe7f3, 0), // VAB2717VecBinaryOp::Add16x8 => (0xe7f3, 1), // VAH2718VecBinaryOp::Add32x4 => (0xe7f3, 2), // VAF2719VecBinaryOp::Add64x2 => (0xe7f3, 3), // VAG2720VecBinaryOp::Add128 => (0xe7f3, 4), // VAQ2721VecBinaryOp::Sub8x16 => (0xe7f7, 0), // VSB2722VecBinaryOp::Sub16x8 => (0xe7f7, 1), // VSH2723VecBinaryOp::Sub32x4 => (0xe7f7, 2), // VSF2724VecBinaryOp::Sub64x2 => (0xe7f7, 3), // VSG2725VecBinaryOp::Sub128 => (0xe7f7, 4), // VSQ2726VecBinaryOp::Mul8x16 => (0xe7a2, 0), // VMLB2727VecBinaryOp::Mul16x8 => (0xe7a2, 1), // VMLHW2728VecBinaryOp::Mul32x4 => (0xe7a2, 2), // VMLF2729VecBinaryOp::Mul64x2 => (0xe7a2, 3), // VMLG2730VecBinaryOp::Mul128 => (0xe7a2, 4), // VMLQ2731VecBinaryOp::UMulHi8x16 => (0xe7a1, 0), // VMLHB2732VecBinaryOp::UMulHi16x8 => (0xe7a1, 1), // VMLHH2733VecBinaryOp::UMulHi32x4 => (0xe7a1, 2), // VMLHF2734VecBinaryOp::UMulHi64x2 => (0xe7a1, 3), // VMLHG2735VecBinaryOp::UMulHi128 => (0xe7a1, 4), // VMLHQ2736VecBinaryOp::SMulHi8x16 => (0xe7a3, 0), // VMHB2737VecBinaryOp::SMulHi16x8 => (0xe7a3, 1), // VMHH2738VecBinaryOp::SMulHi32x4 => (0xe7a3, 2), // VMHF2739VecBinaryOp::SMulHi64x2 => (0xe7a3, 3), // VMHG2740VecBinaryOp::SMulHi128 => (0xe7a3, 4), // VMHQ2741VecBinaryOp::UMulEven8x16 => (0xe7a4, 0), // VMLEB2742VecBinaryOp::UMulEven16x8 => (0xe7a4, 1), // VMLEH2743VecBinaryOp::UMulEven32x4 => (0xe7a4, 2), // VMLEF2744VecBinaryOp::UMulEven64x2 => (0xe7a4, 3), // VMLEG2745VecBinaryOp::SMulEven8x16 => (0xe7a6, 0), // VMEB2746VecBinaryOp::SMulEven16x8 => (0xe7a6, 1), // VMEH2747VecBinaryOp::SMulEven32x4 => (0xe7a6, 2), // VMEF2748VecBinaryOp::SMulEven64x2 => (0xe7a6, 3), // VMEG2749VecBinaryOp::UMulOdd8x16 => (0xe7a5, 0), // VMLOB2750VecBinaryOp::UMulOdd16x8 => (0xe7a5, 1), // VMLOH2751VecBinaryOp::UMulOdd32x4 => (0xe7a5, 2), // VMLOF2752VecBinaryOp::UMulOdd64x2 => (0xe7a5, 3), // VMLOG2753VecBinaryOp::SMulOdd8x16 => (0xe7a7, 0), // VMOB2754VecBinaryOp::SMulOdd16x8 => (0xe7a7, 1), // VMOH2755VecBinaryOp::SMulOdd32x4 => (0xe7a7, 2), // VMOF2756VecBinaryOp::SMulOdd64x2 => (0xe7a7, 3), // VMOG2757VecBinaryOp::UDiv32x4 => (0xe7b0, 2), // VDLF2758VecBinaryOp::UDiv64x2 => (0xe7b0, 3), // VDLG2759VecBinaryOp::UDiv128 => (0xe7b0, 4), // VDLQ2760VecBinaryOp::SDiv32x4 => (0xe7b2, 2), // VDF2761VecBinaryOp::SDiv64x2 => (0xe7b2, 3), // VDG2762VecBinaryOp::SDiv128 => (0xe7b2, 4), // VDQ2763VecBinaryOp::URem32x4 => (0xe7b1, 2), // VRLF2764VecBinaryOp::URem64x2 => (0xe7b1, 3), // VRLG2765VecBinaryOp::URem128 => (0xe7b1, 4), // VRLQ2766VecBinaryOp::SRem32x4 => (0xe7b3, 2), // VRF2767VecBinaryOp::SRem64x2 => (0xe7b3, 3), // VRG2768VecBinaryOp::SRem128 => (0xe7b3, 4), // VRQ2769VecBinaryOp::UMax8x16 => (0xe7fd, 0), // VMXLB2770VecBinaryOp::UMax16x8 => (0xe7fd, 1), // VMXLH2771VecBinaryOp::UMax32x4 => (0xe7fd, 2), // VMXLF2772VecBinaryOp::UMax64x2 => (0xe7fd, 3), // VMXLG2773VecBinaryOp::UMax128 => (0xe7fd, 4), // VMXLQ2774VecBinaryOp::SMax8x16 => (0xe7ff, 0), // VMXB2775VecBinaryOp::SMax16x8 => (0xe7ff, 1), // VMXH2776VecBinaryOp::SMax32x4 => (0xe7ff, 2), // VMXF2777VecBinaryOp::SMax64x2 => (0xe7ff, 3), // VMXG2778VecBinaryOp::SMax128 => (0xe7ff, 4), // VMXQ2779VecBinaryOp::UMin8x16 => (0xe7fc, 0), // VMNLB2780VecBinaryOp::UMin16x8 => (0xe7fc, 1), // VMNLH2781VecBinaryOp::UMin32x4 => (0xe7fc, 2), // VMNLF2782VecBinaryOp::UMin64x2 => (0xe7fc, 3), // VMNLG2783VecBinaryOp::UMin128 => (0xe7fc, 4), // VMNLQ2784VecBinaryOp::SMin8x16 => (0xe7fe, 0), // VMNB2785VecBinaryOp::SMin16x8 => (0xe7fe, 1), // VMNH2786VecBinaryOp::SMin32x4 => (0xe7fe, 2), // VMNF2787VecBinaryOp::SMin64x2 => (0xe7fe, 3), // VMNG2788VecBinaryOp::SMin128 => (0xe7fe, 4), // VMNQ2789VecBinaryOp::UAvg8x16 => (0xe7f0, 0), // VAVGLB2790VecBinaryOp::UAvg16x8 => (0xe7f0, 1), // VAVGLH2791VecBinaryOp::UAvg32x4 => (0xe7f0, 2), // VAVGLF2792VecBinaryOp::UAvg64x2 => (0xe7f0, 3), // VAVGLG2793VecBinaryOp::UAvg128 => (0xe7f0, 4), // VAVGLQ2794VecBinaryOp::SAvg8x16 => (0xe7f2, 0), // VAVGB2795VecBinaryOp::SAvg16x8 => (0xe7f2, 1), // VAVGH2796VecBinaryOp::SAvg32x4 => (0xe7f2, 2), // VAVGF2797VecBinaryOp::SAvg64x2 => (0xe7f2, 3), // VAVGG2798VecBinaryOp::SAvg128 => (0xe7f2, 4), // VAVGQ2799VecBinaryOp::And128 => (0xe768, 0), // VN2800VecBinaryOp::Orr128 => (0xe76a, 0), // VO2801VecBinaryOp::Xor128 => (0xe76d, 0), // VX2802VecBinaryOp::NotAnd128 => (0xe76e, 0), // VNN2803VecBinaryOp::NotOrr128 => (0xe76b, 0), // VNO2804VecBinaryOp::NotXor128 => (0xe76c, 0), // VNX2805VecBinaryOp::AndNot128 => (0xe769, 0), // VNC2806VecBinaryOp::OrrNot128 => (0xe76f, 0), // VOC2807VecBinaryOp::BitPermute128 => (0xe785, 0), // VBPERM2808VecBinaryOp::LShLByByte128 => (0xe775, 0), // VSLB2809VecBinaryOp::LShRByByte128 => (0xe77d, 0), // VSRLB2810VecBinaryOp::AShRByByte128 => (0xe77f, 0), // VSRAB2811VecBinaryOp::LShLByBit128 => (0xe774, 0), // VSL2812VecBinaryOp::LShRByBit128 => (0xe77c, 0), // VSRL2813VecBinaryOp::AShRByBit128 => (0xe77e, 0), // VSRA2814VecBinaryOp::Pack16x8 => (0xe794, 1), // VPKH2815VecBinaryOp::Pack32x4 => (0xe794, 2), // VPKF2816VecBinaryOp::Pack64x2 => (0xe794, 3), // VPKG2817VecBinaryOp::PackUSat16x8 => (0xe795, 1), // VPKLSH2818VecBinaryOp::PackUSat32x4 => (0xe795, 2), // VPKLSF2819VecBinaryOp::PackUSat64x2 => (0xe795, 3), // VPKLSG2820VecBinaryOp::PackSSat16x8 => (0xe797, 1), // VPKSH2821VecBinaryOp::PackSSat32x4 => (0xe797, 2), // VPKSF2822VecBinaryOp::PackSSat64x2 => (0xe797, 3), // VPKSG2823VecBinaryOp::MergeLow8x16 => (0xe760, 0), // VMRLB2824VecBinaryOp::MergeLow16x8 => (0xe760, 1), // VMRLH2825VecBinaryOp::MergeLow32x4 => (0xe760, 2), // VMRLF2826VecBinaryOp::MergeLow64x2 => (0xe760, 3), // VMRLG2827VecBinaryOp::MergeHigh8x16 => (0xe761, 0), // VMRHB2828VecBinaryOp::MergeHigh16x8 => (0xe761, 1), // VMRHH2829VecBinaryOp::MergeHigh32x4 => (0xe761, 2), // VMRHF2830VecBinaryOp::MergeHigh64x2 => (0xe761, 3), // VMRHG2831};28322833let enc = &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, 0, 0);2834let may_trap = match op {2835VecBinaryOp::UDiv32x42836| VecBinaryOp::UDiv64x22837| VecBinaryOp::UDiv1282838| VecBinaryOp::SDiv32x42839| VecBinaryOp::SDiv64x22840| VecBinaryOp::SDiv1282841| VecBinaryOp::URem32x42842| VecBinaryOp::URem64x22843| VecBinaryOp::URem1282844| VecBinaryOp::SRem32x42845| VecBinaryOp::SRem64x22846| VecBinaryOp::SRem128 => true,2847_ => false,2848};2849if may_trap {2850put_with_trap(sink, enc, TrapCode::INTEGER_DIVISION_BY_ZERO);2851} else {2852put(sink, enc);2853}2854}2855&Inst::VecRR { op, rd, rn } => {2856let (opcode, m3) = match op {2857VecUnaryOp::Abs8x16 => (0xe7df, 0), // VLPB2858VecUnaryOp::Abs16x8 => (0xe7df, 1), // VLPH2859VecUnaryOp::Abs32x4 => (0xe7df, 2), // VLPF2860VecUnaryOp::Abs64x2 => (0xe7df, 3), // VLPG2861VecUnaryOp::Abs128 => (0xe7df, 4), // VLPQ2862VecUnaryOp::Neg8x16 => (0xe7de, 0), // VLCB2863VecUnaryOp::Neg16x8 => (0xe7de, 1), // VLCH2864VecUnaryOp::Neg32x4 => (0xe7de, 2), // VLCF2865VecUnaryOp::Neg64x2 => (0xe7de, 3), // VLCG2866VecUnaryOp::Neg128 => (0xe7de, 4), // VLCQ2867VecUnaryOp::Popcnt8x16 => (0xe750, 0), // VPOPCTB2868VecUnaryOp::Popcnt16x8 => (0xe750, 1), // VPOPCTH2869VecUnaryOp::Popcnt32x4 => (0xe750, 2), // VPOPCTF2870VecUnaryOp::Popcnt64x2 => (0xe750, 3), // VPOPCTG2871VecUnaryOp::Clz8x16 => (0xe753, 0), // VCLZB2872VecUnaryOp::Clz16x8 => (0xe753, 1), // VCLZH2873VecUnaryOp::Clz32x4 => (0xe753, 2), // VCLZF2874VecUnaryOp::Clz64x2 => (0xe753, 3), // VCLZG2875VecUnaryOp::Clz128 => (0xe753, 4), // VCLZQ2876VecUnaryOp::Ctz8x16 => (0xe752, 0), // VCTZB2877VecUnaryOp::Ctz16x8 => (0xe752, 1), // VCTZH2878VecUnaryOp::Ctz32x4 => (0xe752, 2), // VCTZF2879VecUnaryOp::Ctz64x2 => (0xe752, 3), // VCTZG2880VecUnaryOp::Ctz128 => (0xe752, 4), // VCTZQ2881VecUnaryOp::UnpackULow8x16 => (0xe7d4, 0), // VUPLLB2882VecUnaryOp::UnpackULow16x8 => (0xe7d4, 1), // VUPLLH2883VecUnaryOp::UnpackULow32x4 => (0xe7d4, 2), // VUPLLF2884VecUnaryOp::UnpackULow64x2 => (0xe7d4, 3), // VUPLLG2885VecUnaryOp::UnpackUHigh8x16 => (0xe7d5, 0), // VUPLHB2886VecUnaryOp::UnpackUHigh16x8 => (0xe7d5, 1), // VUPLHH2887VecUnaryOp::UnpackUHigh32x4 => (0xe7d5, 2), // VUPLHF2888VecUnaryOp::UnpackUHigh64x2 => (0xe7d5, 3), // VUPLHG2889VecUnaryOp::UnpackSLow8x16 => (0xe7d6, 0), // VUPLB2890VecUnaryOp::UnpackSLow16x8 => (0xe7d6, 1), // VUPLH2891VecUnaryOp::UnpackSLow32x4 => (0xe7d6, 2), // VUPLF2892VecUnaryOp::UnpackSLow64x2 => (0xe7d6, 3), // VUPLG2893VecUnaryOp::UnpackSHigh8x16 => (0xe7d7, 0), // VUPHB2894VecUnaryOp::UnpackSHigh16x8 => (0xe7d7, 1), // VUPHH2895VecUnaryOp::UnpackSHigh32x4 => (0xe7d7, 2), // VUPHF2896VecUnaryOp::UnpackSHigh64x2 => (0xe7d7, 3), // VUPHG2897};28982899put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, m3, 0, 0));2900}2901&Inst::VecShiftRR {2902shift_op,2903rd,2904rn,2905shift_imm,2906shift_reg,2907} => {2908let (opcode, m4) = match shift_op {2909VecShiftOp::RotL8x16 => (0xe733, 0), // VERLLB2910VecShiftOp::RotL16x8 => (0xe733, 1), // VERLLH2911VecShiftOp::RotL32x4 => (0xe733, 2), // VERLLF2912VecShiftOp::RotL64x2 => (0xe733, 3), // VERLLG2913VecShiftOp::LShL8x16 => (0xe730, 0), // VESLB2914VecShiftOp::LShL16x8 => (0xe730, 1), // VESLH2915VecShiftOp::LShL32x4 => (0xe730, 2), // VESLF2916VecShiftOp::LShL64x2 => (0xe730, 3), // VESLG2917VecShiftOp::LShR8x16 => (0xe738, 0), // VESRLB2918VecShiftOp::LShR16x8 => (0xe738, 1), // VESRLH2919VecShiftOp::LShR32x4 => (0xe738, 2), // VESRLF2920VecShiftOp::LShR64x2 => (0xe738, 3), // VESRLG2921VecShiftOp::AShR8x16 => (0xe73a, 0), // VESRAB2922VecShiftOp::AShR16x8 => (0xe73a, 1), // VESRAH2923VecShiftOp::AShR32x4 => (0xe73a, 2), // VESRAF2924VecShiftOp::AShR64x2 => (0xe73a, 3), // VESRAG2925};2926put(2927sink,2928&enc_vrs_a(opcode, rd.to_reg(), shift_reg, shift_imm.into(), rn, m4),2929);2930}2931&Inst::VecSelect { rd, rn, rm, ra } => {2932let opcode = 0xe78d; // VSEL2933put(sink, &enc_vrr_e(opcode, rd.to_reg(), rn, rm, ra, 0, 0));2934}2935&Inst::VecPermute { rd, rn, rm, ra } => {2936let opcode = 0xe78c; // VPERM2937put(sink, &enc_vrr_e(opcode, rd.to_reg(), rn, rm, ra, 0, 0));2938}2939&Inst::VecBlend { rd, rn, rm, ra } => {2940let opcode = 0xe789; // VBLEND2941put(sink, &enc_vrr_d(opcode, rd.to_reg(), rn, rm, ra, 0, 0));2942}2943&Inst::VecEvaluate {2944imm,2945rd,2946rn,2947rm,2948ra,2949} => {2950let opcode = 0xe788; //VEVAL2951put(sink, &enc_vri_k(opcode, imm, rd.to_reg(), rn, rm, ra));2952}2953&Inst::VecPermuteDWImm {2954rd,2955rn,2956rm,2957idx1,2958idx2,2959} => {2960let m4 = (idx1 & 1) * 4 + (idx2 & 1);29612962let opcode = 0xe784; // VPDI2963put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, 0, 0));2964}2965&Inst::VecIntCmp { op, rd, rn, rm } | &Inst::VecIntCmpS { op, rd, rn, rm } => {2966let (opcode, m4) = match op {2967VecIntCmpOp::CmpEq8x16 => (0xe7f8, 0), // VCEQB2968VecIntCmpOp::CmpEq16x8 => (0xe7f8, 1), // VCEQH2969VecIntCmpOp::CmpEq32x4 => (0xe7f8, 2), // VCEQF2970VecIntCmpOp::CmpEq64x2 => (0xe7f8, 3), // VCEQG2971VecIntCmpOp::CmpEq128 => (0xe7f8, 4), // VCEQQ2972VecIntCmpOp::SCmpHi8x16 => (0xe7fb, 0), // VCHB2973VecIntCmpOp::SCmpHi16x8 => (0xe7fb, 1), // VCHH2974VecIntCmpOp::SCmpHi32x4 => (0xe7fb, 2), // VCHG2975VecIntCmpOp::SCmpHi64x2 => (0xe7fb, 3), // VCHG2976VecIntCmpOp::SCmpHi128 => (0xe7fb, 4), // VCHQ2977VecIntCmpOp::UCmpHi8x16 => (0xe7f9, 0), // VCHLB2978VecIntCmpOp::UCmpHi16x8 => (0xe7f9, 1), // VCHLH2979VecIntCmpOp::UCmpHi32x4 => (0xe7f9, 2), // VCHLG2980VecIntCmpOp::UCmpHi64x2 => (0xe7f9, 3), // VCHLG2981VecIntCmpOp::UCmpHi128 => (0xe7f9, 4), // VCHLQ2982};2983let m5 = match self {2984&Inst::VecIntCmp { .. } => 0,2985&Inst::VecIntCmpS { .. } => 1,2986_ => unreachable!(),2987};29882989put(sink, &enc_vrr_b(opcode, rd.to_reg(), rn, rm, m4, m5));2990}2991&Inst::VecFloatCmp { op, rd, rn, rm } | &Inst::VecFloatCmpS { op, rd, rn, rm } => {2992let (opcode, m4) = match op {2993VecFloatCmpOp::CmpEq32x4 => (0xe7e8, 2), // VFCESB2994VecFloatCmpOp::CmpEq64x2 => (0xe7e8, 3), // VFCEDB2995VecFloatCmpOp::CmpHi32x4 => (0xe7eb, 2), // VFCHSB2996VecFloatCmpOp::CmpHi64x2 => (0xe7eb, 3), // VFCHDB2997VecFloatCmpOp::CmpHiEq32x4 => (0xe7ea, 2), // VFCHESB2998VecFloatCmpOp::CmpHiEq64x2 => (0xe7ea, 3), // VFCHEDB2999};3000let m6 = match self {3001&Inst::VecFloatCmp { .. } => 0,3002&Inst::VecFloatCmpS { .. } => 1,3003_ => unreachable!(),3004};30053006put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, 0, m6));3007}3008&Inst::VecIntEltCmp { op, rn, rm } => {3009let (opcode, m3) = match op {3010VecIntEltCmpOp::SCmp128 => (0xe7db, 4), // VECQ3011VecIntEltCmpOp::UCmp128 => (0xe7d9, 4), // VECLQ3012};30133014put(sink, &enc_vrr_a(opcode, rn, rm, m3, 0, 0));3015}3016&Inst::VecInt128SCmpHi { tmp, rn, rm } | &Inst::VecInt128UCmpHi { tmp, rn, rm } => {3017// Synthetic instruction to compare 128-bit values.3018// Sets CC 1 if rn > rm, sets a different CC otherwise.30193020// Use VECTOR ELEMENT COMPARE to compare the high parts.3021// Swap the inputs to get:3022// CC 1 if high(rn) > high(rm)3023// CC 2 if high(rn) < high(rm)3024// CC 0 if high(rn) == high(rm)3025let (opcode, m3) = match self {3026&Inst::VecInt128SCmpHi { .. } => (0xe7db, 3), // VECG3027&Inst::VecInt128UCmpHi { .. } => (0xe7d9, 3), // VECLG3028_ => unreachable!(),3029};3030put(sink, &enc_vrr_a(opcode, rm, rn, m3, 0, 0));30313032// If CC != 0, we'd done, so jump over the next instruction.3033put(sink, &enc_ri_c(OPCODE_BCR, 7, 4 + 6));30343035// Otherwise, use VECTOR COMPARE HIGH LOGICAL.3036// Since we already know the high parts are equal, the CC3037// result will only depend on the low parts:3038// CC 1 if low(rn) > low(rm)3039// CC 3 if low(rn) <= low(rm)3040let inst = Inst::VecIntCmpS {3041op: VecIntCmpOp::UCmpHi64x2,3042// N.B.: This is the first write to tmp, and it happens3043// after all uses of rn and rm. If this were to ever3044// change, tmp would have to become an early-def.3045rd: tmp,3046rn,3047rm,3048};3049inst.emit(sink, emit_info, state);3050}30513052&Inst::VecLoad { rd, ref mem }3053| &Inst::VecLoadRev { rd, ref mem }3054| &Inst::VecLoadByte16Rev { rd, ref mem }3055| &Inst::VecLoadByte32Rev { rd, ref mem }3056| &Inst::VecLoadByte64Rev { rd, ref mem }3057| &Inst::VecLoadElt16Rev { rd, ref mem }3058| &Inst::VecLoadElt32Rev { rd, ref mem }3059| &Inst::VecLoadElt64Rev { rd, ref mem } => {3060let mem = mem.clone();30613062let (opcode, m3) = match self {3063&Inst::VecLoad { .. } => (0xe706, 0), // VL3064&Inst::VecLoadRev { .. } => (0xe606, 4), // VLBRQ3065&Inst::VecLoadByte16Rev { .. } => (0xe606, 1), // VLBRH3066&Inst::VecLoadByte32Rev { .. } => (0xe606, 2), // VLBRF3067&Inst::VecLoadByte64Rev { .. } => (0xe606, 3), // VLBRG3068&Inst::VecLoadElt16Rev { .. } => (0xe607, 1), // VLERH3069&Inst::VecLoadElt32Rev { .. } => (0xe607, 2), // VLERF3070&Inst::VecLoadElt64Rev { .. } => (0xe607, 3), // VLERG3071_ => unreachable!(),3072};3073mem_vrx_emit(rd.to_reg(), &mem, opcode, m3, true, sink, emit_info, state);3074}3075&Inst::VecStore { rd, ref mem }3076| &Inst::VecStoreRev { rd, ref mem }3077| &Inst::VecStoreByte16Rev { rd, ref mem }3078| &Inst::VecStoreByte32Rev { rd, ref mem }3079| &Inst::VecStoreByte64Rev { rd, ref mem }3080| &Inst::VecStoreElt16Rev { rd, ref mem }3081| &Inst::VecStoreElt32Rev { rd, ref mem }3082| &Inst::VecStoreElt64Rev { rd, ref mem } => {3083let mem = mem.clone();30843085let (opcode, m3) = match self {3086&Inst::VecStore { .. } => (0xe70e, 0), // VST3087&Inst::VecStoreRev { .. } => (0xe60e, 4), // VSTBRQ3088&Inst::VecStoreByte16Rev { .. } => (0xe60e, 1), // VSTBRH3089&Inst::VecStoreByte32Rev { .. } => (0xe60e, 2), // VSTBRF3090&Inst::VecStoreByte64Rev { .. } => (0xe60e, 3), // VSTBRG3091&Inst::VecStoreElt16Rev { .. } => (0xe60f, 1), // VSTERH3092&Inst::VecStoreElt32Rev { .. } => (0xe60f, 2), // VSTERF3093&Inst::VecStoreElt64Rev { .. } => (0xe60f, 3), // VSTERG3094_ => unreachable!(),3095};3096mem_vrx_emit(rd, &mem, opcode, m3, true, sink, emit_info, state);3097}3098&Inst::VecLoadReplicate { size, rd, ref mem }3099| &Inst::VecLoadReplicateRev { size, rd, ref mem } => {3100let mem = mem.clone();31013102let (opcode, m3) = match (self, size) {3103(&Inst::VecLoadReplicate { .. }, 8) => (0xe705, 0), // VLREPB3104(&Inst::VecLoadReplicate { .. }, 16) => (0xe705, 1), // VLREPH3105(&Inst::VecLoadReplicate { .. }, 32) => (0xe705, 2), // VLREPF3106(&Inst::VecLoadReplicate { .. }, 64) => (0xe705, 3), // VLREPG3107(&Inst::VecLoadReplicateRev { .. }, 16) => (0xe605, 1), // VLREPBRH3108(&Inst::VecLoadReplicateRev { .. }, 32) => (0xe605, 2), // VLREPBRF3109(&Inst::VecLoadReplicateRev { .. }, 64) => (0xe605, 3), // VLREPBRG3110_ => unreachable!(),3111};3112mem_vrx_emit(rd.to_reg(), &mem, opcode, m3, true, sink, emit_info, state);3113}31143115&Inst::VecMov { rd, rn } => {3116put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rn, 0, 0, 0));3117}3118&Inst::VecCMov { rd, cond, ri, rm } => {3119debug_assert_eq!(rd.to_reg(), ri);31203121put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 6));3122put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rm, 0, 0, 0));3123}3124&Inst::MovToVec128 { rd, rn, rm } => {3125let opcode = 0xe762; // VLVGP3126put(sink, &enc_vrr_f(opcode, rd.to_reg(), rn, rm));3127}3128&Inst::VecImmByteMask { rd, mask } => {3129let opcode = 0xe744; // VGBM3130put(sink, &enc_vri_a(opcode, rd.to_reg(), mask, 0));3131}3132&Inst::VecImmBitMask {3133size,3134rd,3135start_bit,3136end_bit,3137} => {3138let (opcode, m4) = match size {31398 => (0xe746, 0), // VGMB314016 => (0xe746, 1), // VGMH314132 => (0xe746, 2), // VGMF314264 => (0xe746, 3), // VGMG3143_ => unreachable!(),3144};3145put(3146sink,3147&enc_vri_b(opcode, rd.to_reg(), start_bit, end_bit, m4),3148);3149}3150&Inst::VecImmReplicate { size, rd, imm } => {3151let (opcode, m3) = match size {31528 => (0xe745, 0), // VREPIB315316 => (0xe745, 1), // VREPIH315432 => (0xe745, 2), // VREPIF315564 => (0xe745, 3), // VREPIG3156_ => unreachable!(),3157};3158put(sink, &enc_vri_a(opcode, rd.to_reg(), imm as u16, m3));3159}3160&Inst::VecLoadLane {3161size,3162rd,3163ri,3164ref mem,3165lane_imm,3166}3167| &Inst::VecLoadLaneRev {3168size,3169rd,3170ri,3171ref mem,3172lane_imm,3173} => {3174debug_assert_eq!(rd.to_reg(), ri);3175let mem = mem.clone();31763177let opcode_vrx = match (self, size) {3178(&Inst::VecLoadLane { .. }, 8) => 0xe700, // VLEB3179(&Inst::VecLoadLane { .. }, 16) => 0xe701, // VLEH3180(&Inst::VecLoadLane { .. }, 32) => 0xe703, // VLEF3181(&Inst::VecLoadLane { .. }, 64) => 0xe702, // VLEG3182(&Inst::VecLoadLaneRev { .. }, 16) => 0xe601, // VLEBRH3183(&Inst::VecLoadLaneRev { .. }, 32) => 0xe603, // VLEBRF3184(&Inst::VecLoadLaneRev { .. }, 64) => 0xe602, // VLEBRG3185_ => unreachable!(),3186};31873188let rd = rd.to_reg();3189mem_vrx_emit(rd, &mem, opcode_vrx, lane_imm, true, sink, emit_info, state);3190}3191&Inst::VecLoadLaneUndef {3192size,3193rd,3194ref mem,3195lane_imm,3196}3197| &Inst::VecLoadLaneRevUndef {3198size,3199rd,3200ref mem,3201lane_imm,3202} => {3203let mem = mem.clone();32043205let (opcode_vrx, opcode_rx, opcode_rxy) = match (self, size) {3206(&Inst::VecLoadLaneUndef { .. }, 8) => (0xe700, None, None), // VLEB3207(&Inst::VecLoadLaneUndef { .. }, 16) => (0xe701, None, None), // VLEH3208(&Inst::VecLoadLaneUndef { .. }, 32) => (0xe703, Some(0x78), Some(0xed64)), // VLEF, LE(Y)3209(&Inst::VecLoadLaneUndef { .. }, 64) => (0xe702, Some(0x68), Some(0xed65)), // VLEG, LD(Y)3210(&Inst::VecLoadLaneRevUndef { .. }, 16) => (0xe601, None, None), // VLEBRH3211(&Inst::VecLoadLaneRevUndef { .. }, 32) => (0xe603, None, None), // VLEBRF3212(&Inst::VecLoadLaneRevUndef { .. }, 64) => (0xe602, None, None), // VLEBRG3213_ => unreachable!(),3214};32153216let rd = rd.to_reg();3217if lane_imm == 0 && is_fpr(rd) && opcode_rx.is_some() {3218mem_emit(3219rd, &mem, opcode_rx, opcode_rxy, None, true, sink, emit_info, state,3220);3221} else {3222mem_vrx_emit(rd, &mem, opcode_vrx, lane_imm, true, sink, emit_info, state);3223}3224}3225&Inst::VecStoreLane {3226size,3227rd,3228ref mem,3229lane_imm,3230}3231| &Inst::VecStoreLaneRev {3232size,3233rd,3234ref mem,3235lane_imm,3236} => {3237let mem = mem.clone();32383239let (opcode_vrx, opcode_rx, opcode_rxy) = match (self, size) {3240(&Inst::VecStoreLane { .. }, 8) => (0xe708, None, None), // VSTEB3241(&Inst::VecStoreLane { .. }, 16) => (0xe709, None, None), // VSTEH3242(&Inst::VecStoreLane { .. }, 32) => (0xe70b, Some(0x70), Some(0xed66)), // VSTEF, STE(Y)3243(&Inst::VecStoreLane { .. }, 64) => (0xe70a, Some(0x60), Some(0xed67)), // VSTEG, STD(Y)3244(&Inst::VecStoreLaneRev { .. }, 16) => (0xe609, None, None), // VSTEBRH3245(&Inst::VecStoreLaneRev { .. }, 32) => (0xe60b, None, None), // VSTEBRF3246(&Inst::VecStoreLaneRev { .. }, 64) => (0xe60a, None, None), // VSTEBRG3247_ => unreachable!(),3248};32493250if lane_imm == 0 && is_fpr(rd) && opcode_rx.is_some() {3251mem_emit(3252rd, &mem, opcode_rx, opcode_rxy, None, true, sink, emit_info, state,3253);3254} else {3255mem_vrx_emit(rd, &mem, opcode_vrx, lane_imm, true, sink, emit_info, state);3256}3257}3258&Inst::VecInsertLane {3259size,3260rd,3261ri,3262rn,3263lane_imm,3264lane_reg,3265} => {3266debug_assert_eq!(rd.to_reg(), ri);32673268let (opcode_vrs, m4) = match size {32698 => (0xe722, 0), // VLVGB327016 => (0xe722, 1), // VLVGH327132 => (0xe722, 2), // VLVGF327264 => (0xe722, 3), // VLVGG3273_ => unreachable!(),3274};3275put(3276sink,3277&enc_vrs_b(opcode_vrs, rd.to_reg(), lane_reg, lane_imm.into(), rn, m4),3278);3279}3280&Inst::VecInsertLaneUndef {3281size,3282rd,3283rn,3284lane_imm,3285lane_reg,3286} => {3287let (opcode_vrs, m4, opcode_rre) = match size {32888 => (0xe722, 0, None), // VLVGB328916 => (0xe722, 1, None), // VLVGH329032 => (0xe722, 2, None), // VLVGF329164 => (0xe722, 3, Some(0xb3c1)), // VLVGG, LDGR3292_ => unreachable!(),3293};3294if opcode_rre.is_some()3295&& lane_imm == 03296&& lane_reg == zero_reg()3297&& is_fpr(rd.to_reg())3298{3299put(sink, &enc_rre(opcode_rre.unwrap(), rd.to_reg(), rn));3300} else {3301put(3302sink,3303&enc_vrs_b(opcode_vrs, rd.to_reg(), lane_reg, lane_imm.into(), rn, m4),3304);3305}3306}3307&Inst::VecExtractLane {3308size,3309rd,3310rn,3311lane_imm,3312lane_reg,3313} => {3314let (opcode_vrs, m4, opcode_rre) = match size {33158 => (0xe721, 0, None), // VLGVB331616 => (0xe721, 1, None), // VLGVH331732 => (0xe721, 2, None), // VLGVF331864 => (0xe721, 3, Some(0xb3cd)), // VLGVG, LGDR3319_ => unreachable!(),3320};3321if opcode_rre.is_some() && lane_imm == 0 && lane_reg == zero_reg() && is_fpr(rn) {3322put(sink, &enc_rre(opcode_rre.unwrap(), rd.to_reg(), rn));3323} else {3324put(3325sink,3326&enc_vrs_c(opcode_vrs, rd.to_reg(), lane_reg, lane_imm.into(), rn, m4),3327);3328}3329}3330&Inst::VecInsertLaneImm {3331size,3332rd,3333ri,3334imm,3335lane_imm,3336} => {3337debug_assert_eq!(rd.to_reg(), ri);33383339let opcode = match size {33408 => 0xe740, // VLEIB334116 => 0xe741, // VLEIH334232 => 0xe743, // VLEIF334364 => 0xe742, // VLEIG3344_ => unreachable!(),3345};3346put(sink, &enc_vri_a(opcode, rd.to_reg(), imm as u16, lane_imm));3347}3348&Inst::VecInsertLaneImmUndef {3349size,3350rd,3351imm,3352lane_imm,3353} => {3354let opcode = match size {33558 => 0xe740, // VLEIB335616 => 0xe741, // VLEIH335732 => 0xe743, // VLEIF335864 => 0xe742, // VLEIG3359_ => unreachable!(),3360};3361put(sink, &enc_vri_a(opcode, rd.to_reg(), imm as u16, lane_imm));3362}3363&Inst::VecReplicateLane {3364size,3365rd,3366rn,3367lane_imm,3368} => {3369let (opcode, m4) = match size {33708 => (0xe74d, 0), // VREPB337116 => (0xe74d, 1), // VREPH337232 => (0xe74d, 2), // VREPF337364 => (0xe74d, 3), // VREPG3374_ => unreachable!(),3375};3376put(3377sink,3378&enc_vri_c(opcode, rd.to_reg(), lane_imm.into(), rn, m4),3379);3380}33813382&Inst::VecEltRev { lane_count, rd, rn } => {3383assert!(lane_count >= 2 && lane_count <= 16);3384let inst = Inst::VecPermuteDWImm {3385rd,3386rn,3387rm: rn,3388idx1: 1,3389idx2: 0,3390};3391inst.emit(sink, emit_info, state);3392if lane_count >= 4 {3393let inst = Inst::VecShiftRR {3394shift_op: VecShiftOp::RotL64x2,3395rd,3396rn: rd.to_reg(),3397shift_imm: 32,3398shift_reg: zero_reg(),3399};3400inst.emit(sink, emit_info, state);3401}3402if lane_count >= 8 {3403let inst = Inst::VecShiftRR {3404shift_op: VecShiftOp::RotL32x4,3405rd,3406rn: rd.to_reg(),3407shift_imm: 16,3408shift_reg: zero_reg(),3409};3410inst.emit(sink, emit_info, state);3411}3412if lane_count >= 16 {3413let inst = Inst::VecShiftRR {3414shift_op: VecShiftOp::RotL16x8,3415rd,3416rn: rd.to_reg(),3417shift_imm: 8,3418shift_reg: zero_reg(),3419};3420inst.emit(sink, emit_info, state);3421}3422}34233424&Inst::AllocateArgs { size } => {3425let inst = if let Ok(size) = i16::try_from(size) {3426Inst::AluRSImm16 {3427alu_op: ALUOp::Add64,3428rd: writable_stack_reg(),3429ri: stack_reg(),3430imm: -size,3431}3432} else {3433Inst::AluRUImm32 {3434alu_op: ALUOp::SubLogical64,3435rd: writable_stack_reg(),3436ri: stack_reg(),3437imm: size,3438}3439};3440inst.emit(sink, emit_info, state);3441assert_eq!(state.nominal_sp_offset, 0);3442state.nominal_sp_offset += size;3443}3444&Inst::Call { link, ref info } => {3445let start = sink.cur_offset();34463447let enc: &[u8] = match &info.dest {3448CallInstDest::Direct { name } => {3449let offset = sink.cur_offset() + 2;3450sink.add_reloc_at_offset(offset, Reloc::S390xPLTRel32Dbl, name, 2);3451let opcode = 0xc05; // BRASL3452&enc_ril_b(opcode, link.to_reg(), 0)3453}3454CallInstDest::Indirect { reg } => {3455let opcode = 0x0d; // BASR3456&enc_rr(opcode, link.to_reg(), *reg)3457}3458};3459if let Some(s) = state.take_stack_map() {3460let offset = sink.cur_offset() + enc.len() as u32;3461sink.push_user_stack_map(state, offset, s);3462}3463put(sink, enc);34643465if let Some(try_call) = info.try_call_info.as_ref() {3466sink.add_try_call_site(3467Some(state.frame_layout.sp_to_fp()),3468try_call.exception_handlers(&state.frame_layout),3469);3470} else {3471sink.add_call_site();3472}34733474state.nominal_sp_offset -= info.callee_pop_size;3475assert_eq!(state.nominal_sp_offset, 0);34763477if info.patchable {3478sink.add_patchable_call_site(sink.cur_offset() - start);3479} else {3480state.outgoing_sp_offset = info.callee_pop_size;3481for inst in S390xMachineDeps::gen_retval_loads(info) {3482inst.emit(sink, emit_info, state);3483}3484state.outgoing_sp_offset = 0;3485}34863487// If this is a try-call, jump to the continuation3488// (normal-return) block.3489if let Some(try_call) = info.try_call_info.as_ref() {3490let jmp = Inst::Jump {3491dest: try_call.continuation,3492};3493jmp.emit(sink, emit_info, state);3494}3495}3496&Inst::ReturnCall { ref info } => {3497let (epilogue_insts, temp_dest) = S390xMachineDeps::gen_tail_epilogue(3498state.frame_layout(),3499info.callee_pop_size,3500&info.dest,3501);3502for inst in epilogue_insts {3503inst.emit(sink, emit_info, state);3504}35053506let enc: &[u8] = match &info.dest {3507CallInstDest::Direct { name } => {3508let offset = sink.cur_offset() + 2;3509sink.add_reloc_at_offset(offset, Reloc::S390xPLTRel32Dbl, name, 2);3510let opcode = 0xc04; // BCRL3511&enc_ril_c(opcode, 15, 0)3512}3513CallInstDest::Indirect { reg } => {3514let opcode = 0x07; // BCR3515&enc_rr(opcode, gpr(15), temp_dest.unwrap_or(*reg))3516}3517};3518put(sink, enc);3519sink.add_call_site();3520}3521&Inst::ElfTlsGetOffset { ref symbol, .. } => {3522let opcode = 0xc05; // BRASL35233524// Add relocation for target function. This has to be done3525// *before* the S390xTlsGdCall, to ensure linker relaxation3526// works correctly.3527let dest = ExternalName::LibCall(LibCall::ElfTlsGetOffset);3528let offset = sink.cur_offset() + 2;3529sink.add_reloc_at_offset(offset, Reloc::S390xPLTRel32Dbl, &dest, 2);3530match &**symbol {3531SymbolReloc::TlsGd { name } => sink.add_reloc(Reloc::S390xTlsGdCall, name, 0),3532_ => unreachable!(),3533}35343535put(sink, &enc_ril_b(opcode, gpr(14), 0));3536sink.add_call_site();3537}3538&Inst::Args { .. } => {}3539&Inst::Rets { .. } => {}3540&Inst::Ret { link } => {3541let opcode = 0x07; // BCR3542put(sink, &enc_rr(opcode, gpr(15), link));3543}3544&Inst::Jump { dest } => {3545let off = sink.cur_offset();3546// Indicate that the jump uses a label, if so, so that a fixup can occur later.3547sink.use_label_at_offset(off, dest, LabelUse::BranchRIL);3548sink.add_uncond_branch(off, off + 6, dest);3549// Emit the jump itself.3550let opcode = 0xc04; // BCRL3551put(sink, &enc_ril_c(opcode, 15, 0));3552}3553&Inst::IndirectBr { rn, .. } => {3554let opcode = 0x07; // BCR3555put(sink, &enc_rr(opcode, gpr(15), rn));3556}3557&Inst::CondBr {3558taken,3559not_taken,3560cond,3561} => {3562let opcode = 0xc04; // BCRL35633564// Conditional part first.3565let cond_off = sink.cur_offset();3566sink.use_label_at_offset(cond_off, taken, LabelUse::BranchRIL);3567let inverted = &enc_ril_c(opcode, cond.invert().bits(), 0);3568sink.add_cond_branch(cond_off, cond_off + 6, taken, inverted);3569put(sink, &enc_ril_c(opcode, cond.bits(), 0));35703571// Unconditional part next.3572let uncond_off = sink.cur_offset();3573sink.use_label_at_offset(uncond_off, not_taken, LabelUse::BranchRIL);3574sink.add_uncond_branch(uncond_off, uncond_off + 6, not_taken);3575put(sink, &enc_ril_c(opcode, 15, 0));3576}3577&Inst::Nop0 => {}3578&Inst::Nop2 => {3579put(sink, &enc_e(0x0707));3580}3581&Inst::Debugtrap => {3582put(sink, &enc_e(0x0001));3583}3584&Inst::Trap { trap_code } => {3585put_with_trap(sink, &enc_e(0x0000), trap_code);3586}3587&Inst::TrapIf { cond, trap_code } => {3588// We implement a TrapIf as a conditional branch into the middle3589// of the branch (BRCL) instruction itself - those middle two bytes3590// are zero, which matches the trap instruction itself.3591let opcode = 0xc04; // BCRL3592let enc = &enc_ril_c(opcode, cond.bits(), 2);3593debug_assert!(enc.len() == 6 && enc[2] == 0 && enc[3] == 0);3594// The trap must be placed on the last byte of the embedded trap3595// instruction, so we need to emit the encoding in two parts.3596put_with_trap(sink, &enc[0..4], trap_code);3597put(sink, &enc[4..6]);3598}3599&Inst::JTSequence {3600ridx,3601default,3602default_cond,3603ref targets,3604} => {3605let table_label = sink.get_label();36063607// This sequence is *one* instruction in the vcode, and is expanded only here at3608// emission time, because we cannot allow the regalloc to insert spills/reloads in3609// the middle; we depend on hardcoded PC-rel addressing below.36103611// Branch to the default target if the given default condition is true.3612let opcode = 0xc04; // BCRL3613sink.use_label_at_offset(sink.cur_offset(), default, LabelUse::BranchRIL);3614put(sink, &enc_ril_c(opcode, default_cond.bits(), 0));36153616// Set temp register to address of jump table.3617let rtmp = writable_spilltmp_reg();3618let inst = Inst::LoadAddr {3619rd: rtmp,3620mem: MemArg::Label {3621target: table_label,3622},3623};3624inst.emit(sink, emit_info, state);36253626// Set temp to target address by adding the value of the jump table entry.3627let inst = Inst::AluRX {3628alu_op: ALUOp::Add64Ext32,3629rd: rtmp,3630ri: rtmp.to_reg(),3631mem: MemArg::reg_plus_reg(rtmp.to_reg(), ridx, MemFlags::trusted()),3632};3633inst.emit(sink, emit_info, state);36343635// Branch to computed address. (`targets` here is only used for successor queries3636// and is not needed for emission.)3637let inst = Inst::IndirectBr {3638rn: rtmp.to_reg(),3639targets: vec![],3640};3641inst.emit(sink, emit_info, state);36423643// Emit jump table (table of 32-bit offsets).3644sink.bind_label(table_label, &mut state.ctrl_plane);3645let jt_off = sink.cur_offset();3646for &target in targets.iter() {3647let word_off = sink.cur_offset();3648let off_into_table = word_off - jt_off;3649sink.use_label_at_offset(word_off, target, LabelUse::PCRel32);3650sink.put4(off_into_table.swap_bytes());3651}3652}36533654Inst::StackProbeLoop {3655probe_count,3656guard_size,3657} => {3658// Emit the loop start label3659let loop_start = sink.get_label();3660sink.bind_label(loop_start, state.ctrl_plane_mut());36613662// aghi %r15, -GUARD_SIZE3663let inst = Inst::AluRSImm16 {3664alu_op: ALUOp::Add64,3665rd: writable_stack_reg(),3666ri: stack_reg(),3667imm: -guard_size,3668};3669inst.emit(sink, emit_info, state);36703671// mvi 0(%r15), 03672let inst = Inst::StoreImm8 {3673imm: 0,3674mem: MemArg::reg(stack_reg(), MemFlags::trusted()),3675};3676inst.emit(sink, emit_info, state);36773678// brct PROBE_COUNT, LOOP_START3679let opcode = 0xa76; // BRCT3680sink.use_label_at_offset(sink.cur_offset(), loop_start, LabelUse::BranchRI);3681put(sink, &enc_ri_b(opcode, probe_count.to_reg(), 0));3682}36833684&Inst::Unwind { ref inst } => {3685sink.add_unwind(inst.clone());3686}36873688&Inst::DummyUse { .. } => {}36893690&Inst::LabelAddress { dst, label } => {3691let inst = Inst::LoadAddr {3692rd: dst,3693mem: MemArg::Label { target: label },3694};3695inst.emit(sink, emit_info, state);3696}36973698&Inst::SequencePoint { .. } => {3699// Nothing.3700}3701}37023703state.clear_post_insn();3704}3705}370637073708