Path: blob/main/cranelift/codegen/src/isa/s390x/inst/mod.rs
1693 views
//! This module defines s390x-specific machine instruction types.12use crate::binemit::{Addend, CodeOffset, Reloc};3use crate::ir::{ExternalName, Type, types};4use crate::isa::s390x::abi::S390xMachineDeps;5use crate::isa::{CallConv, FunctionAlignment};6use crate::machinst::*;7use crate::{CodegenError, CodegenResult, settings};8use alloc::boxed::Box;9use alloc::vec::Vec;10use smallvec::SmallVec;11use std::fmt::Write;12use std::string::{String, ToString};13pub mod regs;14pub use self::regs::*;15pub mod imms;16pub use self::imms::*;17pub mod args;18pub use self::args::*;19pub mod emit;20pub use self::emit::*;21pub mod unwind;2223#[cfg(test)]24mod emit_tests;2526//=============================================================================27// Instructions (top level): definition2829pub use crate::isa::s390x::lower::isle::generated_code::{30ALUOp, CmpOp, FPUOp1, FPUOp2, FPUOp3, FpuConv128Op, FpuRoundMode, FpuRoundOp, LaneOrder,31MInst as Inst, RxSBGOp, ShiftOp, SymbolReloc, UnaryOp, VecBinaryOp, VecFloatCmpOp, VecIntCmpOp,32VecShiftOp, VecUnaryOp,33};3435/// The destination of a call instruction.36#[derive(Clone, Debug)]37pub enum CallInstDest {38/// Direct call.39Direct { name: ExternalName },40/// Indirect call.41Indirect { reg: Reg },42}4344/// Additional information for (direct) ReturnCall instructions, left out of line to lower the size of45/// the Inst enum.46#[derive(Clone, Debug)]47pub struct ReturnCallInfo<T> {48pub dest: T,49pub uses: CallArgList,50pub callee_pop_size: u32,51}5253#[test]54fn inst_size_test() {55// This test will help with unintentionally growing the size56// of the Inst enum.57assert_eq!(32, std::mem::size_of::<Inst>());58}5960/// A register pair. Enum so it can be destructured in ISLE.61#[derive(Clone, Copy, Debug)]62pub struct RegPair {63pub hi: Reg,64pub lo: Reg,65}6667/// A writable register pair. Enum so it can be destructured in ISLE.68#[derive(Clone, Copy, Debug)]69pub struct WritableRegPair {70pub hi: Writable<Reg>,71pub lo: Writable<Reg>,72}7374impl WritableRegPair {75pub fn to_regpair(&self) -> RegPair {76RegPair {77hi: self.hi.to_reg(),78lo: self.lo.to_reg(),79}80}81}8283/// Supported instruction sets84#[expect(non_camel_case_types, reason = "matching native names")]85#[derive(Debug)]86pub(crate) enum InstructionSet {87/// Baseline ISA for cranelift is z14.88Base,89/// Miscellaneous-Instruction-Extensions Facility 3 (z15)90MIE3,91/// Vector-Enhancements Facility 2 (z15)92VXRS_EXT2,93}9495impl Inst {96/// Retrieve the ISA feature set in which the instruction is available.97fn available_in_isa(&self) -> InstructionSet {98match self {99// These instructions are part of the baseline ISA for cranelift (z14)100Inst::Nop0101| Inst::Nop2102| Inst::AluRRSImm16 { .. }103| Inst::AluRR { .. }104| Inst::AluRX { .. }105| Inst::AluRSImm16 { .. }106| Inst::AluRSImm32 { .. }107| Inst::AluRUImm32 { .. }108| Inst::AluRUImm16Shifted { .. }109| Inst::AluRUImm32Shifted { .. }110| Inst::ShiftRR { .. }111| Inst::RxSBG { .. }112| Inst::RxSBGTest { .. }113| Inst::SMulWide { .. }114| Inst::UMulWide { .. }115| Inst::SDivMod32 { .. }116| Inst::SDivMod64 { .. }117| Inst::UDivMod32 { .. }118| Inst::UDivMod64 { .. }119| Inst::Flogr { .. }120| Inst::CmpRR { .. }121| Inst::CmpRX { .. }122| Inst::CmpRSImm16 { .. }123| Inst::CmpRSImm32 { .. }124| Inst::CmpRUImm32 { .. }125| Inst::CmpTrapRR { .. }126| Inst::CmpTrapRSImm16 { .. }127| Inst::CmpTrapRUImm16 { .. }128| Inst::AtomicRmw { .. }129| Inst::AtomicCas32 { .. }130| Inst::AtomicCas64 { .. }131| Inst::Fence132| Inst::Load32 { .. }133| Inst::Load32ZExt8 { .. }134| Inst::Load32SExt8 { .. }135| Inst::Load32ZExt16 { .. }136| Inst::Load32SExt16 { .. }137| Inst::Load64 { .. }138| Inst::Load64ZExt8 { .. }139| Inst::Load64SExt8 { .. }140| Inst::Load64ZExt16 { .. }141| Inst::Load64SExt16 { .. }142| Inst::Load64ZExt32 { .. }143| Inst::Load64SExt32 { .. }144| Inst::LoadRev16 { .. }145| Inst::LoadRev32 { .. }146| Inst::LoadRev64 { .. }147| Inst::Store8 { .. }148| Inst::Store16 { .. }149| Inst::Store32 { .. }150| Inst::Store64 { .. }151| Inst::StoreImm8 { .. }152| Inst::StoreImm16 { .. }153| Inst::StoreImm32SExt16 { .. }154| Inst::StoreImm64SExt16 { .. }155| Inst::StoreRev16 { .. }156| Inst::StoreRev32 { .. }157| Inst::StoreRev64 { .. }158| Inst::LoadMultiple64 { .. }159| Inst::StoreMultiple64 { .. }160| Inst::Mov32 { .. }161| Inst::Mov64 { .. }162| Inst::MovPReg { .. }163| Inst::Mov32Imm { .. }164| Inst::Mov32SImm16 { .. }165| Inst::Mov64SImm16 { .. }166| Inst::Mov64SImm32 { .. }167| Inst::Mov64UImm16Shifted { .. }168| Inst::Mov64UImm32Shifted { .. }169| Inst::Insert64UImm16Shifted { .. }170| Inst::Insert64UImm32Shifted { .. }171| Inst::LoadAR { .. }172| Inst::InsertAR { .. }173| Inst::Extend { .. }174| Inst::CMov32 { .. }175| Inst::CMov64 { .. }176| Inst::CMov32SImm16 { .. }177| Inst::CMov64SImm16 { .. }178| Inst::FpuMove32 { .. }179| Inst::FpuMove64 { .. }180| Inst::FpuCMov32 { .. }181| Inst::FpuCMov64 { .. }182| Inst::FpuRR { .. }183| Inst::FpuRRR { .. }184| Inst::FpuRRRR { .. }185| Inst::FpuConv128FromInt { .. }186| Inst::FpuConv128ToInt { .. }187| Inst::FpuCmp32 { .. }188| Inst::FpuCmp64 { .. }189| Inst::FpuCmp128 { .. }190| Inst::VecRRR { .. }191| Inst::VecRR { .. }192| Inst::VecShiftRR { .. }193| Inst::VecSelect { .. }194| Inst::VecPermute { .. }195| Inst::VecPermuteDWImm { .. }196| Inst::VecIntCmp { .. }197| Inst::VecIntCmpS { .. }198| Inst::VecFloatCmp { .. }199| Inst::VecFloatCmpS { .. }200| Inst::VecInt128SCmpHi { .. }201| Inst::VecInt128UCmpHi { .. }202| Inst::VecLoad { .. }203| Inst::VecStore { .. }204| Inst::VecLoadReplicate { .. }205| Inst::VecMov { .. }206| Inst::VecCMov { .. }207| Inst::MovToVec128 { .. }208| Inst::VecImmByteMask { .. }209| Inst::VecImmBitMask { .. }210| Inst::VecImmReplicate { .. }211| Inst::VecLoadLane { .. }212| Inst::VecLoadLaneUndef { .. }213| Inst::VecStoreLane { .. }214| Inst::VecInsertLane { .. }215| Inst::VecInsertLaneUndef { .. }216| Inst::VecExtractLane { .. }217| Inst::VecInsertLaneImm { .. }218| Inst::VecInsertLaneImmUndef { .. }219| Inst::VecReplicateLane { .. }220| Inst::VecEltRev { .. }221| Inst::AllocateArgs { .. }222| Inst::Call { .. }223| Inst::ReturnCall { .. }224| Inst::Args { .. }225| Inst::Rets { .. }226| Inst::Ret { .. }227| Inst::Jump { .. }228| Inst::CondBr { .. }229| Inst::TrapIf { .. }230| Inst::IndirectBr { .. }231| Inst::Debugtrap232| Inst::Trap { .. }233| Inst::JTSequence { .. }234| Inst::StackProbeLoop { .. }235| Inst::LoadSymbolReloc { .. }236| Inst::LoadAddr { .. }237| Inst::Loop { .. }238| Inst::CondBreak { .. }239| Inst::Unwind { .. }240| Inst::ElfTlsGetOffset { .. } => InstructionSet::Base,241242// These depend on the opcode243Inst::AluRRR { alu_op, .. } => match alu_op {244ALUOp::NotAnd32 | ALUOp::NotAnd64 => InstructionSet::MIE3,245ALUOp::NotOrr32 | ALUOp::NotOrr64 => InstructionSet::MIE3,246ALUOp::NotXor32 | ALUOp::NotXor64 => InstructionSet::MIE3,247ALUOp::AndNot32 | ALUOp::AndNot64 => InstructionSet::MIE3,248ALUOp::OrrNot32 | ALUOp::OrrNot64 => InstructionSet::MIE3,249_ => InstructionSet::Base,250},251Inst::UnaryRR { op, .. } => match op {252UnaryOp::PopcntReg => InstructionSet::MIE3,253_ => InstructionSet::Base,254},255Inst::FpuRound { op, .. } => match op {256FpuRoundOp::ToSInt32 | FpuRoundOp::FromSInt32 => InstructionSet::VXRS_EXT2,257FpuRoundOp::ToUInt32 | FpuRoundOp::FromUInt32 => InstructionSet::VXRS_EXT2,258FpuRoundOp::ToSInt32x4 | FpuRoundOp::FromSInt32x4 => InstructionSet::VXRS_EXT2,259FpuRoundOp::ToUInt32x4 | FpuRoundOp::FromUInt32x4 => InstructionSet::VXRS_EXT2,260_ => InstructionSet::Base,261},262263// These are all part of VXRS_EXT2264Inst::VecLoadRev { .. }265| Inst::VecLoadByte16Rev { .. }266| Inst::VecLoadByte32Rev { .. }267| Inst::VecLoadByte64Rev { .. }268| Inst::VecLoadElt16Rev { .. }269| Inst::VecLoadElt32Rev { .. }270| Inst::VecLoadElt64Rev { .. }271| Inst::VecStoreRev { .. }272| Inst::VecStoreByte16Rev { .. }273| Inst::VecStoreByte32Rev { .. }274| Inst::VecStoreByte64Rev { .. }275| Inst::VecStoreElt16Rev { .. }276| Inst::VecStoreElt32Rev { .. }277| Inst::VecStoreElt64Rev { .. }278| Inst::VecLoadReplicateRev { .. }279| Inst::VecLoadLaneRev { .. }280| Inst::VecLoadLaneRevUndef { .. }281| Inst::VecStoreLaneRev { .. } => InstructionSet::VXRS_EXT2,282283Inst::DummyUse { .. } => InstructionSet::Base,284285Inst::LabelAddress { .. } => InstructionSet::Base,286}287}288289/// Create a 128-bit move instruction.290pub fn mov128(to_reg: Writable<Reg>, from_reg: Reg) -> Inst {291assert!(to_reg.to_reg().class() == RegClass::Float);292assert!(from_reg.class() == RegClass::Float);293Inst::VecMov {294rd: to_reg,295rn: from_reg,296}297}298299/// Create a 64-bit move instruction.300pub fn mov64(to_reg: Writable<Reg>, from_reg: Reg) -> Inst {301assert!(to_reg.to_reg().class() == from_reg.class());302if from_reg.class() == RegClass::Int {303Inst::Mov64 {304rd: to_reg,305rm: from_reg,306}307} else {308Inst::FpuMove64 {309rd: to_reg,310rn: from_reg,311}312}313}314315/// Create a 32-bit move instruction.316pub fn mov32(to_reg: Writable<Reg>, from_reg: Reg) -> Inst {317if from_reg.class() == RegClass::Int {318Inst::Mov32 {319rd: to_reg,320rm: from_reg,321}322} else {323Inst::FpuMove32 {324rd: to_reg,325rn: from_reg,326}327}328}329330/// Generic constructor for a load (zero-extending where appropriate).331pub fn gen_load(into_reg: Writable<Reg>, mem: MemArg, ty: Type) -> Inst {332match ty {333types::I8 => Inst::Load64ZExt8 { rd: into_reg, mem },334types::I16 => Inst::Load64ZExt16 { rd: into_reg, mem },335types::I32 => Inst::Load64ZExt32 { rd: into_reg, mem },336types::I64 => Inst::Load64 { rd: into_reg, mem },337types::F16 => Inst::VecLoadLaneUndef {338size: 16,339rd: into_reg,340mem,341lane_imm: 0,342},343types::F32 => Inst::VecLoadLaneUndef {344size: 32,345rd: into_reg,346mem,347lane_imm: 0,348},349types::F64 => Inst::VecLoadLaneUndef {350size: 64,351rd: into_reg,352mem,353lane_imm: 0,354},355_ if ty.bits() == 128 => Inst::VecLoad { rd: into_reg, mem },356_ => unimplemented!("gen_load({})", ty),357}358}359360/// Generic constructor for a store.361pub fn gen_store(mem: MemArg, from_reg: Reg, ty: Type) -> Inst {362match ty {363types::I8 => Inst::Store8 { rd: from_reg, mem },364types::I16 => Inst::Store16 { rd: from_reg, mem },365types::I32 => Inst::Store32 { rd: from_reg, mem },366types::I64 => Inst::Store64 { rd: from_reg, mem },367types::F16 => Inst::VecStoreLane {368size: 16,369rd: from_reg,370mem,371lane_imm: 0,372},373types::F32 => Inst::VecStoreLane {374size: 32,375rd: from_reg,376mem,377lane_imm: 0,378},379types::F64 => Inst::VecStoreLane {380size: 64,381rd: from_reg,382mem,383lane_imm: 0,384},385_ if ty.bits() == 128 => Inst::VecStore { rd: from_reg, mem },386_ => unimplemented!("gen_store({})", ty),387}388}389}390391//=============================================================================392// Instructions: get_regs393394fn memarg_operands(memarg: &mut MemArg, collector: &mut impl OperandVisitor) {395match memarg {396MemArg::BXD12 { base, index, .. } | MemArg::BXD20 { base, index, .. } => {397collector.reg_use(base);398collector.reg_use(index);399}400MemArg::Label { .. } | MemArg::Constant { .. } | MemArg::Symbol { .. } => {}401MemArg::RegOffset { reg, .. } => {402collector.reg_use(reg);403}404MemArg::InitialSPOffset { .. }405| MemArg::IncomingArgOffset { .. }406| MemArg::OutgoingArgOffset { .. }407| MemArg::SlotOffset { .. }408| MemArg::SpillOffset { .. } => {}409}410// mem_finalize might require %r1 to hold (part of) the address.411// Conservatively assume this will always be necessary here.412collector.reg_fixed_nonallocatable(gpr_preg(1));413}414415fn s390x_get_operands(inst: &mut Inst, collector: &mut DenyReuseVisitor<impl OperandVisitor>) {416match inst {417Inst::AluRRR { rd, rn, rm, .. } => {418collector.reg_def(rd);419collector.reg_use(rn);420collector.reg_use(rm);421}422Inst::AluRRSImm16 { rd, rn, .. } => {423collector.reg_def(rd);424collector.reg_use(rn);425}426Inst::AluRR { rd, ri, rm, .. } => {427collector.reg_reuse_def(rd, 1);428collector.reg_use(ri);429collector.reg_use(rm);430}431Inst::AluRX { rd, ri, mem, .. } => {432collector.reg_reuse_def(rd, 1);433collector.reg_use(ri);434memarg_operands(mem, collector);435}436Inst::AluRSImm16 { rd, ri, .. } => {437collector.reg_reuse_def(rd, 1);438collector.reg_use(ri);439}440Inst::AluRSImm32 { rd, ri, .. } => {441collector.reg_reuse_def(rd, 1);442collector.reg_use(ri);443}444Inst::AluRUImm32 { rd, ri, .. } => {445collector.reg_reuse_def(rd, 1);446collector.reg_use(ri);447}448Inst::AluRUImm16Shifted { rd, ri, .. } => {449collector.reg_reuse_def(rd, 1);450collector.reg_use(ri);451}452Inst::AluRUImm32Shifted { rd, ri, .. } => {453collector.reg_reuse_def(rd, 1);454collector.reg_use(ri);455}456Inst::SMulWide { rd, rn, rm } => {457collector.reg_use(rn);458collector.reg_use(rm);459// FIXME: The pair is hard-coded as %r2/%r3 because regalloc cannot handle pairs. If460// that changes, all the hard-coded uses of %r2/%r3 can be changed.461collector.reg_fixed_def(&mut rd.hi, gpr(2));462collector.reg_fixed_def(&mut rd.lo, gpr(3));463}464Inst::UMulWide { rd, ri, rn } => {465collector.reg_use(rn);466collector.reg_fixed_def(&mut rd.hi, gpr(2));467collector.reg_fixed_def(&mut rd.lo, gpr(3));468collector.reg_fixed_use(ri, gpr(3));469}470Inst::SDivMod32 { rd, ri, rn } | Inst::SDivMod64 { rd, ri, rn } => {471collector.reg_use(rn);472collector.reg_fixed_def(&mut rd.hi, gpr(2));473collector.reg_fixed_def(&mut rd.lo, gpr(3));474collector.reg_fixed_use(ri, gpr(3));475}476Inst::UDivMod32 { rd, ri, rn } | Inst::UDivMod64 { rd, ri, rn } => {477collector.reg_use(rn);478collector.reg_fixed_def(&mut rd.hi, gpr(2));479collector.reg_fixed_def(&mut rd.lo, gpr(3));480collector.reg_fixed_use(&mut ri.hi, gpr(2));481collector.reg_fixed_use(&mut ri.lo, gpr(3));482}483Inst::Flogr { rd, rn } => {484collector.reg_use(rn);485collector.reg_fixed_def(&mut rd.hi, gpr(2));486collector.reg_fixed_def(&mut rd.lo, gpr(3));487}488Inst::ShiftRR {489rd, rn, shift_reg, ..490} => {491collector.reg_def(rd);492collector.reg_use(rn);493collector.reg_use(shift_reg);494}495Inst::RxSBG { rd, ri, rn, .. } => {496collector.reg_reuse_def(rd, 1);497collector.reg_use(ri);498collector.reg_use(rn);499}500Inst::RxSBGTest { rd, rn, .. } => {501collector.reg_use(rd);502collector.reg_use(rn);503}504Inst::UnaryRR { rd, rn, .. } => {505collector.reg_def(rd);506collector.reg_use(rn);507}508Inst::CmpRR { rn, rm, .. } => {509collector.reg_use(rn);510collector.reg_use(rm);511}512Inst::CmpRX { rn, mem, .. } => {513collector.reg_use(rn);514memarg_operands(mem, collector);515}516Inst::CmpRSImm16 { rn, .. } => {517collector.reg_use(rn);518}519Inst::CmpRSImm32 { rn, .. } => {520collector.reg_use(rn);521}522Inst::CmpRUImm32 { rn, .. } => {523collector.reg_use(rn);524}525Inst::CmpTrapRR { rn, rm, .. } => {526collector.reg_use(rn);527collector.reg_use(rm);528}529Inst::CmpTrapRSImm16 { rn, .. } => {530collector.reg_use(rn);531}532Inst::CmpTrapRUImm16 { rn, .. } => {533collector.reg_use(rn);534}535Inst::AtomicRmw { rd, rn, mem, .. } => {536collector.reg_def(rd);537collector.reg_use(rn);538memarg_operands(mem, collector);539}540Inst::AtomicCas32 {541rd, ri, rn, mem, ..542}543| Inst::AtomicCas64 {544rd, ri, rn, mem, ..545} => {546collector.reg_reuse_def(rd, 1);547collector.reg_use(ri);548collector.reg_use(rn);549memarg_operands(mem, collector);550}551Inst::Fence => {}552Inst::Load32 { rd, mem, .. }553| Inst::Load32ZExt8 { rd, mem, .. }554| Inst::Load32SExt8 { rd, mem, .. }555| Inst::Load32ZExt16 { rd, mem, .. }556| Inst::Load32SExt16 { rd, mem, .. }557| Inst::Load64 { rd, mem, .. }558| Inst::Load64ZExt8 { rd, mem, .. }559| Inst::Load64SExt8 { rd, mem, .. }560| Inst::Load64ZExt16 { rd, mem, .. }561| Inst::Load64SExt16 { rd, mem, .. }562| Inst::Load64ZExt32 { rd, mem, .. }563| Inst::Load64SExt32 { rd, mem, .. }564| Inst::LoadRev16 { rd, mem, .. }565| Inst::LoadRev32 { rd, mem, .. }566| Inst::LoadRev64 { rd, mem, .. } => {567collector.reg_def(rd);568memarg_operands(mem, collector);569}570Inst::Store8 { rd, mem, .. }571| Inst::Store16 { rd, mem, .. }572| Inst::Store32 { rd, mem, .. }573| Inst::Store64 { rd, mem, .. }574| Inst::StoreRev16 { rd, mem, .. }575| Inst::StoreRev32 { rd, mem, .. }576| Inst::StoreRev64 { rd, mem, .. } => {577collector.reg_use(rd);578memarg_operands(mem, collector);579}580Inst::StoreImm8 { mem, .. }581| Inst::StoreImm16 { mem, .. }582| Inst::StoreImm32SExt16 { mem, .. }583| Inst::StoreImm64SExt16 { mem, .. } => {584memarg_operands(mem, collector);585}586Inst::LoadMultiple64 { rt, rt2, mem, .. } => {587memarg_operands(mem, collector);588let first_regnum = rt.to_reg().to_real_reg().unwrap().hw_enc();589let last_regnum = rt2.to_reg().to_real_reg().unwrap().hw_enc();590for regnum in first_regnum..last_regnum + 1 {591collector.reg_fixed_nonallocatable(gpr_preg(regnum));592}593}594Inst::StoreMultiple64 { rt, rt2, mem, .. } => {595memarg_operands(mem, collector);596let first_regnum = rt.to_real_reg().unwrap().hw_enc();597let last_regnum = rt2.to_real_reg().unwrap().hw_enc();598for regnum in first_regnum..last_regnum + 1 {599collector.reg_fixed_nonallocatable(gpr_preg(regnum));600}601}602Inst::Mov64 { rd, rm } => {603collector.reg_def(rd);604collector.reg_use(rm);605}606Inst::MovPReg { rd, rm } => {607collector.reg_def(rd);608collector.reg_fixed_nonallocatable(*rm);609}610Inst::Mov32 { rd, rm } => {611collector.reg_def(rd);612collector.reg_use(rm);613}614Inst::Mov32Imm { rd, .. }615| Inst::Mov32SImm16 { rd, .. }616| Inst::Mov64SImm16 { rd, .. }617| Inst::Mov64SImm32 { rd, .. }618| Inst::Mov64UImm16Shifted { rd, .. }619| Inst::Mov64UImm32Shifted { rd, .. } => {620collector.reg_def(rd);621}622Inst::CMov32 { rd, ri, rm, .. } | Inst::CMov64 { rd, ri, rm, .. } => {623collector.reg_reuse_def(rd, 1);624collector.reg_use(ri);625collector.reg_use(rm);626}627Inst::CMov32SImm16 { rd, ri, .. } | Inst::CMov64SImm16 { rd, ri, .. } => {628collector.reg_reuse_def(rd, 1);629collector.reg_use(ri);630}631Inst::Insert64UImm16Shifted { rd, ri, .. } | Inst::Insert64UImm32Shifted { rd, ri, .. } => {632collector.reg_reuse_def(rd, 1);633collector.reg_use(ri);634}635Inst::LoadAR { rd, .. } => {636collector.reg_def(rd);637}638Inst::InsertAR { rd, ri, .. } => {639collector.reg_reuse_def(rd, 1);640collector.reg_use(ri);641}642Inst::FpuMove32 { rd, rn } | Inst::FpuMove64 { rd, rn } => {643collector.reg_def(rd);644collector.reg_use(rn);645}646Inst::FpuCMov32 { rd, ri, rm, .. } | Inst::FpuCMov64 { rd, ri, rm, .. } => {647collector.reg_reuse_def(rd, 1);648collector.reg_use(ri);649collector.reg_use(rm);650}651Inst::FpuRR { rd, rn, .. } => {652collector.reg_def(rd);653collector.reg_use(rn);654}655Inst::FpuRRR { rd, rn, rm, .. } => {656collector.reg_def(rd);657collector.reg_use(rn);658collector.reg_use(rm);659}660Inst::FpuRRRR { rd, rn, rm, ra, .. } => {661collector.reg_def(rd);662collector.reg_use(rn);663collector.reg_use(rm);664collector.reg_use(ra);665}666Inst::FpuCmp32 { rn, rm } | Inst::FpuCmp64 { rn, rm } | Inst::FpuCmp128 { rn, rm } => {667collector.reg_use(rn);668collector.reg_use(rm);669}670Inst::FpuRound { rd, rn, .. } => {671collector.reg_def(rd);672collector.reg_use(rn);673}674Inst::FpuConv128FromInt { rd, rn, .. } => {675collector.reg_fixed_def(&mut rd.hi, vr(1));676collector.reg_fixed_def(&mut rd.lo, vr(3));677collector.reg_use(rn);678}679Inst::FpuConv128ToInt { rd, rn, .. } => {680collector.reg_def(rd);681collector.reg_fixed_use(&mut rn.hi, vr(1));682collector.reg_fixed_use(&mut rn.lo, vr(3));683}684Inst::VecRRR { rd, rn, rm, .. } => {685collector.reg_def(rd);686collector.reg_use(rn);687collector.reg_use(rm);688}689Inst::VecRR { rd, rn, .. } => {690collector.reg_def(rd);691collector.reg_use(rn);692}693Inst::VecShiftRR {694rd, rn, shift_reg, ..695} => {696collector.reg_def(rd);697collector.reg_use(rn);698collector.reg_use(shift_reg);699}700Inst::VecSelect { rd, rn, rm, ra, .. } => {701collector.reg_def(rd);702collector.reg_use(rn);703collector.reg_use(rm);704collector.reg_use(ra);705}706Inst::VecPermute { rd, rn, rm, ra, .. } => {707collector.reg_def(rd);708collector.reg_use(rn);709collector.reg_use(rm);710collector.reg_use(ra);711}712Inst::VecPermuteDWImm { rd, rn, rm, .. } => {713collector.reg_def(rd);714collector.reg_use(rn);715collector.reg_use(rm);716}717Inst::VecIntCmp { rd, rn, rm, .. } | Inst::VecIntCmpS { rd, rn, rm, .. } => {718collector.reg_def(rd);719collector.reg_use(rn);720collector.reg_use(rm);721}722Inst::VecFloatCmp { rd, rn, rm, .. } | Inst::VecFloatCmpS { rd, rn, rm, .. } => {723collector.reg_def(rd);724collector.reg_use(rn);725collector.reg_use(rm);726}727Inst::VecInt128SCmpHi { tmp, rn, rm, .. } | Inst::VecInt128UCmpHi { tmp, rn, rm, .. } => {728collector.reg_def(tmp);729collector.reg_use(rn);730collector.reg_use(rm);731}732Inst::VecLoad { rd, mem, .. } => {733collector.reg_def(rd);734memarg_operands(mem, collector);735}736Inst::VecLoadRev { rd, mem, .. } => {737collector.reg_def(rd);738memarg_operands(mem, collector);739}740Inst::VecLoadByte16Rev { rd, mem, .. } => {741collector.reg_def(rd);742memarg_operands(mem, collector);743}744Inst::VecLoadByte32Rev { rd, mem, .. } => {745collector.reg_def(rd);746memarg_operands(mem, collector);747}748Inst::VecLoadByte64Rev { rd, mem, .. } => {749collector.reg_def(rd);750memarg_operands(mem, collector);751}752Inst::VecLoadElt16Rev { rd, mem, .. } => {753collector.reg_def(rd);754memarg_operands(mem, collector);755}756Inst::VecLoadElt32Rev { rd, mem, .. } => {757collector.reg_def(rd);758memarg_operands(mem, collector);759}760Inst::VecLoadElt64Rev { rd, mem, .. } => {761collector.reg_def(rd);762memarg_operands(mem, collector);763}764Inst::VecStore { rd, mem, .. } => {765collector.reg_use(rd);766memarg_operands(mem, collector);767}768Inst::VecStoreRev { rd, mem, .. } => {769collector.reg_use(rd);770memarg_operands(mem, collector);771}772Inst::VecStoreByte16Rev { rd, mem, .. } => {773collector.reg_use(rd);774memarg_operands(mem, collector);775}776Inst::VecStoreByte32Rev { rd, mem, .. } => {777collector.reg_use(rd);778memarg_operands(mem, collector);779}780Inst::VecStoreByte64Rev { rd, mem, .. } => {781collector.reg_use(rd);782memarg_operands(mem, collector);783}784Inst::VecStoreElt16Rev { rd, mem, .. } => {785collector.reg_use(rd);786memarg_operands(mem, collector);787}788Inst::VecStoreElt32Rev { rd, mem, .. } => {789collector.reg_use(rd);790memarg_operands(mem, collector);791}792Inst::VecStoreElt64Rev { rd, mem, .. } => {793collector.reg_use(rd);794memarg_operands(mem, collector);795}796Inst::VecLoadReplicate { rd, mem, .. } => {797collector.reg_def(rd);798memarg_operands(mem, collector);799}800Inst::VecLoadReplicateRev { rd, mem, .. } => {801collector.reg_def(rd);802memarg_operands(mem, collector);803}804Inst::VecMov { rd, rn } => {805collector.reg_def(rd);806collector.reg_use(rn);807}808Inst::VecCMov { rd, ri, rm, .. } => {809collector.reg_reuse_def(rd, 1);810collector.reg_use(ri);811collector.reg_use(rm);812}813Inst::MovToVec128 { rd, rn, rm } => {814collector.reg_def(rd);815collector.reg_use(rn);816collector.reg_use(rm);817}818Inst::VecImmByteMask { rd, .. } => {819collector.reg_def(rd);820}821Inst::VecImmBitMask { rd, .. } => {822collector.reg_def(rd);823}824Inst::VecImmReplicate { rd, .. } => {825collector.reg_def(rd);826}827Inst::VecLoadLane { rd, ri, mem, .. } => {828collector.reg_reuse_def(rd, 1);829collector.reg_use(ri);830memarg_operands(mem, collector);831}832Inst::VecLoadLaneUndef { rd, mem, .. } => {833collector.reg_def(rd);834memarg_operands(mem, collector);835}836Inst::VecStoreLaneRev { rd, mem, .. } => {837collector.reg_use(rd);838memarg_operands(mem, collector);839}840Inst::VecLoadLaneRevUndef { rd, mem, .. } => {841collector.reg_def(rd);842memarg_operands(mem, collector);843}844Inst::VecStoreLane { rd, mem, .. } => {845collector.reg_use(rd);846memarg_operands(mem, collector);847}848Inst::VecLoadLaneRev { rd, ri, mem, .. } => {849collector.reg_reuse_def(rd, 1);850collector.reg_use(ri);851memarg_operands(mem, collector);852}853Inst::VecInsertLane {854rd,855ri,856rn,857lane_reg,858..859} => {860collector.reg_reuse_def(rd, 1);861collector.reg_use(ri);862collector.reg_use(rn);863collector.reg_use(lane_reg);864}865Inst::VecInsertLaneUndef {866rd, rn, lane_reg, ..867} => {868collector.reg_def(rd);869collector.reg_use(rn);870collector.reg_use(lane_reg);871}872Inst::VecExtractLane {873rd, rn, lane_reg, ..874} => {875collector.reg_def(rd);876collector.reg_use(rn);877collector.reg_use(lane_reg);878}879Inst::VecInsertLaneImm { rd, ri, .. } => {880collector.reg_reuse_def(rd, 1);881collector.reg_use(ri);882}883Inst::VecInsertLaneImmUndef { rd, .. } => {884collector.reg_def(rd);885}886Inst::VecReplicateLane { rd, rn, .. } => {887collector.reg_def(rd);888collector.reg_use(rn);889}890Inst::VecEltRev { rd, rn, .. } => {891collector.reg_def(rd);892collector.reg_use(rn);893}894Inst::Extend { rd, rn, .. } => {895collector.reg_def(rd);896collector.reg_use(rn);897}898Inst::AllocateArgs { .. } => {}899Inst::Call { link, info, .. } => {900let CallInfo {901dest,902uses,903defs,904clobbers,905try_call_info,906..907} = &mut **info;908match dest {909CallInstDest::Direct { .. } => {}910CallInstDest::Indirect { reg } => collector.reg_use(reg),911}912for CallArgPair { vreg, preg } in uses {913collector.reg_fixed_use(vreg, *preg);914}915for CallRetPair { vreg, location } in defs {916match location {917RetLocation::Reg(preg, ..) => collector.reg_fixed_def(vreg, *preg),918RetLocation::Stack(..) => collector.any_def(vreg),919}920}921let mut clobbers = *clobbers;922clobbers.add(link.to_reg().to_real_reg().unwrap().into());923collector.reg_clobbers(clobbers);924if let Some(try_call_info) = try_call_info {925try_call_info.collect_operands(collector);926}927}928Inst::ReturnCall { info } => {929let ReturnCallInfo { dest, uses, .. } = &mut **info;930match dest {931CallInstDest::Direct { .. } => {}932CallInstDest::Indirect { reg } => collector.reg_use(reg),933}934for CallArgPair { vreg, preg } in uses {935collector.reg_fixed_use(vreg, *preg);936}937}938Inst::ElfTlsGetOffset {939tls_offset,940got,941got_offset,942..943} => {944collector.reg_fixed_use(got, gpr(12));945collector.reg_fixed_use(got_offset, gpr(2));946collector.reg_fixed_def(tls_offset, gpr(2));947948let mut clobbers =949S390xMachineDeps::get_regs_clobbered_by_call(CallConv::SystemV, false);950clobbers.add(gpr_preg(14));951clobbers.remove(gpr_preg(2));952collector.reg_clobbers(clobbers);953}954Inst::Args { args } => {955for ArgPair { vreg, preg } in args {956collector.reg_fixed_def(vreg, *preg);957}958}959Inst::Rets { rets } => {960for RetPair { vreg, preg } in rets {961collector.reg_fixed_use(vreg, *preg);962}963}964Inst::Ret { .. } => {965// NOTE: we explicitly don't mark the link register as used here, as the use is only in966// the epilog where callee-save registers are restored.967}968Inst::Jump { .. } => {}969Inst::IndirectBr { rn, .. } => {970collector.reg_use(rn);971}972Inst::CondBr { .. } => {}973Inst::Nop0 | Inst::Nop2 => {}974Inst::Debugtrap => {}975Inst::Trap { .. } => {}976Inst::TrapIf { .. } => {}977Inst::JTSequence { ridx, .. } => {978collector.reg_use(ridx);979collector.reg_fixed_nonallocatable(gpr_preg(1));980}981Inst::LoadSymbolReloc { rd, .. } => {982collector.reg_def(rd);983collector.reg_fixed_nonallocatable(gpr_preg(1));984}985Inst::LoadAddr { rd, mem } => {986collector.reg_def(rd);987memarg_operands(mem, collector);988}989Inst::StackProbeLoop { probe_count, .. } => {990collector.reg_early_def(probe_count);991}992Inst::Loop { body, .. } => {993// `reuse_def` constraints can't be permitted in a Loop instruction because the operand994// index will always be relative to the Loop instruction, not the individual995// instruction in the loop body. However, fixed-nonallocatable registers used with996// instructions that would have emitted `reuse_def` constraints are fine.997let mut collector = DenyReuseVisitor {998inner: collector.inner,999deny_reuse: true,1000};1001for inst in body {1002s390x_get_operands(inst, &mut collector);1003}1004}1005Inst::CondBreak { .. } => {}1006Inst::Unwind { .. } => {}1007Inst::DummyUse { reg } => {1008collector.reg_use(reg);1009}1010Inst::LabelAddress { dst, .. } => {1011collector.reg_def(dst);1012}1013}1014}10151016struct DenyReuseVisitor<'a, T> {1017inner: &'a mut T,1018deny_reuse: bool,1019}10201021impl<T: OperandVisitor> OperandVisitor for DenyReuseVisitor<'_, T> {1022fn add_operand(1023&mut self,1024reg: &mut Reg,1025constraint: regalloc2::OperandConstraint,1026kind: regalloc2::OperandKind,1027pos: regalloc2::OperandPos,1028) {1029debug_assert!(1030!self.deny_reuse || !matches!(constraint, regalloc2::OperandConstraint::Reuse(_))1031);1032self.inner.add_operand(reg, constraint, kind, pos);1033}10341035fn debug_assert_is_allocatable_preg(&self, reg: regalloc2::PReg, expected: bool) {1036self.inner.debug_assert_is_allocatable_preg(reg, expected);1037}10381039fn reg_clobbers(&mut self, regs: regalloc2::PRegSet) {1040self.inner.reg_clobbers(regs);1041}1042}10431044//=============================================================================1045// Instructions: misc functions and external interface10461047impl MachInst for Inst {1048type ABIMachineSpec = S390xMachineDeps;1049type LabelUse = LabelUse;1050const TRAP_OPCODE: &'static [u8] = &[0, 0];10511052fn get_operands(&mut self, collector: &mut impl OperandVisitor) {1053s390x_get_operands(1054self,1055&mut DenyReuseVisitor {1056inner: collector,1057deny_reuse: false,1058},1059);1060}10611062fn is_move(&self) -> Option<(Writable<Reg>, Reg)> {1063match self {1064&Inst::Mov32 { rd, rm } => Some((rd, rm)),1065&Inst::Mov64 { rd, rm } => Some((rd, rm)),1066&Inst::FpuMove32 { rd, rn } => Some((rd, rn)),1067&Inst::FpuMove64 { rd, rn } => Some((rd, rn)),1068&Inst::VecMov { rd, rn } => Some((rd, rn)),1069_ => None,1070}1071}10721073fn is_included_in_clobbers(&self) -> bool {1074// We exclude call instructions from the clobber-set when they are calls1075// from caller to callee with the same ABI. Such calls cannot possibly1076// force any new registers to be saved in the prologue, because anything1077// that the callee clobbers, the caller is also allowed to clobber. This1078// both saves work and enables us to more precisely follow the1079// half-caller-save, half-callee-save SysV ABI for some vector1080// registers.1081match self {1082&Inst::Args { .. } => false,1083&Inst::Call { ref info, .. } => {1084info.caller_conv != info.callee_conv || info.try_call_info.is_some()1085}1086&Inst::ElfTlsGetOffset { .. } => false,1087_ => true,1088}1089}10901091fn is_trap(&self) -> bool {1092match self {1093Self::Trap { .. } => true,1094_ => false,1095}1096}10971098fn is_args(&self) -> bool {1099match self {1100Self::Args { .. } => true,1101_ => false,1102}1103}11041105fn is_term(&self) -> MachTerminator {1106match self {1107&Inst::Rets { .. } => MachTerminator::Ret,1108&Inst::ReturnCall { .. } => MachTerminator::RetCall,1109&Inst::Jump { .. } => MachTerminator::Branch,1110&Inst::CondBr { .. } => MachTerminator::Branch,1111&Inst::IndirectBr { .. } => MachTerminator::Branch,1112&Inst::JTSequence { .. } => MachTerminator::Branch,1113&Inst::Call { ref info, .. } if info.try_call_info.is_some() => MachTerminator::Branch,1114_ => MachTerminator::None,1115}1116}11171118fn is_mem_access(&self) -> bool {1119panic!("TODO FILL ME OUT")1120}11211122fn is_safepoint(&self) -> bool {1123match self {1124Inst::Call { .. } => true,1125_ => false,1126}1127}11281129fn call_type(&self) -> CallType {1130match self {1131Inst::Call { .. } | Inst::ElfTlsGetOffset { .. } => CallType::Regular,11321133Inst::ReturnCall { .. } => CallType::TailCall,11341135_ => CallType::None,1136}1137}11381139fn gen_move(to_reg: Writable<Reg>, from_reg: Reg, ty: Type) -> Inst {1140assert!(ty.bits() <= 128);1141if ty.bits() <= 32 {1142Inst::mov32(to_reg, from_reg)1143} else if ty.bits() <= 64 {1144Inst::mov64(to_reg, from_reg)1145} else {1146Inst::mov128(to_reg, from_reg)1147}1148}11491150fn gen_nop(preferred_size: usize) -> Inst {1151if preferred_size == 0 {1152Inst::Nop01153} else {1154// We can't give a NOP (or any insn) < 2 bytes.1155assert!(preferred_size >= 2);1156Inst::Nop21157}1158}11591160fn rc_for_type(ty: Type) -> CodegenResult<(&'static [RegClass], &'static [Type])> {1161match ty {1162types::I8 => Ok((&[RegClass::Int], &[types::I8])),1163types::I16 => Ok((&[RegClass::Int], &[types::I16])),1164types::I32 => Ok((&[RegClass::Int], &[types::I32])),1165types::I64 => Ok((&[RegClass::Int], &[types::I64])),1166types::F16 => Ok((&[RegClass::Float], &[types::F16])),1167types::F32 => Ok((&[RegClass::Float], &[types::F32])),1168types::F64 => Ok((&[RegClass::Float], &[types::F64])),1169types::F128 => Ok((&[RegClass::Float], &[types::F128])),1170types::I128 => Ok((&[RegClass::Float], &[types::I128])),1171_ if ty.is_vector() && ty.bits() == 128 => Ok((&[RegClass::Float], &[types::I8X16])),1172_ => Err(CodegenError::Unsupported(format!(1173"Unexpected SSA-value type: {ty}"1174))),1175}1176}11771178fn canonical_type_for_rc(rc: RegClass) -> Type {1179match rc {1180RegClass::Int => types::I64,1181RegClass::Float => types::I8X16,1182RegClass::Vector => unreachable!(),1183}1184}11851186fn gen_jump(target: MachLabel) -> Inst {1187Inst::Jump { dest: target }1188}11891190fn worst_case_size() -> CodeOffset {1191// The maximum size, in bytes, of any `Inst`'s emitted code. We have at least one case of1192// an 8-instruction sequence (saturating int-to-float conversions) with three embedded1193// 64-bit f64 constants.1194//1195// Note that inline jump-tables handle island/pool insertion separately, so we do not need1196// to account for them here (otherwise the worst case would be 2^31 * 4, clearly not1197// feasible for other reasons).1198441199}12001201fn ref_type_regclass(_: &settings::Flags) -> RegClass {1202RegClass::Int1203}12041205fn gen_dummy_use(reg: Reg) -> Inst {1206Inst::DummyUse { reg }1207}12081209fn function_alignment() -> FunctionAlignment {1210FunctionAlignment {1211minimum: 4,1212preferred: 4,1213}1214}1215}12161217//=============================================================================1218// Pretty-printing of instructions.12191220fn mem_finalize_for_show(mem: &MemArg, state: &EmitState, mi: MemInstType) -> (String, MemArg) {1221let (mem_insts, mem) = mem_finalize(mem, state, mi);1222let mut mem_str = mem_insts1223.into_iter()1224.map(|inst| inst.print_with_state(&mut EmitState::default()))1225.collect::<Vec<_>>()1226.join(" ; ");1227if !mem_str.is_empty() {1228mem_str += " ; ";1229}12301231(mem_str, mem)1232}12331234impl Inst {1235fn print_with_state(&self, state: &mut EmitState) -> String {1236match self {1237&Inst::Nop0 => "nop-zero-len".to_string(),1238&Inst::Nop2 => "nop".to_string(),1239&Inst::AluRRR { alu_op, rd, rn, rm } => {1240let (op, have_rr) = match alu_op {1241ALUOp::Add32 => ("ark", true),1242ALUOp::Add64 => ("agrk", true),1243ALUOp::AddLogical32 => ("alrk", true),1244ALUOp::AddLogical64 => ("algrk", true),1245ALUOp::Sub32 => ("srk", true),1246ALUOp::Sub64 => ("sgrk", true),1247ALUOp::SubLogical32 => ("slrk", true),1248ALUOp::SubLogical64 => ("slgrk", true),1249ALUOp::Mul32 => ("msrkc", true),1250ALUOp::Mul64 => ("msgrkc", true),1251ALUOp::And32 => ("nrk", true),1252ALUOp::And64 => ("ngrk", true),1253ALUOp::Orr32 => ("ork", true),1254ALUOp::Orr64 => ("ogrk", true),1255ALUOp::Xor32 => ("xrk", true),1256ALUOp::Xor64 => ("xgrk", true),1257ALUOp::NotAnd32 => ("nnrk", false),1258ALUOp::NotAnd64 => ("nngrk", false),1259ALUOp::NotOrr32 => ("nork", false),1260ALUOp::NotOrr64 => ("nogrk", false),1261ALUOp::NotXor32 => ("nxrk", false),1262ALUOp::NotXor64 => ("nxgrk", false),1263ALUOp::AndNot32 => ("ncrk", false),1264ALUOp::AndNot64 => ("ncgrk", false),1265ALUOp::OrrNot32 => ("ocrk", false),1266ALUOp::OrrNot64 => ("ocgrk", false),1267_ => unreachable!(),1268};1269if have_rr && rd.to_reg() == rn {1270let inst = Inst::AluRR {1271alu_op,1272rd,1273ri: rd.to_reg(),1274rm,1275};1276return inst.print_with_state(state);1277}1278let rd = pretty_print_reg(rd.to_reg());1279let rn = pretty_print_reg(rn);1280let rm = pretty_print_reg(rm);1281format!("{op} {rd}, {rn}, {rm}")1282}1283&Inst::AluRRSImm16 {1284alu_op,1285rd,1286rn,1287imm,1288} => {1289if rd.to_reg() == rn {1290let inst = Inst::AluRSImm16 {1291alu_op,1292rd,1293ri: rd.to_reg(),1294imm,1295};1296return inst.print_with_state(state);1297}1298let op = match alu_op {1299ALUOp::Add32 => "ahik",1300ALUOp::Add64 => "aghik",1301_ => unreachable!(),1302};1303let rd = pretty_print_reg(rd.to_reg());1304let rn = pretty_print_reg(rn);1305format!("{op} {rd}, {rn}, {imm}")1306}1307&Inst::AluRR { alu_op, rd, ri, rm } => {1308let op = match alu_op {1309ALUOp::Add32 => "ar",1310ALUOp::Add64 => "agr",1311ALUOp::Add64Ext32 => "agfr",1312ALUOp::AddLogical32 => "alr",1313ALUOp::AddLogical64 => "algr",1314ALUOp::AddLogical64Ext32 => "algfr",1315ALUOp::Sub32 => "sr",1316ALUOp::Sub64 => "sgr",1317ALUOp::Sub64Ext32 => "sgfr",1318ALUOp::SubLogical32 => "slr",1319ALUOp::SubLogical64 => "slgr",1320ALUOp::SubLogical64Ext32 => "slgfr",1321ALUOp::Mul32 => "msr",1322ALUOp::Mul64 => "msgr",1323ALUOp::Mul64Ext32 => "msgfr",1324ALUOp::And32 => "nr",1325ALUOp::And64 => "ngr",1326ALUOp::Orr32 => "or",1327ALUOp::Orr64 => "ogr",1328ALUOp::Xor32 => "xr",1329ALUOp::Xor64 => "xgr",1330_ => unreachable!(),1331};1332let rd = pretty_print_reg_mod(rd, ri);1333let rm = pretty_print_reg(rm);1334format!("{op} {rd}, {rm}")1335}1336&Inst::AluRX {1337alu_op,1338rd,1339ri,1340ref mem,1341} => {1342let (opcode_rx, opcode_rxy) = match alu_op {1343ALUOp::Add32 => (Some("a"), Some("ay")),1344ALUOp::Add32Ext16 => (Some("ah"), Some("ahy")),1345ALUOp::Add64 => (None, Some("ag")),1346ALUOp::Add64Ext16 => (None, Some("agh")),1347ALUOp::Add64Ext32 => (None, Some("agf")),1348ALUOp::AddLogical32 => (Some("al"), Some("aly")),1349ALUOp::AddLogical64 => (None, Some("alg")),1350ALUOp::AddLogical64Ext32 => (None, Some("algf")),1351ALUOp::Sub32 => (Some("s"), Some("sy")),1352ALUOp::Sub32Ext16 => (Some("sh"), Some("shy")),1353ALUOp::Sub64 => (None, Some("sg")),1354ALUOp::Sub64Ext16 => (None, Some("sgh")),1355ALUOp::Sub64Ext32 => (None, Some("sgf")),1356ALUOp::SubLogical32 => (Some("sl"), Some("sly")),1357ALUOp::SubLogical64 => (None, Some("slg")),1358ALUOp::SubLogical64Ext32 => (None, Some("slgf")),1359ALUOp::Mul32 => (Some("ms"), Some("msy")),1360ALUOp::Mul32Ext16 => (Some("mh"), Some("mhy")),1361ALUOp::Mul64 => (None, Some("msg")),1362ALUOp::Mul64Ext16 => (None, Some("mgh")),1363ALUOp::Mul64Ext32 => (None, Some("msgf")),1364ALUOp::And32 => (Some("n"), Some("ny")),1365ALUOp::And64 => (None, Some("ng")),1366ALUOp::Orr32 => (Some("o"), Some("oy")),1367ALUOp::Orr64 => (None, Some("og")),1368ALUOp::Xor32 => (Some("x"), Some("xy")),1369ALUOp::Xor64 => (None, Some("xg")),1370_ => unreachable!(),1371};13721373let rd = pretty_print_reg_mod(rd, ri);1374let mem = mem.clone();1375let (mem_str, mem) = mem_finalize_for_show(1376&mem,1377state,1378MemInstType {1379have_d12: opcode_rx.is_some(),1380have_d20: opcode_rxy.is_some(),1381have_pcrel: false,1382have_unaligned_pcrel: false,1383have_index: true,1384},1385);1386let op = match &mem {1387&MemArg::BXD12 { .. } => opcode_rx,1388&MemArg::BXD20 { .. } => opcode_rxy,1389_ => unreachable!(),1390};1391let mem = mem.pretty_print_default();13921393format!("{}{} {}, {}", mem_str, op.unwrap(), rd, mem)1394}1395&Inst::AluRSImm16 {1396alu_op,1397rd,1398ri,1399imm,1400} => {1401let op = match alu_op {1402ALUOp::Add32 => "ahi",1403ALUOp::Add64 => "aghi",1404ALUOp::Mul32 => "mhi",1405ALUOp::Mul64 => "mghi",1406_ => unreachable!(),1407};1408let rd = pretty_print_reg_mod(rd, ri);1409format!("{op} {rd}, {imm}")1410}1411&Inst::AluRSImm32 {1412alu_op,1413rd,1414ri,1415imm,1416} => {1417let op = match alu_op {1418ALUOp::Add32 => "afi",1419ALUOp::Add64 => "agfi",1420ALUOp::Mul32 => "msfi",1421ALUOp::Mul64 => "msgfi",1422_ => unreachable!(),1423};1424let rd = pretty_print_reg_mod(rd, ri);1425format!("{op} {rd}, {imm}")1426}1427&Inst::AluRUImm32 {1428alu_op,1429rd,1430ri,1431imm,1432} => {1433let op = match alu_op {1434ALUOp::AddLogical32 => "alfi",1435ALUOp::AddLogical64 => "algfi",1436ALUOp::SubLogical32 => "slfi",1437ALUOp::SubLogical64 => "slgfi",1438_ => unreachable!(),1439};1440let rd = pretty_print_reg_mod(rd, ri);1441format!("{op} {rd}, {imm}")1442}1443&Inst::AluRUImm16Shifted {1444alu_op,1445rd,1446ri,1447imm,1448} => {1449let op = match (alu_op, imm.shift) {1450(ALUOp::And32, 0) => "nill",1451(ALUOp::And32, 1) => "nilh",1452(ALUOp::And64, 0) => "nill",1453(ALUOp::And64, 1) => "nilh",1454(ALUOp::And64, 2) => "nihl",1455(ALUOp::And64, 3) => "nihh",1456(ALUOp::Orr32, 0) => "oill",1457(ALUOp::Orr32, 1) => "oilh",1458(ALUOp::Orr64, 0) => "oill",1459(ALUOp::Orr64, 1) => "oilh",1460(ALUOp::Orr64, 2) => "oihl",1461(ALUOp::Orr64, 3) => "oihh",1462_ => unreachable!(),1463};1464let rd = pretty_print_reg_mod(rd, ri);1465format!("{} {}, {}", op, rd, imm.bits)1466}1467&Inst::AluRUImm32Shifted {1468alu_op,1469rd,1470ri,1471imm,1472} => {1473let op = match (alu_op, imm.shift) {1474(ALUOp::And32, 0) => "nilf",1475(ALUOp::And64, 0) => "nilf",1476(ALUOp::And64, 1) => "nihf",1477(ALUOp::Orr32, 0) => "oilf",1478(ALUOp::Orr64, 0) => "oilf",1479(ALUOp::Orr64, 1) => "oihf",1480(ALUOp::Xor32, 0) => "xilf",1481(ALUOp::Xor64, 0) => "xilf",1482(ALUOp::Xor64, 1) => "xihf",1483_ => unreachable!(),1484};1485let rd = pretty_print_reg_mod(rd, ri);1486format!("{} {}, {}", op, rd, imm.bits)1487}1488&Inst::SMulWide { rd, rn, rm } => {1489let op = "mgrk";1490let rn = pretty_print_reg(rn);1491let rm = pretty_print_reg(rm);1492let rd = pretty_print_regpair(rd.to_regpair());1493format!("{op} {rd}, {rn}, {rm}")1494}1495&Inst::UMulWide { rd, ri, rn } => {1496let op = "mlgr";1497let rn = pretty_print_reg(rn);1498let rd = pretty_print_regpair_mod_lo(rd, ri);1499format!("{op} {rd}, {rn}")1500}1501&Inst::SDivMod32 { rd, ri, rn } => {1502let op = "dsgfr";1503let rn = pretty_print_reg(rn);1504let rd = pretty_print_regpair_mod_lo(rd, ri);1505format!("{op} {rd}, {rn}")1506}1507&Inst::SDivMod64 { rd, ri, rn } => {1508let op = "dsgr";1509let rn = pretty_print_reg(rn);1510let rd = pretty_print_regpair_mod_lo(rd, ri);1511format!("{op} {rd}, {rn}")1512}1513&Inst::UDivMod32 { rd, ri, rn } => {1514let op = "dlr";1515let rn = pretty_print_reg(rn);1516let rd = pretty_print_regpair_mod(rd, ri);1517format!("{op} {rd}, {rn}")1518}1519&Inst::UDivMod64 { rd, ri, rn } => {1520let op = "dlgr";1521let rn = pretty_print_reg(rn);1522let rd = pretty_print_regpair_mod(rd, ri);1523format!("{op} {rd}, {rn}")1524}1525&Inst::Flogr { rd, rn } => {1526let op = "flogr";1527let rn = pretty_print_reg(rn);1528let rd = pretty_print_regpair(rd.to_regpair());1529format!("{op} {rd}, {rn}")1530}1531&Inst::ShiftRR {1532shift_op,1533rd,1534rn,1535shift_imm,1536shift_reg,1537} => {1538let op = match shift_op {1539ShiftOp::RotL32 => "rll",1540ShiftOp::RotL64 => "rllg",1541ShiftOp::LShL32 => "sllk",1542ShiftOp::LShL64 => "sllg",1543ShiftOp::LShR32 => "srlk",1544ShiftOp::LShR64 => "srlg",1545ShiftOp::AShR32 => "srak",1546ShiftOp::AShR64 => "srag",1547};1548let rd = pretty_print_reg(rd.to_reg());1549let rn = pretty_print_reg(rn);1550let shift_reg = if shift_reg != zero_reg() {1551format!("({})", pretty_print_reg(shift_reg))1552} else {1553"".to_string()1554};1555format!("{op} {rd}, {rn}, {shift_imm}{shift_reg}")1556}1557&Inst::RxSBG {1558op,1559rd,1560ri,1561rn,1562start_bit,1563end_bit,1564rotate_amt,1565} => {1566let op = match op {1567RxSBGOp::Insert => "risbgn",1568RxSBGOp::And => "rnsbg",1569RxSBGOp::Or => "rosbg",1570RxSBGOp::Xor => "rxsbg",1571};1572let rd = pretty_print_reg_mod(rd, ri);1573let rn = pretty_print_reg(rn);1574format!(1575"{} {}, {}, {}, {}, {}",1576op,1577rd,1578rn,1579start_bit,1580end_bit,1581(rotate_amt as u8) & 631582)1583}1584&Inst::RxSBGTest {1585op,1586rd,1587rn,1588start_bit,1589end_bit,1590rotate_amt,1591} => {1592let op = match op {1593RxSBGOp::And => "rnsbg",1594RxSBGOp::Or => "rosbg",1595RxSBGOp::Xor => "rxsbg",1596_ => unreachable!(),1597};1598let rd = pretty_print_reg(rd);1599let rn = pretty_print_reg(rn);1600format!(1601"{} {}, {}, {}, {}, {}",1602op,1603rd,1604rn,1605start_bit | 0x80,1606end_bit,1607(rotate_amt as u8) & 631608)1609}1610&Inst::UnaryRR { op, rd, rn } => {1611let (op, extra) = match op {1612UnaryOp::Abs32 => ("lpr", ""),1613UnaryOp::Abs64 => ("lpgr", ""),1614UnaryOp::Abs64Ext32 => ("lpgfr", ""),1615UnaryOp::Neg32 => ("lcr", ""),1616UnaryOp::Neg64 => ("lcgr", ""),1617UnaryOp::Neg64Ext32 => ("lcgfr", ""),1618UnaryOp::PopcntByte => ("popcnt", ""),1619UnaryOp::PopcntReg => ("popcnt", ", 8"),1620UnaryOp::BSwap32 => ("lrvr", ""),1621UnaryOp::BSwap64 => ("lrvgr", ""),1622};1623let rd = pretty_print_reg(rd.to_reg());1624let rn = pretty_print_reg(rn);1625format!("{op} {rd}, {rn}{extra}")1626}1627&Inst::CmpRR { op, rn, rm } => {1628let op = match op {1629CmpOp::CmpS32 => "cr",1630CmpOp::CmpS64 => "cgr",1631CmpOp::CmpS64Ext32 => "cgfr",1632CmpOp::CmpL32 => "clr",1633CmpOp::CmpL64 => "clgr",1634CmpOp::CmpL64Ext32 => "clgfr",1635_ => unreachable!(),1636};1637let rn = pretty_print_reg(rn);1638let rm = pretty_print_reg(rm);1639format!("{op} {rn}, {rm}")1640}1641&Inst::CmpRX { op, rn, ref mem } => {1642let (opcode_rx, opcode_rxy, opcode_ril) = match op {1643CmpOp::CmpS32 => (Some("c"), Some("cy"), Some("crl")),1644CmpOp::CmpS32Ext16 => (Some("ch"), Some("chy"), Some("chrl")),1645CmpOp::CmpS64 => (None, Some("cg"), Some("cgrl")),1646CmpOp::CmpS64Ext16 => (None, Some("cgh"), Some("cghrl")),1647CmpOp::CmpS64Ext32 => (None, Some("cgf"), Some("cgfrl")),1648CmpOp::CmpL32 => (Some("cl"), Some("cly"), Some("clrl")),1649CmpOp::CmpL32Ext16 => (None, None, Some("clhrl")),1650CmpOp::CmpL64 => (None, Some("clg"), Some("clgrl")),1651CmpOp::CmpL64Ext16 => (None, None, Some("clghrl")),1652CmpOp::CmpL64Ext32 => (None, Some("clgf"), Some("clgfrl")),1653};16541655let rn = pretty_print_reg(rn);1656let mem = mem.clone();1657let (mem_str, mem) = mem_finalize_for_show(1658&mem,1659state,1660MemInstType {1661have_d12: opcode_rx.is_some(),1662have_d20: opcode_rxy.is_some(),1663have_pcrel: opcode_ril.is_some(),1664have_unaligned_pcrel: false,1665have_index: true,1666},1667);1668let op = match &mem {1669&MemArg::BXD12 { .. } => opcode_rx,1670&MemArg::BXD20 { .. } => opcode_rxy,1671&MemArg::Label { .. } | &MemArg::Constant { .. } | &MemArg::Symbol { .. } => {1672opcode_ril1673}1674_ => unreachable!(),1675};1676let mem = mem.pretty_print_default();16771678format!("{}{} {}, {}", mem_str, op.unwrap(), rn, mem)1679}1680&Inst::CmpRSImm16 { op, rn, imm } => {1681let op = match op {1682CmpOp::CmpS32 => "chi",1683CmpOp::CmpS64 => "cghi",1684_ => unreachable!(),1685};1686let rn = pretty_print_reg(rn);1687format!("{op} {rn}, {imm}")1688}1689&Inst::CmpRSImm32 { op, rn, imm } => {1690let op = match op {1691CmpOp::CmpS32 => "cfi",1692CmpOp::CmpS64 => "cgfi",1693_ => unreachable!(),1694};1695let rn = pretty_print_reg(rn);1696format!("{op} {rn}, {imm}")1697}1698&Inst::CmpRUImm32 { op, rn, imm } => {1699let op = match op {1700CmpOp::CmpL32 => "clfi",1701CmpOp::CmpL64 => "clgfi",1702_ => unreachable!(),1703};1704let rn = pretty_print_reg(rn);1705format!("{op} {rn}, {imm}")1706}1707&Inst::CmpTrapRR {1708op, rn, rm, cond, ..1709} => {1710let op = match op {1711CmpOp::CmpS32 => "crt",1712CmpOp::CmpS64 => "cgrt",1713CmpOp::CmpL32 => "clrt",1714CmpOp::CmpL64 => "clgrt",1715_ => unreachable!(),1716};1717let rn = pretty_print_reg(rn);1718let rm = pretty_print_reg(rm);1719let cond = cond.pretty_print_default();1720format!("{op}{cond} {rn}, {rm}")1721}1722&Inst::CmpTrapRSImm16 {1723op, rn, imm, cond, ..1724} => {1725let op = match op {1726CmpOp::CmpS32 => "cit",1727CmpOp::CmpS64 => "cgit",1728_ => unreachable!(),1729};1730let rn = pretty_print_reg(rn);1731let cond = cond.pretty_print_default();1732format!("{op}{cond} {rn}, {imm}")1733}1734&Inst::CmpTrapRUImm16 {1735op, rn, imm, cond, ..1736} => {1737let op = match op {1738CmpOp::CmpL32 => "clfit",1739CmpOp::CmpL64 => "clgit",1740_ => unreachable!(),1741};1742let rn = pretty_print_reg(rn);1743let cond = cond.pretty_print_default();1744format!("{op}{cond} {rn}, {imm}")1745}1746&Inst::AtomicRmw {1747alu_op,1748rd,1749rn,1750ref mem,1751} => {1752let op = match alu_op {1753ALUOp::Add32 => "laa",1754ALUOp::Add64 => "laag",1755ALUOp::AddLogical32 => "laal",1756ALUOp::AddLogical64 => "laalg",1757ALUOp::And32 => "lan",1758ALUOp::And64 => "lang",1759ALUOp::Orr32 => "lao",1760ALUOp::Orr64 => "laog",1761ALUOp::Xor32 => "lax",1762ALUOp::Xor64 => "laxg",1763_ => unreachable!(),1764};17651766let rd = pretty_print_reg(rd.to_reg());1767let rn = pretty_print_reg(rn);1768let mem = mem.clone();1769let (mem_str, mem) = mem_finalize_for_show(1770&mem,1771state,1772MemInstType {1773have_d12: false,1774have_d20: true,1775have_pcrel: false,1776have_unaligned_pcrel: false,1777have_index: false,1778},1779);1780let mem = mem.pretty_print_default();1781format!("{mem_str}{op} {rd}, {rn}, {mem}")1782}1783&Inst::AtomicCas32 {1784rd,1785ri,1786rn,1787ref mem,1788}1789| &Inst::AtomicCas64 {1790rd,1791ri,1792rn,1793ref mem,1794} => {1795let (opcode_rs, opcode_rsy) = match self {1796&Inst::AtomicCas32 { .. } => (Some("cs"), Some("csy")),1797&Inst::AtomicCas64 { .. } => (None, Some("csg")),1798_ => unreachable!(),1799};18001801let rd = pretty_print_reg_mod(rd, ri);1802let rn = pretty_print_reg(rn);1803let mem = mem.clone();1804let (mem_str, mem) = mem_finalize_for_show(1805&mem,1806state,1807MemInstType {1808have_d12: opcode_rs.is_some(),1809have_d20: opcode_rsy.is_some(),1810have_pcrel: false,1811have_unaligned_pcrel: false,1812have_index: false,1813},1814);1815let op = match &mem {1816&MemArg::BXD12 { .. } => opcode_rs,1817&MemArg::BXD20 { .. } => opcode_rsy,1818_ => unreachable!(),1819};1820let mem = mem.pretty_print_default();18211822format!("{}{} {}, {}, {}", mem_str, op.unwrap(), rd, rn, mem)1823}1824&Inst::Fence => "bcr 14, 0".to_string(),1825&Inst::Load32 { rd, ref mem }1826| &Inst::Load32ZExt8 { rd, ref mem }1827| &Inst::Load32SExt8 { rd, ref mem }1828| &Inst::Load32ZExt16 { rd, ref mem }1829| &Inst::Load32SExt16 { rd, ref mem }1830| &Inst::Load64 { rd, ref mem }1831| &Inst::Load64ZExt8 { rd, ref mem }1832| &Inst::Load64SExt8 { rd, ref mem }1833| &Inst::Load64ZExt16 { rd, ref mem }1834| &Inst::Load64SExt16 { rd, ref mem }1835| &Inst::Load64ZExt32 { rd, ref mem }1836| &Inst::Load64SExt32 { rd, ref mem }1837| &Inst::LoadRev16 { rd, ref mem }1838| &Inst::LoadRev32 { rd, ref mem }1839| &Inst::LoadRev64 { rd, ref mem } => {1840let (opcode_rx, opcode_rxy, opcode_ril) = match self {1841&Inst::Load32 { .. } => (Some("l"), Some("ly"), Some("lrl")),1842&Inst::Load32ZExt8 { .. } => (None, Some("llc"), None),1843&Inst::Load32SExt8 { .. } => (None, Some("lb"), None),1844&Inst::Load32ZExt16 { .. } => (None, Some("llh"), Some("llhrl")),1845&Inst::Load32SExt16 { .. } => (Some("lh"), Some("lhy"), Some("lhrl")),1846&Inst::Load64 { .. } => (None, Some("lg"), Some("lgrl")),1847&Inst::Load64ZExt8 { .. } => (None, Some("llgc"), None),1848&Inst::Load64SExt8 { .. } => (None, Some("lgb"), None),1849&Inst::Load64ZExt16 { .. } => (None, Some("llgh"), Some("llghrl")),1850&Inst::Load64SExt16 { .. } => (None, Some("lgh"), Some("lghrl")),1851&Inst::Load64ZExt32 { .. } => (None, Some("llgf"), Some("llgfrl")),1852&Inst::Load64SExt32 { .. } => (None, Some("lgf"), Some("lgfrl")),1853&Inst::LoadRev16 { .. } => (None, Some("lrvh"), None),1854&Inst::LoadRev32 { .. } => (None, Some("lrv"), None),1855&Inst::LoadRev64 { .. } => (None, Some("lrvg"), None),1856_ => unreachable!(),1857};18581859let rd = pretty_print_reg(rd.to_reg());1860let mem = mem.clone();1861let (mem_str, mem) = mem_finalize_for_show(1862&mem,1863state,1864MemInstType {1865have_d12: opcode_rx.is_some(),1866have_d20: opcode_rxy.is_some(),1867have_pcrel: opcode_ril.is_some(),1868have_unaligned_pcrel: false,1869have_index: true,1870},1871);1872let op = match &mem {1873&MemArg::BXD12 { .. } => opcode_rx,1874&MemArg::BXD20 { .. } => opcode_rxy,1875&MemArg::Label { .. } | &MemArg::Constant { .. } | &MemArg::Symbol { .. } => {1876opcode_ril1877}1878_ => unreachable!(),1879};1880let mem = mem.pretty_print_default();1881format!("{}{} {}, {}", mem_str, op.unwrap(), rd, mem)1882}1883&Inst::Store8 { rd, ref mem }1884| &Inst::Store16 { rd, ref mem }1885| &Inst::Store32 { rd, ref mem }1886| &Inst::Store64 { rd, ref mem }1887| &Inst::StoreRev16 { rd, ref mem }1888| &Inst::StoreRev32 { rd, ref mem }1889| &Inst::StoreRev64 { rd, ref mem } => {1890let (opcode_rx, opcode_rxy, opcode_ril) = match self {1891&Inst::Store8 { .. } => (Some("stc"), Some("stcy"), None),1892&Inst::Store16 { .. } => (Some("sth"), Some("sthy"), Some("sthrl")),1893&Inst::Store32 { .. } => (Some("st"), Some("sty"), Some("strl")),1894&Inst::Store64 { .. } => (None, Some("stg"), Some("stgrl")),1895&Inst::StoreRev16 { .. } => (None, Some("strvh"), None),1896&Inst::StoreRev32 { .. } => (None, Some("strv"), None),1897&Inst::StoreRev64 { .. } => (None, Some("strvg"), None),1898_ => unreachable!(),1899};19001901let rd = pretty_print_reg(rd);1902let mem = mem.clone();1903let (mem_str, mem) = mem_finalize_for_show(1904&mem,1905state,1906MemInstType {1907have_d12: opcode_rx.is_some(),1908have_d20: opcode_rxy.is_some(),1909have_pcrel: opcode_ril.is_some(),1910have_unaligned_pcrel: false,1911have_index: true,1912},1913);1914let op = match &mem {1915&MemArg::BXD12 { .. } => opcode_rx,1916&MemArg::BXD20 { .. } => opcode_rxy,1917&MemArg::Label { .. } | &MemArg::Constant { .. } | &MemArg::Symbol { .. } => {1918opcode_ril1919}1920_ => unreachable!(),1921};1922let mem = mem.pretty_print_default();19231924format!("{}{} {}, {}", mem_str, op.unwrap(), rd, mem)1925}1926&Inst::StoreImm8 { imm, ref mem } => {1927let mem = mem.clone();1928let (mem_str, mem) = mem_finalize_for_show(1929&mem,1930state,1931MemInstType {1932have_d12: true,1933have_d20: true,1934have_pcrel: false,1935have_unaligned_pcrel: false,1936have_index: false,1937},1938);1939let op = match &mem {1940&MemArg::BXD12 { .. } => "mvi",1941&MemArg::BXD20 { .. } => "mviy",1942_ => unreachable!(),1943};1944let mem = mem.pretty_print_default();19451946format!("{mem_str}{op} {mem}, {imm}")1947}1948&Inst::StoreImm16 { imm, ref mem }1949| &Inst::StoreImm32SExt16 { imm, ref mem }1950| &Inst::StoreImm64SExt16 { imm, ref mem } => {1951let mem = mem.clone();1952let (mem_str, mem) = mem_finalize_for_show(1953&mem,1954state,1955MemInstType {1956have_d12: false,1957have_d20: true,1958have_pcrel: false,1959have_unaligned_pcrel: false,1960have_index: false,1961},1962);1963let op = match self {1964&Inst::StoreImm16 { .. } => "mvhhi",1965&Inst::StoreImm32SExt16 { .. } => "mvhi",1966&Inst::StoreImm64SExt16 { .. } => "mvghi",1967_ => unreachable!(),1968};1969let mem = mem.pretty_print_default();19701971format!("{mem_str}{op} {mem}, {imm}")1972}1973&Inst::LoadMultiple64 { rt, rt2, ref mem } => {1974let mem = mem.clone();1975let (mem_str, mem) = mem_finalize_for_show(1976&mem,1977state,1978MemInstType {1979have_d12: false,1980have_d20: true,1981have_pcrel: false,1982have_unaligned_pcrel: false,1983have_index: false,1984},1985);1986let rt = pretty_print_reg(rt.to_reg());1987let rt2 = pretty_print_reg(rt2.to_reg());1988let mem = mem.pretty_print_default();1989format!("{mem_str}lmg {rt}, {rt2}, {mem}")1990}1991&Inst::StoreMultiple64 { rt, rt2, ref mem } => {1992let mem = mem.clone();1993let (mem_str, mem) = mem_finalize_for_show(1994&mem,1995state,1996MemInstType {1997have_d12: false,1998have_d20: true,1999have_pcrel: false,2000have_unaligned_pcrel: false,2001have_index: false,2002},2003);2004let rt = pretty_print_reg(rt);2005let rt2 = pretty_print_reg(rt2);2006let mem = mem.pretty_print_default();2007format!("{mem_str}stmg {rt}, {rt2}, {mem}")2008}2009&Inst::Mov64 { rd, rm } => {2010let rd = pretty_print_reg(rd.to_reg());2011let rm = pretty_print_reg(rm);2012format!("lgr {rd}, {rm}")2013}2014&Inst::MovPReg { rd, rm } => {2015let rd = pretty_print_reg(rd.to_reg());2016let rm = show_reg(rm.into());2017format!("lgr {rd}, {rm}")2018}2019&Inst::Mov32 { rd, rm } => {2020let rd = pretty_print_reg(rd.to_reg());2021let rm = pretty_print_reg(rm);2022format!("lr {rd}, {rm}")2023}2024&Inst::Mov32Imm { rd, ref imm } => {2025let rd = pretty_print_reg(rd.to_reg());2026format!("iilf {rd}, {imm}")2027}2028&Inst::Mov32SImm16 { rd, ref imm } => {2029let rd = pretty_print_reg(rd.to_reg());2030format!("lhi {rd}, {imm}")2031}2032&Inst::Mov64SImm16 { rd, ref imm } => {2033let rd = pretty_print_reg(rd.to_reg());2034format!("lghi {rd}, {imm}")2035}2036&Inst::Mov64SImm32 { rd, ref imm } => {2037let rd = pretty_print_reg(rd.to_reg());2038format!("lgfi {rd}, {imm}")2039}2040&Inst::Mov64UImm16Shifted { rd, ref imm } => {2041let rd = pretty_print_reg(rd.to_reg());2042let op = match imm.shift {20430 => "llill",20441 => "llilh",20452 => "llihl",20463 => "llihh",2047_ => unreachable!(),2048};2049format!("{} {}, {}", op, rd, imm.bits)2050}2051&Inst::Mov64UImm32Shifted { rd, ref imm } => {2052let rd = pretty_print_reg(rd.to_reg());2053let op = match imm.shift {20540 => "llilf",20551 => "llihf",2056_ => unreachable!(),2057};2058format!("{} {}, {}", op, rd, imm.bits)2059}2060&Inst::Insert64UImm16Shifted { rd, ri, ref imm } => {2061let rd = pretty_print_reg_mod(rd, ri);2062let op = match imm.shift {20630 => "iill",20641 => "iilh",20652 => "iihl",20663 => "iihh",2067_ => unreachable!(),2068};2069format!("{} {}, {}", op, rd, imm.bits)2070}2071&Inst::Insert64UImm32Shifted { rd, ri, ref imm } => {2072let rd = pretty_print_reg_mod(rd, ri);2073let op = match imm.shift {20740 => "iilf",20751 => "iihf",2076_ => unreachable!(),2077};2078format!("{} {}, {}", op, rd, imm.bits)2079}2080&Inst::LoadAR { rd, ar } => {2081let rd = pretty_print_reg(rd.to_reg());2082format!("ear {rd}, %a{ar}")2083}2084&Inst::InsertAR { rd, ri, ar } => {2085let rd = pretty_print_reg_mod(rd, ri);2086format!("ear {rd}, %a{ar}")2087}2088&Inst::CMov32 { rd, cond, ri, rm } => {2089let rd = pretty_print_reg_mod(rd, ri);2090let rm = pretty_print_reg(rm);2091let cond = cond.pretty_print_default();2092format!("locr{cond} {rd}, {rm}")2093}2094&Inst::CMov64 { rd, cond, ri, rm } => {2095let rd = pretty_print_reg_mod(rd, ri);2096let rm = pretty_print_reg(rm);2097let cond = cond.pretty_print_default();2098format!("locgr{cond} {rd}, {rm}")2099}2100&Inst::CMov32SImm16 {2101rd,2102cond,2103ri,2104ref imm,2105} => {2106let rd = pretty_print_reg_mod(rd, ri);2107let cond = cond.pretty_print_default();2108format!("lochi{cond} {rd}, {imm}")2109}2110&Inst::CMov64SImm16 {2111rd,2112cond,2113ri,2114ref imm,2115} => {2116let rd = pretty_print_reg_mod(rd, ri);2117let cond = cond.pretty_print_default();2118format!("locghi{cond} {rd}, {imm}")2119}2120&Inst::FpuMove32 { rd, rn } => {2121let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());2122let (rn, rn_fpr) = pretty_print_fpr(rn);2123if rd_fpr.is_some() && rn_fpr.is_some() {2124format!("ler {}, {}", rd_fpr.unwrap(), rn_fpr.unwrap())2125} else {2126format!("vlr {rd}, {rn}")2127}2128}2129&Inst::FpuMove64 { rd, rn } => {2130let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());2131let (rn, rn_fpr) = pretty_print_fpr(rn);2132if rd_fpr.is_some() && rn_fpr.is_some() {2133format!("ldr {}, {}", rd_fpr.unwrap(), rn_fpr.unwrap())2134} else {2135format!("vlr {rd}, {rn}")2136}2137}2138&Inst::FpuCMov32 { rd, cond, rm, .. } => {2139let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());2140let (rm, rm_fpr) = pretty_print_fpr(rm);2141if rd_fpr.is_some() && rm_fpr.is_some() {2142let cond = cond.invert().pretty_print_default();2143format!("j{} 6 ; ler {}, {}", cond, rd_fpr.unwrap(), rm_fpr.unwrap())2144} else {2145let cond = cond.invert().pretty_print_default();2146format!("j{cond} 10 ; vlr {rd}, {rm}")2147}2148}2149&Inst::FpuCMov64 { rd, cond, rm, .. } => {2150let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());2151let (rm, rm_fpr) = pretty_print_fpr(rm);2152if rd_fpr.is_some() && rm_fpr.is_some() {2153let cond = cond.invert().pretty_print_default();2154format!("j{} 6 ; ldr {}, {}", cond, rd_fpr.unwrap(), rm_fpr.unwrap())2155} else {2156let cond = cond.invert().pretty_print_default();2157format!("j{cond} 10 ; vlr {rd}, {rm}")2158}2159}2160&Inst::FpuRR { fpu_op, rd, rn } => {2161let (op, op_fpr) = match fpu_op {2162FPUOp1::Abs32 => ("wflpsb", Some("lpebr")),2163FPUOp1::Abs64 => ("wflpdb", Some("lpdbr")),2164FPUOp1::Abs128 => ("wflpxb", None),2165FPUOp1::Abs32x4 => ("vflpsb", None),2166FPUOp1::Abs64x2 => ("vflpdb", None),2167FPUOp1::Neg32 => ("wflcsb", Some("lcebr")),2168FPUOp1::Neg64 => ("wflcdb", Some("lcdbr")),2169FPUOp1::Neg128 => ("wflcxb", None),2170FPUOp1::Neg32x4 => ("vflcsb", None),2171FPUOp1::Neg64x2 => ("vflcdb", None),2172FPUOp1::NegAbs32 => ("wflnsb", Some("lnebr")),2173FPUOp1::NegAbs64 => ("wflndb", Some("lndbr")),2174FPUOp1::NegAbs128 => ("wflnxb", None),2175FPUOp1::NegAbs32x4 => ("vflnsb", None),2176FPUOp1::NegAbs64x2 => ("vflndb", None),2177FPUOp1::Sqrt32 => ("wfsqsb", Some("sqebr")),2178FPUOp1::Sqrt64 => ("wfsqdb", Some("sqdbr")),2179FPUOp1::Sqrt128 => ("wfsqxb", None),2180FPUOp1::Sqrt32x4 => ("vfsqsb", None),2181FPUOp1::Sqrt64x2 => ("vfsqdb", None),2182FPUOp1::Cvt32To64 => ("wldeb", Some("ldebr")),2183FPUOp1::Cvt32x4To64x2 => ("vldeb", None),2184FPUOp1::Cvt64To128 => ("wflld", None),2185};21862187let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());2188let (rn, rn_fpr) = pretty_print_fpr(rn);2189if op_fpr.is_some() && rd_fpr.is_some() && rn_fpr.is_some() {2190format!(2191"{} {}, {}",2192op_fpr.unwrap(),2193rd_fpr.unwrap(),2194rn_fpr.unwrap()2195)2196} else if op.starts_with('w') {2197format!("{} {}, {}", op, rd_fpr.unwrap_or(rd), rn_fpr.unwrap_or(rn))2198} else {2199format!("{op} {rd}, {rn}")2200}2201}2202&Inst::FpuRRR { fpu_op, rd, rn, rm } => {2203let (op, opt_m6, op_fpr) = match fpu_op {2204FPUOp2::Add32 => ("wfasb", "", Some("aebr")),2205FPUOp2::Add64 => ("wfadb", "", Some("adbr")),2206FPUOp2::Add128 => ("wfaxb", "", None),2207FPUOp2::Add32x4 => ("vfasb", "", None),2208FPUOp2::Add64x2 => ("vfadb", "", None),2209FPUOp2::Sub32 => ("wfssb", "", Some("sebr")),2210FPUOp2::Sub64 => ("wfsdb", "", Some("sdbr")),2211FPUOp2::Sub128 => ("wfsxb", "", None),2212FPUOp2::Sub32x4 => ("vfssb", "", None),2213FPUOp2::Sub64x2 => ("vfsdb", "", None),2214FPUOp2::Mul32 => ("wfmsb", "", Some("meebr")),2215FPUOp2::Mul64 => ("wfmdb", "", Some("mdbr")),2216FPUOp2::Mul128 => ("wfmxb", "", None),2217FPUOp2::Mul32x4 => ("vfmsb", "", None),2218FPUOp2::Mul64x2 => ("vfmdb", "", None),2219FPUOp2::Div32 => ("wfdsb", "", Some("debr")),2220FPUOp2::Div64 => ("wfddb", "", Some("ddbr")),2221FPUOp2::Div128 => ("wfdxb", "", None),2222FPUOp2::Div32x4 => ("vfdsb", "", None),2223FPUOp2::Div64x2 => ("vfddb", "", None),2224FPUOp2::Max32 => ("wfmaxsb", ", 1", None),2225FPUOp2::Max64 => ("wfmaxdb", ", 1", None),2226FPUOp2::Max128 => ("wfmaxxb", ", 1", None),2227FPUOp2::Max32x4 => ("vfmaxsb", ", 1", None),2228FPUOp2::Max64x2 => ("vfmaxdb", ", 1", None),2229FPUOp2::Min32 => ("wfminsb", ", 1", None),2230FPUOp2::Min64 => ("wfmindb", ", 1", None),2231FPUOp2::Min128 => ("wfminxb", ", 1", None),2232FPUOp2::Min32x4 => ("vfminsb", ", 1", None),2233FPUOp2::Min64x2 => ("vfmindb", ", 1", None),2234FPUOp2::MaxPseudo32 => ("wfmaxsb", ", 3", None),2235FPUOp2::MaxPseudo64 => ("wfmaxdb", ", 3", None),2236FPUOp2::MaxPseudo128 => ("wfmaxxb", ", 3", None),2237FPUOp2::MaxPseudo32x4 => ("vfmaxsb", ", 3", None),2238FPUOp2::MaxPseudo64x2 => ("vfmaxdb", ", 3", None),2239FPUOp2::MinPseudo32 => ("wfminsb", ", 3", None),2240FPUOp2::MinPseudo64 => ("wfmindb", ", 3", None),2241FPUOp2::MinPseudo128 => ("wfminxb", ", 3", None),2242FPUOp2::MinPseudo32x4 => ("vfminsb", ", 3", None),2243FPUOp2::MinPseudo64x2 => ("vfmindb", ", 3", None),2244};22452246let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());2247let (rn, rn_fpr) = pretty_print_fpr(rn);2248let (rm, rm_fpr) = pretty_print_fpr(rm);2249if op_fpr.is_some() && rd == rn && rd_fpr.is_some() && rm_fpr.is_some() {2250format!(2251"{} {}, {}",2252op_fpr.unwrap(),2253rd_fpr.unwrap(),2254rm_fpr.unwrap()2255)2256} else if op.starts_with('w') {2257format!(2258"{} {}, {}, {}{}",2259op,2260rd_fpr.unwrap_or(rd),2261rn_fpr.unwrap_or(rn),2262rm_fpr.unwrap_or(rm),2263opt_m62264)2265} else {2266format!("{op} {rd}, {rn}, {rm}{opt_m6}")2267}2268}2269&Inst::FpuRRRR {2270fpu_op,2271rd,2272rn,2273rm,2274ra,2275} => {2276let (op, op_fpr) = match fpu_op {2277FPUOp3::MAdd32 => ("wfmasb", Some("maebr")),2278FPUOp3::MAdd64 => ("wfmadb", Some("madbr")),2279FPUOp3::MAdd128 => ("wfmaxb", None),2280FPUOp3::MAdd32x4 => ("vfmasb", None),2281FPUOp3::MAdd64x2 => ("vfmadb", None),2282FPUOp3::MSub32 => ("wfmssb", Some("msebr")),2283FPUOp3::MSub64 => ("wfmsdb", Some("msdbr")),2284FPUOp3::MSub128 => ("wfmsxb", None),2285FPUOp3::MSub32x4 => ("vfmssb", None),2286FPUOp3::MSub64x2 => ("vfmsdb", None),2287};22882289let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());2290let (rn, rn_fpr) = pretty_print_fpr(rn);2291let (rm, rm_fpr) = pretty_print_fpr(rm);2292let (ra, ra_fpr) = pretty_print_fpr(ra);2293if op_fpr.is_some()2294&& rd == ra2295&& rd_fpr.is_some()2296&& rn_fpr.is_some()2297&& rm_fpr.is_some()2298{2299format!(2300"{} {}, {}, {}",2301op_fpr.unwrap(),2302rd_fpr.unwrap(),2303rn_fpr.unwrap(),2304rm_fpr.unwrap()2305)2306} else if op.starts_with('w') {2307format!(2308"{} {}, {}, {}, {}",2309op,2310rd_fpr.unwrap_or(rd),2311rn_fpr.unwrap_or(rn),2312rm_fpr.unwrap_or(rm),2313ra_fpr.unwrap_or(ra)2314)2315} else {2316format!("{op} {rd}, {rn}, {rm}, {ra}")2317}2318}2319&Inst::FpuCmp32 { rn, rm } => {2320let (rn, rn_fpr) = pretty_print_fpr(rn);2321let (rm, rm_fpr) = pretty_print_fpr(rm);2322if rn_fpr.is_some() && rm_fpr.is_some() {2323format!("cebr {}, {}", rn_fpr.unwrap(), rm_fpr.unwrap())2324} else {2325format!("wfcsb {}, {}", rn_fpr.unwrap_or(rn), rm_fpr.unwrap_or(rm))2326}2327}2328&Inst::FpuCmp64 { rn, rm } => {2329let (rn, rn_fpr) = pretty_print_fpr(rn);2330let (rm, rm_fpr) = pretty_print_fpr(rm);2331if rn_fpr.is_some() && rm_fpr.is_some() {2332format!("cdbr {}, {}", rn_fpr.unwrap(), rm_fpr.unwrap())2333} else {2334format!("wfcdb {}, {}", rn_fpr.unwrap_or(rn), rm_fpr.unwrap_or(rm))2335}2336}2337&Inst::FpuCmp128 { rn, rm } => {2338let (rn, rn_fpr) = pretty_print_fpr(rn);2339let (rm, rm_fpr) = pretty_print_fpr(rm);2340format!("wfcxb {}, {}", rn_fpr.unwrap_or(rn), rm_fpr.unwrap_or(rm))2341}2342&Inst::FpuRound { op, mode, rd, rn } => {2343let mode = match mode {2344FpuRoundMode::Current => 0,2345FpuRoundMode::ToNearest => 1,2346FpuRoundMode::ShorterPrecision => 3,2347FpuRoundMode::ToNearestTiesToEven => 4,2348FpuRoundMode::ToZero => 5,2349FpuRoundMode::ToPosInfinity => 6,2350FpuRoundMode::ToNegInfinity => 7,2351};2352let (opcode, opcode_fpr) = match op {2353FpuRoundOp::Cvt64To32 => ("wledb", Some("ledbra")),2354FpuRoundOp::Cvt64x2To32x4 => ("vledb", None),2355FpuRoundOp::Cvt128To64 => ("wflrx", None),2356FpuRoundOp::Round32 => ("wfisb", Some("fiebr")),2357FpuRoundOp::Round64 => ("wfidb", Some("fidbr")),2358FpuRoundOp::Round128 => ("wfixb", None),2359FpuRoundOp::Round32x4 => ("vfisb", None),2360FpuRoundOp::Round64x2 => ("vfidb", None),2361FpuRoundOp::ToSInt32 => ("wcfeb", None),2362FpuRoundOp::ToSInt64 => ("wcgdb", None),2363FpuRoundOp::ToUInt32 => ("wclfeb", None),2364FpuRoundOp::ToUInt64 => ("wclgdb", None),2365FpuRoundOp::ToSInt32x4 => ("vcfeb", None),2366FpuRoundOp::ToSInt64x2 => ("vcgdb", None),2367FpuRoundOp::ToUInt32x4 => ("vclfeb", None),2368FpuRoundOp::ToUInt64x2 => ("vclgdb", None),2369FpuRoundOp::FromSInt32 => ("wcefb", None),2370FpuRoundOp::FromSInt64 => ("wcdgb", None),2371FpuRoundOp::FromUInt32 => ("wcelfb", None),2372FpuRoundOp::FromUInt64 => ("wcdlgb", None),2373FpuRoundOp::FromSInt32x4 => ("vcefb", None),2374FpuRoundOp::FromSInt64x2 => ("vcdgb", None),2375FpuRoundOp::FromUInt32x4 => ("vcelfb", None),2376FpuRoundOp::FromUInt64x2 => ("vcdlgb", None),2377};23782379let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());2380let (rn, rn_fpr) = pretty_print_fpr(rn);2381if opcode_fpr.is_some() && rd_fpr.is_some() && rn_fpr.is_some() {2382format!(2383"{} {}, {}, {}{}",2384opcode_fpr.unwrap(),2385rd_fpr.unwrap(),2386mode,2387rn_fpr.unwrap(),2388if opcode_fpr.unwrap().ends_with('a') {2389", 0"2390} else {2391""2392}2393)2394} else if opcode.starts_with('w') {2395format!(2396"{} {}, {}, 0, {}",2397opcode,2398rd_fpr.unwrap_or(rd),2399rn_fpr.unwrap_or(rn),2400mode2401)2402} else {2403format!("{opcode} {rd}, {rn}, 0, {mode}")2404}2405}2406&Inst::FpuConv128FromInt { op, mode, rd, rn } => {2407let mode = match mode {2408FpuRoundMode::Current => 0,2409FpuRoundMode::ToNearest => 1,2410FpuRoundMode::ShorterPrecision => 3,2411FpuRoundMode::ToNearestTiesToEven => 4,2412FpuRoundMode::ToZero => 5,2413FpuRoundMode::ToPosInfinity => 6,2414FpuRoundMode::ToNegInfinity => 7,2415};2416let opcode = match op {2417FpuConv128Op::SInt32 => "cxfbra",2418FpuConv128Op::SInt64 => "cxgbra",2419FpuConv128Op::UInt32 => "cxlfbr",2420FpuConv128Op::UInt64 => "cxlgbr",2421};2422let rd = pretty_print_fp_regpair(rd.to_regpair());2423let rn = pretty_print_reg(rn);2424format!("{opcode} {rd}, {mode}, {rn}, 0")2425}2426&Inst::FpuConv128ToInt { op, mode, rd, rn } => {2427let mode = match mode {2428FpuRoundMode::Current => 0,2429FpuRoundMode::ToNearest => 1,2430FpuRoundMode::ShorterPrecision => 3,2431FpuRoundMode::ToNearestTiesToEven => 4,2432FpuRoundMode::ToZero => 5,2433FpuRoundMode::ToPosInfinity => 6,2434FpuRoundMode::ToNegInfinity => 7,2435};2436let opcode = match op {2437FpuConv128Op::SInt32 => "cfxbra",2438FpuConv128Op::SInt64 => "cgxbra",2439FpuConv128Op::UInt32 => "clfxbr",2440FpuConv128Op::UInt64 => "clgxbr",2441};2442let rd = pretty_print_reg(rd.to_reg());2443let rn = pretty_print_fp_regpair(rn);2444format!("{opcode} {rd}, {mode}, {rn}, 0")2445}24462447&Inst::VecRRR { op, rd, rn, rm } => {2448let op = match op {2449VecBinaryOp::Add8x16 => "vab",2450VecBinaryOp::Add16x8 => "vah",2451VecBinaryOp::Add32x4 => "vaf",2452VecBinaryOp::Add64x2 => "vag",2453VecBinaryOp::Add128 => "vaq",2454VecBinaryOp::Sub8x16 => "vsb",2455VecBinaryOp::Sub16x8 => "vsh",2456VecBinaryOp::Sub32x4 => "vsf",2457VecBinaryOp::Sub64x2 => "vsg",2458VecBinaryOp::Sub128 => "vsq",2459VecBinaryOp::Mul8x16 => "vmlb",2460VecBinaryOp::Mul16x8 => "vmlhw",2461VecBinaryOp::Mul32x4 => "vmlf",2462VecBinaryOp::UMulHi8x16 => "vmlhb",2463VecBinaryOp::UMulHi16x8 => "vmlhh",2464VecBinaryOp::UMulHi32x4 => "vmlhf",2465VecBinaryOp::SMulHi8x16 => "vmhb",2466VecBinaryOp::SMulHi16x8 => "vmhh",2467VecBinaryOp::SMulHi32x4 => "vmhf",2468VecBinaryOp::UMulEven8x16 => "vmleb",2469VecBinaryOp::UMulEven16x8 => "vmleh",2470VecBinaryOp::UMulEven32x4 => "vmlef",2471VecBinaryOp::SMulEven8x16 => "vmeb",2472VecBinaryOp::SMulEven16x8 => "vmeh",2473VecBinaryOp::SMulEven32x4 => "vmef",2474VecBinaryOp::UMulOdd8x16 => "vmlob",2475VecBinaryOp::UMulOdd16x8 => "vmloh",2476VecBinaryOp::UMulOdd32x4 => "vmlof",2477VecBinaryOp::SMulOdd8x16 => "vmob",2478VecBinaryOp::SMulOdd16x8 => "vmoh",2479VecBinaryOp::SMulOdd32x4 => "vmof",2480VecBinaryOp::UMax8x16 => "vmxlb",2481VecBinaryOp::UMax16x8 => "vmxlh",2482VecBinaryOp::UMax32x4 => "vmxlf",2483VecBinaryOp::UMax64x2 => "vmxlg",2484VecBinaryOp::SMax8x16 => "vmxb",2485VecBinaryOp::SMax16x8 => "vmxh",2486VecBinaryOp::SMax32x4 => "vmxf",2487VecBinaryOp::SMax64x2 => "vmxg",2488VecBinaryOp::UMin8x16 => "vmnlb",2489VecBinaryOp::UMin16x8 => "vmnlh",2490VecBinaryOp::UMin32x4 => "vmnlf",2491VecBinaryOp::UMin64x2 => "vmnlg",2492VecBinaryOp::SMin8x16 => "vmnb",2493VecBinaryOp::SMin16x8 => "vmnh",2494VecBinaryOp::SMin32x4 => "vmnf",2495VecBinaryOp::SMin64x2 => "vmng",2496VecBinaryOp::UAvg8x16 => "vavglb",2497VecBinaryOp::UAvg16x8 => "vavglh",2498VecBinaryOp::UAvg32x4 => "vavglf",2499VecBinaryOp::UAvg64x2 => "vavglg",2500VecBinaryOp::SAvg8x16 => "vavgb",2501VecBinaryOp::SAvg16x8 => "vavgh",2502VecBinaryOp::SAvg32x4 => "vavgf",2503VecBinaryOp::SAvg64x2 => "vavgg",2504VecBinaryOp::And128 => "vn",2505VecBinaryOp::Orr128 => "vo",2506VecBinaryOp::Xor128 => "vx",2507VecBinaryOp::NotAnd128 => "vnn",2508VecBinaryOp::NotOrr128 => "vno",2509VecBinaryOp::NotXor128 => "vnx",2510VecBinaryOp::AndNot128 => "vnc",2511VecBinaryOp::OrrNot128 => "voc",2512VecBinaryOp::BitPermute128 => "vbperm",2513VecBinaryOp::LShLByByte128 => "vslb",2514VecBinaryOp::LShRByByte128 => "vsrlb",2515VecBinaryOp::AShRByByte128 => "vsrab",2516VecBinaryOp::LShLByBit128 => "vsl",2517VecBinaryOp::LShRByBit128 => "vsrl",2518VecBinaryOp::AShRByBit128 => "vsra",2519VecBinaryOp::Pack16x8 => "vpkh",2520VecBinaryOp::Pack32x4 => "vpkf",2521VecBinaryOp::Pack64x2 => "vpkg",2522VecBinaryOp::PackUSat16x8 => "vpklsh",2523VecBinaryOp::PackUSat32x4 => "vpklsf",2524VecBinaryOp::PackUSat64x2 => "vpklsg",2525VecBinaryOp::PackSSat16x8 => "vpksh",2526VecBinaryOp::PackSSat32x4 => "vpksf",2527VecBinaryOp::PackSSat64x2 => "vpksg",2528VecBinaryOp::MergeLow8x16 => "vmrlb",2529VecBinaryOp::MergeLow16x8 => "vmrlh",2530VecBinaryOp::MergeLow32x4 => "vmrlf",2531VecBinaryOp::MergeLow64x2 => "vmrlg",2532VecBinaryOp::MergeHigh8x16 => "vmrhb",2533VecBinaryOp::MergeHigh16x8 => "vmrhh",2534VecBinaryOp::MergeHigh32x4 => "vmrhf",2535VecBinaryOp::MergeHigh64x2 => "vmrhg",2536};2537let rd = pretty_print_reg(rd.to_reg());2538let rn = pretty_print_reg(rn);2539let rm = pretty_print_reg(rm);2540format!("{op} {rd}, {rn}, {rm}")2541}2542&Inst::VecRR { op, rd, rn } => {2543let op = match op {2544VecUnaryOp::Abs8x16 => "vlpb",2545VecUnaryOp::Abs16x8 => "vlph",2546VecUnaryOp::Abs32x4 => "vlpf",2547VecUnaryOp::Abs64x2 => "vlpg",2548VecUnaryOp::Neg8x16 => "vlcb",2549VecUnaryOp::Neg16x8 => "vlch",2550VecUnaryOp::Neg32x4 => "vlcf",2551VecUnaryOp::Neg64x2 => "vlcg",2552VecUnaryOp::Popcnt8x16 => "vpopctb",2553VecUnaryOp::Popcnt16x8 => "vpopcth",2554VecUnaryOp::Popcnt32x4 => "vpopctf",2555VecUnaryOp::Popcnt64x2 => "vpopctg",2556VecUnaryOp::Clz8x16 => "vclzb",2557VecUnaryOp::Clz16x8 => "vclzh",2558VecUnaryOp::Clz32x4 => "vclzf",2559VecUnaryOp::Clz64x2 => "vclzg",2560VecUnaryOp::Ctz8x16 => "vctzb",2561VecUnaryOp::Ctz16x8 => "vctzh",2562VecUnaryOp::Ctz32x4 => "vctzf",2563VecUnaryOp::Ctz64x2 => "vctzg",2564VecUnaryOp::UnpackULow8x16 => "vupllb",2565VecUnaryOp::UnpackULow16x8 => "vupllh",2566VecUnaryOp::UnpackULow32x4 => "vupllf",2567VecUnaryOp::UnpackUHigh8x16 => "vuplhb",2568VecUnaryOp::UnpackUHigh16x8 => "vuplhh",2569VecUnaryOp::UnpackUHigh32x4 => "vuplhf",2570VecUnaryOp::UnpackSLow8x16 => "vuplb",2571VecUnaryOp::UnpackSLow16x8 => "vuplh",2572VecUnaryOp::UnpackSLow32x4 => "vuplf",2573VecUnaryOp::UnpackSHigh8x16 => "vuphb",2574VecUnaryOp::UnpackSHigh16x8 => "vuphh",2575VecUnaryOp::UnpackSHigh32x4 => "vuphf",2576};2577let rd = pretty_print_reg(rd.to_reg());2578let rn = pretty_print_reg(rn);2579format!("{op} {rd}, {rn}")2580}2581&Inst::VecShiftRR {2582shift_op,2583rd,2584rn,2585shift_imm,2586shift_reg,2587} => {2588let op = match shift_op {2589VecShiftOp::RotL8x16 => "verllb",2590VecShiftOp::RotL16x8 => "verllh",2591VecShiftOp::RotL32x4 => "verllf",2592VecShiftOp::RotL64x2 => "verllg",2593VecShiftOp::LShL8x16 => "veslb",2594VecShiftOp::LShL16x8 => "veslh",2595VecShiftOp::LShL32x4 => "veslf",2596VecShiftOp::LShL64x2 => "veslg",2597VecShiftOp::LShR8x16 => "vesrlb",2598VecShiftOp::LShR16x8 => "vesrlh",2599VecShiftOp::LShR32x4 => "vesrlf",2600VecShiftOp::LShR64x2 => "vesrlg",2601VecShiftOp::AShR8x16 => "vesrab",2602VecShiftOp::AShR16x8 => "vesrah",2603VecShiftOp::AShR32x4 => "vesraf",2604VecShiftOp::AShR64x2 => "vesrag",2605};2606let rd = pretty_print_reg(rd.to_reg());2607let rn = pretty_print_reg(rn);2608let shift_reg = if shift_reg != zero_reg() {2609format!("({})", pretty_print_reg(shift_reg))2610} else {2611"".to_string()2612};2613format!("{op} {rd}, {rn}, {shift_imm}{shift_reg}")2614}2615&Inst::VecSelect { rd, rn, rm, ra } => {2616let rd = pretty_print_reg(rd.to_reg());2617let rn = pretty_print_reg(rn);2618let rm = pretty_print_reg(rm);2619let ra = pretty_print_reg(ra);2620format!("vsel {rd}, {rn}, {rm}, {ra}")2621}2622&Inst::VecPermute { rd, rn, rm, ra } => {2623let rd = pretty_print_reg(rd.to_reg());2624let rn = pretty_print_reg(rn);2625let rm = pretty_print_reg(rm);2626let ra = pretty_print_reg(ra);2627format!("vperm {rd}, {rn}, {rm}, {ra}")2628}2629&Inst::VecPermuteDWImm {2630rd,2631rn,2632rm,2633idx1,2634idx2,2635} => {2636let rd = pretty_print_reg(rd.to_reg());2637let rn = pretty_print_reg(rn);2638let rm = pretty_print_reg(rm);2639let m4 = (idx1 & 1) * 4 + (idx2 & 1);2640format!("vpdi {rd}, {rn}, {rm}, {m4}")2641}2642&Inst::VecIntCmp { op, rd, rn, rm } | &Inst::VecIntCmpS { op, rd, rn, rm } => {2643let op = match op {2644VecIntCmpOp::CmpEq8x16 => "vceqb",2645VecIntCmpOp::CmpEq16x8 => "vceqh",2646VecIntCmpOp::CmpEq32x4 => "vceqf",2647VecIntCmpOp::CmpEq64x2 => "vceqg",2648VecIntCmpOp::SCmpHi8x16 => "vchb",2649VecIntCmpOp::SCmpHi16x8 => "vchh",2650VecIntCmpOp::SCmpHi32x4 => "vchf",2651VecIntCmpOp::SCmpHi64x2 => "vchg",2652VecIntCmpOp::UCmpHi8x16 => "vchlb",2653VecIntCmpOp::UCmpHi16x8 => "vchlh",2654VecIntCmpOp::UCmpHi32x4 => "vchlf",2655VecIntCmpOp::UCmpHi64x2 => "vchlg",2656};2657let s = match self {2658&Inst::VecIntCmp { .. } => "",2659&Inst::VecIntCmpS { .. } => "s",2660_ => unreachable!(),2661};2662let rd = pretty_print_reg(rd.to_reg());2663let rn = pretty_print_reg(rn);2664let rm = pretty_print_reg(rm);2665format!("{op}{s} {rd}, {rn}, {rm}")2666}2667&Inst::VecFloatCmp { op, rd, rn, rm } | &Inst::VecFloatCmpS { op, rd, rn, rm } => {2668let op = match op {2669VecFloatCmpOp::CmpEq32x4 => "vfcesb",2670VecFloatCmpOp::CmpEq64x2 => "vfcedb",2671VecFloatCmpOp::CmpHi32x4 => "vfchsb",2672VecFloatCmpOp::CmpHi64x2 => "vfchdb",2673VecFloatCmpOp::CmpHiEq32x4 => "vfchesb",2674VecFloatCmpOp::CmpHiEq64x2 => "vfchedb",2675};2676let s = match self {2677&Inst::VecFloatCmp { .. } => "",2678&Inst::VecFloatCmpS { .. } => "s",2679_ => unreachable!(),2680};2681let rd = pretty_print_reg(rd.to_reg());2682let rn = pretty_print_reg(rn);2683let rm = pretty_print_reg(rm);2684format!("{op}{s} {rd}, {rn}, {rm}")2685}2686&Inst::VecInt128SCmpHi { tmp, rn, rm } | &Inst::VecInt128UCmpHi { tmp, rn, rm } => {2687let op = match self {2688&Inst::VecInt128SCmpHi { .. } => "vecg",2689&Inst::VecInt128UCmpHi { .. } => "veclg",2690_ => unreachable!(),2691};2692let tmp = pretty_print_reg(tmp.to_reg());2693let rn = pretty_print_reg(rn);2694let rm = pretty_print_reg(rm);2695format!("{op} {rm}, {rn} ; jne 10 ; vchlgs {tmp}, {rn}, {rm}")2696}2697&Inst::VecLoad { rd, ref mem }2698| &Inst::VecLoadRev { rd, ref mem }2699| &Inst::VecLoadByte16Rev { rd, ref mem }2700| &Inst::VecLoadByte32Rev { rd, ref mem }2701| &Inst::VecLoadByte64Rev { rd, ref mem }2702| &Inst::VecLoadElt16Rev { rd, ref mem }2703| &Inst::VecLoadElt32Rev { rd, ref mem }2704| &Inst::VecLoadElt64Rev { rd, ref mem } => {2705let opcode = match self {2706&Inst::VecLoad { .. } => "vl",2707&Inst::VecLoadRev { .. } => "vlbrq",2708&Inst::VecLoadByte16Rev { .. } => "vlbrh",2709&Inst::VecLoadByte32Rev { .. } => "vlbrf",2710&Inst::VecLoadByte64Rev { .. } => "vlbrg",2711&Inst::VecLoadElt16Rev { .. } => "vlerh",2712&Inst::VecLoadElt32Rev { .. } => "vlerf",2713&Inst::VecLoadElt64Rev { .. } => "vlerg",2714_ => unreachable!(),2715};27162717let rd = pretty_print_reg(rd.to_reg());2718let mem = mem.clone();2719let (mem_str, mem) = mem_finalize_for_show(2720&mem,2721state,2722MemInstType {2723have_d12: true,2724have_d20: false,2725have_pcrel: false,2726have_unaligned_pcrel: false,2727have_index: true,2728},2729);2730let mem = mem.pretty_print_default();2731format!("{mem_str}{opcode} {rd}, {mem}")2732}2733&Inst::VecStore { rd, ref mem }2734| &Inst::VecStoreRev { rd, ref mem }2735| &Inst::VecStoreByte16Rev { rd, ref mem }2736| &Inst::VecStoreByte32Rev { rd, ref mem }2737| &Inst::VecStoreByte64Rev { rd, ref mem }2738| &Inst::VecStoreElt16Rev { rd, ref mem }2739| &Inst::VecStoreElt32Rev { rd, ref mem }2740| &Inst::VecStoreElt64Rev { rd, ref mem } => {2741let opcode = match self {2742&Inst::VecStore { .. } => "vst",2743&Inst::VecStoreRev { .. } => "vstbrq",2744&Inst::VecStoreByte16Rev { .. } => "vstbrh",2745&Inst::VecStoreByte32Rev { .. } => "vstbrf",2746&Inst::VecStoreByte64Rev { .. } => "vstbrg",2747&Inst::VecStoreElt16Rev { .. } => "vsterh",2748&Inst::VecStoreElt32Rev { .. } => "vsterf",2749&Inst::VecStoreElt64Rev { .. } => "vsterg",2750_ => unreachable!(),2751};27522753let rd = pretty_print_reg(rd);2754let mem = mem.clone();2755let (mem_str, mem) = mem_finalize_for_show(2756&mem,2757state,2758MemInstType {2759have_d12: true,2760have_d20: false,2761have_pcrel: false,2762have_unaligned_pcrel: false,2763have_index: true,2764},2765);2766let mem = mem.pretty_print_default();2767format!("{mem_str}{opcode} {rd}, {mem}")2768}2769&Inst::VecLoadReplicate { size, rd, ref mem }2770| &Inst::VecLoadReplicateRev { size, rd, ref mem } => {2771let opcode = match (self, size) {2772(&Inst::VecLoadReplicate { .. }, 8) => "vlrepb",2773(&Inst::VecLoadReplicate { .. }, 16) => "vlreph",2774(&Inst::VecLoadReplicate { .. }, 32) => "vlrepf",2775(&Inst::VecLoadReplicate { .. }, 64) => "vlrepg",2776(&Inst::VecLoadReplicateRev { .. }, 16) => "vlbrreph",2777(&Inst::VecLoadReplicateRev { .. }, 32) => "vlbrrepf",2778(&Inst::VecLoadReplicateRev { .. }, 64) => "vlbrrepg",2779_ => unreachable!(),2780};27812782let rd = pretty_print_reg(rd.to_reg());2783let mem = mem.clone();2784let (mem_str, mem) = mem_finalize_for_show(2785&mem,2786state,2787MemInstType {2788have_d12: true,2789have_d20: false,2790have_pcrel: false,2791have_unaligned_pcrel: false,2792have_index: true,2793},2794);2795let mem = mem.pretty_print_default();2796format!("{mem_str}{opcode} {rd}, {mem}")2797}2798&Inst::VecMov { rd, rn } => {2799let rd = pretty_print_reg(rd.to_reg());2800let rn = pretty_print_reg(rn);2801format!("vlr {rd}, {rn}")2802}2803&Inst::VecCMov { rd, cond, ri, rm } => {2804let rd = pretty_print_reg_mod(rd, ri);2805let rm = pretty_print_reg(rm);2806let cond = cond.invert().pretty_print_default();2807format!("j{cond} 10 ; vlr {rd}, {rm}")2808}2809&Inst::MovToVec128 { rd, rn, rm } => {2810let rd = pretty_print_reg(rd.to_reg());2811let rn = pretty_print_reg(rn);2812let rm = pretty_print_reg(rm);2813format!("vlvgp {rd}, {rn}, {rm}")2814}2815&Inst::VecImmByteMask { rd, mask } => {2816let rd = pretty_print_reg(rd.to_reg());2817format!("vgbm {rd}, {mask}")2818}2819&Inst::VecImmBitMask {2820size,2821rd,2822start_bit,2823end_bit,2824} => {2825let rd = pretty_print_reg(rd.to_reg());2826let op = match size {28278 => "vgmb",282816 => "vgmh",282932 => "vgmf",283064 => "vgmg",2831_ => unreachable!(),2832};2833format!("{op} {rd}, {start_bit}, {end_bit}")2834}2835&Inst::VecImmReplicate { size, rd, imm } => {2836let rd = pretty_print_reg(rd.to_reg());2837let op = match size {28388 => "vrepib",283916 => "vrepih",284032 => "vrepif",284164 => "vrepig",2842_ => unreachable!(),2843};2844format!("{op} {rd}, {imm}")2845}2846&Inst::VecLoadLane {2847size,2848rd,2849ref mem,2850lane_imm,2851..2852}2853| &Inst::VecLoadLaneRev {2854size,2855rd,2856ref mem,2857lane_imm,2858..2859} => {2860let opcode_vrx = match (self, size) {2861(&Inst::VecLoadLane { .. }, 8) => "vleb",2862(&Inst::VecLoadLane { .. }, 16) => "vleh",2863(&Inst::VecLoadLane { .. }, 32) => "vlef",2864(&Inst::VecLoadLane { .. }, 64) => "vleg",2865(&Inst::VecLoadLaneRev { .. }, 16) => "vlebrh",2866(&Inst::VecLoadLaneRev { .. }, 32) => "vlebrf",2867(&Inst::VecLoadLaneRev { .. }, 64) => "vlebrg",2868_ => unreachable!(),2869};28702871let (rd, _) = pretty_print_fpr(rd.to_reg());2872let mem = mem.clone();2873let (mem_str, mem) = mem_finalize_for_show(2874&mem,2875state,2876MemInstType {2877have_d12: true,2878have_d20: false,2879have_pcrel: false,2880have_unaligned_pcrel: false,2881have_index: true,2882},2883);2884let mem = mem.pretty_print_default();2885format!("{mem_str}{opcode_vrx} {rd}, {mem}, {lane_imm}")2886}2887&Inst::VecLoadLaneUndef {2888size,2889rd,2890ref mem,2891lane_imm,2892}2893| &Inst::VecLoadLaneRevUndef {2894size,2895rd,2896ref mem,2897lane_imm,2898} => {2899let (opcode_vrx, opcode_rx, opcode_rxy) = match (self, size) {2900(&Inst::VecLoadLaneUndef { .. }, 8) => ("vleb", None, None),2901(&Inst::VecLoadLaneUndef { .. }, 16) => ("vleh", None, None),2902(&Inst::VecLoadLaneUndef { .. }, 32) => ("vlef", Some("le"), Some("ley")),2903(&Inst::VecLoadLaneUndef { .. }, 64) => ("vleg", Some("ld"), Some("ldy")),2904(&Inst::VecLoadLaneRevUndef { .. }, 16) => ("vlebrh", None, None),2905(&Inst::VecLoadLaneRevUndef { .. }, 32) => ("vlebrf", None, None),2906(&Inst::VecLoadLaneRevUndef { .. }, 64) => ("vlebrg", None, None),2907_ => unreachable!(),2908};29092910let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());2911let mem = mem.clone();2912if lane_imm == 0 && rd_fpr.is_some() && opcode_rx.is_some() {2913let (mem_str, mem) = mem_finalize_for_show(2914&mem,2915state,2916MemInstType {2917have_d12: true,2918have_d20: true,2919have_pcrel: false,2920have_unaligned_pcrel: false,2921have_index: true,2922},2923);2924let op = match &mem {2925&MemArg::BXD12 { .. } => opcode_rx,2926&MemArg::BXD20 { .. } => opcode_rxy,2927_ => unreachable!(),2928};2929let mem = mem.pretty_print_default();2930format!("{}{} {}, {}", mem_str, op.unwrap(), rd_fpr.unwrap(), mem)2931} else {2932let (mem_str, mem) = mem_finalize_for_show(2933&mem,2934state,2935MemInstType {2936have_d12: true,2937have_d20: false,2938have_pcrel: false,2939have_unaligned_pcrel: false,2940have_index: true,2941},2942);2943let mem = mem.pretty_print_default();2944format!("{mem_str}{opcode_vrx} {rd}, {mem}, {lane_imm}")2945}2946}2947&Inst::VecStoreLane {2948size,2949rd,2950ref mem,2951lane_imm,2952}2953| &Inst::VecStoreLaneRev {2954size,2955rd,2956ref mem,2957lane_imm,2958} => {2959let (opcode_vrx, opcode_rx, opcode_rxy) = match (self, size) {2960(&Inst::VecStoreLane { .. }, 8) => ("vsteb", None, None),2961(&Inst::VecStoreLane { .. }, 16) => ("vsteh", None, None),2962(&Inst::VecStoreLane { .. }, 32) => ("vstef", Some("ste"), Some("stey")),2963(&Inst::VecStoreLane { .. }, 64) => ("vsteg", Some("std"), Some("stdy")),2964(&Inst::VecStoreLaneRev { .. }, 16) => ("vstebrh", None, None),2965(&Inst::VecStoreLaneRev { .. }, 32) => ("vstebrf", None, None),2966(&Inst::VecStoreLaneRev { .. }, 64) => ("vstebrg", None, None),2967_ => unreachable!(),2968};29692970let (rd, rd_fpr) = pretty_print_fpr(rd);2971let mem = mem.clone();2972if lane_imm == 0 && rd_fpr.is_some() && opcode_rx.is_some() {2973let (mem_str, mem) = mem_finalize_for_show(2974&mem,2975state,2976MemInstType {2977have_d12: true,2978have_d20: true,2979have_pcrel: false,2980have_unaligned_pcrel: false,2981have_index: true,2982},2983);2984let op = match &mem {2985&MemArg::BXD12 { .. } => opcode_rx,2986&MemArg::BXD20 { .. } => opcode_rxy,2987_ => unreachable!(),2988};2989let mem = mem.pretty_print_default();2990format!("{}{} {}, {}", mem_str, op.unwrap(), rd_fpr.unwrap(), mem)2991} else {2992let (mem_str, mem) = mem_finalize_for_show(2993&mem,2994state,2995MemInstType {2996have_d12: true,2997have_d20: false,2998have_pcrel: false,2999have_unaligned_pcrel: false,3000have_index: true,3001},3002);3003let mem = mem.pretty_print_default();3004format!("{mem_str}{opcode_vrx} {rd}, {mem}, {lane_imm}",)3005}3006}3007&Inst::VecInsertLane {3008size,3009rd,3010ri,3011rn,3012lane_imm,3013lane_reg,3014} => {3015let op = match size {30168 => "vlvgb",301716 => "vlvgh",301832 => "vlvgf",301964 => "vlvgg",3020_ => unreachable!(),3021};3022let rd = pretty_print_reg_mod(rd, ri);3023let rn = pretty_print_reg(rn);3024let lane_reg = if lane_reg != zero_reg() {3025format!("({})", pretty_print_reg(lane_reg))3026} else {3027"".to_string()3028};3029format!("{op} {rd}, {rn}, {lane_imm}{lane_reg}")3030}3031&Inst::VecInsertLaneUndef {3032size,3033rd,3034rn,3035lane_imm,3036lane_reg,3037} => {3038let (opcode_vrs, opcode_rre) = match size {30398 => ("vlvgb", None),304016 => ("vlvgh", None),304132 => ("vlvgf", None),304264 => ("vlvgg", Some("ldgr")),3043_ => unreachable!(),3044};3045let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());3046let rn = pretty_print_reg(rn);3047let lane_reg = if lane_reg != zero_reg() {3048format!("({})", pretty_print_reg(lane_reg))3049} else {3050"".to_string()3051};3052if opcode_rre.is_some() && lane_imm == 0 && lane_reg.is_empty() && rd_fpr.is_some()3053{3054format!("{} {}, {}", opcode_rre.unwrap(), rd_fpr.unwrap(), rn)3055} else {3056format!("{opcode_vrs} {rd}, {rn}, {lane_imm}{lane_reg}")3057}3058}3059&Inst::VecExtractLane {3060size,3061rd,3062rn,3063lane_imm,3064lane_reg,3065} => {3066let (opcode_vrs, opcode_rre) = match size {30678 => ("vlgvb", None),306816 => ("vlgvh", None),306932 => ("vlgvf", None),307064 => ("vlgvg", Some("lgdr")),3071_ => unreachable!(),3072};3073let rd = pretty_print_reg(rd.to_reg());3074let (rn, rn_fpr) = pretty_print_fpr(rn);3075let lane_reg = if lane_reg != zero_reg() {3076format!("({})", pretty_print_reg(lane_reg))3077} else {3078"".to_string()3079};3080if opcode_rre.is_some() && lane_imm == 0 && lane_reg.is_empty() && rn_fpr.is_some()3081{3082format!("{} {}, {}", opcode_rre.unwrap(), rd, rn_fpr.unwrap())3083} else {3084format!("{opcode_vrs} {rd}, {rn}, {lane_imm}{lane_reg}")3085}3086}3087&Inst::VecInsertLaneImm {3088size,3089rd,3090ri,3091imm,3092lane_imm,3093} => {3094let op = match size {30958 => "vleib",309616 => "vleih",309732 => "vleif",309864 => "vleig",3099_ => unreachable!(),3100};3101let rd = pretty_print_reg_mod(rd, ri);3102format!("{op} {rd}, {imm}, {lane_imm}")3103}3104&Inst::VecInsertLaneImmUndef {3105size,3106rd,3107imm,3108lane_imm,3109} => {3110let op = match size {31118 => "vleib",311216 => "vleih",311332 => "vleif",311464 => "vleig",3115_ => unreachable!(),3116};3117let rd = pretty_print_reg(rd.to_reg());3118format!("{op} {rd}, {imm}, {lane_imm}")3119}3120&Inst::VecReplicateLane {3121size,3122rd,3123rn,3124lane_imm,3125} => {3126let op = match size {31278 => "vrepb",312816 => "vreph",312932 => "vrepf",313064 => "vrepg",3131_ => unreachable!(),3132};3133let rd = pretty_print_reg(rd.to_reg());3134let rn = pretty_print_reg(rn);3135format!("{op} {rd}, {rn}, {lane_imm}")3136}3137&Inst::VecEltRev { lane_count, rd, rn } => {3138assert!(lane_count >= 2 && lane_count <= 16);3139let rd = pretty_print_reg(rd.to_reg());3140let rn = pretty_print_reg(rn);3141let mut print = format!("vpdi {rd}, {rn}, {rn}, 4");3142if lane_count >= 4 {3143print = format!("{print} ; verllg {rn}, {rn}, 32");3144}3145if lane_count >= 8 {3146print = format!("{print} ; verllf {rn}, {rn}, 16");3147}3148if lane_count >= 16 {3149print = format!("{print} ; verllh {rn}, {rn}, 8");3150}31513152}3153&Inst::Extend {3154rd,3155rn,3156signed,3157from_bits,3158to_bits,3159} => {3160let rd = pretty_print_reg(rd.to_reg());3161let rn = pretty_print_reg(rn);3162let op = match (signed, from_bits, to_bits) {3163(_, 1, 32) => "llcr",3164(_, 1, 64) => "llgcr",3165(false, 8, 32) => "llcr",3166(false, 8, 64) => "llgcr",3167(true, 8, 32) => "lbr",3168(true, 8, 64) => "lgbr",3169(false, 16, 32) => "llhr",3170(false, 16, 64) => "llghr",3171(true, 16, 32) => "lhr",3172(true, 16, 64) => "lghr",3173(false, 32, 64) => "llgfr",3174(true, 32, 64) => "lgfr",3175_ => panic!("Unsupported Extend case: {self:?}"),3176};3177format!("{op} {rd}, {rn}")3178}3179&Inst::AllocateArgs { size } => {3180state.nominal_sp_offset = size;3181if let Ok(size) = i16::try_from(size) {3182format!("aghi {}, {}", show_reg(stack_reg()), -size)3183} else {3184format!("slgfi {}, {}", show_reg(stack_reg()), size)3185}3186}3187&Inst::Call { link, ref info } => {3188state.nominal_sp_offset = 0;3189let link = link.to_reg();3190let (opcode, dest) = match &info.dest {3191CallInstDest::Direct { name } => ("brasl", name.display(None).to_string()),3192CallInstDest::Indirect { reg } => ("basr", pretty_print_reg(*reg)),3193};3194state.outgoing_sp_offset = info.callee_pop_size;3195let mut retval_loads = S390xMachineDeps::gen_retval_loads(info)3196.into_iter()3197.map(|inst| inst.print_with_state(state))3198.collect::<Vec<_>>()3199.join(" ; ");3200if !retval_loads.is_empty() {3201retval_loads = " ; ".to_string() + &retval_loads;3202}3203state.outgoing_sp_offset = 0;3204let try_call = if let Some(try_call_info) = &info.try_call_info {3205format!(3206"; jg {:?}; catch [{}]",3207try_call_info.continuation,3208try_call_info.pretty_print_dests()3209)3210} else {3211"".to_string()3212};3213let callee_pop_size = if info.callee_pop_size > 0 {3214format!(" ; callee_pop_size {}", info.callee_pop_size)3215} else {3216"".to_string()3217};3218format!(3219"{} {}, {}{}{}{}",3220opcode,3221show_reg(link),3222dest,3223callee_pop_size,3224retval_loads,3225try_call3226)3227}3228&Inst::ReturnCall { ref info } => {3229let (epilogue_insts, temp_dest) = S390xMachineDeps::gen_tail_epilogue(3230state.frame_layout(),3231info.callee_pop_size,3232&info.dest,3233);3234let mut epilogue_str = epilogue_insts3235.into_iter()3236.map(|inst| inst.print_with_state(state))3237.collect::<Vec<_>>()3238.join(" ; ");3239if !epilogue_str.is_empty() {3240epilogue_str += " ; ";3241}3242let (opcode, dest) = match &info.dest {3243CallInstDest::Direct { name } => ("jg", name.display(None).to_string()),3244CallInstDest::Indirect { reg } => {3245("br", pretty_print_reg(temp_dest.unwrap_or(*reg)))3246}3247};3248let callee_pop_size = if info.callee_pop_size > 0 {3249format!(" ; callee_pop_size {}", info.callee_pop_size)3250} else {3251"".to_string()3252};3253format!("{epilogue_str}{opcode} {dest}{callee_pop_size}")3254}3255&Inst::ElfTlsGetOffset { ref symbol, .. } => {3256let dest = match &**symbol {3257SymbolReloc::TlsGd { name } => {3258format!("tls_gdcall:{}", name.display(None))3259}3260_ => unreachable!(),3261};3262format!("brasl {}, {}", show_reg(gpr(14)), dest)3263}3264&Inst::Args { ref args } => {3265let mut s = "args".to_string();3266for arg in args {3267let preg = pretty_print_reg(arg.preg);3268let def = pretty_print_reg(arg.vreg.to_reg());3269write!(&mut s, " {def}={preg}").unwrap();3270}3271s3272}3273&Inst::Rets { ref rets } => {3274let mut s = "rets".to_string();3275for ret in rets {3276let preg = pretty_print_reg(ret.preg);3277let vreg = pretty_print_reg(ret.vreg);3278write!(&mut s, " {vreg}={preg}").unwrap();3279}3280s3281}3282&Inst::Ret { link } => {3283let link = show_reg(link);3284format!("br {link}")3285}3286&Inst::Jump { dest } => {3287let dest = dest.to_string();3288format!("jg {dest}")3289}3290&Inst::IndirectBr { rn, .. } => {3291let rn = pretty_print_reg(rn);3292format!("br {rn}")3293}3294&Inst::CondBr {3295taken,3296not_taken,3297cond,3298} => {3299let taken = taken.to_string();3300let not_taken = not_taken.to_string();3301let cond = cond.pretty_print_default();3302format!("jg{cond} {taken} ; jg {not_taken}")3303}3304&Inst::Debugtrap => ".word 0x0001 # debugtrap".to_string(),3305&Inst::Trap { trap_code } => {3306format!(".word 0x0000 # trap={trap_code}")3307}3308&Inst::TrapIf { cond, trap_code } => {3309let cond = cond.pretty_print_default();3310format!("jg{cond} .+2 # trap={trap_code}")3311}3312&Inst::JTSequence {3313ridx,3314default,3315default_cond,3316ref targets,3317} => {3318let ridx = pretty_print_reg(ridx);3319let rtmp = pretty_print_reg(writable_spilltmp_reg().to_reg());3320let jt_entries: String = targets3321.iter()3322.map(|label| format!(" {}", label.to_string()))3323.collect();3324format!(3325concat!(3326"jg{} {} ; ",3327"larl {}, 14 ; ",3328"agf {}, 0({}, {}) ; ",3329"br {} ; ",3330"jt_entries{}"3331),3332default_cond.pretty_print_default(),3333default.to_string(),3334rtmp,3335rtmp,3336rtmp,3337ridx,3338rtmp,3339jt_entries,3340)3341}3342&Inst::LoadSymbolReloc {3343rd,3344ref symbol_reloc,3345} => {3346let rd = pretty_print_reg(rd.to_reg());3347let tmp = pretty_print_reg(writable_spilltmp_reg().to_reg());3348let symbol = match &**symbol_reloc {3349SymbolReloc::Absolute { name, offset } => {3350format!("{} + {}", name.display(None), offset)3351}3352SymbolReloc::TlsGd { name } => format!("{}@tlsgd", name.display(None)),3353};3354format!("bras {tmp}, 12 ; data {symbol} ; lg {rd}, 0({tmp})")3355}3356&Inst::LoadAddr { rd, ref mem } => {3357let rd = pretty_print_reg(rd.to_reg());3358let mem = mem.clone();3359let (mem_str, mem) = mem_finalize_for_show(3360&mem,3361state,3362MemInstType {3363have_d12: true,3364have_d20: true,3365have_pcrel: true,3366have_unaligned_pcrel: true,3367have_index: true,3368},3369);3370let op = match &mem {3371&MemArg::BXD12 { .. } => "la",3372&MemArg::BXD20 { .. } => "lay",3373&MemArg::Label { .. } | &MemArg::Constant { .. } | &MemArg::Symbol { .. } => {3374"larl"3375}3376_ => unreachable!(),3377};3378let mem = mem.pretty_print_default();33793380format!("{mem_str}{op} {rd}, {mem}")3381}3382&Inst::StackProbeLoop {3383probe_count,3384guard_size,3385} => {3386let probe_count = pretty_print_reg(probe_count.to_reg());3387let stack_reg = pretty_print_reg(stack_reg());3388format!(3389"0: aghi {stack_reg}, -{guard_size} ; mvi 0({stack_reg}), 0 ; brct {probe_count}, 0b"3390)3391}3392&Inst::Loop { ref body, cond } => {3393let body = body3394.into_iter()3395.map(|inst| inst.print_with_state(state))3396.collect::<Vec<_>>()3397.join(" ; ");3398let cond = cond.pretty_print_default();3399format!("0: {body} ; jg{cond} 0b ; 1:")3400}3401&Inst::CondBreak { cond } => {3402let cond = cond.pretty_print_default();3403format!("jg{cond} 1f")3404}3405&Inst::Unwind { ref inst } => {3406format!("unwind {inst:?}")3407}3408&Inst::DummyUse { reg } => {3409let reg = pretty_print_reg(reg);3410format!("dummy_use {reg}")3411}3412&Inst::LabelAddress { dst, label } => {3413let dst = pretty_print_reg(dst.to_reg());3414format!("label_address {dst}, {label:?}")3415}3416}3417}3418}34193420//=============================================================================3421// Label fixups and jump veneers.34223423/// Different forms of label references for different instruction formats.3424#[derive(Clone, Copy, Debug, PartialEq, Eq)]3425pub enum LabelUse {3426/// RI-format branch. 16-bit signed offset. PC-relative, offset is imm << 1.3427BranchRI,3428/// RIL-format branch. 32-bit signed offset. PC-relative, offset is imm << 1.3429BranchRIL,3430/// 32-bit PC relative constant offset (from address of constant itself),3431/// signed. Used in jump tables.3432PCRel32,3433/// 32-bit PC relative constant offset (from address of call instruction),3434/// signed. Offset is imm << 1. Used for call relocations.3435PCRel32Dbl,3436}34373438impl MachInstLabelUse for LabelUse {3439/// Alignment for veneer code.3440const ALIGN: CodeOffset = 2;34413442/// Maximum PC-relative range (positive), inclusive.3443fn max_pos_range(self) -> CodeOffset {3444match self {3445// 16-bit signed immediate, left-shifted by 1.3446LabelUse::BranchRI => ((1 << 15) - 1) << 1,3447// 32-bit signed immediate, left-shifted by 1.3448LabelUse::BranchRIL => 0xffff_fffe,3449// 32-bit signed immediate.3450LabelUse::PCRel32 => 0x7fff_ffff,3451// 32-bit signed immediate, left-shifted by 1, offset by 2.3452LabelUse::PCRel32Dbl => 0xffff_fffc,3453}3454}34553456/// Maximum PC-relative range (negative).3457fn max_neg_range(self) -> CodeOffset {3458match self {3459// 16-bit signed immediate, left-shifted by 1.3460LabelUse::BranchRI => (1 << 15) << 1,3461// 32-bit signed immediate, left-shifted by 1.3462// NOTE: This should be 4GB, but CodeOffset is only u32.3463LabelUse::BranchRIL => 0xffff_ffff,3464// 32-bit signed immediate.3465LabelUse::PCRel32 => 0x8000_0000,3466// 32-bit signed immediate, left-shifted by 1, offset by 2.3467// NOTE: This should be 4GB + 2, but CodeOffset is only u32.3468LabelUse::PCRel32Dbl => 0xffff_ffff,3469}3470}34713472/// Size of window into code needed to do the patch.3473fn patch_size(self) -> CodeOffset {3474match self {3475LabelUse::BranchRI => 4,3476LabelUse::BranchRIL => 6,3477LabelUse::PCRel32 => 4,3478LabelUse::PCRel32Dbl => 4,3479}3480}34813482/// Perform the patch.3483fn patch(self, buffer: &mut [u8], use_offset: CodeOffset, label_offset: CodeOffset) {3484let pc_rel = (label_offset as i64) - (use_offset as i64);3485debug_assert!(pc_rel <= self.max_pos_range() as i64);3486debug_assert!(pc_rel >= -(self.max_neg_range() as i64));3487debug_assert!(pc_rel & 1 == 0);3488let pc_rel_shifted = pc_rel >> 1;34893490match self {3491LabelUse::BranchRI => {3492buffer[2..4].clone_from_slice(&u16::to_be_bytes(pc_rel_shifted as u16));3493}3494LabelUse::BranchRIL => {3495buffer[2..6].clone_from_slice(&u32::to_be_bytes(pc_rel_shifted as u32));3496}3497LabelUse::PCRel32 => {3498let insn_word = u32::from_be_bytes([buffer[0], buffer[1], buffer[2], buffer[3]]);3499let insn_word = insn_word.wrapping_add(pc_rel as u32);3500buffer[0..4].clone_from_slice(&u32::to_be_bytes(insn_word));3501}3502LabelUse::PCRel32Dbl => {3503let insn_word = u32::from_be_bytes([buffer[0], buffer[1], buffer[2], buffer[3]]);3504let insn_word = insn_word.wrapping_add((pc_rel_shifted + 1) as u32);3505buffer[0..4].clone_from_slice(&u32::to_be_bytes(insn_word));3506}3507}3508}35093510/// Is a veneer supported for this label reference type?3511fn supports_veneer(self) -> bool {3512false3513}35143515/// How large is the veneer, if supported?3516fn veneer_size(self) -> CodeOffset {351703518}35193520fn worst_case_veneer_size() -> CodeOffset {352103522}35233524/// Generate a veneer into the buffer, given that this veneer is at `veneer_offset`, and return3525/// an offset and label-use for the veneer's use of the original label.3526fn generate_veneer(3527self,3528_buffer: &mut [u8],3529_veneer_offset: CodeOffset,3530) -> (CodeOffset, LabelUse) {3531unreachable!();3532}35333534fn from_reloc(reloc: Reloc, addend: Addend) -> Option<Self> {3535match (reloc, addend) {3536(Reloc::S390xPCRel32Dbl, 2) => Some(LabelUse::PCRel32Dbl),3537(Reloc::S390xPLTRel32Dbl, 2) => Some(LabelUse::PCRel32Dbl),3538_ => None,3539}3540}3541}354235433544