Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions cranelift/codegen/src/isa/s390x/inst.isle
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,22 @@
(rd WritableReg)
(mem MemArg))

;; Load address referenced by `mem` into `rd`.
(LoadIndexedAddr
(rd WritableReg)
(base Reg)
(index Reg)
(offset SImm20)
(size u8))

;; Load address referenced by `mem` into `rd`.
(LoadLogicalIndexedAddr
(rd WritableReg)
(base Reg)
(index Reg)
(offset SImm20)
(size u8))

;; Meta-instruction to emit a loop around a sequence of instructions.
;; This control flow is not visible to the compiler core, in particular
;; the register allocator. Therefore, instructions in the loop may not
Expand Down Expand Up @@ -1774,6 +1790,9 @@
(decl uimm16shifted_from_value (UImm16Shifted) Value)
(extern extractor uimm16shifted_from_value uimm16shifted_from_value)

(decl simm20_from_value (SImm20) Value)
(extern extractor simm20_from_value simm20_from_value)

(decl uimm32shifted_from_value (UImm32Shifted) Value)
(extern extractor uimm32shifted_from_value uimm32shifted_from_value)

Expand Down Expand Up @@ -1927,6 +1946,23 @@
(if-let final_offset (memarg_symbol_offset_sum offset sym_offset))
(memarg_symbol name final_offset flags))

(rule 2 (lower_address flags (has_type (mie4_enabled)
(iadd $I64 (ishl $I64 (uextend $I64 (iadd $I32 x (simm20_from_value z)))
(u8_from_value shift)) y)) (i64_from_offset offset))
(memarg_reg_plus_off (load_logical_indexed_addr x y z shift) offset 0 flags))

(rule 3 (lower_address flags (has_type (mie4_enabled)
(iadd $I64 y (ishl $I64 (uextend $I64 (iadd $I32 x (simm20_from_value z)))
(u8_from_value shift)))) (i64_from_offset offset))
(memarg_reg_plus_off (load_logical_indexed_addr y x z shift) offset 0 flags))

(rule 4 (lower_address flags (has_type (mie4_enabled)
(iadd $I64 (ishl $I64 (sextend $I64 (iadd $I32 x (simm20_from_value z))) (u8_from_value shift)) y)) (i64_from_offset offset))
(memarg_reg_plus_off (load_indexed_addr x y z shift) offset 0 flags))

(rule 5 (lower_address flags (has_type (mie4_enabled)
(iadd $I64 y (ishl $I64 (sextend $I64 (iadd $I32 x (simm20_from_value z))) (u8_from_value shift)))) (i64_from_offset offset))
(memarg_reg_plus_off (load_indexed_addr y x z shift) offset 0 flags))

;; Lower an address plus a small bias into a `MemArg`.

Expand Down Expand Up @@ -2817,6 +2853,20 @@
(_ Unit (emit (MInst.LoadAddr dst mem))))
dst))

;; Helper for emitting `MInst.LoadIndexedAddr` instructions.
(decl load_indexed_addr (Reg Reg SImm20 u8) Reg)
(rule (load_indexed_addr base index offset size)
(let ((dst WritableReg (temp_writable_reg $I64))
(_ Unit (emit (MInst.LoadIndexedAddr dst base index offset size))))
dst))

;; Helper for emitting `MInst.LoadLogicalIndexedAddr` instructions.
(decl load_logical_indexed_addr (Reg Reg SImm20 u8) Reg)
(rule (load_logical_indexed_addr base index offset size)
(let ((dst WritableReg (temp_writable_reg $I64))
(_ Unit (emit (MInst.LoadLogicalIndexedAddr dst base index offset size))))
dst))

;; Helper for emitting `MInst.Call` instructions.
(decl call_impl (WritableReg BoxCallInfo) SideEffectNoResult)
(rule (call_impl reg info)
Expand Down
26 changes: 26 additions & 0 deletions cranelift/codegen/src/isa/s390x/inst/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2321,6 +2321,32 @@ impl Inst {
rd, &mem, opcode_rx, opcode_rxy, opcode_ril, false, sink, emit_info, state,
);
}
&Inst::LoadIndexedAddr {
rd,
base,
index,
offset,
size,
} => {
let opcode: u16 = 0xe360 | (size as u16 & 0xf) << 1;
put(
sink,
&enc_rxy(opcode, rd.to_reg(), base, index, offset.bits()),
);
}
&Inst::LoadLogicalIndexedAddr {
rd,
base,
index,
offset,
size,
} => {
let opcode: u16 = 0xe361 | (size as u16 & 0xf) << 1;
put(
sink,
&enc_rxy(opcode, rd.to_reg(), base, index, offset.bits()),
);
}

