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