Files
wasmtime/cranelift/codegen/src/isa/s390x/lower/isle.rs
Ulrich Weigand a94e72b5b7 s390x: Add ISLE support
This adds ISLE support for the s390x back-end and moves lowering
of most instructions to ISLE.  The only instructions still remaining
are calls, returns, traps, and branches, most of which will need
additional support in common code.

Generated code is not intended to be (significantly) different
than before; any additional optimizations now made easier to
implement due to the ISLE layer can be added in follow-on patches.

There were a few differences in some filetests, but those are all
just simple register allocation changes (and all to the better!).
2022-01-21 19:30:56 +01:00

476 lines
12 KiB
Rust

//! ISLE integration glue code for s390x lowering.
// Pull in the ISLE generated code.
pub mod generated_code;
// Types that the generated ISLE code uses via `use super::*`.
use super::{
BranchTarget, CallIndInfo, CallInfo, Cond, Inst as MInst, JTSequenceInfo, MachLabel, MemArg,
MemFlags, Opcode, Reg, UImm16Shifted, UImm32Shifted,
};
use crate::isa::s390x::settings::Flags as IsaFlags;
use crate::machinst::isle::*;
use crate::settings::Flags;
use crate::{
ir::{
condcodes::*, immediates::*, types::*, AtomicRmwOp, Endianness, ExternalName, Inst,
InstructionData, StackSlot, TrapCode, Value, ValueLabel, ValueList,
},
isa::s390x::inst::s390x_map_regs,
isa::unwind::UnwindInst,
machinst::{InsnOutput, LowerCtx, RelocDistance},
};
use std::boxed::Box;
use std::convert::TryFrom;
use std::vec::Vec;
type BoxCallInfo = Box<CallInfo>;
type BoxCallIndInfo = Box<CallIndInfo>;
type VecMachLabel = Vec<MachLabel>;
type BoxJTSequenceInfo = Box<JTSequenceInfo>;
type BoxExternalName = Box<ExternalName>;
/// The main entry point for lowering with ISLE.
pub(crate) fn lower<C>(
lower_ctx: &mut C,
flags: &Flags,
isa_flags: &IsaFlags,
outputs: &[InsnOutput],
inst: Inst,
) -> Result<(), ()>
where
C: LowerCtx<I = MInst>,
{
lower_common(
lower_ctx,
flags,
isa_flags,
outputs,
inst,
|cx, insn| generated_code::constructor_lower(cx, insn),
s390x_map_regs,
)
}
impl<C> generated_code::Context for IsleContext<'_, C, Flags, IsaFlags, 6>
where
C: LowerCtx<I = MInst>,
{
isle_prelude_methods!();
#[inline]
fn allow_div_traps(&mut self, _: Type) -> Option<()> {
if !self.flags.avoid_div_traps() {
Some(())
} else {
None
}
}
#[inline]
fn mie2_enabled(&mut self, _: Type) -> Option<()> {
if self.isa_flags.has_mie2() {
Some(())
} else {
None
}
}
#[inline]
fn mie2_disabled(&mut self, _: Type) -> Option<()> {
if !self.isa_flags.has_mie2() {
Some(())
} else {
None
}
}
#[inline]
fn vxrs_ext2_enabled(&mut self, _: Type) -> Option<()> {
if self.isa_flags.has_vxrs_ext2() {
Some(())
} else {
None
}
}
#[inline]
fn vxrs_ext2_disabled(&mut self, _: Type) -> Option<()> {
if !self.isa_flags.has_vxrs_ext2() {
Some(())
} else {
None
}
}
#[inline]
fn symbol_value_data(&mut self, inst: Inst) -> Option<(BoxExternalName, RelocDistance, i64)> {
let (name, dist, offset) = self.lower_ctx.symbol_value(inst)?;
Some((Box::new(name.clone()), dist, offset))
}
#[inline]
fn call_target_data(&mut self, inst: Inst) -> Option<(BoxExternalName, RelocDistance)> {
let (name, dist) = self.lower_ctx.call_target(inst)?;
Some((Box::new(name.clone()), dist))
}
#[inline]
fn writable_gpr(&mut self, regno: u8) -> WritableReg {
super::writable_gpr(regno)
}
#[inline]
fn zero_reg(&mut self) -> Reg {
super::zero_reg()
}
#[inline]
fn gpr32_ty(&mut self, ty: Type) -> Option<Type> {
match ty {
I8 | I16 | I32 | B1 | B8 | B16 | B32 => Some(ty),
_ => None,
}
}
#[inline]
fn gpr64_ty(&mut self, ty: Type) -> Option<Type> {
match ty {
I64 | B64 | R64 => Some(ty),
_ => None,
}
}
#[inline]
fn uimm32shifted(&mut self, n: u32, shift: u8) -> UImm32Shifted {
UImm32Shifted::maybe_with_shift(n, shift).unwrap()
}
#[inline]
fn uimm16shifted(&mut self, n: u16, shift: u8) -> UImm16Shifted {
UImm16Shifted::maybe_with_shift(n, shift).unwrap()
}
#[inline]
fn i64_nonequal(&mut self, val: i64, cmp: i64) -> Option<i64> {
if val != cmp {
Some(val)
} else {
None
}
}
#[inline]
fn u8_as_u16(&mut self, n: u8) -> u16 {
n as u16
}
#[inline]
fn u64_as_u32(&mut self, n: u64) -> u32 {
n as u32
}
#[inline]
fn u64_as_i16(&mut self, n: u64) -> i16 {
n as i16
}
#[inline]
fn u64_nonzero_hipart(&mut self, n: u64) -> Option<u64> {
let part = n & 0xffff_ffff_0000_0000;
if part != 0 {
Some(part)
} else {
None
}
}
#[inline]
fn u64_nonzero_lopart(&mut self, n: u64) -> Option<u64> {
let part = n & 0x0000_0000_ffff_ffff;
if part != 0 {
Some(part)
} else {
None
}
}
#[inline]
fn i32_from_u64(&mut self, n: u64) -> Option<i32> {
if let Ok(imm) = i32::try_from(n as i64) {
Some(imm)
} else {
None
}
}
#[inline]
fn i16_from_u64(&mut self, n: u64) -> Option<i16> {
if let Ok(imm) = i16::try_from(n as i64) {
Some(imm)
} else {
None
}
}
#[inline]
fn uimm32shifted_from_u64(&mut self, n: u64) -> Option<UImm32Shifted> {
UImm32Shifted::maybe_from_u64(n)
}
#[inline]
fn uimm16shifted_from_u64(&mut self, n: u64) -> Option<UImm16Shifted> {
UImm16Shifted::maybe_from_u64(n)
}
#[inline]
fn u64_from_value(&mut self, val: Value) -> Option<u64> {
let inst = self.lower_ctx.dfg().value_def(val).inst()?;
let constant = self.lower_ctx.get_constant(inst)?;
Some(constant)
}
#[inline]
fn u32_from_value(&mut self, val: Value) -> Option<u32> {
let constant = self.u64_from_value(val)?;
let imm = u32::try_from(constant).ok()?;
Some(imm)
}
#[inline]
fn u8_from_value(&mut self, val: Value) -> Option<u8> {
let constant = self.u64_from_value(val)?;
let imm = u8::try_from(constant).ok()?;
Some(imm)
}
#[inline]
fn u64_from_signed_value(&mut self, val: Value) -> Option<u64> {
let inst = self.lower_ctx.dfg().value_def(val).inst()?;
let constant = self.lower_ctx.get_constant(inst)?;
let ty = self.lower_ctx.output_ty(inst, 0);
Some(super::sign_extend_to_u64(constant, self.ty_bits(ty)))
}
#[inline]
fn i64_from_value(&mut self, val: Value) -> Option<i64> {
let constant = self.u64_from_signed_value(val)? as i64;
Some(constant)
}
#[inline]
fn i32_from_value(&mut self, val: Value) -> Option<i32> {
let constant = self.u64_from_signed_value(val)? as i64;
let imm = i32::try_from(constant).ok()?;
Some(imm)
}
#[inline]
fn i16_from_value(&mut self, val: Value) -> Option<i16> {
let constant = self.u64_from_signed_value(val)? as i64;
let imm = i16::try_from(constant).ok()?;
Some(imm)
}
#[inline]
fn i16_from_swapped_value(&mut self, val: Value) -> Option<i16> {
let constant = self.u64_from_signed_value(val)? as i64;
let imm = i16::try_from(constant).ok()?;
Some(imm.swap_bytes())
}
#[inline]
fn i64_from_negated_value(&mut self, val: Value) -> Option<i64> {
let constant = self.u64_from_signed_value(val)? as i64;
let imm = -constant;
Some(imm)
}
#[inline]
fn i32_from_negated_value(&mut self, val: Value) -> Option<i32> {
let constant = self.u64_from_signed_value(val)? as i64;
let imm = i32::try_from(-constant).ok()?;
Some(imm)
}
#[inline]
fn i16_from_negated_value(&mut self, val: Value) -> Option<i16> {
let constant = self.u64_from_signed_value(val)? as i64;
let imm = i16::try_from(-constant).ok()?;
Some(imm)
}
#[inline]
fn uimm16shifted_from_value(&mut self, val: Value) -> Option<UImm16Shifted> {
let constant = self.u64_from_value(val)?;
UImm16Shifted::maybe_from_u64(constant)
}
#[inline]
fn uimm32shifted_from_value(&mut self, val: Value) -> Option<UImm32Shifted> {
let constant = self.u64_from_value(val)?;
UImm32Shifted::maybe_from_u64(constant)
}
#[inline]
fn uimm16shifted_from_inverted_value(&mut self, val: Value) -> Option<UImm16Shifted> {
let constant = self.u64_from_value(val)?;
let imm = UImm16Shifted::maybe_from_u64(!constant)?;
Some(imm.negate_bits())
}
#[inline]
fn uimm32shifted_from_inverted_value(&mut self, val: Value) -> Option<UImm32Shifted> {
let constant = self.u64_from_value(val)?;
let imm = UImm32Shifted::maybe_from_u64(!constant)?;
Some(imm.negate_bits())
}
#[inline]
fn mask_amt_imm(&mut self, ty: Type, amt: i64) -> u8 {
let mask = self.ty_bits(ty) - 1;
(amt as u8) & mask
}
#[inline]
fn mask_as_cond(&mut self, mask: u8) -> Cond {
Cond::from_mask(mask)
}
#[inline]
fn intcc_as_cond(&mut self, cc: &IntCC) -> Cond {
Cond::from_intcc(*cc)
}
#[inline]
fn floatcc_as_cond(&mut self, cc: &FloatCC) -> Cond {
Cond::from_floatcc(*cc)
}
#[inline]
fn invert_cond(&mut self, cond: &Cond) -> Cond {
Cond::invert(*cond)
}
#[inline]
fn signed(&mut self, cc: &IntCC) -> Option<()> {
if super::condcode_is_signed(*cc) {
Some(())
} else {
None
}
}
#[inline]
fn unsigned(&mut self, cc: &IntCC) -> Option<()> {
if !super::condcode_is_signed(*cc) {
Some(())
} else {
None
}
}
#[inline]
fn reloc_distance_near(&mut self, dist: &RelocDistance) -> Option<()> {
if *dist == RelocDistance::Near {
Some(())
} else {
None
}
}
#[inline]
fn zero_offset(&mut self) -> Offset32 {
Offset32::new(0)
}
#[inline]
fn i64_from_offset(&mut self, off: Offset32) -> i64 {
i64::from(off)
}
#[inline]
fn littleendian(&mut self, flags: MemFlags) -> Option<()> {
let endianness = flags.endianness(Endianness::Big);
if endianness == Endianness::Little {
Some(())
} else {
None
}
}
#[inline]
fn bigendian(&mut self, flags: MemFlags) -> Option<()> {
let endianness = flags.endianness(Endianness::Big);
if endianness == Endianness::Big {
Some(())
} else {
None
}
}
#[inline]
fn memflags_trusted(&mut self) -> MemFlags {
MemFlags::trusted()
}
#[inline]
fn memarg_reg_plus_reg(&mut self, x: Reg, y: Reg, flags: MemFlags) -> MemArg {
MemArg::reg_plus_reg(x, y, flags)
}
#[inline]
fn memarg_reg_plus_off(&mut self, reg: Reg, off: i64, flags: MemFlags) -> MemArg {
MemArg::reg_plus_off(reg, off, flags)
}
#[inline]
fn memarg_symbol(&mut self, name: BoxExternalName, offset: i32, flags: MemFlags) -> MemArg {
MemArg::Symbol {
name,
offset,
flags,
}
}
#[inline]
fn memarg_symbol_offset_sum(&mut self, off1: i64, off2: i64) -> Option<i32> {
let off = i32::try_from(off1 + off2).ok()?;
if off & 1 == 0 {
Some(off)
} else {
None
}
}
#[inline]
fn abi_stackslot_addr(
&mut self,
dst: WritableReg,
stack_slot: StackSlot,
offset: Offset32,
) -> MInst {
let offset = u32::try_from(i32::from(offset)).unwrap();
self.lower_ctx.abi().stackslot_addr(stack_slot, offset, dst)
}
#[inline]
fn sinkable_inst(&mut self, val: Value) -> Option<Inst> {
let input = self.lower_ctx.get_value_as_source_or_const(val);
if let Some((inst, 0)) = input.inst {
return Some(inst);
}
None
}
#[inline]
fn sink_inst(&mut self, inst: Inst) -> Unit {
self.lower_ctx.sink_inst(inst);
}
#[inline]
fn emit(&mut self, inst: &MInst) -> Unit {
self.emitted_insts.push(inst.clone());
}
}