| //! Lowering rules for S390x. |
| |
| use crate::ir::Inst as IRInst; |
| use crate::ir::Opcode; |
| use crate::isa::s390x::inst::Inst; |
| use crate::isa::s390x::S390xBackend; |
| use crate::machinst::{InsnOutput, Lower, LowerBackend, MachLabel}; |
| use crate::CodegenResult; |
| use smallvec::SmallVec; |
| |
| pub mod isle; |
| |
| //============================================================================= |
| // Lowering-backend trait implementation. |
| |
| impl LowerBackend for S390xBackend { |
| type MInst = Inst; |
| |
| fn lower(&self, ctx: &mut Lower<Inst>, ir_inst: IRInst) -> CodegenResult<()> { |
| let op = ctx.data(ir_inst).opcode(); |
| let outputs: SmallVec<[InsnOutput; 2]> = (0..ctx.num_outputs(ir_inst)) |
| .map(|i| InsnOutput { |
| insn: ir_inst, |
| output: i, |
| }) |
| .collect(); |
| let ty = if outputs.len() > 0 { |
| Some(ctx.output_ty(ir_inst, 0)) |
| } else { |
| None |
| }; |
| |
| if let Ok(()) = super::lower::isle::lower( |
| ctx, |
| &self.triple, |
| &self.flags, |
| &self.isa_flags, |
| &outputs, |
| ir_inst, |
| ) { |
| return Ok(()); |
| } |
| |
| match op { |
| Opcode::Nop |
| | Opcode::Copy |
| | Opcode::Iconst |
| | Opcode::Bconst |
| | Opcode::F32const |
| | Opcode::F64const |
| | Opcode::Vconst |
| | Opcode::Null |
| | Opcode::Isplit |
| | Opcode::Iconcat |
| | Opcode::Iadd |
| | Opcode::IaddIfcout |
| | Opcode::Isub |
| | Opcode::UaddSat |
| | Opcode::SaddSat |
| | Opcode::UsubSat |
| | Opcode::SsubSat |
| | Opcode::IaddPairwise |
| | Opcode::Imin |
| | Opcode::Umin |
| | Opcode::Imax |
| | Opcode::Umax |
| | Opcode::AvgRound |
| | Opcode::Iabs |
| | Opcode::Ineg |
| | Opcode::Imul |
| | Opcode::Umulhi |
| | Opcode::Smulhi |
| | Opcode::WideningPairwiseDotProductS |
| | Opcode::SqmulRoundSat |
| | Opcode::Udiv |
| | Opcode::Urem |
| | Opcode::Sdiv |
| | Opcode::Srem |
| | Opcode::Ishl |
| | Opcode::Ushr |
| | Opcode::Sshr |
| | Opcode::Rotr |
| | Opcode::Rotl |
| | Opcode::Ireduce |
| | Opcode::Uextend |
| | Opcode::Sextend |
| | Opcode::Snarrow |
| | Opcode::Unarrow |
| | Opcode::Uunarrow |
| | Opcode::SwidenLow |
| | Opcode::SwidenHigh |
| | Opcode::UwidenLow |
| | Opcode::UwidenHigh |
| | Opcode::Bnot |
| | Opcode::Band |
| | Opcode::Bor |
| | Opcode::Bxor |
| | Opcode::BandNot |
| | Opcode::BorNot |
| | Opcode::BxorNot |
| | Opcode::Bitselect |
| | Opcode::Vselect |
| | Opcode::Breduce |
| | Opcode::Bextend |
| | Opcode::Bmask |
| | Opcode::Bint |
| | Opcode::Bitrev |
| | Opcode::Clz |
| | Opcode::Cls |
| | Opcode::Ctz |
| | Opcode::Popcnt |
| | Opcode::Fadd |
| | Opcode::Fsub |
| | Opcode::Fmul |
| | Opcode::Fdiv |
| | Opcode::Fmin |
| | Opcode::Fmax |
| | Opcode::FminPseudo |
| | Opcode::FmaxPseudo |
| | Opcode::Sqrt |
| | Opcode::Fneg |
| | Opcode::Fabs |
| | Opcode::Fpromote |
| | Opcode::Fdemote |
| | Opcode::FvpromoteLow |
| | Opcode::Fvdemote |
| | Opcode::Ceil |
| | Opcode::Floor |
| | Opcode::Trunc |
| | Opcode::Nearest |
| | Opcode::Fma |
| | Opcode::Fcopysign |
| | Opcode::FcvtFromUint |
| | Opcode::FcvtFromSint |
| | Opcode::FcvtLowFromSint |
| | Opcode::FcvtToUint |
| | Opcode::FcvtToSint |
| | Opcode::FcvtToUintSat |
| | Opcode::FcvtToSintSat |
| | Opcode::Splat |
| | Opcode::Swizzle |
| | Opcode::Shuffle |
| | Opcode::Insertlane |
| | Opcode::Extractlane |
| | Opcode::ScalarToVector |
| | Opcode::VhighBits |
| | Opcode::Bitcast |
| | Opcode::RawBitcast |
| | Opcode::Load |
| | Opcode::Uload8 |
| | Opcode::Sload8 |
| | Opcode::Uload16 |
| | Opcode::Sload16 |
| | Opcode::Uload32 |
| | Opcode::Sload32 |
| | Opcode::Uload8x8 |
| | Opcode::Sload8x8 |
| | Opcode::Uload16x4 |
| | Opcode::Sload16x4 |
| | Opcode::Uload32x2 |
| | Opcode::Sload32x2 |
| | Opcode::Store |
| | Opcode::Istore8 |
| | Opcode::Istore16 |
| | Opcode::Istore32 |
| | Opcode::AtomicRmw |
| | Opcode::AtomicCas |
| | Opcode::AtomicLoad |
| | Opcode::AtomicStore |
| | Opcode::Fence |
| | Opcode::Icmp |
| | Opcode::Fcmp |
| | Opcode::VanyTrue |
| | Opcode::VallTrue |
| | Opcode::IsNull |
| | Opcode::IsInvalid |
| | Opcode::Select |
| | Opcode::SelectifSpectreGuard |
| | Opcode::Trap |
| | Opcode::ResumableTrap |
| | Opcode::Trapz |
| | Opcode::Trapnz |
| | Opcode::ResumableTrapnz |
| | Opcode::Trapif |
| | Opcode::Debugtrap |
| | Opcode::Call |
| | Opcode::CallIndirect |
| | Opcode::Return |
| | Opcode::StackAddr |
| | Opcode::FuncAddr |
| | Opcode::SymbolValue |
| | Opcode::TlsValue |
| | Opcode::GetFramePointer |
| | Opcode::GetStackPointer |
| | Opcode::GetReturnAddress => { |
| unreachable!( |
| "implemented in ISLE: inst = `{}`, type = `{:?}`", |
| ctx.dfg().display_inst(ir_inst), |
| ty |
| ) |
| } |
| |
| Opcode::GetPinnedReg |
| | Opcode::SetPinnedReg |
| | Opcode::Vsplit |
| | Opcode::Vconcat |
| | Opcode::DynamicStackLoad |
| | Opcode::DynamicStackStore |
| | Opcode::DynamicStackAddr |
| | Opcode::ExtractVector => { |
| unreachable!( |
| "TODO: not yet implemented in ISLE: inst = `{}`, type = `{:?}`", |
| ctx.dfg().display_inst(ir_inst), |
| ty |
| ) |
| } |
| |
| Opcode::StackLoad | Opcode::StackStore => { |
| panic!("Direct stack memory access not supported; should not be used by Wasm"); |
| } |
| Opcode::HeapAddr => { |
| panic!("heap_addr should have been removed by legalization!"); |
| } |
| Opcode::TableAddr => { |
| panic!("table_addr should have been removed by legalization!"); |
| } |
| Opcode::GlobalValue => { |
| panic!("global_value should have been removed by legalization!"); |
| } |
| Opcode::Ifcmp |
| | Opcode::Ffcmp |
| | Opcode::Trapff |
| | Opcode::Trueif |
| | Opcode::Trueff |
| | Opcode::Selectif => { |
| panic!("Flags opcode should not be encountered."); |
| } |
| Opcode::Jump |
| | Opcode::Brz |
| | Opcode::Brnz |
| | Opcode::BrIcmp |
| | Opcode::Brif |
| | Opcode::Brff |
| | Opcode::BrTable => { |
| panic!("Branch opcode reached non-branch lowering logic!"); |
| } |
| Opcode::IaddImm |
| | Opcode::ImulImm |
| | Opcode::UdivImm |
| | Opcode::SdivImm |
| | Opcode::UremImm |
| | Opcode::SremImm |
| | Opcode::IrsubImm |
| | Opcode::IaddCin |
| | Opcode::IaddIfcin |
| | Opcode::IaddCout |
| | Opcode::IaddCarry |
| | Opcode::IaddIfcarry |
| | Opcode::IsubBin |
| | Opcode::IsubIfbin |
| | Opcode::IsubBout |
| | Opcode::IsubIfbout |
| | Opcode::IsubBorrow |
| | Opcode::IsubIfborrow |
| | Opcode::BandImm |
| | Opcode::BorImm |
| | Opcode::BxorImm |
| | Opcode::RotlImm |
| | Opcode::RotrImm |
| | Opcode::IshlImm |
| | Opcode::UshrImm |
| | Opcode::SshrImm |
| | Opcode::IcmpImm |
| | Opcode::IfcmpImm => { |
| panic!("ALU+imm and ALU+carry ops should not appear here!"); |
| } |
| } |
| } |
| |
| fn lower_branch_group( |
| &self, |
| ctx: &mut Lower<Inst>, |
| branches: &[IRInst], |
| targets: &[MachLabel], |
| ) -> CodegenResult<()> { |
| // A block should end with at most two branches. The first may be a |
| // conditional branch; a conditional branch can be followed only by an |
| // unconditional branch or fallthrough. Otherwise, if only one branch, |
| // it may be an unconditional branch, a fallthrough, a return, or a |
| // trap. These conditions are verified by `is_ebb_basic()` during the |
| // verifier pass. |
| assert!(branches.len() <= 2); |
| if branches.len() == 2 { |
| let op1 = ctx.data(branches[1]).opcode(); |
| assert!(op1 == Opcode::Jump); |
| } |
| |
| // Lower the first branch in ISLE. This will automatically handle |
| // the second branch (if any) by emitting a two-way conditional branch. |
| if let Ok(()) = super::lower::isle::lower_branch( |
| ctx, |
| &self.triple, |
| &self.flags, |
| &self.isa_flags, |
| branches[0], |
| targets, |
| ) { |
| return Ok(()); |
| } |
| unreachable!( |
| "implemented in ISLE: branch = `{}`", |
| ctx.dfg().display_inst(branches[0]), |
| ); |
| } |
| } |