diff --git a/cranelift/codegen/src/isa/s390x/inst.isle b/cranelift/codegen/src/isa/s390x/inst.isle index 46576a42d42a..9375c41f95d7 100644 --- a/cranelift/codegen/src/isa/s390x/inst.isle +++ b/cranelift/codegen/src/isa/s390x/inst.isle @@ -1773,6 +1773,14 @@ (decl i64_from_offset (i64) Offset32) (extern extractor infallible i64_from_offset i64_from_offset) +(type SImm20 extern (enum)) + +(decl pure partial memarg_imm_from_offset (SImm20) Offset32) +(extern extractor memarg_imm_from_offset memarg_imm_from_offset) + +(decl pure memarg_imm_from_u16 (SImm20) u16) +(extern extractor infallible memarg_imm_from_u16 memarg_imm_from_u16) + ;; Accessors for `MemFlags`. (decl littleendian () MemFlags) @@ -1788,10 +1796,10 @@ (type MemArg extern (enum)) -(decl memarg_reg_plus_reg (Reg Reg u8 MemFlags) MemArg) +(decl memarg_reg_plus_reg (Reg Reg SImm20 MemFlags) MemArg) (extern constructor memarg_reg_plus_reg memarg_reg_plus_reg) -(decl memarg_reg_plus_off (Reg i64 u8 MemFlags) MemArg) +(decl memarg_reg_plus_off (Reg i64 u16 MemFlags) MemArg) (extern constructor memarg_reg_plus_off memarg_reg_plus_off) (decl memarg_symbol (ExternalName i32 MemFlags) MemArg) @@ -1828,8 +1836,8 @@ (rule (lower_address flags addr @ (value_type (ty_addr64 _)) (i64_from_offset offset)) (memarg_reg_plus_off addr offset 0 flags)) -(rule 1 (lower_address flags (has_type (ty_addr64 _) (iadd x y)) (i64_from_offset 0)) - (memarg_reg_plus_reg x y 0 flags)) +(rule 1 (lower_address flags (has_type (ty_addr64 _) (iadd x y)) (memarg_imm_from_offset z)) + (memarg_reg_plus_reg x y z flags)) (rule 1 (lower_address flags (symbol_value (symbol_value_data name (RelocDistance.Near) sym_offset)) @@ -1840,12 +1848,12 @@ ;; Lower an address plus a small bias into a `MemArg`. -(decl lower_address_bias (MemFlags Value Offset32 u8) MemArg) +(decl lower_address_bias (MemFlags Value Offset32 u16) MemArg) (rule (lower_address_bias flags addr @ (value_type $I64) (i64_from_offset offset) bias) (memarg_reg_plus_off addr offset bias flags)) -(rule 1 (lower_address_bias flags (has_type $I64 (iadd x y)) (i64_from_offset 0) bias) +(rule 1 (lower_address_bias flags (has_type $I64 (iadd x y)) (i64_from_offset 0) (memarg_imm_from_u16 bias)) (memarg_reg_plus_reg x y bias flags)) diff --git a/cranelift/codegen/src/isa/s390x/inst/imms.rs b/cranelift/codegen/src/isa/s390x/inst/imms.rs index 8ceebbcdac15..18dcb56c8b78 100644 --- a/cranelift/codegen/src/isa/s390x/inst/imms.rs +++ b/cranelift/codegen/src/isa/s390x/inst/imms.rs @@ -21,6 +21,15 @@ impl UImm12 { } } + pub fn maybe_from_simm20(value: SImm20) -> Option { + let SImm20 { value } = value; + if value >= 0 { + Self::maybe_from_u64(value as u64) + } else { + None + } + } + /// Create a zero immediate of this format. pub fn zero() -> UImm12 { UImm12 { value: 0 } diff --git a/cranelift/codegen/src/isa/s390x/lower/isle.rs b/cranelift/codegen/src/isa/s390x/lower/isle.rs index 1660a07e9757..d90e6744a863 100644 --- a/cranelift/codegen/src/isa/s390x/lower/isle.rs +++ b/cranelift/codegen/src/isa/s390x/lower/isle.rs @@ -8,8 +8,9 @@ use crate::ir::ExternalName; use crate::isa::s390x::S390xBackend; use crate::isa::s390x::abi::REG_SAVE_AREA_SIZE; use crate::isa::s390x::inst::{ - CallInstDest, Cond, Inst as MInst, LaneOrder, MemArg, RegPair, ReturnCallInfo, SymbolReloc, - UImm12, UImm16Shifted, UImm32Shifted, WritableRegPair, gpr, stack_reg, writable_gpr, zero_reg, + CallInstDest, Cond, Inst as MInst, LaneOrder, MemArg, RegPair, ReturnCallInfo, SImm20, + SymbolReloc, UImm12, UImm16Shifted, UImm32Shifted, WritableRegPair, gpr, stack_reg, + writable_gpr, zero_reg, }; use crate::machinst::isle::*; use crate::machinst::{CallInfo, MachLabel, Reg, TryCallInfo, non_writable_value_regs}; @@ -680,17 +681,36 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, S390xBackend> { } #[inline] - fn memarg_reg_plus_reg(&mut self, x: Reg, y: Reg, bias: u8, flags: MemFlags) -> MemArg { - MemArg::BXD12 { - base: x, - index: y, - disp: UImm12::maybe_from_u64(bias as u64).unwrap(), - flags, + fn memarg_imm_from_offset(&mut self, imm: Offset32) -> Option { + SImm20::maybe_from_i64(i64::from(imm)) + } + + #[inline] + fn memarg_imm_from_u16(&mut self, imm: u16) -> SImm20 { + SImm20::maybe_from_i64(imm as i64).unwrap() + } + + #[inline] + fn memarg_reg_plus_reg(&mut self, x: Reg, y: Reg, bias: &SImm20, flags: MemFlags) -> MemArg { + if let Some(imm) = UImm12::maybe_from_simm20(*bias) { + MemArg::BXD12 { + base: x, + index: y, + disp: imm, + flags, + } + } else { + MemArg::BXD20 { + base: x, + index: y, + disp: *bias, + flags, + } } } #[inline] - fn memarg_reg_plus_off(&mut self, reg: Reg, off: i64, bias: u8, flags: MemFlags) -> MemArg { + fn memarg_reg_plus_off(&mut self, reg: Reg, off: i64, bias: u16, flags: MemFlags) -> MemArg { MemArg::reg_plus_off(reg, off + (bias as i64), flags) } diff --git a/cranelift/filetests/filetests/isa/s390x/load.clif b/cranelift/filetests/filetests/isa/s390x/load.clif index 962eb40f5eba..1a947be813c8 100644 --- a/cranelift/filetests/filetests/isa/s390x/load.clif +++ b/cranelift/filetests/filetests/isa/s390x/load.clif @@ -52,6 +52,43 @@ block0(v0: i64): ; llgc %r2, 0(%r2) ; trap: heap_oob ; br %r14 +function %uload8_i64_i64_bias(i64, i64) -> i64 { +block0(v0: i64, v1: i64): + v2 = iadd v0, v1 + v3 = uload8.i64 v2+100000 + return v3 +} + +; VCode: +; block0: +; llgc %r2, 100000(%r3,%r2) +; br %r14 +; +; Disassembled: +; block0: ; offset 0x0 +; llgc %r2, 0x186a0(%r3, %r2) ; trap: heap_oob +; br %r14 + +function %uload8_i64_i64_bias_too_big(i64, i64) -> i64 { +block0(v0: i64, v1: i64): + v2 = iadd v0, v1 + v3 = uload8.i64 v2+10000000 + return v3 +} + +; VCode: +; block0: +; agr %r2, %r3 +; lgfi %r1, 10000000 ; llgc %r2, 0(%r1,%r2) +; br %r14 +; +; Disassembled: +; block0: ; offset 0x0 +; agr %r2, %r3 +; lgfi %r1, 0x989680 +; llgc %r2, 0(%r1, %r2) ; trap: heap_oob +; br %r14 + function %sload8_i64(i64) -> i64 { block0(v0: i64): v1 = sload8.i64 v0