&Inst::Mov64 { rd, rm } => {
let opcode = 0xb904; // LGR
Expand Down
44 changes: 44 additions & 0 deletions cranelift/codegen/src/isa/s390x/inst/emit_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13929,6 +13929,50 @@ fn test_s390x_binemit() {
"E7480001384D",
"vrepg %v20, %v8, 1",
));
insns.push((
Inst::LoadIndexedAddr {
rd: writable_gpr(1),
base: gpr(2),
index: gpr(3),
offset: SImm20::maybe_from_i64(0x7ffff).unwrap(),
size: 3,
},
"E3132FFF7F66",
"lxag %r1, 524287(%r3,%r2)",
));
insns.push((
Inst::LoadIndexedAddr {
rd: writable_gpr(1),
base: gpr(2),
index: gpr(3),
offset: SImm20::maybe_from_i64(-2).unwrap(),
size: 4,
},
"E3132FFEFF68",
"lxaq %r1, -2(%r3,%r2)",
));
insns.push((
Inst::LoadLogicalIndexedAddr {
rd: writable_gpr(1),
base: gpr(2),
index: gpr(3),
offset: SImm20::maybe_from_i64(0x7ffff).unwrap(),
size: 2,
},
"E3132FFF7F65",
"llxaf %r1, 524287(%r3,%r2)",
));
insns.push((
Inst::LoadLogicalIndexedAddr {
rd: writable_gpr(1),
base: gpr(2),
index: gpr(3),
offset: SImm20::maybe_from_i64(-2).unwrap(),
size: 1,
},
"E3132FFEFF63",
"llxah %r1, -2(%r3,%r2)",
));

let flags = settings::Flags::new(settings::builder());

Expand Down
70 changes: 69 additions & 1 deletion cranelift/codegen/src/isa/s390x/inst/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! This module defines s390x-specific machine instruction types.

use crate::binemit::{Addend, CodeOffset, Reloc};
use crate::ir::{ExternalName, Type, types};
use crate::ir::{ExternalName, MemFlags, Type, types};
use crate::isa::s390x::abi::S390xMachineDeps;
use crate::isa::{CallConv, FunctionAlignment};
use crate::machinst::*;
Expand Down Expand Up @@ -240,6 +240,10 @@ impl Inst {
| Inst::Unwind { .. }
| Inst::ElfTlsGetOffset { .. } => InstructionSet::Base,

Inst::LoadIndexedAddr { .. } | Inst::LoadLogicalIndexedAddr { .. } => {
InstructionSet::MIE4
}

// These depend on the opcode
Inst::AluRRR { alu_op, .. } => match alu_op {
ALUOp::NotAnd32 | ALUOp::NotAnd64 => InstructionSet::MIE3,
Expand Down Expand Up @@ -1030,6 +1034,20 @@ fn s390x_get_operands(inst: &mut Inst, collector: &mut DenyReuseVisitor<impl Ope
collector.reg_def(rd);
memarg_operands(mem, collector);
}
Inst::LoadIndexedAddr {
rd, base, index, ..
} => {
collector.reg_def(rd);
collector.reg_use(base);
collector.reg_use(index);
}
Inst::LoadLogicalIndexedAddr {
rd, base, index, ..
} => {
collector.reg_def(rd);
collector.reg_use(base);
collector.reg_use(index);
}
Inst::StackProbeLoop { probe_count, .. } => {
collector.reg_early_def(probe_count);
}
Expand Down Expand Up @@ -3507,6 +3525,56 @@ impl Inst {

format!("{mem_str}{op} {rd}, {mem}")
}
&Inst::LoadIndexedAddr {
rd,
base,
index,
offset,
size,
} => {
let rd = pretty_print_reg(rd.to_reg());
let op = match size {
1 => "lxah",
2 => "lxaf",
3 => "lxag",
4 => "lxaq",
_ => unreachable!(),
};
let flags = MemFlags::trusted();
let mem = MemArg::BXD20 {
base,
index,
disp: offset,
flags,
};
let mem = mem.pretty_print_default();
format!("{op} {rd}, {mem}")
}
&Inst::LoadLogicalIndexedAddr {
rd,
base,
index,
offset,
size,
} => {
let rd = pretty_print_reg(rd.to_reg());
let op = match size {
1 => "llxah",
2 => "llxaf",
3 => "llxag",
4 => "llxaq",
_ => unreachable!(),
};
let flags = MemFlags::trusted();
let mem = MemArg::BXD20 {
base,
index,
disp: offset,
flags,
};
let mem = mem.pretty_print_default();
format!("{op} {rd}, {mem}")
}
&Inst::StackProbeLoop {
probe_count,
guard_size,
Expand Down
15 changes: 15 additions & 0 deletions cranelift/codegen/src/isa/s390x/lower.isle
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,21 @@
(rule 1 (lower (has_type (vr128_ty ty) (iadd _ x y)))
(vec_add ty x y))

(rule 16 (lower (has_type (mie4_enabled)
(iadd $I64 (ishl $I64 (uextend $I64 (iadd $I32 x (simm20_from_value z))) (u8_from_value shift)) y)))
(load_logical_indexed_addr x y z shift))

(rule 17 (lower (has_type (mie4_enabled)
(iadd $I64 y (ishl $I64 (uextend $I64 (iadd $I32 x (simm20_from_value z))) (u8_from_value shift)))))
(load_logical_indexed_addr y x z shift))

(rule 18 (lower (has_type (and (ty_addr64 _) (mie4_enabled))
(iadd $I64 (ishl $I64 (sextend $I64 (iadd $I32 x (simm20_from_value z))) (u8_from_value shift)) y)))
(load_indexed_addr x y z shift))

(rule 19 (lower (has_type (and (ty_addr64 _) (mie4_enabled))
(iadd $I64 y (ishl $I64 (sextend $I64 (iadd $I32 x (simm20_from_value z))) (u8_from_value shift)))))
(load_indexed_addr y x z shift))

;;;; Rules for `uadd_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Expand Down
6 changes: 6 additions & 0 deletions cranelift/codegen/src/isa/s390x/lower/isle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,12 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, S390xBackend> {
UImm16Shifted::maybe_from_u64(constant)
}

#[inline]
fn simm20_from_value(&mut self, val: Value) -> Option<SImm20> {
let constant = self.u64_from_signed_value(val)? as i64;
SImm20::maybe_from_i64(constant)
}

#[inline]
fn uimm32shifted_from_value(&mut self, val: Value) -> Option<UImm32Shifted> {
let constant = self.u64_from_value(val)?;
Expand Down
46 changes: 46 additions & 0 deletions cranelift/filetests/filetests/isa/s390x/arithmetic-arch15.clif
Original file line number Diff line number Diff line change
Expand Up @@ -327,3 +327,49 @@ block0(v0: i128):
; vst %v4, 0(%r2)
; br %r14

function %i64_i32_offset_mul_unsigned(i64, i32) -> i64 {
block0(v0: i64, v1: i32):
v2 = iconst.i8 4
v3 = iconst.i32 8000
v4 = iadd v1, v3
v5 = uextend.i64 v4
v6 = ishl v5, v2
v7 = iadd v0, v6
return v7
}

; VCode:
; block0:
; llxaq %r2, 8000(%r3,%r2)
; br %r14
;
; Disassembled:
; block0: ; offset 0x0
; .byte 0xe3, 0x23
; swr %f4, %f0
; .byte 0x01, 0x69
; br %r14

function %uload8_i64_i64_offset_mul_signed(i64, i32) -> i64 {
block0(v0: i64, v1: i32):
v2 = iconst.i8 4
v3 = iconst.i32 8000
v4 = iadd v1, v3
v5 = sextend.i64 v4
v6 = ishl v5, v2
v7 = iadd v0, v6
return v7
}

; VCode:
; block0:
; lxaq %r2, 8000(%r3,%r2)
; br %r14
;
; Disassembled:
; block0: ; offset 0x0
; .byte 0xe3, 0x23
; swr %f4, %f0
; .byte 0x01, 0x68
; br %r14

Loading
Loading