Support IBM z/Architecture
This adds support for the IBM z/Architecture (s390x-ibm-linux). The status of the s390x backend in its current form is: - Wasmtime is fully functional and passes all tests on s390x. - All back-end features supported, with the exception of SIMD. - There is still a lot of potential for performance improvements. - Currently the only supported processor type is z15.
This commit is contained in:
7
build.rs
7
build.rs
@@ -219,6 +219,9 @@ fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool {
|
||||
_ => (),
|
||||
},
|
||||
"Cranelift" => match (testsuite, testname) {
|
||||
// No simd support yet for s390x.
|
||||
("simd", _) if platform_is_s390x() => return true,
|
||||
|
||||
("simd", _) if cfg!(feature = "old-x86-backend") => return true, // skip all SIMD tests on old backend.
|
||||
// These are new instructions that are not really implemented in any backend.
|
||||
("simd", "simd_i8x16_arith2")
|
||||
@@ -243,3 +246,7 @@ fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool {
|
||||
fn platform_is_x64() -> bool {
|
||||
env::var("CARGO_CFG_TARGET_ARCH").unwrap() == "x86_64"
|
||||
}
|
||||
|
||||
fn platform_is_s390x() -> bool {
|
||||
env::var("CARGO_CFG_TARGET_ARCH").unwrap() == "s390x"
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ unwind = ["gimli"]
|
||||
x86 = []
|
||||
arm64 = []
|
||||
riscv = []
|
||||
s390x = []
|
||||
arm32 = [] # Work-in-progress codegen backend for ARM.
|
||||
|
||||
# Stub feature that does nothing, for Cargo-features compatibility: the new
|
||||
@@ -75,7 +76,8 @@ old-x86-backend = []
|
||||
all-arch = [
|
||||
"x86",
|
||||
"arm64",
|
||||
"riscv"
|
||||
"riscv",
|
||||
"s390x"
|
||||
]
|
||||
|
||||
# For dependent crates that want to serialize some parts of cranelift
|
||||
|
||||
@@ -6,6 +6,7 @@ use std::fmt;
|
||||
mod arm32;
|
||||
mod arm64;
|
||||
mod riscv;
|
||||
mod s390x;
|
||||
pub(crate) mod x86;
|
||||
|
||||
/// Represents known ISA target.
|
||||
@@ -15,6 +16,7 @@ pub enum Isa {
|
||||
X86,
|
||||
Arm32,
|
||||
Arm64,
|
||||
S390x,
|
||||
}
|
||||
|
||||
impl Isa {
|
||||
@@ -31,6 +33,7 @@ impl Isa {
|
||||
match arch {
|
||||
"riscv" => Some(Isa::Riscv),
|
||||
"aarch64" => Some(Isa::Arm64),
|
||||
"s390x" => Some(Isa::S390x),
|
||||
x if ["x86_64", "i386", "i586", "i686"].contains(&x) => Some(Isa::X86),
|
||||
x if x.starts_with("arm") || arch.starts_with("thumb") => Some(Isa::Arm32),
|
||||
_ => None,
|
||||
@@ -39,7 +42,7 @@ impl Isa {
|
||||
|
||||
/// Returns all supported isa targets.
|
||||
pub fn all() -> &'static [Isa] {
|
||||
&[Isa::Riscv, Isa::X86, Isa::Arm32, Isa::Arm64]
|
||||
&[Isa::Riscv, Isa::X86, Isa::Arm32, Isa::Arm64, Isa::S390x]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +54,7 @@ impl fmt::Display for Isa {
|
||||
Isa::X86 => write!(f, "x86"),
|
||||
Isa::Arm32 => write!(f, "arm32"),
|
||||
Isa::Arm64 => write!(f, "arm64"),
|
||||
Isa::S390x => write!(f, "s390x"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,6 +66,7 @@ pub(crate) fn define(isas: &[Isa], shared_defs: &mut SharedDefinitions) -> Vec<T
|
||||
Isa::X86 => x86::define(shared_defs),
|
||||
Isa::Arm32 => arm32::define(shared_defs),
|
||||
Isa::Arm64 => arm64::define(shared_defs),
|
||||
Isa::S390x => s390x::define(shared_defs),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
31
cranelift/codegen/meta/src/isa/s390x/mod.rs
Normal file
31
cranelift/codegen/meta/src/isa/s390x/mod.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
use crate::cdsl::cpu_modes::CpuMode;
|
||||
use crate::cdsl::instructions::{InstructionGroupBuilder, InstructionPredicateMap};
|
||||
use crate::cdsl::isa::TargetIsa;
|
||||
use crate::cdsl::recipes::Recipes;
|
||||
use crate::cdsl::regs::IsaRegsBuilder;
|
||||
use crate::cdsl::settings::SettingGroupBuilder;
|
||||
|
||||
use crate::shared::Definitions as SharedDefinitions;
|
||||
|
||||
pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
|
||||
let inst_group = InstructionGroupBuilder::new(&mut shared_defs.all_instructions).build();
|
||||
let settings = SettingGroupBuilder::new("s390x").build();
|
||||
let regs = IsaRegsBuilder::new().build();
|
||||
let recipes = Recipes::new();
|
||||
let encodings_predicates = InstructionPredicateMap::new();
|
||||
|
||||
let mut mode = CpuMode::new("s390x");
|
||||
let expand = shared_defs.transform_groups.by_name("expand");
|
||||
mode.legalize_default(expand);
|
||||
let cpu_modes = vec![mode];
|
||||
|
||||
TargetIsa::new(
|
||||
"s390x",
|
||||
inst_group,
|
||||
settings,
|
||||
regs,
|
||||
recipes,
|
||||
cpu_modes,
|
||||
encodings_predicates,
|
||||
)
|
||||
}
|
||||
@@ -116,6 +116,9 @@ pub fn generate(
|
||||
isa::Isa::Arm64 => {
|
||||
// aarch64 doesn't have platform-specific settings.
|
||||
}
|
||||
isa::Isa::S390x => {
|
||||
// s390x doesn't have platform-specific settings.
|
||||
}
|
||||
isa::Isa::Arm32 | isa::Isa::Riscv => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,9 @@ mod arm32;
|
||||
#[cfg(feature = "arm64")]
|
||||
pub(crate) mod aarch64;
|
||||
|
||||
#[cfg(feature = "s390x")]
|
||||
mod s390x;
|
||||
|
||||
pub mod unwind;
|
||||
|
||||
mod call_conv;
|
||||
@@ -160,6 +163,7 @@ pub fn lookup_variant(triple: Triple, variant: BackendVariant) -> Result<Builder
|
||||
}
|
||||
(Architecture::Arm { .. }, _) => isa_builder!(arm32, (feature = "arm32"), triple),
|
||||
(Architecture::Aarch64 { .. }, _) => isa_builder!(aarch64, (feature = "arm64"), triple),
|
||||
(Architecture::S390x { .. }, _) => isa_builder!(s390x, (feature = "s390x"), triple),
|
||||
_ => Err(LookupError::Unsupported),
|
||||
}
|
||||
}
|
||||
|
||||
770
cranelift/codegen/src/isa/s390x/abi.rs
Normal file
770
cranelift/codegen/src/isa/s390x/abi.rs
Normal file
@@ -0,0 +1,770 @@
|
||||
//! Implementation of a standard S390x ABI.
|
||||
//!
|
||||
//! This machine uses the "vanilla" ABI implementation from abi_impl.rs,
|
||||
//! however a few details are different from the description there:
|
||||
//!
|
||||
//! - On s390x, the caller must provide a "register save area" of 160
|
||||
//! bytes to any function it calls. The called function is free to use
|
||||
//! this space for any purpose; usually to save callee-saved GPRs.
|
||||
//! (Note that while this area is allocated by the caller, it is counted
|
||||
//! as part of the callee's stack frame; in particular, the callee's CFA
|
||||
//! is the top of the register save area, not the incoming SP value.)
|
||||
//!
|
||||
//! - Overflow arguments are passed on the stack starting immediately
|
||||
//! above the register save area. On s390x, this space is allocated
|
||||
//! only once directly in the prologue, using a size large enough to
|
||||
//! hold overflow arguments for every call in the function.
|
||||
//!
|
||||
//! - On s390x we do not use a frame pointer register; instead, every
|
||||
//! element of the stack frame is addressed via (constant) offsets
|
||||
//! from the stack pointer. Note that due to the above (and because
|
||||
//! there are no variable-sized stack allocations in cranelift), the
|
||||
//! value of the stack pointer register never changes after the
|
||||
//! initial allocation in the function prologue.
|
||||
//!
|
||||
//! Overall, the stack frame layout on s390x is as follows:
|
||||
//!
|
||||
//! ```plain
|
||||
//! (high address)
|
||||
//!
|
||||
//! +---------------------------+
|
||||
//! | ... |
|
||||
//! CFA -----> | stack args |
|
||||
//! +---------------------------+
|
||||
//! | ... |
|
||||
//! | 160 bytes reg save area |
|
||||
//! SP at function entry -----> | (used to save GPRs) |
|
||||
//! +---------------------------+
|
||||
//! | ... |
|
||||
//! | clobbered callee-saves |
|
||||
//! | (used to save FPRs) |
|
||||
//! unwind-frame base ----> | (alloc'd by prologue) |
|
||||
//! +---------------------------+
|
||||
//! | ... |
|
||||
//! | spill slots |
|
||||
//! | (accessed via nominal SP) |
|
||||
//! | ... |
|
||||
//! | stack slots |
|
||||
//! | (accessed via nominal SP) |
|
||||
//! nominal SP ---------------> | (alloc'd by prologue) |
|
||||
//! +---------------------------+
|
||||
//! | ... |
|
||||
//! | args for call |
|
||||
//! | outgoing reg save area |
|
||||
//! SP during function ------> | (alloc'd by prologue) |
|
||||
//! +---------------------------+
|
||||
//!
|
||||
//! (low address)
|
||||
//! ```
|
||||
|
||||
use crate::ir;
|
||||
use crate::ir::condcodes::IntCC;
|
||||
use crate::ir::types;
|
||||
use crate::ir::MemFlags;
|
||||
use crate::ir::Type;
|
||||
use crate::isa;
|
||||
use crate::isa::s390x::inst::*;
|
||||
use crate::isa::unwind::UnwindInst;
|
||||
use crate::machinst::*;
|
||||
use crate::settings;
|
||||
use crate::{CodegenError, CodegenResult};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use regalloc::{RealReg, Reg, RegClass, Set, Writable};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
// We use a generic implementation that factors out ABI commonalities.
|
||||
|
||||
/// Support for the S390x ABI from the callee side (within a function body).
|
||||
pub type S390xABICallee = ABICalleeImpl<S390xMachineDeps>;
|
||||
|
||||
/// Support for the S390x ABI from the caller side (at a callsite).
|
||||
pub type S390xABICaller = ABICallerImpl<S390xMachineDeps>;
|
||||
|
||||
/// ABI Register usage
|
||||
|
||||
fn in_int_reg(ty: Type) -> bool {
|
||||
match ty {
|
||||
types::I8 | types::I16 | types::I32 | types::I64 | types::R64 => true,
|
||||
types::B1 | types::B8 | types::B16 | types::B32 | types::B64 => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn in_flt_reg(ty: Type) -> bool {
|
||||
match ty {
|
||||
types::F32 | types::F64 => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_intreg_for_arg(idx: usize) -> Option<Reg> {
|
||||
match idx {
|
||||
0 => Some(regs::gpr(2)),
|
||||
1 => Some(regs::gpr(3)),
|
||||
2 => Some(regs::gpr(4)),
|
||||
3 => Some(regs::gpr(5)),
|
||||
4 => Some(regs::gpr(6)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_fltreg_for_arg(idx: usize) -> Option<Reg> {
|
||||
match idx {
|
||||
0 => Some(regs::fpr(0)),
|
||||
1 => Some(regs::fpr(2)),
|
||||
2 => Some(regs::fpr(4)),
|
||||
3 => Some(regs::fpr(6)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_intreg_for_ret(idx: usize) -> Option<Reg> {
|
||||
match idx {
|
||||
0 => Some(regs::gpr(2)),
|
||||
// ABI extension to support multi-value returns:
|
||||
1 => Some(regs::gpr(3)),
|
||||
2 => Some(regs::gpr(4)),
|
||||
3 => Some(regs::gpr(5)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_fltreg_for_ret(idx: usize) -> Option<Reg> {
|
||||
match idx {
|
||||
0 => Some(regs::fpr(0)),
|
||||
// ABI extension to support multi-value returns:
|
||||
1 => Some(regs::fpr(2)),
|
||||
2 => Some(regs::fpr(4)),
|
||||
3 => Some(regs::fpr(6)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// This is the limit for the size of argument and return-value areas on the
|
||||
/// stack. We place a reasonable limit here to avoid integer overflow issues
|
||||
/// with 32-bit arithmetic: for now, 128 MB.
|
||||
static STACK_ARG_RET_SIZE_LIMIT: u64 = 128 * 1024 * 1024;
|
||||
|
||||
impl Into<MemArg> for StackAMode {
|
||||
fn into(self) -> MemArg {
|
||||
match self {
|
||||
StackAMode::FPOffset(off, _ty) => MemArg::InitialSPOffset { off },
|
||||
StackAMode::NominalSPOffset(off, _ty) => MemArg::NominalSPOffset { off },
|
||||
StackAMode::SPOffset(off, _ty) => {
|
||||
MemArg::reg_plus_off(stack_reg(), off, MemFlags::trusted())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// S390x-specific ABI behavior. This struct just serves as an implementation
|
||||
/// point for the trait; it is never actually instantiated.
|
||||
pub struct S390xMachineDeps;
|
||||
|
||||
impl ABIMachineSpec for S390xMachineDeps {
|
||||
type I = Inst;
|
||||
|
||||
fn word_bits() -> u32 {
|
||||
64
|
||||
}
|
||||
|
||||
/// Return required stack alignment in bytes.
|
||||
fn stack_align(_call_conv: isa::CallConv) -> u32 {
|
||||
8
|
||||
}
|
||||
|
||||
fn compute_arg_locs(
|
||||
call_conv: isa::CallConv,
|
||||
_flags: &settings::Flags,
|
||||
params: &[ir::AbiParam],
|
||||
args_or_rets: ArgsOrRets,
|
||||
add_ret_area_ptr: bool,
|
||||
) -> CodegenResult<(Vec<ABIArg>, i64, Option<usize>)> {
|
||||
let mut next_gpr = 0;
|
||||
let mut next_fpr = 0;
|
||||
let mut next_stack: u64 = 0;
|
||||
let mut ret = vec![];
|
||||
|
||||
if args_or_rets == ArgsOrRets::Args {
|
||||
next_stack = 160;
|
||||
}
|
||||
|
||||
for i in 0..params.len() {
|
||||
let param = ¶ms[i];
|
||||
|
||||
// Validate "purpose".
|
||||
match ¶m.purpose {
|
||||
&ir::ArgumentPurpose::VMContext
|
||||
| &ir::ArgumentPurpose::Normal
|
||||
| &ir::ArgumentPurpose::StackLimit
|
||||
| &ir::ArgumentPurpose::SignatureId => {}
|
||||
_ => panic!(
|
||||
"Unsupported argument purpose {:?} in signature: {:?}",
|
||||
param.purpose, params
|
||||
),
|
||||
}
|
||||
|
||||
let intreg = in_int_reg(param.value_type);
|
||||
let fltreg = in_flt_reg(param.value_type);
|
||||
debug_assert!(intreg || fltreg);
|
||||
debug_assert!(!(intreg && fltreg));
|
||||
|
||||
let (next_reg, candidate) = if intreg {
|
||||
let candidate = match args_or_rets {
|
||||
ArgsOrRets::Args => get_intreg_for_arg(next_gpr),
|
||||
ArgsOrRets::Rets => get_intreg_for_ret(next_gpr),
|
||||
};
|
||||
(&mut next_gpr, candidate)
|
||||
} else {
|
||||
let candidate = match args_or_rets {
|
||||
ArgsOrRets::Args => get_fltreg_for_arg(next_fpr),
|
||||
ArgsOrRets::Rets => get_fltreg_for_ret(next_fpr),
|
||||
};
|
||||
(&mut next_fpr, candidate)
|
||||
};
|
||||
|
||||
// In the Wasmtime ABI only the first return value can be in a register.
|
||||
let candidate =
|
||||
if call_conv.extends_wasmtime() && args_or_rets == ArgsOrRets::Rets && i > 0 {
|
||||
None
|
||||
} else {
|
||||
candidate
|
||||
};
|
||||
|
||||
if let Some(reg) = candidate {
|
||||
ret.push(ABIArg::reg(
|
||||
reg.to_real_reg(),
|
||||
param.value_type,
|
||||
param.extension,
|
||||
param.purpose,
|
||||
));
|
||||
*next_reg += 1;
|
||||
} else {
|
||||
// Compute size. Every argument or return value takes a slot of
|
||||
// at least 8 bytes, except for return values in the Wasmtime ABI.
|
||||
let size = (ty_bits(param.value_type) / 8) as u64;
|
||||
let slot_size = if call_conv.extends_wasmtime() && args_or_rets == ArgsOrRets::Rets
|
||||
{
|
||||
size
|
||||
} else {
|
||||
std::cmp::max(size, 8)
|
||||
};
|
||||
|
||||
// Align the stack slot.
|
||||
debug_assert!(slot_size.is_power_of_two());
|
||||
next_stack = align_to(next_stack, slot_size);
|
||||
|
||||
// If the type is actually of smaller size (and the argument
|
||||
// was not extended), it is passed right-aligned.
|
||||
let offset = if size < slot_size && param.extension == ir::ArgumentExtension::None {
|
||||
slot_size - size
|
||||
} else {
|
||||
0
|
||||
};
|
||||
ret.push(ABIArg::stack(
|
||||
(next_stack + offset) as i64,
|
||||
param.value_type,
|
||||
param.extension,
|
||||
param.purpose,
|
||||
));
|
||||
next_stack += slot_size;
|
||||
}
|
||||
}
|
||||
|
||||
next_stack = align_to(next_stack, 8);
|
||||
|
||||
let extra_arg = if add_ret_area_ptr {
|
||||
debug_assert!(args_or_rets == ArgsOrRets::Args);
|
||||
if let Some(reg) = get_intreg_for_arg(next_gpr) {
|
||||
ret.push(ABIArg::reg(
|
||||
reg.to_real_reg(),
|
||||
types::I64,
|
||||
ir::ArgumentExtension::None,
|
||||
ir::ArgumentPurpose::Normal,
|
||||
));
|
||||
} else {
|
||||
ret.push(ABIArg::stack(
|
||||
next_stack as i64,
|
||||
types::I64,
|
||||
ir::ArgumentExtension::None,
|
||||
ir::ArgumentPurpose::Normal,
|
||||
));
|
||||
next_stack += 8;
|
||||
}
|
||||
Some(ret.len() - 1)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// To avoid overflow issues, limit the arg/return size to something
|
||||
// reasonable -- here, 128 MB.
|
||||
if next_stack > STACK_ARG_RET_SIZE_LIMIT {
|
||||
return Err(CodegenError::ImplLimitExceeded);
|
||||
}
|
||||
|
||||
Ok((ret, next_stack as i64, extra_arg))
|
||||
}
|
||||
|
||||
fn fp_to_arg_offset(_call_conv: isa::CallConv, _flags: &settings::Flags) -> i64 {
|
||||
0
|
||||
}
|
||||
|
||||
fn gen_load_stack(mem: StackAMode, into_reg: Writable<Reg>, ty: Type) -> Inst {
|
||||
Inst::gen_load(into_reg, mem.into(), ty)
|
||||
}
|
||||
|
||||
fn gen_store_stack(mem: StackAMode, from_reg: Reg, ty: Type) -> Inst {
|
||||
Inst::gen_store(mem.into(), from_reg, ty)
|
||||
}
|
||||
|
||||
fn gen_move(to_reg: Writable<Reg>, from_reg: Reg, ty: Type) -> Inst {
|
||||
Inst::gen_move(to_reg, from_reg, ty)
|
||||
}
|
||||
|
||||
fn gen_extend(
|
||||
to_reg: Writable<Reg>,
|
||||
from_reg: Reg,
|
||||
signed: bool,
|
||||
from_bits: u8,
|
||||
to_bits: u8,
|
||||
) -> Inst {
|
||||
assert!(from_bits < to_bits);
|
||||
Inst::Extend {
|
||||
rd: to_reg,
|
||||
rn: from_reg,
|
||||
signed,
|
||||
from_bits,
|
||||
to_bits,
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_ret() -> Inst {
|
||||
Inst::Ret { link: gpr(14) }
|
||||
}
|
||||
|
||||
fn gen_add_imm(into_reg: Writable<Reg>, from_reg: Reg, imm: u32) -> SmallInstVec<Inst> {
|
||||
let mut insts = SmallVec::new();
|
||||
if let Some(imm) = UImm12::maybe_from_u64(imm as u64) {
|
||||
insts.push(Inst::LoadAddr {
|
||||
rd: into_reg,
|
||||
mem: MemArg::BXD12 {
|
||||
base: from_reg,
|
||||
index: zero_reg(),
|
||||
disp: imm,
|
||||
flags: MemFlags::trusted(),
|
||||
},
|
||||
});
|
||||
} else if let Some(imm) = SImm20::maybe_from_i64(imm as i64) {
|
||||
insts.push(Inst::LoadAddr {
|
||||
rd: into_reg,
|
||||
mem: MemArg::BXD20 {
|
||||
base: from_reg,
|
||||
index: zero_reg(),
|
||||
disp: imm,
|
||||
flags: MemFlags::trusted(),
|
||||
},
|
||||
});
|
||||
} else {
|
||||
if from_reg != into_reg.to_reg() {
|
||||
insts.push(Inst::mov64(into_reg, from_reg));
|
||||
}
|
||||
insts.push(Inst::AluRUImm32 {
|
||||
alu_op: ALUOp::Add64,
|
||||
rd: into_reg,
|
||||
imm,
|
||||
});
|
||||
}
|
||||
insts
|
||||
}
|
||||
|
||||
fn gen_stack_lower_bound_trap(limit_reg: Reg) -> SmallInstVec<Inst> {
|
||||
let mut insts = SmallVec::new();
|
||||
insts.push(Inst::CmpTrapRR {
|
||||
op: CmpOp::CmpL64,
|
||||
rn: stack_reg(),
|
||||
rm: limit_reg,
|
||||
cond: Cond::from_intcc(IntCC::UnsignedLessThanOrEqual),
|
||||
trap_code: ir::TrapCode::StackOverflow,
|
||||
});
|
||||
insts
|
||||
}
|
||||
|
||||
fn gen_epilogue_placeholder() -> Inst {
|
||||
Inst::EpiloguePlaceholder
|
||||
}
|
||||
|
||||
fn gen_get_stack_addr(mem: StackAMode, into_reg: Writable<Reg>, _ty: Type) -> Inst {
|
||||
let mem = mem.into();
|
||||
Inst::LoadAddr { rd: into_reg, mem }
|
||||
}
|
||||
|
||||
fn get_stacklimit_reg() -> Reg {
|
||||
spilltmp_reg()
|
||||
}
|
||||
|
||||
fn gen_load_base_offset(into_reg: Writable<Reg>, base: Reg, offset: i32, ty: Type) -> Inst {
|
||||
let mem = MemArg::reg_plus_off(base, offset.into(), MemFlags::trusted());
|
||||
Inst::gen_load(into_reg, mem, ty)
|
||||
}
|
||||
|
||||
fn gen_store_base_offset(base: Reg, offset: i32, from_reg: Reg, ty: Type) -> Inst {
|
||||
let mem = MemArg::reg_plus_off(base, offset.into(), MemFlags::trusted());
|
||||
Inst::gen_store(mem, from_reg, ty)
|
||||
}
|
||||
|
||||
fn gen_sp_reg_adjust(imm: i32) -> SmallInstVec<Inst> {
|
||||
if imm == 0 {
|
||||
return SmallVec::new();
|
||||
}
|
||||
|
||||
let mut insts = SmallVec::new();
|
||||
if let Ok(imm) = i16::try_from(imm) {
|
||||
insts.push(Inst::AluRSImm16 {
|
||||
alu_op: ALUOp::Add64,
|
||||
rd: writable_stack_reg(),
|
||||
imm,
|
||||
});
|
||||
} else {
|
||||
insts.push(Inst::AluRSImm32 {
|
||||
alu_op: ALUOp::Add64,
|
||||
rd: writable_stack_reg(),
|
||||
imm,
|
||||
});
|
||||
}
|
||||
insts
|
||||
}
|
||||
|
||||
fn gen_nominal_sp_adj(offset: i32) -> Inst {
|
||||
Inst::VirtualSPOffsetAdj {
|
||||
offset: offset.into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_prologue_frame_setup(_flags: &settings::Flags) -> SmallInstVec<Inst> {
|
||||
SmallVec::new()
|
||||
}
|
||||
|
||||
fn gen_epilogue_frame_restore(_flags: &settings::Flags) -> SmallInstVec<Inst> {
|
||||
SmallVec::new()
|
||||
}
|
||||
|
||||
fn gen_probestack(_: u32) -> SmallInstVec<Self::I> {
|
||||
// TODO: implement if we ever require stack probes on an s390x host
|
||||
// (unlikely unless Lucet is ported)
|
||||
smallvec![]
|
||||
}
|
||||
|
||||
// Returns stack bytes used as well as instructions. Does not adjust
|
||||
// nominal SP offset; abi_impl generic code will do that.
|
||||
fn gen_clobber_save(
|
||||
call_conv: isa::CallConv,
|
||||
flags: &settings::Flags,
|
||||
clobbers: &Set<Writable<RealReg>>,
|
||||
fixed_frame_storage_size: u32,
|
||||
outgoing_args_size: u32,
|
||||
) -> (u64, SmallVec<[Inst; 16]>) {
|
||||
let mut insts = SmallVec::new();
|
||||
|
||||
// Collect clobbered registers.
|
||||
let (clobbered_gpr, clobbered_fpr) = get_regs_saved_in_prologue(call_conv, clobbers);
|
||||
let mut first_clobbered_gpr = 16;
|
||||
for reg in clobbered_gpr {
|
||||
let enc = reg.to_reg().get_hw_encoding();
|
||||
if enc < first_clobbered_gpr {
|
||||
first_clobbered_gpr = enc;
|
||||
}
|
||||
}
|
||||
let clobber_size = clobbered_fpr.len() * 8;
|
||||
if flags.unwind_info() {
|
||||
insts.push(Inst::Unwind {
|
||||
inst: UnwindInst::DefineNewFrame {
|
||||
offset_upward_to_caller_sp: 160,
|
||||
offset_downward_to_clobbers: clobber_size as u32,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Use STMG to save clobbered GPRs into save area.
|
||||
if first_clobbered_gpr < 16 {
|
||||
let offset = 8 * first_clobbered_gpr as i64;
|
||||
insts.push(Inst::StoreMultiple64 {
|
||||
rt: gpr(first_clobbered_gpr as u8),
|
||||
rt2: gpr(15),
|
||||
addr_reg: stack_reg(),
|
||||
addr_off: SImm20::maybe_from_i64(offset).unwrap(),
|
||||
});
|
||||
}
|
||||
if flags.unwind_info() {
|
||||
for i in first_clobbered_gpr..16 {
|
||||
insts.push(Inst::Unwind {
|
||||
inst: UnwindInst::SaveReg {
|
||||
clobber_offset: clobber_size as u32 + (i * 8) as u32,
|
||||
reg: gpr(i as u8).to_real_reg(),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Decrement stack pointer.
|
||||
let stack_size =
|
||||
outgoing_args_size as i32 + clobber_size as i32 + fixed_frame_storage_size as i32;
|
||||
insts.extend(Self::gen_sp_reg_adjust(-stack_size));
|
||||
if flags.unwind_info() {
|
||||
insts.push(Inst::Unwind {
|
||||
inst: UnwindInst::StackAlloc {
|
||||
size: stack_size as u32,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
let sp_adj = outgoing_args_size as i32;
|
||||
if sp_adj > 0 {
|
||||
insts.push(Self::gen_nominal_sp_adj(sp_adj));
|
||||
}
|
||||
|
||||
// Save FPRs.
|
||||
for (i, reg) in clobbered_fpr.iter().enumerate() {
|
||||
insts.push(Inst::FpuStore64 {
|
||||
rd: reg.to_reg().to_reg(),
|
||||
mem: MemArg::reg_plus_off(
|
||||
stack_reg(),
|
||||
(i * 8) as i64 + outgoing_args_size as i64 + fixed_frame_storage_size as i64,
|
||||
MemFlags::trusted(),
|
||||
),
|
||||
});
|
||||
if flags.unwind_info() {
|
||||
insts.push(Inst::Unwind {
|
||||
inst: UnwindInst::SaveReg {
|
||||
clobber_offset: (i * 8) as u32,
|
||||
reg: reg.to_reg(),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
(clobber_size as u64, insts)
|
||||
}
|
||||
|
||||
fn gen_clobber_restore(
|
||||
call_conv: isa::CallConv,
|
||||
_: &settings::Flags,
|
||||
clobbers: &Set<Writable<RealReg>>,
|
||||
fixed_frame_storage_size: u32,
|
||||
outgoing_args_size: u32,
|
||||
) -> SmallVec<[Inst; 16]> {
|
||||
let mut insts = SmallVec::new();
|
||||
|
||||
// Collect clobbered registers.
|
||||
let (clobbered_gpr, clobbered_fpr) = get_regs_saved_in_prologue(call_conv, clobbers);
|
||||
let mut first_clobbered_gpr = 16;
|
||||
for reg in clobbered_gpr {
|
||||
let enc = reg.to_reg().get_hw_encoding();
|
||||
if enc < first_clobbered_gpr {
|
||||
first_clobbered_gpr = enc;
|
||||
}
|
||||
}
|
||||
let clobber_size = clobbered_fpr.len() * 8;
|
||||
|
||||
// Restore FPRs.
|
||||
for (i, reg) in clobbered_fpr.iter().enumerate() {
|
||||
insts.push(Inst::FpuLoad64 {
|
||||
rd: Writable::from_reg(reg.to_reg().to_reg()),
|
||||
mem: MemArg::reg_plus_off(
|
||||
stack_reg(),
|
||||
(i * 8) as i64 + outgoing_args_size as i64 + fixed_frame_storage_size as i64,
|
||||
MemFlags::trusted(),
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
// Increment stack pointer unless it will be restored implicitly.
|
||||
let stack_size =
|
||||
outgoing_args_size as i32 + clobber_size as i32 + fixed_frame_storage_size as i32;
|
||||
let implicit_sp_restore = first_clobbered_gpr < 16
|
||||
&& SImm20::maybe_from_i64(8 * first_clobbered_gpr as i64 + stack_size as i64).is_some();
|
||||
if !implicit_sp_restore {
|
||||
insts.extend(Self::gen_sp_reg_adjust(stack_size));
|
||||
}
|
||||
|
||||
// Use LMG to restore clobbered GPRs from save area.
|
||||
if first_clobbered_gpr < 16 {
|
||||
let mut offset = 8 * first_clobbered_gpr as i64;
|
||||
if implicit_sp_restore {
|
||||
offset += stack_size as i64;
|
||||
}
|
||||
insts.push(Inst::LoadMultiple64 {
|
||||
rt: writable_gpr(first_clobbered_gpr as u8),
|
||||
rt2: writable_gpr(15),
|
||||
addr_reg: stack_reg(),
|
||||
addr_off: SImm20::maybe_from_i64(offset).unwrap(),
|
||||
});
|
||||
}
|
||||
|
||||
insts
|
||||
}
|
||||
|
||||
fn gen_call(
|
||||
dest: &CallDest,
|
||||
uses: Vec<Reg>,
|
||||
defs: Vec<Writable<Reg>>,
|
||||
opcode: ir::Opcode,
|
||||
tmp: Writable<Reg>,
|
||||
_callee_conv: isa::CallConv,
|
||||
_caller_conv: isa::CallConv,
|
||||
) -> SmallVec<[(InstIsSafepoint, Inst); 2]> {
|
||||
let mut insts = SmallVec::new();
|
||||
match &dest {
|
||||
&CallDest::ExtName(ref name, RelocDistance::Near) => insts.push((
|
||||
InstIsSafepoint::Yes,
|
||||
Inst::Call {
|
||||
link: writable_gpr(14),
|
||||
info: Box::new(CallInfo {
|
||||
dest: name.clone(),
|
||||
uses,
|
||||
defs,
|
||||
opcode,
|
||||
}),
|
||||
},
|
||||
)),
|
||||
&CallDest::ExtName(ref name, RelocDistance::Far) => {
|
||||
insts.push((
|
||||
InstIsSafepoint::No,
|
||||
Inst::LoadExtNameFar {
|
||||
rd: tmp,
|
||||
name: Box::new(name.clone()),
|
||||
offset: 0,
|
||||
},
|
||||
));
|
||||
insts.push((
|
||||
InstIsSafepoint::Yes,
|
||||
Inst::CallInd {
|
||||
link: writable_gpr(14),
|
||||
info: Box::new(CallIndInfo {
|
||||
rn: tmp.to_reg(),
|
||||
uses,
|
||||
defs,
|
||||
opcode,
|
||||
}),
|
||||
},
|
||||
));
|
||||
}
|
||||
&CallDest::Reg(reg) => insts.push((
|
||||
InstIsSafepoint::Yes,
|
||||
Inst::CallInd {
|
||||
link: writable_gpr(14),
|
||||
info: Box::new(CallIndInfo {
|
||||
rn: *reg,
|
||||
uses,
|
||||
defs,
|
||||
opcode,
|
||||
}),
|
||||
},
|
||||
)),
|
||||
}
|
||||
|
||||
insts
|
||||
}
|
||||
|
||||
fn gen_memcpy(
|
||||
_call_conv: isa::CallConv,
|
||||
_dst: Reg,
|
||||
_src: Reg,
|
||||
_size: usize,
|
||||
) -> SmallVec<[Self::I; 8]> {
|
||||
unimplemented!("StructArgs not implemented for S390X yet");
|
||||
}
|
||||
|
||||
fn get_number_of_spillslots_for_value(rc: RegClass, ty: Type) -> u32 {
|
||||
// We allocate in terms of 8-byte slots.
|
||||
match (rc, ty) {
|
||||
(RegClass::I64, _) => 1,
|
||||
(RegClass::F64, _) => 1,
|
||||
_ => panic!("Unexpected register class!"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the current virtual-SP offset from an instruction-emission state.
|
||||
fn get_virtual_sp_offset_from_state(s: &EmitState) -> i64 {
|
||||
s.virtual_sp_offset
|
||||
}
|
||||
|
||||
/// Get the nominal-SP-to-FP offset from an instruction-emission state.
|
||||
fn get_nominal_sp_to_fp(s: &EmitState) -> i64 {
|
||||
s.initial_sp_offset
|
||||
}
|
||||
|
||||
fn get_regs_clobbered_by_call(call_conv_of_callee: isa::CallConv) -> Vec<Writable<Reg>> {
|
||||
let mut caller_saved = Vec::new();
|
||||
for i in 0..15 {
|
||||
let x = writable_gpr(i);
|
||||
if is_reg_clobbered_by_call(call_conv_of_callee, x.to_reg().to_real_reg()) {
|
||||
caller_saved.push(x);
|
||||
}
|
||||
}
|
||||
for i in 0..15 {
|
||||
let v = writable_fpr(i);
|
||||
if is_reg_clobbered_by_call(call_conv_of_callee, v.to_reg().to_real_reg()) {
|
||||
caller_saved.push(v);
|
||||
}
|
||||
}
|
||||
caller_saved
|
||||
}
|
||||
|
||||
fn get_ext_mode(
|
||||
_call_conv: isa::CallConv,
|
||||
specified: ir::ArgumentExtension,
|
||||
) -> ir::ArgumentExtension {
|
||||
specified
|
||||
}
|
||||
}
|
||||
|
||||
fn is_reg_saved_in_prologue(_call_conv: isa::CallConv, r: RealReg) -> bool {
|
||||
match r.get_class() {
|
||||
RegClass::I64 => {
|
||||
// r6 - r15 inclusive are callee-saves.
|
||||
r.get_hw_encoding() >= 6 && r.get_hw_encoding() <= 15
|
||||
}
|
||||
RegClass::F64 => {
|
||||
// f8 - f15 inclusive are callee-saves.
|
||||
r.get_hw_encoding() >= 8 && r.get_hw_encoding() <= 15
|
||||
}
|
||||
_ => panic!("Unexpected RegClass"),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_regs_saved_in_prologue(
|
||||
call_conv: isa::CallConv,
|
||||
regs: &Set<Writable<RealReg>>,
|
||||
) -> (Vec<Writable<RealReg>>, Vec<Writable<RealReg>>) {
|
||||
let mut int_saves = vec![];
|
||||
let mut fpr_saves = vec![];
|
||||
for ® in regs.iter() {
|
||||
if is_reg_saved_in_prologue(call_conv, reg.to_reg()) {
|
||||
match reg.to_reg().get_class() {
|
||||
RegClass::I64 => int_saves.push(reg),
|
||||
RegClass::F64 => fpr_saves.push(reg),
|
||||
_ => panic!("Unexpected RegClass"),
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sort registers for deterministic code output.
|
||||
int_saves.sort_by_key(|r| r.to_reg().get_index());
|
||||
fpr_saves.sort_by_key(|r| r.to_reg().get_index());
|
||||
(int_saves, fpr_saves)
|
||||
}
|
||||
|
||||
fn is_reg_clobbered_by_call(_call_conv: isa::CallConv, r: RealReg) -> bool {
|
||||
match r.get_class() {
|
||||
RegClass::I64 => {
|
||||
// r0 - r5 inclusive are caller-saves.
|
||||
r.get_hw_encoding() <= 5
|
||||
}
|
||||
RegClass::F64 => {
|
||||
// f0 - f7 inclusive are caller-saves.
|
||||
r.get_hw_encoding() <= 7
|
||||
}
|
||||
_ => panic!("Unexpected RegClass"),
|
||||
}
|
||||
}
|
||||
317
cranelift/codegen/src/isa/s390x/inst/args.rs
Normal file
317
cranelift/codegen/src/isa/s390x/inst/args.rs
Normal file
@@ -0,0 +1,317 @@
|
||||
//! S390x ISA definitions: instruction arguments.
|
||||
|
||||
// Some variants are never constructed, but we still want them as options in the future.
|
||||
#![allow(dead_code)]
|
||||
|
||||
use crate::ir::condcodes::{FloatCC, IntCC};
|
||||
use crate::ir::MemFlags;
|
||||
use crate::isa::s390x::inst::*;
|
||||
use crate::machinst::MachLabel;
|
||||
|
||||
use regalloc::{PrettyPrint, RealRegUniverse, Reg};
|
||||
|
||||
use std::string::String;
|
||||
|
||||
//=============================================================================
|
||||
// Instruction sub-components (memory addresses): definitions
|
||||
|
||||
/// A memory argument to load/store, encapsulating the possible addressing modes.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum MemArg {
|
||||
//
|
||||
// Real IBM Z addressing modes:
|
||||
//
|
||||
/// Base register, index register, and 12-bit unsigned displacement.
|
||||
BXD12 {
|
||||
base: Reg,
|
||||
index: Reg,
|
||||
disp: UImm12,
|
||||
flags: MemFlags,
|
||||
},
|
||||
|
||||
/// Base register, index register, and 20-bit signed displacement.
|
||||
BXD20 {
|
||||
base: Reg,
|
||||
index: Reg,
|
||||
disp: SImm20,
|
||||
flags: MemFlags,
|
||||
},
|
||||
|
||||
/// PC-relative Reference to a label.
|
||||
Label { target: BranchTarget },
|
||||
|
||||
/// PC-relative Reference to a near symbol.
|
||||
Symbol {
|
||||
name: Box<ExternalName>,
|
||||
offset: i32,
|
||||
flags: MemFlags,
|
||||
},
|
||||
|
||||
//
|
||||
// Virtual addressing modes that are lowered at emission time:
|
||||
//
|
||||
/// Arbitrary offset from a register. Converted to generation of large
|
||||
/// offsets with multiple instructions as necessary during code emission.
|
||||
RegOffset { reg: Reg, off: i64, flags: MemFlags },
|
||||
|
||||
/// Offset from the stack pointer at function entry.
|
||||
InitialSPOffset { off: i64 },
|
||||
|
||||
/// Offset from the "nominal stack pointer", which is where the real SP is
|
||||
/// just after stack and spill slots are allocated in the function prologue.
|
||||
/// At emission time, this is converted to `SPOffset` with a fixup added to
|
||||
/// the offset constant. The fixup is a running value that is tracked as
|
||||
/// emission iterates through instructions in linear order, and can be
|
||||
/// adjusted up and down with [Inst::VirtualSPOffsetAdj].
|
||||
///
|
||||
/// The standard ABI is in charge of handling this (by emitting the
|
||||
/// adjustment meta-instructions). It maintains the invariant that "nominal
|
||||
/// SP" is where the actual SP is after the function prologue and before
|
||||
/// clobber pushes. See the diagram in the documentation for
|
||||
/// [crate::isa::s390x::abi](the ABI module) for more details.
|
||||
NominalSPOffset { off: i64 },
|
||||
}
|
||||
|
||||
impl MemArg {
|
||||
/// Memory reference using an address in a register.
|
||||
pub fn reg(reg: Reg, flags: MemFlags) -> MemArg {
|
||||
MemArg::BXD12 {
|
||||
base: reg,
|
||||
index: zero_reg(),
|
||||
disp: UImm12::zero(),
|
||||
flags,
|
||||
}
|
||||
}
|
||||
|
||||
/// Memory reference using the sum of two registers as an address.
|
||||
pub fn reg_plus_reg(reg1: Reg, reg2: Reg, flags: MemFlags) -> MemArg {
|
||||
MemArg::BXD12 {
|
||||
base: reg1,
|
||||
index: reg2,
|
||||
disp: UImm12::zero(),
|
||||
flags,
|
||||
}
|
||||
}
|
||||
|
||||
/// Memory reference using the sum of a register an an offset as address.
|
||||
pub fn reg_plus_off(reg: Reg, off: i64, flags: MemFlags) -> MemArg {
|
||||
MemArg::RegOffset { reg, off, flags }
|
||||
}
|
||||
|
||||
pub(crate) fn get_flags(&self) -> MemFlags {
|
||||
match self {
|
||||
MemArg::BXD12 { flags, .. } => *flags,
|
||||
MemArg::BXD20 { flags, .. } => *flags,
|
||||
MemArg::RegOffset { flags, .. } => *flags,
|
||||
MemArg::Label { .. } => MemFlags::trusted(),
|
||||
MemArg::Symbol { flags, .. } => *flags,
|
||||
MemArg::InitialSPOffset { .. } => MemFlags::trusted(),
|
||||
MemArg::NominalSPOffset { .. } => MemFlags::trusted(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn can_trap(&self) -> bool {
|
||||
!self.get_flags().notrap()
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Instruction sub-components (conditions, branches and branch targets):
|
||||
// definitions
|
||||
|
||||
/// Condition for conditional branches.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct Cond {
|
||||
mask: u8,
|
||||
}
|
||||
|
||||
impl Cond {
|
||||
pub fn from_mask(mask: u8) -> Cond {
|
||||
assert!(mask >= 1 && mask <= 14);
|
||||
Cond { mask }
|
||||
}
|
||||
|
||||
pub fn from_intcc(cc: IntCC) -> Cond {
|
||||
let mask = match cc {
|
||||
IntCC::Equal => 8,
|
||||
IntCC::NotEqual => 4 | 2,
|
||||
IntCC::SignedGreaterThanOrEqual => 8 | 2,
|
||||
IntCC::SignedGreaterThan => 2,
|
||||
IntCC::SignedLessThanOrEqual => 8 | 4,
|
||||
IntCC::SignedLessThan => 4,
|
||||
IntCC::UnsignedGreaterThanOrEqual => 8 | 2,
|
||||
IntCC::UnsignedGreaterThan => 2,
|
||||
IntCC::UnsignedLessThanOrEqual => 8 | 4,
|
||||
IntCC::UnsignedLessThan => 4,
|
||||
IntCC::Overflow => 1,
|
||||
IntCC::NotOverflow => 8 | 4 | 2,
|
||||
};
|
||||
Cond { mask }
|
||||
}
|
||||
|
||||
pub fn from_floatcc(cc: FloatCC) -> Cond {
|
||||
let mask = match cc {
|
||||
FloatCC::Ordered => 8 | 4 | 2,
|
||||
FloatCC::Unordered => 1,
|
||||
FloatCC::Equal => 8,
|
||||
FloatCC::NotEqual => 4 | 2 | 1,
|
||||
FloatCC::OrderedNotEqual => 4 | 2,
|
||||
FloatCC::UnorderedOrEqual => 8 | 1,
|
||||
FloatCC::LessThan => 4,
|
||||
FloatCC::LessThanOrEqual => 8 | 4,
|
||||
FloatCC::GreaterThan => 2,
|
||||
FloatCC::GreaterThanOrEqual => 8 | 2,
|
||||
FloatCC::UnorderedOrLessThan => 4 | 1,
|
||||
FloatCC::UnorderedOrLessThanOrEqual => 8 | 4 | 1,
|
||||
FloatCC::UnorderedOrGreaterThan => 2 | 1,
|
||||
FloatCC::UnorderedOrGreaterThanOrEqual => 8 | 2 | 1,
|
||||
};
|
||||
Cond { mask }
|
||||
}
|
||||
|
||||
/// Return the inverted condition.
|
||||
pub fn invert(self) -> Cond {
|
||||
Cond {
|
||||
mask: !self.mask & 15,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the machine encoding of this condition.
|
||||
pub fn bits(self) -> u8 {
|
||||
self.mask
|
||||
}
|
||||
}
|
||||
|
||||
/// A branch target. Either unresolved (basic-block index) or resolved (offset
|
||||
/// from end of current instruction).
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum BranchTarget {
|
||||
/// An unresolved reference to a Label, as passed into
|
||||
/// `lower_branch_group()`.
|
||||
Label(MachLabel),
|
||||
/// A fixed PC offset.
|
||||
ResolvedOffset(i32),
|
||||
}
|
||||
|
||||
impl BranchTarget {
|
||||
/// Return the target's label, if it is a label-based target.
|
||||
pub fn as_label(self) -> Option<MachLabel> {
|
||||
match self {
|
||||
BranchTarget::Label(l) => Some(l),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the target's offset, if specified, or zero if label-based.
|
||||
pub fn as_ri_offset_or_zero(self) -> u16 {
|
||||
let off = match self {
|
||||
BranchTarget::ResolvedOffset(off) => off >> 1,
|
||||
_ => 0,
|
||||
};
|
||||
assert!(off <= 0x7fff);
|
||||
assert!(off >= -0x8000);
|
||||
off as u16
|
||||
}
|
||||
|
||||
/// Return the target's offset, if specified, or zero if label-based.
|
||||
pub fn as_ril_offset_or_zero(self) -> u32 {
|
||||
let off = match self {
|
||||
BranchTarget::ResolvedOffset(off) => off >> 1,
|
||||
_ => 0,
|
||||
};
|
||||
off as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyPrint for MemArg {
|
||||
fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String {
|
||||
match self {
|
||||
&MemArg::BXD12 {
|
||||
base, index, disp, ..
|
||||
} => {
|
||||
if base != zero_reg() {
|
||||
if index != zero_reg() {
|
||||
format!(
|
||||
"{}({},{})",
|
||||
disp.show_rru(mb_rru),
|
||||
index.show_rru(mb_rru),
|
||||
base.show_rru(mb_rru)
|
||||
)
|
||||
} else {
|
||||
format!("{}({})", disp.show_rru(mb_rru), base.show_rru(mb_rru))
|
||||
}
|
||||
} else {
|
||||
if index != zero_reg() {
|
||||
format!("{}({},)", disp.show_rru(mb_rru), index.show_rru(mb_rru))
|
||||
} else {
|
||||
format!("{}", disp.show_rru(mb_rru))
|
||||
}
|
||||
}
|
||||
}
|
||||
&MemArg::BXD20 {
|
||||
base, index, disp, ..
|
||||
} => {
|
||||
if base != zero_reg() {
|
||||
if index != zero_reg() {
|
||||
format!(
|
||||
"{}({},{})",
|
||||
disp.show_rru(mb_rru),
|
||||
index.show_rru(mb_rru),
|
||||
base.show_rru(mb_rru)
|
||||
)
|
||||
} else {
|
||||
format!("{}({})", disp.show_rru(mb_rru), base.show_rru(mb_rru))
|
||||
}
|
||||
} else {
|
||||
if index != zero_reg() {
|
||||
format!("{}({},)", disp.show_rru(mb_rru), index.show_rru(mb_rru))
|
||||
} else {
|
||||
format!("{}", disp.show_rru(mb_rru))
|
||||
}
|
||||
}
|
||||
}
|
||||
&MemArg::Label { ref target } => target.show_rru(mb_rru),
|
||||
&MemArg::Symbol {
|
||||
ref name, offset, ..
|
||||
} => format!("{} + {}", name, offset),
|
||||
// Eliminated by `mem_finalize()`.
|
||||
&MemArg::InitialSPOffset { .. }
|
||||
| &MemArg::NominalSPOffset { .. }
|
||||
| &MemArg::RegOffset { .. } => {
|
||||
panic!("Unexpected pseudo mem-arg mode (stack-offset or generic reg-offset)!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyPrint for Cond {
|
||||
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
|
||||
let s = match self.mask {
|
||||
1 => "o",
|
||||
2 => "h",
|
||||
3 => "nle",
|
||||
4 => "l",
|
||||
5 => "nhe",
|
||||
6 => "lh",
|
||||
7 => "ne",
|
||||
8 => "e",
|
||||
9 => "nlh",
|
||||
10 => "he",
|
||||
11 => "nl",
|
||||
12 => "le",
|
||||
13 => "nh",
|
||||
14 => "no",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
s.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyPrint for BranchTarget {
|
||||
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
|
||||
match self {
|
||||
&BranchTarget::Label(label) => format!("label{:?}", label.get()),
|
||||
&BranchTarget::ResolvedOffset(off) => format!("{}", off),
|
||||
}
|
||||
}
|
||||
}
|
||||
1965
cranelift/codegen/src/isa/s390x/inst/emit.rs
Normal file
1965
cranelift/codegen/src/isa/s390x/inst/emit.rs
Normal file
File diff suppressed because it is too large
Load Diff
7140
cranelift/codegen/src/isa/s390x/inst/emit_tests.rs
Normal file
7140
cranelift/codegen/src/isa/s390x/inst/emit_tests.rs
Normal file
File diff suppressed because it is too large
Load Diff
231
cranelift/codegen/src/isa/s390x/inst/imms.rs
Normal file
231
cranelift/codegen/src/isa/s390x/inst/imms.rs
Normal file
@@ -0,0 +1,231 @@
|
||||
//! S390x ISA definitions: immediate constants.
|
||||
|
||||
use regalloc::{PrettyPrint, RealRegUniverse};
|
||||
use std::string::String;
|
||||
|
||||
/// An unsigned 12-bit immediate.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct UImm12 {
|
||||
/// The value.
|
||||
value: u16,
|
||||
}
|
||||
|
||||
impl UImm12 {
|
||||
pub fn maybe_from_u64(value: u64) -> Option<UImm12> {
|
||||
if value < 4096 {
|
||||
Some(UImm12 {
|
||||
value: value as u16,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a zero immediate of this format.
|
||||
pub fn zero() -> UImm12 {
|
||||
UImm12 { value: 0 }
|
||||
}
|
||||
|
||||
/// Bits for encoding.
|
||||
pub fn bits(&self) -> u32 {
|
||||
u32::from(self.value)
|
||||
}
|
||||
}
|
||||
|
||||
/// A signed 20-bit immediate.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct SImm20 {
|
||||
/// The value.
|
||||
value: i32,
|
||||
}
|
||||
|
||||
impl SImm20 {
|
||||
pub fn maybe_from_i64(value: i64) -> Option<SImm20> {
|
||||
if value >= -524288 && value < 524288 {
|
||||
Some(SImm20 {
|
||||
value: value as i32,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_uimm12(value: UImm12) -> SImm20 {
|
||||
SImm20 {
|
||||
value: value.bits() as i32,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a zero immediate of this format.
|
||||
pub fn zero() -> SImm20 {
|
||||
SImm20 { value: 0 }
|
||||
}
|
||||
|
||||
/// Bits for encoding.
|
||||
pub fn bits(&self) -> u32 {
|
||||
let encoded: u32 = self.value as u32;
|
||||
encoded & 0xfffff
|
||||
}
|
||||
}
|
||||
|
||||
/// A 16-bit immediate with a {0,16,32,48}-bit shift.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct UImm16Shifted {
|
||||
/// The value.
|
||||
pub bits: u16,
|
||||
/// Result is `bits` shifted 16*shift bits to the left.
|
||||
pub shift: u8,
|
||||
}
|
||||
|
||||
impl UImm16Shifted {
|
||||
/// Construct a UImm16Shifted from an arbitrary 64-bit constant if possible.
|
||||
pub fn maybe_from_u64(value: u64) -> Option<UImm16Shifted> {
|
||||
let mask0 = 0x0000_0000_0000_ffffu64;
|
||||
let mask1 = 0x0000_0000_ffff_0000u64;
|
||||
let mask2 = 0x0000_ffff_0000_0000u64;
|
||||
let mask3 = 0xffff_0000_0000_0000u64;
|
||||
|
||||
if value == (value & mask0) {
|
||||
return Some(UImm16Shifted {
|
||||
bits: (value & mask0) as u16,
|
||||
shift: 0,
|
||||
});
|
||||
}
|
||||
if value == (value & mask1) {
|
||||
return Some(UImm16Shifted {
|
||||
bits: ((value >> 16) & mask0) as u16,
|
||||
shift: 1,
|
||||
});
|
||||
}
|
||||
if value == (value & mask2) {
|
||||
return Some(UImm16Shifted {
|
||||
bits: ((value >> 32) & mask0) as u16,
|
||||
shift: 2,
|
||||
});
|
||||
}
|
||||
if value == (value & mask3) {
|
||||
return Some(UImm16Shifted {
|
||||
bits: ((value >> 48) & mask0) as u16,
|
||||
shift: 3,
|
||||
});
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn maybe_with_shift(imm: u16, shift: u8) -> Option<UImm16Shifted> {
|
||||
let shift_enc = shift / 16;
|
||||
if shift_enc > 3 {
|
||||
None
|
||||
} else {
|
||||
Some(UImm16Shifted {
|
||||
bits: imm,
|
||||
shift: shift_enc,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn negate_bits(&self) -> UImm16Shifted {
|
||||
UImm16Shifted {
|
||||
bits: !self.bits,
|
||||
shift: self.shift,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the value that this constant represents.
|
||||
pub fn value(&self) -> u64 {
|
||||
(self.bits as u64) << (16 * self.shift)
|
||||
}
|
||||
}
|
||||
|
||||
/// A 32-bit immediate with a {0,32}-bit shift.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct UImm32Shifted {
|
||||
/// The value.
|
||||
pub bits: u32,
|
||||
/// Result is `bits` shifted 32*shift bits to the left.
|
||||
pub shift: u8,
|
||||
}
|
||||
|
||||
impl UImm32Shifted {
|
||||
/// Construct a UImm32Shifted from an arbitrary 64-bit constant if possible.
|
||||
pub fn maybe_from_u64(value: u64) -> Option<UImm32Shifted> {
|
||||
let mask0 = 0x0000_0000_ffff_ffffu64;
|
||||
let mask1 = 0xffff_ffff_0000_0000u64;
|
||||
|
||||
if value == (value & mask0) {
|
||||
return Some(UImm32Shifted {
|
||||
bits: (value & mask0) as u32,
|
||||
shift: 0,
|
||||
});
|
||||
}
|
||||
if value == (value & mask1) {
|
||||
return Some(UImm32Shifted {
|
||||
bits: ((value >> 32) & mask0) as u32,
|
||||
shift: 1,
|
||||
});
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn maybe_with_shift(imm: u32, shift: u8) -> Option<UImm32Shifted> {
|
||||
let shift_enc = shift / 32;
|
||||
if shift_enc > 3 {
|
||||
None
|
||||
} else {
|
||||
Some(UImm32Shifted {
|
||||
bits: imm,
|
||||
shift: shift_enc,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_uimm16shifted(value: UImm16Shifted) -> UImm32Shifted {
|
||||
if value.shift % 2 == 0 {
|
||||
UImm32Shifted {
|
||||
bits: value.bits as u32,
|
||||
shift: value.shift / 2,
|
||||
}
|
||||
} else {
|
||||
UImm32Shifted {
|
||||
bits: (value.bits as u32) << 16,
|
||||
shift: value.shift / 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn negate_bits(&self) -> UImm32Shifted {
|
||||
UImm32Shifted {
|
||||
bits: !self.bits,
|
||||
shift: self.shift,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the value that this constant represents.
|
||||
pub fn value(&self) -> u64 {
|
||||
(self.bits as u64) << (32 * self.shift)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyPrint for UImm12 {
|
||||
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
|
||||
format!("{}", self.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyPrint for SImm20 {
|
||||
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
|
||||
format!("{}", self.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyPrint for UImm16Shifted {
|
||||
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
|
||||
format!("{}", self.bits)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyPrint for UImm32Shifted {
|
||||
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
|
||||
format!("{}", self.bits)
|
||||
}
|
||||
}
|
||||
3411
cranelift/codegen/src/isa/s390x/inst/mod.rs
Normal file
3411
cranelift/codegen/src/isa/s390x/inst/mod.rs
Normal file
File diff suppressed because it is too large
Load Diff
168
cranelift/codegen/src/isa/s390x/inst/regs.rs
Normal file
168
cranelift/codegen/src/isa/s390x/inst/regs.rs
Normal file
@@ -0,0 +1,168 @@
|
||||
//! S390x ISA definitions: registers.
|
||||
|
||||
use crate::settings;
|
||||
use regalloc::{RealRegUniverse, Reg, RegClass, RegClassInfo, Writable, NUM_REG_CLASSES};
|
||||
|
||||
//=============================================================================
|
||||
// Registers, the Universe thereof, and printing
|
||||
|
||||
#[rustfmt::skip]
|
||||
const GPR_INDICES: [u8; 16] = [
|
||||
// r0 and r1 reserved
|
||||
30, 31,
|
||||
// r2 - r5 call-clobbered
|
||||
16, 17, 18, 19,
|
||||
// r6 - r14 call-saved (order reversed)
|
||||
28, 27, 26, 25, 24, 23, 22, 21, 20,
|
||||
// r15 (SP)
|
||||
29,
|
||||
];
|
||||
|
||||
#[rustfmt::skip]
|
||||
const FPR_INDICES: [u8; 16] = [
|
||||
// f0 - f7 as pairs
|
||||
0, 4, 1, 5, 2, 6, 3, 7,
|
||||
// f8 - f15 as pairs
|
||||
8, 12, 9, 13, 10, 14, 11, 15,
|
||||
];
|
||||
|
||||
/// Get a reference to a GPR (integer register).
|
||||
pub fn gpr(num: u8) -> Reg {
|
||||
assert!(num < 16);
|
||||
Reg::new_real(
|
||||
RegClass::I64,
|
||||
/* enc = */ num,
|
||||
/* index = */ GPR_INDICES[num as usize],
|
||||
)
|
||||
}
|
||||
|
||||
/// Get a writable reference to a GPR.
|
||||
pub fn writable_gpr(num: u8) -> Writable<Reg> {
|
||||
Writable::from_reg(gpr(num))
|
||||
}
|
||||
|
||||
/// Get a reference to a FPR (floating-point register).
|
||||
pub fn fpr(num: u8) -> Reg {
|
||||
assert!(num < 16);
|
||||
Reg::new_real(
|
||||
RegClass::F64,
|
||||
/* enc = */ num,
|
||||
/* index = */ FPR_INDICES[num as usize],
|
||||
)
|
||||
}
|
||||
|
||||
/// Get a writable reference to a V-register.
|
||||
pub fn writable_fpr(num: u8) -> Writable<Reg> {
|
||||
Writable::from_reg(fpr(num))
|
||||
}
|
||||
|
||||
/// Get a reference to the stack-pointer register.
|
||||
pub fn stack_reg() -> Reg {
|
||||
gpr(15)
|
||||
}
|
||||
|
||||
/// Get a writable reference to the stack-pointer register.
|
||||
pub fn writable_stack_reg() -> Writable<Reg> {
|
||||
Writable::from_reg(stack_reg())
|
||||
}
|
||||
|
||||
/// Get a reference to the first temporary, sometimes "spill temporary", register. This register is
|
||||
/// used to compute the address of a spill slot when a direct offset addressing mode from FP is not
|
||||
/// sufficient (+/- 2^11 words). We exclude this register from regalloc and reserve it for this
|
||||
/// purpose for simplicity; otherwise we need a multi-stage analysis where we first determine how
|
||||
/// many spill slots we have, then perhaps remove the reg from the pool and recompute regalloc.
|
||||
///
|
||||
/// We use r1 for this because it's a scratch register but is slightly special (used for linker
|
||||
/// veneers). We're free to use it as long as we don't expect it to live through call instructions.
|
||||
pub fn spilltmp_reg() -> Reg {
|
||||
gpr(1)
|
||||
}
|
||||
|
||||
/// Get a writable reference to the spilltmp reg.
|
||||
pub fn writable_spilltmp_reg() -> Writable<Reg> {
|
||||
Writable::from_reg(spilltmp_reg())
|
||||
}
|
||||
|
||||
pub fn zero_reg() -> Reg {
|
||||
gpr(0)
|
||||
}
|
||||
|
||||
/// Create the register universe for AArch64.
|
||||
pub fn create_reg_universe(_flags: &settings::Flags) -> RealRegUniverse {
|
||||
let mut regs = vec![];
|
||||
let mut allocable_by_class = [None; NUM_REG_CLASSES];
|
||||
|
||||
// Numbering Scheme: we put FPRs first, then GPRs. The GPRs exclude several registers:
|
||||
// r0 (we cannot use this for addressing // FIXME regalloc)
|
||||
// r1 (spilltmp)
|
||||
// r15 (stack pointer)
|
||||
|
||||
// FPRs.
|
||||
let mut base = regs.len();
|
||||
regs.push((fpr(0).to_real_reg(), "%f0".into()));
|
||||
regs.push((fpr(2).to_real_reg(), "%f2".into()));
|
||||
regs.push((fpr(4).to_real_reg(), "%f4".into()));
|
||||
regs.push((fpr(6).to_real_reg(), "%f6".into()));
|
||||
regs.push((fpr(1).to_real_reg(), "%f1".into()));
|
||||
regs.push((fpr(3).to_real_reg(), "%f3".into()));
|
||||
regs.push((fpr(5).to_real_reg(), "%f5".into()));
|
||||
regs.push((fpr(7).to_real_reg(), "%f7".into()));
|
||||
regs.push((fpr(8).to_real_reg(), "%f8".into()));
|
||||
regs.push((fpr(10).to_real_reg(), "%f10".into()));
|
||||
regs.push((fpr(12).to_real_reg(), "%f12".into()));
|
||||
regs.push((fpr(14).to_real_reg(), "%f14".into()));
|
||||
regs.push((fpr(9).to_real_reg(), "%f9".into()));
|
||||
regs.push((fpr(11).to_real_reg(), "%f11".into()));
|
||||
regs.push((fpr(13).to_real_reg(), "%f13".into()));
|
||||
regs.push((fpr(15).to_real_reg(), "%f15".into()));
|
||||
|
||||
allocable_by_class[RegClass::F64.rc_to_usize()] = Some(RegClassInfo {
|
||||
first: base,
|
||||
last: regs.len() - 1,
|
||||
suggested_scratch: Some(fpr(1).get_index()),
|
||||
});
|
||||
|
||||
// Caller-saved GPRs in the SystemV s390x ABI.
|
||||
base = regs.len();
|
||||
regs.push((gpr(2).to_real_reg(), "%r2".into()));
|
||||
regs.push((gpr(3).to_real_reg(), "%r3".into()));
|
||||
regs.push((gpr(4).to_real_reg(), "%r4".into()));
|
||||
regs.push((gpr(5).to_real_reg(), "%r5".into()));
|
||||
|
||||
// Callee-saved GPRs in the SystemV s390x ABI.
|
||||
// We start from r14 downwards in an attempt to allow the
|
||||
// prolog to use as short a STMG as possible.
|
||||
regs.push((gpr(14).to_real_reg(), "%r14".into()));
|
||||
regs.push((gpr(13).to_real_reg(), "%r13".into()));
|
||||
regs.push((gpr(12).to_real_reg(), "%r12".into()));
|
||||
regs.push((gpr(11).to_real_reg(), "%r11".into()));
|
||||
regs.push((gpr(10).to_real_reg(), "%r10".into()));
|
||||
regs.push((gpr(9).to_real_reg(), "%r9".into()));
|
||||
regs.push((gpr(8).to_real_reg(), "%r8".into()));
|
||||
regs.push((gpr(7).to_real_reg(), "%r7".into()));
|
||||
regs.push((gpr(6).to_real_reg(), "%r6".into()));
|
||||
|
||||
allocable_by_class[RegClass::I64.rc_to_usize()] = Some(RegClassInfo {
|
||||
first: base,
|
||||
last: regs.len() - 1,
|
||||
suggested_scratch: Some(gpr(13).get_index()),
|
||||
});
|
||||
|
||||
// Other regs, not available to the allocator.
|
||||
let allocable = regs.len();
|
||||
regs.push((gpr(15).to_real_reg(), "%r15".into()));
|
||||
regs.push((gpr(0).to_real_reg(), "%r0".into()));
|
||||
regs.push((gpr(1).to_real_reg(), "%r1".into()));
|
||||
|
||||
// Assert sanity: the indices in the register structs must match their
|
||||
// actual indices in the array.
|
||||
for (i, reg) in regs.iter().enumerate() {
|
||||
assert_eq!(i, reg.0.get_index());
|
||||
}
|
||||
|
||||
RealRegUniverse {
|
||||
regs,
|
||||
allocable,
|
||||
allocable_by_class,
|
||||
}
|
||||
}
|
||||
2
cranelift/codegen/src/isa/s390x/inst/unwind.rs
Normal file
2
cranelift/codegen/src/isa/s390x/inst/unwind.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
#[cfg(feature = "unwind")]
|
||||
pub(crate) mod systemv;
|
||||
197
cranelift/codegen/src/isa/s390x/inst/unwind/systemv.rs
Normal file
197
cranelift/codegen/src/isa/s390x/inst/unwind/systemv.rs
Normal file
@@ -0,0 +1,197 @@
|
||||
//! Unwind information for System V ABI (s390x).
|
||||
|
||||
use crate::isa::unwind::systemv::RegisterMappingError;
|
||||
use gimli::{write::CommonInformationEntry, Encoding, Format, Register};
|
||||
use regalloc::{Reg, RegClass};
|
||||
|
||||
/// Creates a new s390x common information entry (CIE).
|
||||
pub fn create_cie() -> CommonInformationEntry {
|
||||
use gimli::write::CallFrameInstruction;
|
||||
|
||||
let mut entry = CommonInformationEntry::new(
|
||||
Encoding {
|
||||
address_size: 8,
|
||||
format: Format::Dwarf32,
|
||||
version: 1,
|
||||
},
|
||||
1, // Code alignment factor
|
||||
-8, // Data alignment factor
|
||||
Register(14), // Return address column - register %r14
|
||||
);
|
||||
|
||||
// Every frame will start with the call frame address (CFA) at %r15 + 160.
|
||||
entry.add_instruction(CallFrameInstruction::Cfa(Register(15), 160));
|
||||
|
||||
entry
|
||||
}
|
||||
|
||||
/// Map Cranelift registers to their corresponding Gimli registers.
|
||||
pub fn map_reg(reg: Reg) -> Result<Register, RegisterMappingError> {
|
||||
const GPR_MAP: [gimli::Register; 16] = [
|
||||
Register(0),
|
||||
Register(1),
|
||||
Register(2),
|
||||
Register(3),
|
||||
Register(4),
|
||||
Register(5),
|
||||
Register(6),
|
||||
Register(7),
|
||||
Register(8),
|
||||
Register(9),
|
||||
Register(10),
|
||||
Register(11),
|
||||
Register(12),
|
||||
Register(13),
|
||||
Register(14),
|
||||
Register(15),
|
||||
];
|
||||
const FPR_MAP: [gimli::Register; 16] = [
|
||||
Register(16),
|
||||
Register(20),
|
||||
Register(17),
|
||||
Register(21),
|
||||
Register(18),
|
||||
Register(22),
|
||||
Register(19),
|
||||
Register(23),
|
||||
Register(24),
|
||||
Register(28),
|
||||
Register(25),
|
||||
Register(29),
|
||||
Register(26),
|
||||
Register(30),
|
||||
Register(27),
|
||||
Register(31),
|
||||
];
|
||||
|
||||
match reg.get_class() {
|
||||
RegClass::I64 => Ok(GPR_MAP[reg.get_hw_encoding() as usize]),
|
||||
RegClass::F64 => Ok(FPR_MAP[reg.get_hw_encoding() as usize]),
|
||||
_ => Err(RegisterMappingError::UnsupportedRegisterBank("class?")),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RegisterMapper;
|
||||
|
||||
impl crate::isa::unwind::systemv::RegisterMapper<Reg> for RegisterMapper {
|
||||
fn map(&self, reg: Reg) -> Result<u16, RegisterMappingError> {
|
||||
Ok(map_reg(reg)?.0)
|
||||
}
|
||||
fn sp(&self) -> u16 {
|
||||
Register(15).0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::cursor::{Cursor, FuncCursor};
|
||||
use crate::ir::{
|
||||
types, AbiParam, ExternalName, Function, InstBuilder, Signature, StackSlotData,
|
||||
StackSlotKind,
|
||||
};
|
||||
use crate::isa::{lookup, CallConv};
|
||||
use crate::settings::{builder, Flags};
|
||||
use crate::Context;
|
||||
use gimli::write::Address;
|
||||
use std::str::FromStr;
|
||||
use target_lexicon::triple;
|
||||
|
||||
#[test]
|
||||
fn test_simple_func() {
|
||||
let isa = lookup(triple!("s390x"))
|
||||
.expect("expect s390x ISA")
|
||||
.finish(Flags::new(builder()));
|
||||
|
||||
let mut context = Context::for_function(create_function(
|
||||
CallConv::SystemV,
|
||||
Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64)),
|
||||
));
|
||||
|
||||
context.compile(&*isa).expect("expected compilation");
|
||||
|
||||
let fde = match context
|
||||
.create_unwind_info(isa.as_ref())
|
||||
.expect("can create unwind info")
|
||||
{
|
||||
Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => {
|
||||
info.to_fde(Address::Constant(1234))
|
||||
}
|
||||
_ => panic!("expected unwind information"),
|
||||
};
|
||||
|
||||
assert_eq!(format!("{:?}", fde), "FrameDescriptionEntry { address: Constant(1234), length: 10, lsda: None, instructions: [(4, CfaOffset(224))] }");
|
||||
}
|
||||
|
||||
fn create_function(call_conv: CallConv, stack_slot: Option<StackSlotData>) -> Function {
|
||||
let mut func =
|
||||
Function::with_name_signature(ExternalName::user(0, 0), Signature::new(call_conv));
|
||||
|
||||
let block0 = func.dfg.make_block();
|
||||
let mut pos = FuncCursor::new(&mut func);
|
||||
pos.insert_block(block0);
|
||||
pos.ins().return_(&[]);
|
||||
|
||||
if let Some(stack_slot) = stack_slot {
|
||||
func.stack_slots.push(stack_slot);
|
||||
}
|
||||
|
||||
func
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multi_return_func() {
|
||||
let isa = lookup(triple!("s390x"))
|
||||
.expect("expect s390x ISA")
|
||||
.finish(Flags::new(builder()));
|
||||
|
||||
let mut context = Context::for_function(create_multi_return_function(
|
||||
CallConv::SystemV,
|
||||
Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64)),
|
||||
));
|
||||
|
||||
context.compile(&*isa).expect("expected compilation");
|
||||
|
||||
let fde = match context
|
||||
.create_unwind_info(isa.as_ref())
|
||||
.expect("can create unwind info")
|
||||
{
|
||||
Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => {
|
||||
info.to_fde(Address::Constant(4321))
|
||||
}
|
||||
_ => panic!("expected unwind information"),
|
||||
};
|
||||
|
||||
assert_eq!(format!("{:?}", fde), "FrameDescriptionEntry { address: Constant(4321), length: 26, lsda: None, instructions: [(4, CfaOffset(224))] }");
|
||||
}
|
||||
|
||||
fn create_multi_return_function(
|
||||
call_conv: CallConv,
|
||||
stack_slot: Option<StackSlotData>,
|
||||
) -> Function {
|
||||
let mut sig = Signature::new(call_conv);
|
||||
sig.params.push(AbiParam::new(types::I32));
|
||||
let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig);
|
||||
|
||||
let block0 = func.dfg.make_block();
|
||||
let v0 = func.dfg.append_block_param(block0, types::I32);
|
||||
let block1 = func.dfg.make_block();
|
||||
let block2 = func.dfg.make_block();
|
||||
|
||||
let mut pos = FuncCursor::new(&mut func);
|
||||
pos.insert_block(block0);
|
||||
pos.ins().brnz(v0, block2, &[]);
|
||||
pos.ins().jump(block1, &[]);
|
||||
|
||||
pos.insert_block(block1);
|
||||
pos.ins().return_(&[]);
|
||||
|
||||
pos.insert_block(block2);
|
||||
pos.ins().return_(&[]);
|
||||
|
||||
if let Some(stack_slot) = stack_slot {
|
||||
func.stack_slots.push(stack_slot);
|
||||
}
|
||||
|
||||
func
|
||||
}
|
||||
}
|
||||
2839
cranelift/codegen/src/isa/s390x/lower.rs
Normal file
2839
cranelift/codegen/src/isa/s390x/lower.rs
Normal file
File diff suppressed because it is too large
Load Diff
296
cranelift/codegen/src/isa/s390x/mod.rs
Normal file
296
cranelift/codegen/src/isa/s390x/mod.rs
Normal file
@@ -0,0 +1,296 @@
|
||||
//! IBM Z 64-bit Instruction Set Architecture.
|
||||
|
||||
use crate::ir::condcodes::IntCC;
|
||||
use crate::ir::Function;
|
||||
use crate::isa::s390x::settings as s390x_settings;
|
||||
use crate::isa::unwind::systemv::RegisterMappingError;
|
||||
use crate::isa::Builder as IsaBuilder;
|
||||
use crate::machinst::{compile, MachBackend, MachCompileResult, TargetIsaAdapter, VCode};
|
||||
use crate::result::CodegenResult;
|
||||
use crate::settings as shared_settings;
|
||||
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use core::hash::{Hash, Hasher};
|
||||
|
||||
use regalloc::{PrettyPrint, RealRegUniverse, Reg};
|
||||
use target_lexicon::{Architecture, Triple};
|
||||
|
||||
// New backend:
|
||||
mod abi;
|
||||
pub(crate) mod inst;
|
||||
mod lower;
|
||||
mod settings;
|
||||
|
||||
use inst::create_reg_universe;
|
||||
|
||||
use self::inst::EmitInfo;
|
||||
|
||||
/// A IBM Z backend.
|
||||
pub struct S390xBackend {
|
||||
triple: Triple,
|
||||
flags: shared_settings::Flags,
|
||||
isa_flags: s390x_settings::Flags,
|
||||
reg_universe: RealRegUniverse,
|
||||
}
|
||||
|
||||
impl S390xBackend {
|
||||
/// Create a new IBM Z backend with the given (shared) flags.
|
||||
pub fn new_with_flags(
|
||||
triple: Triple,
|
||||
flags: shared_settings::Flags,
|
||||
isa_flags: s390x_settings::Flags,
|
||||
) -> S390xBackend {
|
||||
let reg_universe = create_reg_universe(&flags);
|
||||
S390xBackend {
|
||||
triple,
|
||||
flags,
|
||||
isa_flags,
|
||||
reg_universe,
|
||||
}
|
||||
}
|
||||
|
||||
/// This performs lowering to VCode, register-allocates the code, computes block layout and
|
||||
/// finalizes branches. The result is ready for binary emission.
|
||||
fn compile_vcode(
|
||||
&self,
|
||||
func: &Function,
|
||||
flags: shared_settings::Flags,
|
||||
) -> CodegenResult<VCode<inst::Inst>> {
|
||||
let emit_info = EmitInfo::new(flags.clone());
|
||||
let abi = Box::new(abi::S390xABICallee::new(func, flags)?);
|
||||
compile::compile::<S390xBackend>(func, self, abi, emit_info)
|
||||
}
|
||||
}
|
||||
|
||||
impl MachBackend for S390xBackend {
|
||||
fn compile_function(
|
||||
&self,
|
||||
func: &Function,
|
||||
want_disasm: bool,
|
||||
) -> CodegenResult<MachCompileResult> {
|
||||
let flags = self.flags();
|
||||
let vcode = self.compile_vcode(func, flags.clone())?;
|
||||
let buffer = vcode.emit();
|
||||
let frame_size = vcode.frame_size();
|
||||
let value_labels_ranges = vcode.value_labels_ranges();
|
||||
let stackslot_offsets = vcode.stackslot_offsets().clone();
|
||||
|
||||
let disasm = if want_disasm {
|
||||
Some(vcode.show_rru(Some(&create_reg_universe(flags))))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let buffer = buffer.finish();
|
||||
|
||||
Ok(MachCompileResult {
|
||||
buffer,
|
||||
frame_size,
|
||||
disasm,
|
||||
value_labels_ranges,
|
||||
stackslot_offsets,
|
||||
})
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"s390x"
|
||||
}
|
||||
|
||||
fn triple(&self) -> Triple {
|
||||
self.triple.clone()
|
||||
}
|
||||
|
||||
fn flags(&self) -> &shared_settings::Flags {
|
||||
&self.flags
|
||||
}
|
||||
|
||||
fn isa_flags(&self) -> Vec<shared_settings::Value> {
|
||||
self.isa_flags.iter().collect()
|
||||
}
|
||||
|
||||
fn hash_all_flags(&self, mut hasher: &mut dyn Hasher) {
|
||||
self.flags.hash(&mut hasher);
|
||||
self.isa_flags.hash(&mut hasher);
|
||||
}
|
||||
|
||||
fn reg_universe(&self) -> &RealRegUniverse {
|
||||
&self.reg_universe
|
||||
}
|
||||
|
||||
fn unsigned_add_overflow_condition(&self) -> IntCC {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn unsigned_sub_overflow_condition(&self) -> IntCC {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(feature = "unwind")]
|
||||
fn emit_unwind_info(
|
||||
&self,
|
||||
result: &MachCompileResult,
|
||||
kind: crate::machinst::UnwindInfoKind,
|
||||
) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
|
||||
use crate::isa::unwind::UnwindInfo;
|
||||
use crate::machinst::UnwindInfoKind;
|
||||
Ok(match kind {
|
||||
UnwindInfoKind::SystemV => {
|
||||
let mapper = self::inst::unwind::systemv::RegisterMapper;
|
||||
Some(UnwindInfo::SystemV(
|
||||
crate::isa::unwind::systemv::create_unwind_info_from_insts(
|
||||
&result.buffer.unwind_info[..],
|
||||
result.buffer.data.len(),
|
||||
&mapper,
|
||||
)?,
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "unwind")]
|
||||
fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
|
||||
Some(inst::unwind::systemv::create_cie())
|
||||
}
|
||||
|
||||
#[cfg(feature = "unwind")]
|
||||
fn map_reg_to_dwarf(&self, reg: Reg) -> Result<u16, RegisterMappingError> {
|
||||
inst::unwind::systemv::map_reg(reg).map(|reg| reg.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `isa::Builder`.
|
||||
pub fn isa_builder(triple: Triple) -> IsaBuilder {
|
||||
assert!(triple.architecture == Architecture::S390x);
|
||||
IsaBuilder {
|
||||
triple,
|
||||
setup: s390x_settings::builder(),
|
||||
constructor: |triple, shared_flags, builder| {
|
||||
let isa_flags = s390x_settings::Flags::new(&shared_flags, builder);
|
||||
let backend = S390xBackend::new_with_flags(triple, shared_flags, isa_flags);
|
||||
Box::new(TargetIsaAdapter::new(backend))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::cursor::{Cursor, FuncCursor};
|
||||
use crate::ir::types::*;
|
||||
use crate::ir::{AbiParam, ExternalName, Function, InstBuilder, Signature};
|
||||
use crate::isa::CallConv;
|
||||
use crate::settings;
|
||||
use crate::settings::Configurable;
|
||||
use core::str::FromStr;
|
||||
use target_lexicon::Triple;
|
||||
|
||||
#[test]
|
||||
fn test_compile_function() {
|
||||
let name = ExternalName::testcase("test0");
|
||||
let mut sig = Signature::new(CallConv::SystemV);
|
||||
sig.params.push(AbiParam::new(I32));
|
||||
sig.returns.push(AbiParam::new(I32));
|
||||
let mut func = Function::with_name_signature(name, sig);
|
||||
|
||||
let bb0 = func.dfg.make_block();
|
||||
let arg0 = func.dfg.append_block_param(bb0, I32);
|
||||
|
||||
let mut pos = FuncCursor::new(&mut func);
|
||||
pos.insert_block(bb0);
|
||||
let v0 = pos.ins().iconst(I32, 0x1234);
|
||||
let v1 = pos.ins().iadd(arg0, v0);
|
||||
pos.ins().return_(&[v1]);
|
||||
|
||||
let mut shared_flags_builder = settings::builder();
|
||||
shared_flags_builder.set("opt_level", "none").unwrap();
|
||||
let shared_flags = settings::Flags::new(shared_flags_builder);
|
||||
let isa_flags = s390x_settings::Flags::new(&shared_flags, s390x_settings::builder());
|
||||
let backend = S390xBackend::new_with_flags(
|
||||
Triple::from_str("s390x").unwrap(),
|
||||
shared_flags,
|
||||
isa_flags,
|
||||
);
|
||||
let result = backend
|
||||
.compile_function(&mut func, /* want_disasm = */ false)
|
||||
.unwrap();
|
||||
let code = &result.buffer.data[..];
|
||||
|
||||
// ahi %r2, 0x1234
|
||||
// br %r14
|
||||
let golden = vec![0xa7, 0x2a, 0x12, 0x34, 0x07, 0xfe];
|
||||
|
||||
assert_eq!(code, &golden[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_branch_lowering() {
|
||||
let name = ExternalName::testcase("test0");
|
||||
let mut sig = Signature::new(CallConv::SystemV);
|
||||
sig.params.push(AbiParam::new(I32));
|
||||
sig.returns.push(AbiParam::new(I32));
|
||||
let mut func = Function::with_name_signature(name, sig);
|
||||
|
||||
let bb0 = func.dfg.make_block();
|
||||
let arg0 = func.dfg.append_block_param(bb0, I32);
|
||||
let bb1 = func.dfg.make_block();
|
||||
let bb2 = func.dfg.make_block();
|
||||
let bb3 = func.dfg.make_block();
|
||||
|
||||
let mut pos = FuncCursor::new(&mut func);
|
||||
pos.insert_block(bb0);
|
||||
let v0 = pos.ins().iconst(I32, 0x1234);
|
||||
let v1 = pos.ins().iadd(arg0, v0);
|
||||
pos.ins().brnz(v1, bb1, &[]);
|
||||
pos.ins().jump(bb2, &[]);
|
||||
pos.insert_block(bb1);
|
||||
pos.ins().brnz(v1, bb2, &[]);
|
||||
pos.ins().jump(bb3, &[]);
|
||||
pos.insert_block(bb2);
|
||||
let v2 = pos.ins().iadd(v1, v0);
|
||||
pos.ins().brnz(v2, bb2, &[]);
|
||||
pos.ins().jump(bb1, &[]);
|
||||
pos.insert_block(bb3);
|
||||
let v3 = pos.ins().isub(v1, v0);
|
||||
pos.ins().return_(&[v3]);
|
||||
|
||||
let mut shared_flags_builder = settings::builder();
|
||||
shared_flags_builder.set("opt_level", "none").unwrap();
|
||||
let shared_flags = settings::Flags::new(shared_flags_builder);
|
||||
let isa_flags = s390x_settings::Flags::new(&shared_flags, s390x_settings::builder());
|
||||
let backend = S390xBackend::new_with_flags(
|
||||
Triple::from_str("s390x").unwrap(),
|
||||
shared_flags,
|
||||
isa_flags,
|
||||
);
|
||||
let result = backend
|
||||
.compile_function(&mut func, /* want_disasm = */ false)
|
||||
.unwrap();
|
||||
let code = &result.buffer.data[..];
|
||||
|
||||
// FIXME: the branching logic should be optimized more
|
||||
|
||||
// ahi %r2, 4660
|
||||
// chi %r2, 0
|
||||
// jglh label1 ; jg label2
|
||||
// jg label6
|
||||
// jg label3
|
||||
// ahik %r3, %r2, 4660
|
||||
// chi %r3, 0
|
||||
// jglh label4 ; jg label5
|
||||
// jg label3
|
||||
// jg label6
|
||||
// chi %r2, 0
|
||||
// jglh label7 ; jg label8
|
||||
// jg label3
|
||||
// ahi %r2, -4660
|
||||
// br %r14
|
||||
let golden = vec![
|
||||
167, 42, 18, 52, 167, 46, 0, 0, 192, 100, 0, 0, 0, 11, 236, 50, 18, 52, 0, 216, 167,
|
||||
62, 0, 0, 192, 100, 255, 255, 255, 251, 167, 46, 0, 0, 192, 100, 255, 255, 255, 246,
|
||||
167, 42, 237, 204, 7, 254,
|
||||
];
|
||||
|
||||
assert_eq!(code, &golden[..]);
|
||||
}
|
||||
}
|
||||
9
cranelift/codegen/src/isa/s390x/settings.rs
Normal file
9
cranelift/codegen/src/isa/s390x/settings.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
//! S390X Settings.
|
||||
|
||||
use crate::settings::{self, detail, Builder, Value};
|
||||
use core::fmt;
|
||||
|
||||
// Include code generated by `cranelift-codegen/meta/src/gen_settings.rs:`. This file contains a
|
||||
// public `Flags` struct with an impl for all of the settings defined in
|
||||
// `cranelift-codegen/meta/src/isa/s390x/settings.rs`.
|
||||
include!(concat!(env!("OUT_DIR"), "/settings-s390x.rs"));
|
||||
1136
cranelift/filetests/filetests/isa/s390x/arithmetic.clif
Normal file
1136
cranelift/filetests/filetests/isa/s390x/arithmetic.clif
Normal file
File diff suppressed because it is too large
Load Diff
243
cranelift/filetests/filetests/isa/s390x/bitops.clif
Normal file
243
cranelift/filetests/filetests/isa/s390x/bitops.clif
Normal file
@@ -0,0 +1,243 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; BITREV
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
; FIXME: bitrev not yet implemented
|
||||
|
||||
;function %bitrev_i64(i64) -> i64 {
|
||||
;block0(v0: i64):
|
||||
; v1 = bitrev v0
|
||||
; return v1
|
||||
;}
|
||||
;
|
||||
;function %bitrev_i32(i32) -> i32 {
|
||||
;block0(v0: i32):
|
||||
; v1 = bitrev v0
|
||||
; return v1
|
||||
;}
|
||||
;
|
||||
;function %bitrev_i16(i16) -> i16 {
|
||||
;block0(v0: i16):
|
||||
; v1 = bitrev v0
|
||||
; return v1
|
||||
;}
|
||||
;
|
||||
;function %bitrev_i8(i8) -> i8 {
|
||||
;block0(v0: i8):
|
||||
; v1 = bitrev v0
|
||||
; return v1
|
||||
;}
|
||||
;
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; CLZ
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %clz_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = clz v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: flogr %r0, %r2
|
||||
; nextln: lgr %r2, %r0
|
||||
; nextln: br %r14
|
||||
|
||||
function %clz_i32(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = clz v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llgfr %r2, %r2
|
||||
; nextln: flogr %r0, %r2
|
||||
; nextln: lr %r2, %r0
|
||||
; nextln: ahi %r2, -32
|
||||
; nextln: br %r14
|
||||
|
||||
function %clz_i16(i16) -> i16 {
|
||||
block0(v0: i16):
|
||||
v1 = clz v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llghr %r2, %r2
|
||||
; nextln: flogr %r0, %r2
|
||||
; nextln: lr %r2, %r0
|
||||
; nextln: ahi %r2, -48
|
||||
; nextln: br %r14
|
||||
|
||||
function %clz_i8(i8) -> i8 {
|
||||
block0(v0: i8):
|
||||
v1 = clz v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llgcr %r2, %r2
|
||||
; nextln: flogr %r0, %r2
|
||||
; nextln: lr %r2, %r0
|
||||
; nextln: ahi %r2, -56
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; CLS
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %cls_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = cls v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: srag %r3, %r2, 63
|
||||
; nextln: xgr %r3, %r2
|
||||
; nextln: flogr %r0, %r2
|
||||
; nextln: lgr %r2, %r0
|
||||
; nextln: br %r14
|
||||
|
||||
function %cls_i32(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = cls v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lgfr %r2, %r2
|
||||
; nextln: srag %r3, %r2, 63
|
||||
; nextln: xgr %r3, %r2
|
||||
; nextln: flogr %r0, %r2
|
||||
; nextln: lr %r2, %r0
|
||||
; nextln: ahi %r2, -32
|
||||
; nextln: br %r14
|
||||
|
||||
function %cls_i16(i16) -> i16 {
|
||||
block0(v0: i16):
|
||||
v1 = cls v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lghr %r2, %r2
|
||||
; nextln: srag %r3, %r2, 63
|
||||
; nextln: xgr %r3, %r2
|
||||
; nextln: flogr %r0, %r2
|
||||
; nextln: lr %r2, %r0
|
||||
; nextln: ahi %r2, -48
|
||||
; nextln: br %r14
|
||||
|
||||
function %cls_i8(i8) -> i8 {
|
||||
block0(v0: i8):
|
||||
v1 = cls v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lgbr %r2, %r2
|
||||
; nextln: srag %r3, %r2, 63
|
||||
; nextln: xgr %r3, %r2
|
||||
; nextln: flogr %r0, %r2
|
||||
; nextln: lr %r2, %r0
|
||||
; nextln: ahi %r2, -56
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; CTZ
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %ctz_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = ctz v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lcgr %r3, %r2
|
||||
; nextln: ngrk %r2, %r3, %r2
|
||||
; nextln: flogr %r0, %r2
|
||||
; nextln: locghie %r0, -1
|
||||
; nextln: lghi %r2, 63
|
||||
; nextln: sgr %r2, %r0
|
||||
; nextln: br %r14
|
||||
|
||||
function %ctz_i32(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = ctz v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: oihl %r2, 1
|
||||
; nextln: lcgr %r3, %r2
|
||||
; nextln: ngrk %r2, %r3, %r2
|
||||
; nextln: flogr %r0, %r2
|
||||
; nextln: lhi %r2, 63
|
||||
; nextln: sr %r2, %r0
|
||||
; nextln: br %r14
|
||||
|
||||
function %ctz_i16(i16) -> i16 {
|
||||
block0(v0: i16):
|
||||
v1 = ctz v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: oilh %r2, 1
|
||||
; nextln: lcgr %r3, %r2
|
||||
; nextln: ngrk %r2, %r3, %r2
|
||||
; nextln: flogr %r0, %r2
|
||||
; nextln: lhi %r2, 63
|
||||
; nextln: sr %r2, %r0
|
||||
; nextln: br %r14
|
||||
|
||||
function %ctz_i8(i8) -> i8 {
|
||||
block0(v0: i8):
|
||||
v1 = ctz v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: oill %r2, 256
|
||||
; nextln: lcgr %r3, %r2
|
||||
; nextln: ngrk %r2, %r3, %r2
|
||||
; nextln: flogr %r0, %r2
|
||||
; nextln: lhi %r2, 63
|
||||
; nextln: sr %r2, %r0
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; POPCNT
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %popcnt_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = popcnt v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: popcnt %r2, %r2, 8
|
||||
; nextln: br %r14
|
||||
|
||||
function %popcnt_i32(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = popcnt v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llgfr %r2, %r2
|
||||
; nextln: popcnt %r2, %r2, 8
|
||||
; nextln: br %r14
|
||||
|
||||
function %popcnt_i16(i16) -> i16 {
|
||||
block0(v0: i16):
|
||||
v1 = popcnt v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llghr %r2, %r2
|
||||
; nextln: popcnt %r2, %r2, 8
|
||||
; nextln: br %r14
|
||||
|
||||
function %popcnt_i8(i8) -> i8 {
|
||||
block0(v0: i8):
|
||||
v1 = popcnt v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: popcnt %r2, %r2
|
||||
; nextln: br %r14
|
||||
490
cranelift/filetests/filetests/isa/s390x/bitwise.clif
Normal file
490
cranelift/filetests/filetests/isa/s390x/bitwise.clif
Normal file
@@ -0,0 +1,490 @@
|
||||
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
; FIXME: add immediate operand versions
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; BAND
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %band_i64(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = band.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: ngr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %band_i64_mem(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = load.i64 v1
|
||||
v3 = band.i64 v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: ng %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %band_i32(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = band.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: nr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %band_i32_mem(i32, i64) -> i32 {
|
||||
block0(v0: i32, v1: i64):
|
||||
v2 = load.i32 v1
|
||||
v3 = band.i32 v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: n %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %band_i32_memoff(i32, i64) -> i32 {
|
||||
block0(v0: i32, v1: i64):
|
||||
v2 = load.i32 v1+4096
|
||||
v3 = band.i32 v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: ny %r2, 4096(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %band_i16(i16, i16) -> i16 {
|
||||
block0(v0: i16, v1: i16):
|
||||
v2 = band.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: nr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %band_i16_mem(i16, i64) -> i16 {
|
||||
block0(v0: i16, v1: i64):
|
||||
v2 = load.i16 v1
|
||||
v3 = band.i16 v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: llh %r3, 0(%r3)
|
||||
; nextln: nr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %band_i8(i8, i8) -> i8 {
|
||||
block0(v0: i8, v1: i8):
|
||||
v2 = band.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: nr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %band_i8_mem(i8, i64) -> i8 {
|
||||
block0(v0: i8, v1: i64):
|
||||
v2 = load.i8 v1
|
||||
v3 = band.i8 v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: llc %r3, 0(%r3)
|
||||
; nextln: nr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; BOR
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %bor_i64(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = bor.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: ogr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bor_i64_mem(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = load.i64 v1
|
||||
v3 = bor.i64 v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: og %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %bor_i32(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = bor.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: or %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bor_i32_mem(i32, i64) -> i32 {
|
||||
block0(v0: i32, v1: i64):
|
||||
v2 = load.i32 v1
|
||||
v3 = bor.i32 v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: o %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %bor_i32_memoff(i32, i64) -> i32 {
|
||||
block0(v0: i32, v1: i64):
|
||||
v2 = load.i32 v1+4096
|
||||
v3 = bor.i32 v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: oy %r2, 4096(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %bor_i16(i16, i16) -> i16 {
|
||||
block0(v0: i16, v1: i16):
|
||||
v2 = bor.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: or %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bor_i16_mem(i16, i64) -> i16 {
|
||||
block0(v0: i16, v1: i64):
|
||||
v2 = load.i16 v1
|
||||
v3 = bor.i16 v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: llh %r3, 0(%r3)
|
||||
; nextln: or %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bor_i8(i8, i8) -> i8 {
|
||||
block0(v0: i8, v1: i8):
|
||||
v2 = bor.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: or %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bor_i8_mem(i8, i64) -> i8 {
|
||||
block0(v0: i8, v1: i64):
|
||||
v2 = load.i8 v1
|
||||
v3 = bor.i8 v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: llc %r3, 0(%r3)
|
||||
; nextln: or %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; BXOR
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %bxor_i64(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = bxor.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: xgr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bxor_i64_mem(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = load.i64 v1
|
||||
v3 = bxor.i64 v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: xg %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %bxor_i32(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = bxor.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: xr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bxor_i32_mem(i32, i64) -> i32 {
|
||||
block0(v0: i32, v1: i64):
|
||||
v2 = load.i32 v1
|
||||
v3 = bxor.i32 v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: x %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %bxor_i32_memoff(i32, i64) -> i32 {
|
||||
block0(v0: i32, v1: i64):
|
||||
v2 = load.i32 v1+4096
|
||||
v3 = bxor.i32 v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: xy %r2, 4096(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %bxor_i16(i16, i16) -> i16 {
|
||||
block0(v0: i16, v1: i16):
|
||||
v2 = bxor.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: xr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bxor_i16_mem(i16, i64) -> i16 {
|
||||
block0(v0: i16, v1: i64):
|
||||
v2 = load.i16 v1
|
||||
v3 = bxor.i16 v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: llh %r3, 0(%r3)
|
||||
; nextln: xr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bxor_i8(i8, i8) -> i8 {
|
||||
block0(v0: i8, v1: i8):
|
||||
v2 = bxor.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: xr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bxor_i8_mem(i8, i64) -> i8 {
|
||||
block0(v0: i8, v1: i64):
|
||||
v2 = load.i8 v1
|
||||
v3 = bxor.i8 v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: llc %r3, 0(%r3)
|
||||
; nextln: xr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; BAND_NOT
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %band_not_i64(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = band_not.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: nngrk %r2, %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %band_not_i32(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = band_not.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: nnrk %r2, %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %band_not_i16(i16, i16) -> i16 {
|
||||
block0(v0: i16, v1: i16):
|
||||
v2 = band_not.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: nnrk %r2, %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %band_not_i8(i8, i8) -> i8 {
|
||||
block0(v0: i8, v1: i8):
|
||||
v2 = band_not.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: nnrk %r2, %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; BOR_NOT
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %bor_not_i64(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = bor_not.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: nogrk %r2, %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bor_not_i32(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = bor_not.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: nork %r2, %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bor_not_i16(i16, i16) -> i16 {
|
||||
block0(v0: i16, v1: i16):
|
||||
v2 = bor_not.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: nork %r2, %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bor_not_i8(i8, i8) -> i8 {
|
||||
block0(v0: i8, v1: i8):
|
||||
v2 = bor_not.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: nork %r2, %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; BXOR_NOT
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %bxor_not_i64(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = bxor_not.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: nxgrk %r2, %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bxor_not_i32(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = bxor_not.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: nxrk %r2, %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bxor_not_i16(i16, i16) -> i16 {
|
||||
block0(v0: i16, v1: i16):
|
||||
v2 = bxor_not.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: nxrk %r2, %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bxor_not_i8(i8, i8) -> i8 {
|
||||
block0(v0: i8, v1: i8):
|
||||
v2 = bxor_not.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: nxrk %r2, %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; BNOT
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %bnot_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = bnot.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nogrk %r2, %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %bnot_i32(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = bnot.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nork %r2, %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %bnot_i16(i16) -> i16 {
|
||||
block0(v0: i16):
|
||||
v1 = bnot.i16 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nork %r2, %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %bnot_i8(i8) -> i8 {
|
||||
block0(v0: i8):
|
||||
v1 = bnot.i8 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nork %r2, %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; BITSELECT
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %bitselect_i64(i64, i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64, v2: i64):
|
||||
v3 = bitselect.i64 v0, v1, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: ngr %r3, %r2
|
||||
; nextln: nngrk %r2, %r4, %r2
|
||||
; nextln: ogr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bitselect_i32(i32, i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32, v2: i32):
|
||||
v3 = bitselect.i32 v0, v1, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: nr %r3, %r2
|
||||
; nextln: nnrk %r2, %r4, %r2
|
||||
; nextln: or %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bitselect_i16(i16, i16, i16) -> i16 {
|
||||
block0(v0: i16, v1: i16, v2: i16):
|
||||
v3 = bitselect.i16 v0, v1, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: nr %r3, %r2
|
||||
; nextln: nnrk %r2, %r4, %r2
|
||||
; nextln: or %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bitselect_i8(i8, i8, i8) -> i8 {
|
||||
block0(v0: i8, v1: i8, v2: i8):
|
||||
v3 = bitselect.i8 v0, v1, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: nr %r3, %r2
|
||||
; nextln: nnrk %r2, %r4, %r2
|
||||
; nextln: or %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
113
cranelift/filetests/filetests/isa/s390x/call.clif
Normal file
113
cranelift/filetests/filetests/isa/s390x/call.clif
Normal file
@@ -0,0 +1,113 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; CALL
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %call(i64) -> i64 {
|
||||
fn0 = %g(i64) -> i64
|
||||
|
||||
block0(v0: i64):
|
||||
v1 = call fn0(v0)
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: stmg %r14, %r15, 112(%r15)
|
||||
; nextln: aghi %r15, -160
|
||||
; nextln: virtual_sp_offset_adjust 160
|
||||
; nextln: bras %r1, 12 ; data %g + 0 ; lg %r3, 0(%r1)
|
||||
; nextln: basr %r14, %r3
|
||||
; nextln: lmg %r14, %r15, 272(%r15)
|
||||
; nextln: br %r14
|
||||
|
||||
function %call_uext(i32) -> i64 {
|
||||
fn0 = %g(i32 uext) -> i64
|
||||
|
||||
block0(v0: i32):
|
||||
v1 = call fn0(v0)
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: stmg %r14, %r15, 112(%r15)
|
||||
; nextln: aghi %r15, -160
|
||||
; nextln: virtual_sp_offset_adjust 160
|
||||
; nextln: llgfr %r2, %r2
|
||||
; nextln: bras %r1, 12 ; data %g + 0 ; lg %r3, 0(%r1)
|
||||
; nextln: basr %r14, %r3
|
||||
; nextln: lmg %r14, %r15, 272(%r15)
|
||||
; nextln: br %r14
|
||||
|
||||
function %ret_uext(i32) -> i32 uext {
|
||||
block0(v0: i32):
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: llgfr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %call_uext(i32) -> i64 {
|
||||
fn0 = %g(i32 sext) -> i64
|
||||
|
||||
block0(v0: i32):
|
||||
v1 = call fn0(v0)
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: stmg %r14, %r15, 112(%r15)
|
||||
; nextln: aghi %r15, -160
|
||||
; nextln: virtual_sp_offset_adjust 160
|
||||
; nextln: lgfr %r2, %r2
|
||||
; nextln: bras %r1, 12 ; data %g + 0 ; lg %r3, 0(%r1)
|
||||
; nextln: basr %r14, %r3
|
||||
; nextln: lmg %r14, %r15, 272(%r15)
|
||||
; nextln: br %r14
|
||||
|
||||
function %ret_uext(i32) -> i32 sext {
|
||||
block0(v0: i32):
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: lgfr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %call_colocated(i64) -> i64 {
|
||||
fn0 = colocated %g(i64) -> i64
|
||||
|
||||
block0(v0: i64):
|
||||
v1 = call fn0(v0)
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: stmg %r14, %r15, 112(%r15)
|
||||
; nextln: aghi %r15, -160
|
||||
; nextln: virtual_sp_offset_adjust 160
|
||||
; nextln: brasl %r14, %g
|
||||
; nextln: lmg %r14, %r15, 272(%r15)
|
||||
; nextln: br %r14
|
||||
|
||||
function %f2(i32) -> i64 {
|
||||
fn0 = %g(i32 uext) -> i64
|
||||
|
||||
block0(v0: i32):
|
||||
v1 = call fn0(v0)
|
||||
return v1
|
||||
}
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; CALL_INDIRECT
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %call_indirect(i64, i64) -> i64 {
|
||||
sig0 = (i64) -> i64
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = call_indirect.i64 sig0, v1(v0)
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: stmg %r14, %r15, 112(%r15)
|
||||
; nextln: aghi %r15, -160
|
||||
; nextln: virtual_sp_offset_adjust 160
|
||||
; nextln: basr %r14, %r3
|
||||
; nextln: lmg %r14, %r15, 272(%r15)
|
||||
; nextln: br %r14
|
||||
62
cranelift/filetests/filetests/isa/s390x/condbr.clif
Normal file
62
cranelift/filetests/filetests/isa/s390x/condbr.clif
Normal file
@@ -0,0 +1,62 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
function %f(i64, i64) -> b1 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = icmp eq v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: clgr %r2, %r3
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochie %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %f(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = icmp eq v0, v1
|
||||
brnz v2, block1
|
||||
jump block2
|
||||
|
||||
block1:
|
||||
v4 = iconst.i64 1
|
||||
return v4
|
||||
|
||||
block2:
|
||||
v5 = iconst.i64 2
|
||||
return v5
|
||||
}
|
||||
|
||||
; check: Block 0:
|
||||
; check: clgr %r2, %r3
|
||||
; nextln: jge label1 ; jg label2
|
||||
; check: Block 1:
|
||||
; check: lghi %r2, 1
|
||||
; nextln: br %r14
|
||||
; check: Block 2:
|
||||
; check: lghi %r2, 2
|
||||
; nextln: br %r14
|
||||
|
||||
function %f(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = icmp eq v0, v1
|
||||
brnz v2, block1
|
||||
jump block1
|
||||
|
||||
block1:
|
||||
v4 = iconst.i64 1
|
||||
return v4
|
||||
}
|
||||
|
||||
; FIXME: Should optimize away branches
|
||||
|
||||
; check: Block 0:
|
||||
; check: clgr %r2, %r3
|
||||
; nextln: jge label1 ; jg label2
|
||||
; check: Block 1:
|
||||
; check: jg label3
|
||||
; check: Block 2:
|
||||
; check: jg label3
|
||||
; check: Block 3:
|
||||
; check: lghi %r2, 1
|
||||
; nextln: br %r14
|
||||
43
cranelift/filetests/filetests/isa/s390x/condops.clif
Normal file
43
cranelift/filetests/filetests/isa/s390x/condops.clif
Normal file
@@ -0,0 +1,43 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
function %f(i8, i64, i64) -> i64 {
|
||||
block0(v0: i8, v1: i64, v2: i64):
|
||||
v3 = iconst.i8 42
|
||||
v4 = icmp eq v0, v3
|
||||
v5 = select.i64 v4, v1, v2
|
||||
return v5
|
||||
}
|
||||
|
||||
; check: llcr %r2, %r2
|
||||
; nextln: clfi %r2, 42
|
||||
; nextln: locgre %r4, %r3
|
||||
; nextln: lgr %r2, %r4
|
||||
; nextln: br %r14
|
||||
|
||||
function %g(b1, i8, i8) -> i8 {
|
||||
block0(v0: b1, v1: i8, v2: i8):
|
||||
v3 = select.i8 v0, v1, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; FIXME: optimize i8/i16 compares
|
||||
|
||||
; check: llcr %r2, %r2
|
||||
; nextln: chi %r2, 0
|
||||
; nextln: locrlh %r4, %r3
|
||||
; nextln: lr %r2, %r4
|
||||
; nextln: br %r14
|
||||
|
||||
function %i(i32, i8, i8) -> i8 {
|
||||
block0(v0: i32, v1: i8, v2: i8):
|
||||
v3 = iconst.i32 42
|
||||
v4 = icmp.i32 eq v0, v3
|
||||
v5 = select.i8 v4, v1, v2
|
||||
return v5
|
||||
}
|
||||
|
||||
; check: clfi %r2, 42
|
||||
; nextln: locre %r4, %r3
|
||||
; nextln: lr %r2, %r4
|
||||
; nextln: br %r14
|
||||
113
cranelift/filetests/filetests/isa/s390x/constants.clif
Normal file
113
cranelift/filetests/filetests/isa/s390x/constants.clif
Normal file
@@ -0,0 +1,113 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
function %f() -> b8 {
|
||||
block0:
|
||||
v0 = bconst.b8 true
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: lhi %r2, 255
|
||||
; nextln: br %r14
|
||||
|
||||
function %f() -> b16 {
|
||||
block0:
|
||||
v0 = bconst.b16 false
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: lhi %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %f() -> i64 {
|
||||
block0:
|
||||
v0 = iconst.i64 0
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: lghi %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %f() -> i64 {
|
||||
block0:
|
||||
v0 = iconst.i64 0xffff
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: lgfi %r2, 65535
|
||||
; nextln: br %r14
|
||||
|
||||
function %f() -> i64 {
|
||||
block0:
|
||||
v0 = iconst.i64 0xffff0000
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: llilh %r2, 65535
|
||||
; nextln: br %r14
|
||||
|
||||
function %f() -> i64 {
|
||||
block0:
|
||||
v0 = iconst.i64 0xffff00000000
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: llihl %r2, 65535
|
||||
; nextln: br %r14
|
||||
|
||||
function %f() -> i64 {
|
||||
block0:
|
||||
v0 = iconst.i64 0xffff000000000000
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: llihh %r2, 65535
|
||||
; nextln: br %r14
|
||||
|
||||
function %f() -> i64 {
|
||||
block0:
|
||||
v0 = iconst.i64 0xffffffffffffffff
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: lghi %r2, -1
|
||||
; nextln: br %r14
|
||||
|
||||
function %f() -> i64 {
|
||||
block0:
|
||||
v0 = iconst.i64 0xffffffffffff0000
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: lgfi %r2, -65536
|
||||
; nextln: br %r14
|
||||
|
||||
function %f() -> i64 {
|
||||
block0:
|
||||
v0 = iconst.i64 0xf34bf0a31212003a ; random digits
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: llihf %r2, 4081840291
|
||||
; nextln: iilf %r2, 303169594
|
||||
; nextln: br %r14
|
||||
|
||||
function %f() -> i64 {
|
||||
block0:
|
||||
v0 = iconst.i64 0x12e900001ef40000 ; random digits with 2 clear half words
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: llihh %r2, 4841
|
||||
; nextln: iilh %r2, 7924
|
||||
; nextln: br %r14
|
||||
|
||||
function %f() -> i32 {
|
||||
block0:
|
||||
v0 = iconst.i32 -1
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: lhi %r2, -1
|
||||
; nextln: br %r14
|
||||
|
||||
748
cranelift/filetests/filetests/isa/s390x/conversions.clif
Normal file
748
cranelift/filetests/filetests/isa/s390x/conversions.clif
Normal file
@@ -0,0 +1,748 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; UEXTEND
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %uextend_i32_i64(i32) -> i64 {
|
||||
block0(v0: i32):
|
||||
v1 = uextend.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llgfr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %uextend_i16_i64(i16) -> i64 {
|
||||
block0(v0: i16):
|
||||
v1 = uextend.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llghr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %uextend_i16_i32(i16) -> i32 {
|
||||
block0(v0: i16):
|
||||
v1 = uextend.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llhr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %uextend_i8_i64(i8) -> i64 {
|
||||
block0(v0: i8):
|
||||
v1 = uextend.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llgcr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %uextend_i8_i32(i8) -> i32 {
|
||||
block0(v0: i8):
|
||||
v1 = uextend.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llcr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %uextend_i8_i16(i8) -> i16 {
|
||||
block0(v0: i8):
|
||||
v1 = uextend.i16 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llcr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; SEXTEND
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %sextend_i32_i64(i32) -> i64 {
|
||||
block0(v0: i32):
|
||||
v1 = sextend.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lgfr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %sextend_i16_i64(i16) -> i64 {
|
||||
block0(v0: i16):
|
||||
v1 = sextend.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lghr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %sextend_i16_i32(i16) -> i32 {
|
||||
block0(v0: i16):
|
||||
v1 = sextend.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lhr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %sextend_i8_i64(i8) -> i64 {
|
||||
block0(v0: i8):
|
||||
v1 = sextend.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lgbr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %sextend_i8_i32(i8) -> i32 {
|
||||
block0(v0: i8):
|
||||
v1 = sextend.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lbr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %sextend_i8_i16(i8) -> i16 {
|
||||
block0(v0: i8):
|
||||
v1 = sextend.i16 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lbr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; IREDUCE
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %ireduce_i64_i32(i64, i64) -> i32 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = ireduce.i32 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %ireduce_i64_i16(i64, i64) -> i16 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = ireduce.i16 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %ireduce_i64_i8(i64, i64) -> i8 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = ireduce.i8 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %ireduce_i32_i16(i32, i32) -> i16 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = ireduce.i16 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %ireduce_i32_i8(i32, i32) -> i8 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = ireduce.i8 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %ireduce_i16_i8(i16, i16) -> i8 {
|
||||
block0(v0: i16, v1: i16):
|
||||
v2 = ireduce.i8 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; BEXTEND
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %bextend_b32_b64(b32) -> b64 {
|
||||
block0(v0: b32):
|
||||
v1 = bextend.b64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lgfr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %bextend_b16_b64(b16) -> b64 {
|
||||
block0(v0: b16):
|
||||
v1 = bextend.b64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lghr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %bextend_b16_b32(b16) -> b32 {
|
||||
block0(v0: b16):
|
||||
v1 = bextend.b32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lhr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %bextend_b8_b64(b8) -> b64 {
|
||||
block0(v0: b8):
|
||||
v1 = bextend.b64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lgbr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %bextend_b8_b32(b8) -> b32 {
|
||||
block0(v0: b8):
|
||||
v1 = bextend.b32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lbr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %bextend_b8_b16(b8) -> b16 {
|
||||
block0(v0: b8):
|
||||
v1 = bextend.b16 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lbr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %bextend_b1_b64(b1) -> b64 {
|
||||
block0(v0: b1):
|
||||
v1 = bextend.b64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: sllg %r2, %r2, 63
|
||||
; nextln: srag %r2, %r2, 63
|
||||
; nextln: br %r14
|
||||
|
||||
function %bextend_b1_b32(b1) -> b32 {
|
||||
block0(v0: b1):
|
||||
v1 = bextend.b32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: sllk %r2, %r2, 31
|
||||
; nextln: srak %r2, %r2, 31
|
||||
; nextln: br %r14
|
||||
|
||||
function %bextend_b1_b16(b1) -> b16 {
|
||||
block0(v0: b1):
|
||||
v1 = bextend.b16 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: sllk %r2, %r2, 31
|
||||
; nextln: srak %r2, %r2, 31
|
||||
; nextln: br %r14
|
||||
|
||||
function %bextend_b1_b8(b1) -> b8 {
|
||||
block0(v0: b1):
|
||||
v1 = bextend.b8 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: sllk %r2, %r2, 31
|
||||
; nextln: srak %r2, %r2, 31
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; BREDUCE
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %breduce_b64_b32(b64, b64) -> b32 {
|
||||
block0(v0: b64, v1: b64):
|
||||
v2 = breduce.b32 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %breduce_b64_b16(b64, b64) -> b16 {
|
||||
block0(v0: b64, v1: b64):
|
||||
v2 = breduce.b16 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %breduce_b64_b8(b64, b64) -> b8 {
|
||||
block0(v0: b64, v1: b64):
|
||||
v2 = breduce.b8 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %breduce_b64_b1(b64, b64) -> b1 {
|
||||
block0(v0: b64, v1: b64):
|
||||
v2 = breduce.b1 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %breduce_b32_b16(b32, b32) -> b16 {
|
||||
block0(v0: b32, v1: b32):
|
||||
v2 = breduce.b16 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %breduce_b32_b8(b32, b32) -> b8 {
|
||||
block0(v0: b32, v1: b32):
|
||||
v2 = breduce.b8 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %breduce_b32_b1(b32, b32) -> b1 {
|
||||
block0(v0: b32, v1: b32):
|
||||
v2 = breduce.b1 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %breduce_b16_b8(b16, b16) -> b8 {
|
||||
block0(v0: b16, v1: b16):
|
||||
v2 = breduce.b8 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %breduce_b16_b1(b16, b16) -> b1 {
|
||||
block0(v0: b16, v1: b16):
|
||||
v2 = breduce.b1 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %breduce_b8_b1(b8, b8) -> b1 {
|
||||
block0(v0: b8, v1: b8):
|
||||
v2 = breduce.b1 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; BMASK
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %bmask_b64_i64(b64, b64) -> i64 {
|
||||
block0(v0: b64, v1: b64):
|
||||
v2 = bmask.i64 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lgr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b64_i32(b64, b64) -> i32 {
|
||||
block0(v0: b64, v1: b64):
|
||||
v2 = bmask.i32 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b64_i16(b64, b64) -> i16 {
|
||||
block0(v0: b64, v1: b64):
|
||||
v2 = bmask.i16 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b64_i8(b64, b64) -> i8 {
|
||||
block0(v0: b64, v1: b64):
|
||||
v2 = bmask.i8 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b32_i64(b32, b32) -> i64 {
|
||||
block0(v0: b32, v1: b32):
|
||||
v2 = bmask.i64 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lgfr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b32_i32(b32, b32) -> i32 {
|
||||
block0(v0: b32, v1: b32):
|
||||
v2 = bmask.i32 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b32_i16(b32, b32) -> i16 {
|
||||
block0(v0: b32, v1: b32):
|
||||
v2 = bmask.i16 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b32_i8(b32, b32) -> i8 {
|
||||
block0(v0: b32, v1: b32):
|
||||
v2 = bmask.i8 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b16_i64(b16, b16) -> i64 {
|
||||
block0(v0: b16, v1: b16):
|
||||
v2 = bmask.i64 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lghr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b16_i32(b16, b16) -> i32 {
|
||||
block0(v0: b16, v1: b16):
|
||||
v2 = bmask.i32 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lhr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b16_i16(b16, b16) -> i16 {
|
||||
block0(v0: b16, v1: b16):
|
||||
v2 = bmask.i16 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b16_i8(b16, b16) -> i8 {
|
||||
block0(v0: b16, v1: b16):
|
||||
v2 = bmask.i8 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b8_i64(b8, b8) -> i64 {
|
||||
block0(v0: b8, v1: b8):
|
||||
v2 = bmask.i64 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lgbr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b8_i32(b8, b8) -> i32 {
|
||||
block0(v0: b8, v1: b8):
|
||||
v2 = bmask.i32 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lbr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b8_i16(b8, b8) -> i16 {
|
||||
block0(v0: b8, v1: b8):
|
||||
v2 = bmask.i16 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lbr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b8_i8(b8, b8) -> i8 {
|
||||
block0(v0: b8, v1: b8):
|
||||
v2 = bmask.i8 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b1_i64(b1, b1) -> i64 {
|
||||
block0(v0: b1, v1: b1):
|
||||
v2 = bmask.i64 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: sllg %r2, %r3, 63
|
||||
; nextln: srag %r2, %r2, 63
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b1_i32(b1, b1) -> i32 {
|
||||
block0(v0: b1, v1: b1):
|
||||
v2 = bmask.i32 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: sllk %r2, %r3, 31
|
||||
; nextln: srak %r2, %r2, 31
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b1_i16(b1, b1) -> i16 {
|
||||
block0(v0: b1, v1: b1):
|
||||
v2 = bmask.i16 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: sllk %r2, %r3, 31
|
||||
; nextln: srak %r2, %r2, 31
|
||||
; nextln: br %r14
|
||||
|
||||
function %bmask_b1_i8(b1, b1) -> i8 {
|
||||
block0(v0: b1, v1: b1):
|
||||
v2 = bmask.i8 v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: sllk %r2, %r3, 31
|
||||
; nextln: srak %r2, %r2, 31
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; BINT
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %bint_b64_i64(b64) -> i64 {
|
||||
block0(v0: b64):
|
||||
v1 = bint.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lghi %r3, 1
|
||||
; nextln: ngr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b64_i32(b64) -> i32 {
|
||||
block0(v0: b64):
|
||||
v1 = bint.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nilf %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b64_i16(b64) -> i16 {
|
||||
block0(v0: b64):
|
||||
v1 = bint.i16 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nill %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b64_i8(b64) -> i8 {
|
||||
block0(v0: b64):
|
||||
v1 = bint.i8 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nill %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b32_i64(b32) -> i64 {
|
||||
block0(v0: b32):
|
||||
v1 = bint.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lghi %r3, 1
|
||||
; nextln: ngr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b32_i32(b32) -> i32 {
|
||||
block0(v0: b32):
|
||||
v1 = bint.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nilf %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b32_i16(b32) -> i16 {
|
||||
block0(v0: b32):
|
||||
v1 = bint.i16 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nill %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b32_i8(b32) -> i8 {
|
||||
block0(v0: b32):
|
||||
v1 = bint.i8 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nill %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b16_i64(b16) -> i64 {
|
||||
block0(v0: b16):
|
||||
v1 = bint.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lghi %r3, 1
|
||||
; nextln: ngr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b16_i32(b16) -> i32 {
|
||||
block0(v0: b16):
|
||||
v1 = bint.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nilf %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b16_i16(b16) -> i16 {
|
||||
block0(v0: b16):
|
||||
v1 = bint.i16 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nill %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b16_i8(b16) -> i8 {
|
||||
block0(v0: b16):
|
||||
v1 = bint.i8 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nill %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b8_i64(b8) -> i64 {
|
||||
block0(v0: b8):
|
||||
v1 = bint.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lghi %r3, 1
|
||||
; nextln: ngr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b8_i32(b8) -> i32 {
|
||||
block0(v0: b8):
|
||||
v1 = bint.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nilf %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b8_i16(b8) -> i16 {
|
||||
block0(v0: b8):
|
||||
v1 = bint.i16 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nill %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b8_i8(b8) -> i8 {
|
||||
block0(v0: b8):
|
||||
v1 = bint.i8 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nill %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b1_i64(b1) -> i64 {
|
||||
block0(v0: b1):
|
||||
v1 = bint.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lghi %r3, 1
|
||||
; nextln: ngr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b1_i32(b1) -> i32 {
|
||||
block0(v0: b1):
|
||||
v1 = bint.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nilf %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b1_i16(b1) -> i16 {
|
||||
block0(v0: b1):
|
||||
v1 = bint.i16 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nill %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %bint_b1_i8(b1) -> i8 {
|
||||
block0(v0: b1):
|
||||
v1 = bint.i8 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: nill %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
355
cranelift/filetests/filetests/isa/s390x/div-traps.clif
Normal file
355
cranelift/filetests/filetests/isa/s390x/div-traps.clif
Normal file
@@ -0,0 +1,355 @@
|
||||
test compile
|
||||
set avoid_div_traps=1
|
||||
target s390x
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; SDIV
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %sdiv_i64(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = sdiv.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lgr %r1, %r2
|
||||
; nextln: cgite %r3, 0
|
||||
; nextln: llihf %r2, 2147483647
|
||||
; nextln: iilf %r2, 4294967295
|
||||
; nextln: xgr %r2, %r1
|
||||
; nextln: ngr %r2, %r3
|
||||
; nextln: cgite %r2, -1
|
||||
; nextln: dsgr %r0, %r3
|
||||
; nextln: lgr %r2, %r1
|
||||
; nextln: br %r14
|
||||
|
||||
function %sdiv_i64_imm(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 2
|
||||
v2 = sdiv.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lgr %r1, %r2
|
||||
; nextln: lghi %r2, 2
|
||||
; nextln: dsgr %r0, %r2
|
||||
; nextln: lgr %r2, %r1
|
||||
; nextln: br %r14
|
||||
|
||||
function %sdiv_i32(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = sdiv.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lgfr %r1, %r2
|
||||
; nextln: cite %r3, 0
|
||||
; nextln: iilf %r2, 2147483647
|
||||
; nextln: xr %r2, %r1
|
||||
; nextln: nr %r2, %r3
|
||||
; nextln: cite %r2, -1
|
||||
; nextln: dsgfr %r0, %r3
|
||||
; nextln: lr %r2, %r1
|
||||
; nextln: br %r14
|
||||
|
||||
function %sdiv_i32_imm(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 2
|
||||
v2 = sdiv.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lgfr %r1, %r2
|
||||
; nextln: lhi %r2, 2
|
||||
; nextln: dsgfr %r0, %r2
|
||||
; nextln: lr %r2, %r1
|
||||
; nextln: br %r14
|
||||
|
||||
function %sdiv_i16(i16, i16) -> i16 {
|
||||
block0(v0: i16, v1: i16):
|
||||
v2 = sdiv.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lghr %r1, %r2
|
||||
; nextln: lhr %r2, %r3
|
||||
; nextln: cite %r2, 0
|
||||
; nextln: lhi %r3, 32767
|
||||
; nextln: xr %r3, %r1
|
||||
; nextln: nr %r3, %r2
|
||||
; nextln: cite %r3, -1
|
||||
; nextln: dsgfr %r0, %r2
|
||||
; nextln: lr %r2, %r1
|
||||
; nextln: br %r14
|
||||
|
||||
function %sdiv_i16_imm(i16) -> i16 {
|
||||
block0(v0: i16):
|
||||
v1 = iconst.i16 2
|
||||
v2 = sdiv.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lghr %r1, %r2
|
||||
; nextln: lhi %r2, 2
|
||||
; nextln: dsgfr %r0, %r2
|
||||
; nextln: lr %r2, %r1
|
||||
; nextln: br %r14
|
||||
|
||||
function %sdiv_i8(i8, i8) -> i8 {
|
||||
block0(v0: i8, v1: i8):
|
||||
v2 = sdiv.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lgbr %r1, %r2
|
||||
; nextln: lbr %r2, %r3
|
||||
; nextln: cite %r2, 0
|
||||
; nextln: lhi %r3, 127
|
||||
; nextln: xr %r3, %r1
|
||||
; nextln: nr %r3, %r2
|
||||
; nextln: cite %r3, -1
|
||||
; nextln: dsgfr %r0, %r2
|
||||
; nextln: lr %r2, %r1
|
||||
; nextln: br %r14
|
||||
|
||||
function %sdiv_i8_imm(i8) -> i8 {
|
||||
block0(v0: i8):
|
||||
v1 = iconst.i8 2
|
||||
v2 = sdiv.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lgbr %r1, %r2
|
||||
; nextln: lhi %r2, 2
|
||||
; nextln: dsgfr %r0, %r2
|
||||
; nextln: lr %r2, %r1
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; UDIV
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %udiv_i64(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = udiv.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lghi %r0, 0
|
||||
; nextln: lgr %r1, %r2
|
||||
; nextln: cgite %r3, 0
|
||||
; nextln: dlgr %r0, %r3
|
||||
; nextln: lgr %r2, %r1
|
||||
; nextln: br %r14
|
||||
|
||||
function %udiv_i64_imm(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 2
|
||||
v2 = udiv.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lghi %r0, 0
|
||||
; nextln: lgr %r1, %r2
|
||||
; nextln: lghi %r2, 2
|
||||
; nextln: dlgr %r0, %r2
|
||||
; nextln: lgr %r2, %r1
|
||||
; nextln: br %r14
|
||||
|
||||
function %udiv_i32(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = udiv.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lhi %r0, 0
|
||||
; nextln: lr %r1, %r2
|
||||
; nextln: cite %r3, 0
|
||||
; nextln: dlr %r0, %r3
|
||||
; nextln: lr %r2, %r1
|
||||
; nextln: br %r14
|
||||
|
||||
function %udiv_i32_imm(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 2
|
||||
v2 = udiv.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lhi %r0, 0
|
||||
; nextln: lr %r1, %r2
|
||||
; nextln: lhi %r2, 2
|
||||
; nextln: dlr %r0, %r2
|
||||
; nextln: lr %r2, %r1
|
||||
; nextln: br %r14
|
||||
|
||||
function %udiv_i16(i16, i16) -> i16 {
|
||||
block0(v0: i16, v1: i16):
|
||||
v2 = udiv.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lhi %r0, 0
|
||||
; nextln: llhr %r1, %r2
|
||||
; nextln: llhr %r2, %r3
|
||||
; nextln: cite %r2, 0
|
||||
; nextln: dlr %r0, %r2
|
||||
; nextln: lr %r2, %r1
|
||||
; nextln: br %r14
|
||||
|
||||
function %udiv_i16_imm(i16) -> i16 {
|
||||
block0(v0: i16):
|
||||
v1 = iconst.i16 2
|
||||
v2 = udiv.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lhi %r0, 0
|
||||
; nextln: llhr %r1, %r2
|
||||
; nextln: lhi %r2, 2
|
||||
; nextln: dlr %r0, %r2
|
||||
; nextln: lr %r2, %r1
|
||||
; nextln: br %r14
|
||||
|
||||
function %udiv_i8(i8, i8) -> i8 {
|
||||
block0(v0: i8, v1: i8):
|
||||
v2 = udiv.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lhi %r0, 0
|
||||
; nextln: llcr %r1, %r2
|
||||
; nextln: llcr %r2, %r3
|
||||
; nextln: cite %r2, 0
|
||||
; nextln: dlr %r0, %r2
|
||||
; nextln: lr %r2, %r1
|
||||
; nextln: br %r14
|
||||
|
||||
function %udiv_i8_imm(i8) -> i8 {
|
||||
block0(v0: i8):
|
||||
v1 = iconst.i8 2
|
||||
v2 = udiv.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lhi %r0, 0
|
||||
; nextln: llcr %r1, %r2
|
||||
; nextln: lhi %r2, 2
|
||||
; nextln: dlr %r0, %r2
|
||||
; nextln: lr %r2, %r1
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; SREM
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %srem_i64(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = srem.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lgr %r1, %r2
|
||||
; nextln: cgite %r3, 0
|
||||
; nextln: cghi %r3, -1
|
||||
; nextln: locghie %r1, 0
|
||||
; nextln: dsgr %r0, %r3
|
||||
; nextln: lgr %r2, %r0
|
||||
; nextln: br %r14
|
||||
|
||||
function %srem_i32(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = srem.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lgfr %r1, %r2
|
||||
; nextln: cite %r3, 0
|
||||
; nextln: dsgfr %r0, %r3
|
||||
; nextln: lr %r2, %r0
|
||||
; nextln: br %r14
|
||||
|
||||
function %srem_i16(i16, i16) -> i16 {
|
||||
block0(v0: i16, v1: i16):
|
||||
v2 = srem.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lghr %r1, %r2
|
||||
; nextln: lhr %r2, %r3
|
||||
; nextln: cite %r2, 0
|
||||
; nextln: dsgfr %r0, %r2
|
||||
; nextln: lr %r2, %r0
|
||||
; nextln: br %r14
|
||||
|
||||
function %srem_i8(i8, i8) -> i8 {
|
||||
block0(v0: i8, v1: i8):
|
||||
v2 = srem.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lgbr %r1, %r2
|
||||
; nextln: lbr %r2, %r3
|
||||
; nextln: cite %r2, 0
|
||||
; nextln: dsgfr %r0, %r2
|
||||
; nextln: lr %r2, %r0
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; UREM
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %urem_i64(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = urem.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lghi %r0, 0
|
||||
; nextln: lgr %r1, %r2
|
||||
; nextln: cgite %r3, 0
|
||||
; nextln: dlgr %r0, %r3
|
||||
; nextln: lgr %r2, %r0
|
||||
; nextln: br %r14
|
||||
|
||||
function %urem_i32(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = urem.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lhi %r0, 0
|
||||
; nextln: lr %r1, %r2
|
||||
; nextln: cite %r3, 0
|
||||
; nextln: dlr %r0, %r3
|
||||
; nextln: lr %r2, %r0
|
||||
; nextln: br %r14
|
||||
|
||||
function %urem_i16(i16, i16) -> i16 {
|
||||
block0(v0: i16, v1: i16):
|
||||
v2 = urem.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lhi %r0, 0
|
||||
; nextln: llhr %r1, %r2
|
||||
; nextln: llhr %r2, %r3
|
||||
; nextln: cite %r2, 0
|
||||
; nextln: dlr %r0, %r2
|
||||
; nextln: lr %r2, %r0
|
||||
; nextln: br %r14
|
||||
|
||||
function %urem_i8(i8, i8) -> i8 {
|
||||
block0(v0: i8, v1: i8):
|
||||
v2 = urem.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lhi %r0, 0
|
||||
; nextln: llcr %r1, %r2
|
||||
; nextln: llcr %r2, %r3
|
||||
; nextln: cite %r2, 0
|
||||
; nextln: dlr %r0, %r2
|
||||
; nextln: lr %r2, %r0
|
||||
; nextln: br %r14
|
||||
|
||||
711
cranelift/filetests/filetests/isa/s390x/floating-point.clif
Normal file
711
cranelift/filetests/filetests/isa/s390x/floating-point.clif
Normal file
@@ -0,0 +1,711 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; F32CONST/F64CONST
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
; FIXME: should use FZERO instruction
|
||||
; FIXME: should use out-of-line literal pool
|
||||
|
||||
function %f32const_zero() -> f32 {
|
||||
block0:
|
||||
v1 = f32const 0x0.0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: bras %r1, 8 ; data.f32 0 ; le %f0, 0(%r1)
|
||||
; nextln: br %r14
|
||||
|
||||
function %f64const_zero() -> f64 {
|
||||
block0:
|
||||
v1 = f64const 0x0.0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: bras %r1, 12 ; data.f64 0 ; ld %f0, 0(%r1)
|
||||
; nextln: br %r14
|
||||
|
||||
function %f32const_one() -> f32 {
|
||||
block0:
|
||||
v1 = f32const 0x1.0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: bras %r1, 8 ; data.f32 1 ; le %f0, 0(%r1)
|
||||
; nextln: br %r14
|
||||
|
||||
function %f64const_one() -> f64 {
|
||||
block0:
|
||||
v1 = f64const 0x1.0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: bras %r1, 12 ; data.f64 1 ; ld %f0, 0(%r1)
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; FADD
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %fadd_f32(f32, f32) -> f32 {
|
||||
block0(v0: f32, v1: f32):
|
||||
v2 = fadd v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: aebr %f0, %f2
|
||||
; nextln: br %r14
|
||||
|
||||
function %fadd_f64(f64, f64) -> f64 {
|
||||
block0(v0: f64, v1: f64):
|
||||
v2 = fadd v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: adbr %f0, %f2
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; FSUB
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %fsub_f32(f32, f32) -> f32 {
|
||||
block0(v0: f32, v1: f32):
|
||||
v2 = fsub v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: sebr %f0, %f2
|
||||
; nextln: br %r14
|
||||
|
||||
function %fsub_f64(f64, f64) -> f64 {
|
||||
block0(v0: f64, v1: f64):
|
||||
v2 = fsub v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: sdbr %f0, %f2
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; FMUL
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %fmul_f32(f32, f32) -> f32 {
|
||||
block0(v0: f32, v1: f32):
|
||||
v2 = fmul v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: meebr %f0, %f2
|
||||
; nextln: br %r14
|
||||
|
||||
function %fmul_f64(f64, f64) -> f64 {
|
||||
block0(v0: f64, v1: f64):
|
||||
v2 = fmul v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: mdbr %f0, %f2
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; FDIV
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %fdiv_f32(f32, f32) -> f32 {
|
||||
block0(v0: f32, v1: f32):
|
||||
v2 = fdiv v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: debr %f0, %f2
|
||||
; nextln: br %r14
|
||||
|
||||
function %fdiv_f64(f64, f64) -> f64 {
|
||||
block0(v0: f64, v1: f64):
|
||||
v2 = fdiv v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: ddbr %f0, %f2
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; FMIN
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %fmin_f32(f32, f32) -> f32 {
|
||||
block0(v0: f32, v1: f32):
|
||||
v2 = fmin v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: wfminsb %f0, %f0, %f2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %fmin_f64(f64, f64) -> f64 {
|
||||
block0(v0: f64, v1: f64):
|
||||
v2 = fmin v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: wfmindb %f0, %f0, %f2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; FMAX
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %fmax_f32(f32, f32) -> f32 {
|
||||
block0(v0: f32, v1: f32):
|
||||
v2 = fmax v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: wfmaxsb %f0, %f0, %f2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %fmax_f64(f64, f64) -> f64 {
|
||||
block0(v0: f64, v1: f64):
|
||||
v2 = fmax v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: wfmaxdb %f0, %f0, %f2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; SQRT
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %sqrt_f32(f32) -> f32 {
|
||||
block0(v0: f32):
|
||||
v1 = sqrt v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: sqebr %f0, %f0
|
||||
; nextln: br %r14
|
||||
|
||||
function %sqrt_f64(f64) -> f64 {
|
||||
block0(v0: f64):
|
||||
v1 = sqrt v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: sqdbr %f0, %f0
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; FABS
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %fabs_f32(f32) -> f32 {
|
||||
block0(v0: f32):
|
||||
v1 = fabs v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lpebr %f0, %f0
|
||||
; nextln: br %r14
|
||||
|
||||
function %fabs_f64(f64) -> f64 {
|
||||
block0(v0: f64):
|
||||
v1 = fabs v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lpdbr %f0, %f0
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; FNEG
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %fneg_f32(f32) -> f32 {
|
||||
block0(v0: f32):
|
||||
v1 = fneg v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lcebr %f0, %f0
|
||||
; nextln: br %r14
|
||||
|
||||
function %fneg_f64(f64) -> f64 {
|
||||
block0(v0: f64):
|
||||
v1 = fneg v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lcdbr %f0, %f0
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; FPROMOTE/FDEMOTE
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %fpromote_f32(f32) -> f64 {
|
||||
block0(v0: f32):
|
||||
v1 = fpromote.f64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: ldebr %f0, %f0
|
||||
; nextln: br %r14
|
||||
|
||||
function %fdemote_f64(f64) -> f32 {
|
||||
block0(v0: f64):
|
||||
v1 = fdemote.f32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: ledbr %f0, %f0
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; CEIL
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %ceil_f32(f32) -> f32 {
|
||||
block0(v0: f32):
|
||||
v1 = ceil v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: fiebr %f0, %f0, 6
|
||||
; nextln: br %r14
|
||||
|
||||
function %ceil_f64(f64) -> f64 {
|
||||
block0(v0: f64):
|
||||
v1 = ceil v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: fidbr %f0, %f0, 6
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; FLOOR
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %floor_f32(f32) -> f32 {
|
||||
block0(v0: f32):
|
||||
v1 = floor v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: fiebr %f0, %f0, 7
|
||||
; nextln: br %r14
|
||||
|
||||
function %floor_f64(f64) -> f64 {
|
||||
block0(v0: f64):
|
||||
v1 = floor v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: fidbr %f0, %f0, 7
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; TRUNC
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %trunc_f32(f32) -> f32 {
|
||||
block0(v0: f32):
|
||||
v1 = trunc v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: fiebr %f0, %f0, 5
|
||||
; nextln: br %r14
|
||||
|
||||
function %trunc_f64(f64) -> f64 {
|
||||
block0(v0: f64):
|
||||
v1 = trunc v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: fidbr %f0, %f0, 5
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; NEAREST
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %nearest_f32(f32) -> f32 {
|
||||
block0(v0: f32):
|
||||
v1 = nearest v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: fiebr %f0, %f0, 4
|
||||
; nextln: br %r14
|
||||
|
||||
function %nearest_f64(f64) -> f64 {
|
||||
block0(v0: f64):
|
||||
v1 = nearest v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: fidbr %f0, %f0, 4
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; FMA
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %fma_f32(f32, f32, f32) -> f32 {
|
||||
block0(v0: f32, v1: f32, v2: f32):
|
||||
v3 = fma v0, v1, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; FIXME: regalloc
|
||||
|
||||
; check: maebr %f4, %f0, %f2
|
||||
; nextln: ler %f0, %f4
|
||||
; nextln: br %r14
|
||||
|
||||
function %fma_f64(f64, f64, f64) -> f64 {
|
||||
block0(v0: f64, v1: f64, v2: f64):
|
||||
v3 = fma v0, v1, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: madbr %f4, %f0, %f2
|
||||
; nextln: ldr %f0, %f4
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; FCOPYSIGN
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %fcopysign_f32(f32, f32) -> f32 {
|
||||
block0(v0: f32, v1: f32):
|
||||
v2 = fcopysign v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: cpsdr %f0, %f2, %f0
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcopysign_f64(f64, f64) -> f64 {
|
||||
block0(v0: f64, v1: f64):
|
||||
v2 = fcopysign v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: cpsdr %f0, %f2, %f0
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; FCVT_TO_UINT/FCVT_TO_SINT
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %fcvt_to_uint_f32_i32(f32) -> i32 {
|
||||
block0(v0: f32):
|
||||
v1 = fcvt_to_uint.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cebr %f0, %f0
|
||||
; nextln: jno 6 ; trap
|
||||
; nextln: clfebr %r2, 5, %f0, 0
|
||||
; nextln: jno 6 ; trap
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_to_sint_f32_i32(f32) -> i32 {
|
||||
block0(v0: f32):
|
||||
v1 = fcvt_to_sint.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cebr %f0, %f0
|
||||
; nextln: jno 6 ; trap
|
||||
; nextln: cfebra %r2, 5, %f0, 0
|
||||
; nextln: jno 6 ; trap
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_to_uint_f32_i64(f32) -> i64 {
|
||||
block0(v0: f32):
|
||||
v1 = fcvt_to_uint.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cebr %f0, %f0
|
||||
; nextln: jno 6 ; trap
|
||||
; nextln: clgebr %r2, 5, %f0, 0
|
||||
; nextln: jno 6 ; trap
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_to_sint_f32_i64(f32) -> i64 {
|
||||
block0(v0: f32):
|
||||
v1 = fcvt_to_sint.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cebr %f0, %f0
|
||||
; nextln: jno 6 ; trap
|
||||
; nextln: cgebra %r2, 5, %f0, 0
|
||||
; nextln: jno 6 ; trap
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_to_uint_f64_i32(f64) -> i32 {
|
||||
block0(v0: f64):
|
||||
v1 = fcvt_to_uint.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cdbr %f0, %f0
|
||||
; nextln: jno 6 ; trap
|
||||
; nextln: clfdbr %r2, 5, %f0, 0
|
||||
; nextln: jno 6 ; trap
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_to_sint_f64_i32(f64) -> i32 {
|
||||
block0(v0: f64):
|
||||
v1 = fcvt_to_sint.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cdbr %f0, %f0
|
||||
; nextln: jno 6 ; trap
|
||||
; nextln: cfdbra %r2, 5, %f0, 0
|
||||
; nextln: jno 6 ; trap
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_to_uint_f64_i64(f64) -> i64 {
|
||||
block0(v0: f64):
|
||||
v1 = fcvt_to_uint.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cdbr %f0, %f0
|
||||
; nextln: jno 6 ; trap
|
||||
; nextln: clgdbr %r2, 5, %f0, 0
|
||||
; nextln: jno 6 ; trap
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_to_sint_f64_i64(f64) -> i64 {
|
||||
block0(v0: f64):
|
||||
v1 = fcvt_to_sint.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cdbr %f0, %f0
|
||||
; nextln: jno 6 ; trap
|
||||
; nextln: cgdbra %r2, 5, %f0, 0
|
||||
; nextln: jno 6 ; trap
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; FCVT_FROM_UINT/FCVT_FROM_SINT
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %fcvt_from_uint_i32_f32(i32) -> f32 {
|
||||
block0(v0: i32):
|
||||
v1 = fcvt_from_uint.f32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: celfbr %f0, 0, %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_from_sint_i32_f32(i32) -> f32 {
|
||||
block0(v0: i32):
|
||||
v1 = fcvt_from_sint.f32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cefbra %f0, 0, %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_from_uint_i64_f32(i64) -> f32 {
|
||||
block0(v0: i64):
|
||||
v1 = fcvt_from_uint.f32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: celgbr %f0, 0, %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_from_sint_i64_f32(i64) -> f32 {
|
||||
block0(v0: i64):
|
||||
v1 = fcvt_from_sint.f32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cegbra %f0, 0, %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_from_uint_i32_f64(i32) -> f64 {
|
||||
block0(v0: i32):
|
||||
v1 = fcvt_from_uint.f64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cdlfbr %f0, 0, %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_from_sint_i32_f64(i32) -> f64 {
|
||||
block0(v0: i32):
|
||||
v1 = fcvt_from_sint.f64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cdfbra %f0, 0, %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_from_uint_i64_f64(i64) -> f64 {
|
||||
block0(v0: i64):
|
||||
v1 = fcvt_from_uint.f64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cdlgbr %f0, 0, %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_from_sint_i64_f64(i64) -> f64 {
|
||||
block0(v0: i64):
|
||||
v1 = fcvt_from_sint.f64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cdgbra %f0, 0, %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; FCVT_TO_UINT_SAT/FCVT_TO_SINT_SAT
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %fcvt_to_uint_sat_f32_i32(f32) -> i32 {
|
||||
block0(v0: f32):
|
||||
v1 = fcvt_to_uint_sat.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: clfebr %r2, 5, %f0, 0
|
||||
; nextln: cebr %f0, %f0
|
||||
; nextln: lochio %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_to_sint_sat_f32_i32(f32) -> i32 {
|
||||
block0(v0: f32):
|
||||
v1 = fcvt_to_sint_sat.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cfebra %r2, 5, %f0, 0
|
||||
; nextln: cebr %f0, %f0
|
||||
; nextln: lochio %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_to_uint_sat_f32_i64(f32) -> i64 {
|
||||
block0(v0: f32):
|
||||
v1 = fcvt_to_uint_sat.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: clgebr %r2, 5, %f0, 0
|
||||
; nextln: cebr %f0, %f0
|
||||
; nextln: locghio %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_to_sint_sat_f32_i64(f32) -> i64 {
|
||||
block0(v0: f32):
|
||||
v1 = fcvt_to_sint_sat.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cgebra %r2, 5, %f0, 0
|
||||
; nextln: cebr %f0, %f0
|
||||
; nextln: locghio %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_to_uint_sat_f64_i32(f64) -> i32 {
|
||||
block0(v0: f64):
|
||||
v1 = fcvt_to_uint_sat.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: clfdbr %r2, 5, %f0, 0
|
||||
; nextln: cdbr %f0, %f0
|
||||
; nextln: lochio %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_to_sint_sat_f64_i32(f64) -> i32 {
|
||||
block0(v0: f64):
|
||||
v1 = fcvt_to_sint_sat.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cfdbra %r2, 5, %f0, 0
|
||||
; nextln: cdbr %f0, %f0
|
||||
; nextln: lochio %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_to_uint_sat_f64_i64(f64) -> i64 {
|
||||
block0(v0: f64):
|
||||
v1 = fcvt_to_uint_sat.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: clgdbr %r2, 5, %f0, 0
|
||||
; nextln: cdbr %f0, %f0
|
||||
; nextln: locghio %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %fcvt_to_sint_sat_f64_i64(f64) -> i64 {
|
||||
block0(v0: f64):
|
||||
v1 = fcvt_to_sint_sat.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cgdbra %r2, 5, %f0, 0
|
||||
; nextln: cdbr %f0, %f0
|
||||
; nextln: locghio %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; BITCAST
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %bitcast_i64_f64(i64) -> f64 {
|
||||
block0(v0: i64):
|
||||
v1 = bitcast.f64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: ldgr %f0, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %bitcast_f64_i64(f64) -> i64 {
|
||||
block0(v0: f64):
|
||||
v1 = bitcast.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lgdr %r2, %f0
|
||||
; nextln: br %r14
|
||||
|
||||
function %bitcast_i32_f32(i32) -> f32 {
|
||||
block0(v0: i32):
|
||||
v1 = bitcast.f32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: sllg %r2, %r2, 32
|
||||
; nextln: ldgr %f0, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %bitcast_f32_i32(f32) -> i32 {
|
||||
block0(v0: f32):
|
||||
v1 = bitcast.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lgdr %r2, %f0
|
||||
; nextln: srlg %r2, %r2, 32
|
||||
; nextln: br %r14
|
||||
49
cranelift/filetests/filetests/isa/s390x/heap_addr.clif
Normal file
49
cranelift/filetests/filetests/isa/s390x/heap_addr.clif
Normal file
@@ -0,0 +1,49 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
function %dynamic_heap_check(i64 vmctx, i32) -> i64 {
|
||||
gv0 = vmctx
|
||||
gv1 = load.i32 notrap aligned gv0
|
||||
heap0 = dynamic gv0, bound gv1, offset_guard 0x1000, index_type i32
|
||||
|
||||
block0(v0: i64, v1: i32):
|
||||
v2 = heap_addr.i64 heap0, v1, 0
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: Block 0:
|
||||
; check: l %r4, 0(%r2)
|
||||
; nextln: ahi %r4, 0
|
||||
; nextln: clr %r3, %r4
|
||||
; nextln: jgnh label1 ; jg label2
|
||||
; check: Block 1:
|
||||
; check: llgfr %r5, %r3
|
||||
; nextln: agr %r2, %r5
|
||||
; nextln: lghi %r5, 0
|
||||
; nextln: clr %r3, %r4
|
||||
; nextln: locgrh %r2, %r5
|
||||
; nextln: br %r14
|
||||
; check: Block 2:
|
||||
; check: trap
|
||||
|
||||
function %static_heap_check(i64 vmctx, i32) -> i64 {
|
||||
gv0 = vmctx
|
||||
heap0 = static gv0, bound 0x1_0000, offset_guard 0x1000, index_type i32
|
||||
|
||||
block0(v0: i64, v1: i32):
|
||||
v2 = heap_addr.i64 heap0, v1, 0
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: Block 0:
|
||||
; check: clfi %r3, 65536
|
||||
; nextln: jgnh label1 ; jg label2
|
||||
; check: Block 1:
|
||||
; check: llgfr %r4, %r3
|
||||
; nextln: agr %r2, %r4
|
||||
; nextln: lghi %r4, 0
|
||||
; nextln: clfi %r3, 65536
|
||||
; nextln: locgrh %r2, %r4
|
||||
; nextln: br %r14
|
||||
; check: Block 2:
|
||||
; check: trap
|
||||
604
cranelift/filetests/filetests/isa/s390x/icmp.clif
Normal file
604
cranelift/filetests/filetests/isa/s390x/icmp.clif
Normal file
@@ -0,0 +1,604 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
function %icmp_slt_i64(i64, i64) -> b1 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = icmp.i64 slt v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: cgr %r2, %r3
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i64_ext32(i64, i32) -> b1 {
|
||||
block0(v0: i64, v1: i32):
|
||||
v2 = sextend.i64 v1
|
||||
v3 = icmp.i64 slt v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: cgfr %r2, %r3
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i64_imm16(i64) -> b1 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 1
|
||||
v2 = icmp.i64 slt v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: cghi %r2, 1
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i64_imm32(i64) -> b1 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 32768
|
||||
v2 = icmp.i64 slt v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: cgfi %r2, 32768
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i64_mem(i64, i64) -> b1 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = load.i64 v1
|
||||
v3 = icmp.i64 slt v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: cg %r2, 0(%r3)
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i64_sym(i64) -> b1 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i64):
|
||||
v1 = symbol_value.i64 gv0
|
||||
v2 = load.i64 v1
|
||||
v3 = icmp.i64 slt v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: cgrl %r2, %sym + 0
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i64_mem_ext16(i64, i64) -> b1 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = sload16.i64 v1
|
||||
v3 = icmp.i64 slt v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: cgh %r2, 0(%r3)
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i64_sym_ext16(i64) -> b1 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i64):
|
||||
v1 = symbol_value.i64 gv0
|
||||
v2 = sload16.i64 v1
|
||||
v3 = icmp.i64 slt v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: cghrl %r2, %sym + 0
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i64_mem_ext32(i64, i64) -> b1 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = sload32.i64 v1
|
||||
v3 = icmp.i64 slt v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: cgf %r2, 0(%r3)
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i64_sym_ext32(i64) -> b1 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i64):
|
||||
v1 = symbol_value.i64 gv0
|
||||
v2 = sload32.i64 v1
|
||||
v3 = icmp.i64 slt v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: cgfrl %r2, %sym + 0
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i32(i32, i32) -> b1 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = icmp.i32 slt v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: cr %r2, %r3
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i32_imm16(i32) -> b1 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 1
|
||||
v2 = icmp.i32 slt v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: chi %r2, 1
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i32_imm(i32) -> b1 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 32768
|
||||
v2 = icmp.i32 slt v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: cfi %r2, 32768
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i32_mem(i32, i64) -> b1 {
|
||||
block0(v0: i32, v1: i64):
|
||||
v2 = load.i32 v1
|
||||
v3 = icmp.i32 slt v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: c %r2, 0(%r3)
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i32_memoff(i32, i64) -> b1 {
|
||||
block0(v0: i32, v1: i64):
|
||||
v2 = load.i32 v1+4096
|
||||
v3 = icmp.i32 slt v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: cy %r2, 4096(%r3)
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i32_sym(i32) -> b1 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i32):
|
||||
v1 = symbol_value.i64 gv0
|
||||
v2 = load.i32 v1
|
||||
v3 = icmp.i32 slt v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: crl %r2, %sym + 0
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i32_mem_ext16(i32, i64) -> b1 {
|
||||
block0(v0: i32, v1: i64):
|
||||
v2 = sload16.i32 v1
|
||||
v3 = icmp.i32 slt v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: ch %r2, 0(%r3)
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i32_memoff_ext16(i32, i64) -> b1 {
|
||||
block0(v0: i32, v1: i64):
|
||||
v2 = sload16.i32 v1+4096
|
||||
v3 = icmp.i32 slt v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: chy %r2, 4096(%r3)
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i32_sym_ext16(i32) -> b1 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i32):
|
||||
v1 = symbol_value.i64 gv0
|
||||
v2 = sload16.i32 v1
|
||||
v3 = icmp.i32 slt v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: chrl %r2, %sym + 0
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i16(i16, i16) -> b1 {
|
||||
block0(v0: i16, v1: i16):
|
||||
v2 = icmp.i16 slt v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lhr %r2, %r2
|
||||
; nextln: lhr %r3, %r3
|
||||
; nextln: cr %r2, %r3
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i16_imm(i16) -> b1 {
|
||||
block0(v0: i16):
|
||||
v1 = iconst.i16 1
|
||||
v2 = icmp.i16 slt v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lhr %r2, %r2
|
||||
; nextln: chi %r2, 1
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i16_mem(i16, i64) -> b1 {
|
||||
block0(v0: i16, v1: i64):
|
||||
v2 = load.i16 v1
|
||||
v3 = icmp.i16 slt v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: lhr %r2, %r2
|
||||
; nextln: ch %r2, 0(%r3)
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i16_sym(i16) -> b1 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i16):
|
||||
v1 = symbol_value.i64 gv0
|
||||
v2 = load.i16 v1
|
||||
v3 = icmp.i16 slt v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: lhr %r2, %r2
|
||||
; nextln: chrl %r2, %sym + 0
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i8(i8, i8) -> b1 {
|
||||
block0(v0: i8, v1: i8):
|
||||
v2 = icmp.i8 slt v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lbr %r2, %r2
|
||||
; nextln: lbr %r3, %r3
|
||||
; nextln: cr %r2, %r3
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i8_imm(i8) -> b1 {
|
||||
block0(v0: i8):
|
||||
v1 = iconst.i8 1
|
||||
v2 = icmp.i8 slt v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lbr %r2, %r2
|
||||
; nextln: chi %r2, 1
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_slt_i8_mem(i8, i64) -> b1 {
|
||||
block0(v0: i8, v1: i64):
|
||||
v2 = load.i8 v1
|
||||
v3 = icmp.i8 slt v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: lbr %r2, %r2
|
||||
; nextln: lb %r3, 0(%r3)
|
||||
; nextln: cr %r2, %r3
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i64(i64, i64) -> b1 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = icmp.i64 ult v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: clgr %r2, %r3
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i64_ext32(i64, i32) -> b1 {
|
||||
block0(v0: i64, v1: i32):
|
||||
v2 = uextend.i64 v1
|
||||
v3 = icmp.i64 ult v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: clgfr %r2, %r3
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i64_imm(i64) -> b1 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 1
|
||||
v2 = icmp.i64 ult v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: clgfi %r2, 1
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i64_mem(i64, i64) -> b1 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = load.i64 v1
|
||||
v3 = icmp.i64 ult v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: clg %r2, 0(%r3)
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i64_sym(i64) -> b1 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i64):
|
||||
v1 = symbol_value.i64 gv0
|
||||
v2 = load.i64 v1
|
||||
v3 = icmp.i64 ult v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: clgrl %r2, %sym + 0
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i64_mem_ext32(i64, i64) -> b1 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = uload32.i64 v1
|
||||
v3 = icmp.i64 ult v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: clgf %r2, 0(%r3)
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i64_sym_ext32(i64) -> b1 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i64):
|
||||
v1 = symbol_value.i64 gv0
|
||||
v2 = uload32.i64 v1
|
||||
v3 = icmp.i64 ult v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: clgfrl %r2, %sym + 0
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i64_sym_ext16(i64) -> b1 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i64):
|
||||
v1 = symbol_value.i64 gv0
|
||||
v2 = uload16.i64 v1
|
||||
v3 = icmp.i64 ult v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: clghrl %r2, %sym + 0
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i32(i32, i32) -> b1 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = icmp.i32 ult v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: clr %r2, %r3
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i32_imm(i32) -> b1 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 1
|
||||
v2 = icmp.i32 ult v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: clfi %r2, 1
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i32_mem(i32, i64) -> b1 {
|
||||
block0(v0: i32, v1: i64):
|
||||
v2 = load.i32 v1
|
||||
v3 = icmp.i32 ult v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: cl %r2, 0(%r3)
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i32_memoff(i32, i64) -> b1 {
|
||||
block0(v0: i32, v1: i64):
|
||||
v2 = load.i32 v1+4096
|
||||
v3 = icmp.i32 ult v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: cly %r2, 4096(%r3)
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i32_sym(i32) -> b1 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i32):
|
||||
v1 = symbol_value.i64 gv0
|
||||
v2 = load.i32 v1
|
||||
v3 = icmp.i32 ult v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: clrl %r2, %sym + 0
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i32_sym_ext16(i32) -> b1 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i32):
|
||||
v1 = symbol_value.i64 gv0
|
||||
v2 = uload16.i32 v1
|
||||
v3 = icmp.i32 ult v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: clhrl %r2, %sym + 0
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i16(i16, i16) -> b1 {
|
||||
block0(v0: i16, v1: i16):
|
||||
v2 = icmp.i16 ult v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: llhr %r2, %r2
|
||||
; nextln: llhr %r3, %r3
|
||||
; nextln: clr %r2, %r3
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i16_imm(i16) -> b1 {
|
||||
block0(v0: i16):
|
||||
v1 = iconst.i16 1
|
||||
v2 = icmp.i16 ult v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: llhr %r2, %r2
|
||||
; nextln: clfi %r2, 1
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i16_mem(i16, i64) -> b1 {
|
||||
block0(v0: i16, v1: i64):
|
||||
v2 = load.i16 v1
|
||||
v3 = icmp.i16 ult v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: llhr %r2, %r2
|
||||
; nextln: llh %r3, 0(%r3)
|
||||
; nextln: clr %r2, %r3
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i16_mem(i16) -> b1 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i16):
|
||||
v1 = symbol_value.i64 gv0
|
||||
v2 = load.i16 v1
|
||||
v3 = icmp.i16 ult v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: llhr %r2, %r2
|
||||
; nextln: clhrl %r2, %sym + 0
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i8(i8, i8) -> b1 {
|
||||
block0(v0: i8, v1: i8):
|
||||
v2 = icmp.i8 ult v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: llcr %r2, %r2
|
||||
; nextln: llcr %r3, %r3
|
||||
; nextln: clr %r2, %r3
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i8_imm(i8) -> b1 {
|
||||
block0(v0: i8):
|
||||
v1 = iconst.i8 1
|
||||
v2 = icmp.i8 ult v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: llcr %r2, %r2
|
||||
; nextln: clfi %r2, 1
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %icmp_ult_i8_mem(i8, i64) -> b1 {
|
||||
block0(v0: i8, v1: i64):
|
||||
v2 = load.i8 v1
|
||||
v3 = icmp.i8 ult v0, v2
|
||||
return v3
|
||||
}
|
||||
|
||||
; check: llcr %r2, %r2
|
||||
; nextln: llc %r3, 0(%r3)
|
||||
; nextln: clr %r2, %r3
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochil %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
45
cranelift/filetests/filetests/isa/s390x/jumptable.clif
Normal file
45
cranelift/filetests/filetests/isa/s390x/jumptable.clif
Normal file
@@ -0,0 +1,45 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
function %f(i64) -> i64 {
|
||||
jt0 = jump_table [block1, block2, block3]
|
||||
|
||||
block0(v0: i64):
|
||||
br_table v0, block4, jt0
|
||||
|
||||
block1:
|
||||
v1 = iconst.i64 1
|
||||
jump block5(v1)
|
||||
|
||||
block2:
|
||||
v2 = iconst.i64 2
|
||||
jump block5(v2)
|
||||
|
||||
block3:
|
||||
v3 = iconst.i64 3
|
||||
jump block5(v3)
|
||||
|
||||
block4:
|
||||
v4 = iconst.i64 4
|
||||
jump block5(v4)
|
||||
|
||||
block5(v5: i64):
|
||||
v6 = iadd.i64 v0, v5
|
||||
return v6
|
||||
}
|
||||
|
||||
; check: clgfi %r2, 3 ; jghe label1 ; sllg %r4, %r2, 2 ; larl %r3, 18 ; lgf %r4, 0(%r4, %r3) ; agrk %r3, %r3, %r4 ; br %r3 ; jt_entries
|
||||
|
||||
; check: lghi %r3, 1
|
||||
; nextln: jg
|
||||
|
||||
; check: lghi %r3, 2
|
||||
; nextln: jg
|
||||
|
||||
; check: lghi %r3, 3
|
||||
; nextln: jg
|
||||
|
||||
; check: agr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
|
||||
258
cranelift/filetests/filetests/isa/s390x/load-little.clif
Normal file
258
cranelift/filetests/filetests/isa/s390x/load-little.clif
Normal file
@@ -0,0 +1,258 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
function %load_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = load.i64 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lrvg %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %load_i64_sym() -> i64 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
v1 = load.i64 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: larl %r1, %sym + 0 ; lrvg %r2, 0(%r1)
|
||||
; nextln: br %r14
|
||||
|
||||
function %uload8_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = uload8.i64 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llgc %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload8_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = sload8.i64 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lgb %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %uload16_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = uload16.i64 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lrvh %r2, 0(%r2)
|
||||
; nextln: llghr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %uload16_i64_sym() -> i64 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
v1 = uload16.i64 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: larl %r1, %sym + 0 ; lrvh %r2, 0(%r1)
|
||||
; nextln: llghr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload16_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = sload16.i64 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lrvh %r2, 0(%r2)
|
||||
; nextln: lghr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload16_i64_sym() -> i64 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
v1 = sload16.i64 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: larl %r1, %sym + 0 ; lrvh %r2, 0(%r1)
|
||||
; nextln: lghr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %uload32_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = uload32.i64 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lrv %r2, 0(%r2)
|
||||
; nextln: llgfr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %uload32_i64_sym() -> i64 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
v1 = uload32.i64 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: larl %r1, %sym + 0 ; lrv %r2, 0(%r1)
|
||||
; nextln: llgfr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload32_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = sload32.i64 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lrv %r2, 0(%r2)
|
||||
; nextln: lgfr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload32_i64_sym() -> i64 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
v1 = sload32.i64 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: larl %r1, %sym + 0 ; lrv %r2, 0(%r1)
|
||||
; nextln: lgfr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %load_i32(i64) -> i32 {
|
||||
block0(v0: i64):
|
||||
v1 = load.i32 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lrv %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %load_i32_sym() -> i32 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
v1 = load.i32 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: larl %r1, %sym + 0 ; lrv %r2, 0(%r1)
|
||||
; nextln: br %r14
|
||||
|
||||
function %uload8_i32(i64) -> i32 {
|
||||
block0(v0: i64):
|
||||
v1 = uload8.i32 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llc %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload8_i32(i64) -> i32 {
|
||||
block0(v0: i64):
|
||||
v1 = sload8.i32 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lb %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %uload16_i32(i64) -> i32 {
|
||||
block0(v0: i64):
|
||||
v1 = uload16.i32 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lrvh %r2, 0(%r2)
|
||||
; nextln: llhr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %uload16_i32_sym() -> i32 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
v1 = uload16.i32 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: larl %r1, %sym + 0 ; lrvh %r2, 0(%r1)
|
||||
; nextln: llhr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload16_i32(i64) -> i32 {
|
||||
block0(v0: i64):
|
||||
v1 = sload16.i32 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lrvh %r2, 0(%r2)
|
||||
; nextln: lhr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload16_i32_sym() -> i32 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
v1 = sload16.i32 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: larl %r1, %sym + 0 ; lrvh %r2, 0(%r1)
|
||||
; nextln: lhr %r2, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %load_i16(i64) -> i16 {
|
||||
block0(v0: i64):
|
||||
v1 = load.i16 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lrvh %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %load_i16_sym() -> i16 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
v1 = load.i16 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: larl %r1, %sym + 0 ; lrvh %r2, 0(%r1)
|
||||
; nextln: br %r14
|
||||
|
||||
function %uload8_i16(i64) -> i16 {
|
||||
block0(v0: i64):
|
||||
v1 = uload8.i16 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llc %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload8_i16(i64) -> i16 {
|
||||
block0(v0: i64):
|
||||
v1 = sload8.i16 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lb %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %load_i8(i64) -> i8 {
|
||||
block0(v0: i64):
|
||||
v1 = load.i8 little v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llc %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
264
cranelift/filetests/filetests/isa/s390x/load.clif
Normal file
264
cranelift/filetests/filetests/isa/s390x/load.clif
Normal file
@@ -0,0 +1,264 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
function %load_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = load.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lg %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %load_i64_sym() -> i64 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
v1 = load.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lgrl %r2, %sym + 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %uload8_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = uload8.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llgc %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload8_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = sload8.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lgb %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %uload16_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = uload16.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llgh %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %uload16_i64_sym() -> i64 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
v1 = uload16.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llghrl %r2, %sym + 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload16_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = sload16.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lgh %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload16_i64_sym() -> i64 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
v1 = sload16.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lghrl %r2, %sym + 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %uload32_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = uload32.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llgf %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %uload32_i64_sym() -> i64 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
v1 = uload32.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llgfrl %r2, %sym + 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload32_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = sload32.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lgf %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload32_i64_sym() -> i64 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
v1 = sload32.i64 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lgfrl %r2, %sym + 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %load_i32(i64) -> i32 {
|
||||
block0(v0: i64):
|
||||
v1 = load.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: l %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %load_i32_sym() -> i32 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
v1 = load.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lrl %r2, %sym + 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %load_i32_off(i64) -> i32 {
|
||||
block0(v0: i64):
|
||||
v1 = load.i32 v0+4096
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: ly %r2, 4096(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %uload8_i32(i64) -> i32 {
|
||||
block0(v0: i64):
|
||||
v1 = uload8.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llc %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload8_i32(i64) -> i32 {
|
||||
block0(v0: i64):
|
||||
v1 = sload8.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lb %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %uload16_i32(i64) -> i32 {
|
||||
block0(v0: i64):
|
||||
v1 = uload16.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llh %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %uload16_i32_sym() -> i32 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
v1 = uload16.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llhrl %r2, %sym + 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload16_i32(i64) -> i32 {
|
||||
block0(v0: i64):
|
||||
v1 = sload16.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lh %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload16_i32_off(i64) -> i32 {
|
||||
block0(v0: i64):
|
||||
v1 = sload16.i32 v0+4096
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lhy %r2, 4096(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload16_i32_sym() -> i32 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
v1 = sload16.i32 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lhrl %r2, %sym + 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %load_i16(i64) -> i16 {
|
||||
block0(v0: i64):
|
||||
v1 = load.i16 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llh %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %load_i16_sym() -> i16 {
|
||||
gv0 = symbol colocated %sym
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
v1 = load.i16 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llhrl %r2, %sym + 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %uload8_i16(i64) -> i16 {
|
||||
block0(v0: i64):
|
||||
v1 = uload8.i16 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llc %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %sload8_i16(i64) -> i16 {
|
||||
block0(v0: i64):
|
||||
v1 = sload8.i16 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lb %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %load_i8(i64) -> i8 {
|
||||
block0(v0: i64):
|
||||
v1 = load.i8 v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: llc %r2, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
79
cranelift/filetests/filetests/isa/s390x/multivalue-ret.clif
Normal file
79
cranelift/filetests/filetests/isa/s390x/multivalue-ret.clif
Normal file
@@ -0,0 +1,79 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
;; Test default (non-SpiderMonkey) ABI.
|
||||
function %f1() -> i64, i64, i64, i64 {
|
||||
block1:
|
||||
v0 = iconst.i64 1
|
||||
v1 = iconst.i64 2
|
||||
v2 = iconst.i64 3
|
||||
v3 = iconst.i64 4
|
||||
return v0, v1, v2, v3
|
||||
}
|
||||
|
||||
; check: lghi %r2, 1
|
||||
; nextln: lghi %r3, 2
|
||||
; nextln: lghi %r4, 3
|
||||
; nextln: lghi %r5, 4
|
||||
; nextln: br %r14
|
||||
|
||||
function %f1() -> i64, i64, i64, i64, i64, i64 {
|
||||
block1:
|
||||
v0 = iconst.i64 1
|
||||
v1 = iconst.i64 2
|
||||
v2 = iconst.i64 3
|
||||
v3 = iconst.i64 4
|
||||
v4 = iconst.i64 5
|
||||
v5 = iconst.i64 6
|
||||
return v0, v1, v2, v3, v4, v5
|
||||
}
|
||||
|
||||
; check: stmg %r12, %r15, 96(%r15)
|
||||
; nextln: lgr %r14, %r2
|
||||
; nextln: lghi %r2, 1
|
||||
; nextln: lghi %r3, 2
|
||||
; nextln: lghi %r4, 3
|
||||
; nextln: lghi %r5, 4
|
||||
; nextln: lghi %r13, 5
|
||||
; nextln: lghi %r12, 6
|
||||
; nextln: stg %r13, 0(%r14)
|
||||
; nextln: stg %r12, 8(%r14)
|
||||
; nextln: lmg %r12, %r15, 96(%r15)
|
||||
; nextln: br %r14
|
||||
|
||||
;; Test default (non-SpiderMonkey) ABI.
|
||||
function %f3() -> f64, f64, f64, f64 {
|
||||
block1:
|
||||
v0 = f64const 0x0.0
|
||||
v1 = f64const 0x1.0
|
||||
v2 = f64const 0x2.0
|
||||
v3 = f64const 0x3.0
|
||||
return v0, v1, v2, v3
|
||||
}
|
||||
|
||||
; check: bras %r1, 12 ; data.f64 0 ; ld %f0, 0(%r1)
|
||||
; nextln: bras %r1, 12 ; data.f64 1 ; ld %f2, 0(%r1)
|
||||
; nextln: bras %r1, 12 ; data.f64 2 ; ld %f4, 0(%r1)
|
||||
; nextln: bras %r1, 12 ; data.f64 3 ; ld %f6, 0(%r1)
|
||||
; nextln: br %r14
|
||||
|
||||
function %f4() -> f64, f64, f64, f64, f64, f64 {
|
||||
block1:
|
||||
v0 = f64const 0x0.0
|
||||
v1 = f64const 0x1.0
|
||||
v2 = f64const 0x2.0
|
||||
v3 = f64const 0x3.0
|
||||
v4 = f64const 0x4.0
|
||||
v5 = f64const 0x5.0
|
||||
return v0, v1, v2, v3, v4, v5
|
||||
}
|
||||
|
||||
; check: bras %r1, 12 ; data.f64 0 ; ld %f0, 0(%r1)
|
||||
; nextln: bras %r1, 12 ; data.f64 1 ; ld %f2, 0(%r1)
|
||||
; nextln: bras %r1, 12 ; data.f64 2 ; ld %f4, 0(%r1)
|
||||
; nextln: bras %r1, 12 ; data.f64 3 ; ld %f6, 0(%r1)
|
||||
; nextln: bras %r1, 12 ; data.f64 4 ; ld %f1, 0(%r1)
|
||||
; nextln: bras %r1, 12 ; data.f64 5 ; ld %f3, 0(%r1)
|
||||
; nextln: std %f1, 0(%r2)
|
||||
; nextln: std %f3, 8(%r2)
|
||||
; nextln: br %r14
|
||||
101
cranelift/filetests/filetests/isa/s390x/reftypes.clif
Normal file
101
cranelift/filetests/filetests/isa/s390x/reftypes.clif
Normal file
@@ -0,0 +1,101 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
function %f0(r64, r64) -> r64 {
|
||||
block0(v0: r64, v1: r64):
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: lgr %r2, %r3
|
||||
; nextln: br %r14
|
||||
|
||||
function %f1(r64) -> b1 {
|
||||
block0(v0: r64):
|
||||
v1 = is_null v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cghi %r2, 0
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochie %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %f2(r64) -> b1 {
|
||||
block0(v0: r64):
|
||||
v1 = is_invalid v0
|
||||
return v1
|
||||
}
|
||||
|
||||
; check: cghi %r2, -1
|
||||
; nextln: lhi %r2, 0
|
||||
; nextln: lochie %r2, 1
|
||||
; nextln: br %r14
|
||||
|
||||
function %f3() -> r64 {
|
||||
block0:
|
||||
v0 = null.r64
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: lghi %r2, 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %f4(r64, r64) -> r64, r64, r64 {
|
||||
fn0 = %f(r64) -> b1
|
||||
ss0 = explicit_slot 8
|
||||
|
||||
block0(v0: r64, v1: r64):
|
||||
v2 = call fn0(v0)
|
||||
stack_store.r64 v0, ss0
|
||||
brz v2, block1(v1, v0)
|
||||
jump block2(v0, v1)
|
||||
|
||||
block1(v3: r64, v4: r64):
|
||||
jump block3(v3, v4)
|
||||
|
||||
block2(v5: r64, v6: r64):
|
||||
jump block3(v5, v6)
|
||||
|
||||
block3(v7: r64, v8: r64):
|
||||
v9 = stack_load.r64 ss0
|
||||
return v7, v8, v9
|
||||
}
|
||||
|
||||
; check: Block 0:
|
||||
; check: stmg %r12, %r15, 96(%r15)
|
||||
; nextln: aghi %r15, -192
|
||||
; nextln: virtual_sp_offset_adjust 160
|
||||
; nextln: lgr %r13, %r2
|
||||
; nextln: lgr %r12, %r3
|
||||
; nextln: lgr %r2, %r13
|
||||
; nextln: bras %r1, 12 ; data %f + 0 ; lg %r3, 0(%r1)
|
||||
; nextln: stg %r2, 168(%r15)
|
||||
; nextln: stg %r13, 176(%r15)
|
||||
; nextln: stg %r12, 184(%r15)
|
||||
; nextln: (safepoint: slots [S0, S1, S2]
|
||||
; nextln: basr %r14, %r3
|
||||
; nextln: lg %r13, 176(%r15)
|
||||
; nextln: lg %r12, 184(%r15)
|
||||
; nextln: la %r3, 160(%r15)
|
||||
; nextln: stg %r13, 0(%r3)
|
||||
; nextln: llcr %r2, %r2
|
||||
; nextln: chi %r2, 0
|
||||
; nextln: jgnlh label1 ; jg label3
|
||||
; check: Block 1:
|
||||
; check: jg label2
|
||||
; check: Block 2:
|
||||
; check: lgr %r2, %r12
|
||||
; nextln: jg label5
|
||||
; check: Block 3:
|
||||
; check: jg label4
|
||||
; check: Block 4:
|
||||
; check: lgr %r2, %r13
|
||||
; nextln: lgr %r13, %r12
|
||||
; nextln: jg label5
|
||||
; check: Block 5:
|
||||
; check: la %r3, 160(%r15)
|
||||
; nextln: lg %r3, 0(%r3)
|
||||
; nextln: lgr %r4, %r3
|
||||
; nextln: lgr %r3, %r13
|
||||
; nextln: lmg %r12, %r15, 288(%r15)
|
||||
; nextln: br %r14
|
||||
12
cranelift/filetests/filetests/isa/s390x/saturating-ops.clif
Normal file
12
cranelift/filetests/filetests/isa/s390x/saturating-ops.clif
Normal file
@@ -0,0 +1,12 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
; FIXME: not yet supported
|
||||
|
||||
function %uaddsat64(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
; v2 = uadd_sat.i64 v0, v1
|
||||
v2 = iconst.i64 0
|
||||
return v2
|
||||
}
|
||||
|
||||
461
cranelift/filetests/filetests/isa/s390x/shift-rotate.clif
Normal file
461
cranelift/filetests/filetests/isa/s390x/shift-rotate.clif
Normal file
@@ -0,0 +1,461 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ROTR
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %rotr_i64_reg(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = rotr.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lcgr %r3, %r3
|
||||
; nextln: rllg %r2, %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %rotr_i64_imm(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i32 17
|
||||
v2 = rotr.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: rllg %r2, %r2, 47
|
||||
; nextln: br %r14
|
||||
|
||||
function %rotr_i32_reg(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = rotr.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lcr %r3, %r3
|
||||
; nextln: rll %r2, %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %rotr_i32_imm(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 17
|
||||
v2 = rotr.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: rll %r2, %r2, 15
|
||||
; nextln: br %r14
|
||||
|
||||
function %rotr_i16_reg(i16, i16) -> i16 {
|
||||
block0(v0: i16, v1: i16):
|
||||
v2 = rotr.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: llhr %r2, %r2
|
||||
; nextln: lr %r5, %r3
|
||||
; nextln: lcr %r4, %r3
|
||||
; nextln: nill %r5, 15
|
||||
; nextln: nill %r4, 15
|
||||
; nextln: sllk %r3, %r2, 0(%r5)
|
||||
; nextln: srlk %r2, %r2, 0(%r4)
|
||||
; nextln: ork %r2, %r3, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %rotr_i16_imm(i16) -> i16 {
|
||||
block0(v0: i16):
|
||||
v1 = iconst.i32 10
|
||||
v2 = rotr.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: llhr %r2, %r2
|
||||
; nextln: sllk %r3, %r2, 6
|
||||
; nextln: srlk %r2, %r2, 10
|
||||
; nextln: ork %r2, %r3, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %rotr_i8_reg(i8, i8) -> i8 {
|
||||
block0(v0: i8, v1: i8):
|
||||
v2 = rotr.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: llcr %r2, %r2
|
||||
; nextln: lr %r5, %r3
|
||||
; nextln: lcr %r4, %r3
|
||||
; nextln: nill %r5, 7
|
||||
; nextln: nill %r4, 7
|
||||
; nextln: sllk %r3, %r2, 0(%r5)
|
||||
; nextln: srlk %r2, %r2, 0(%r4)
|
||||
; nextln: ork %r2, %r3, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %rotr_i8_imm(i8) -> i8 {
|
||||
block0(v0: i8):
|
||||
v1 = iconst.i32 3
|
||||
v2 = rotr.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: llcr %r2, %r2
|
||||
; nextln: sllk %r3, %r2, 5
|
||||
; nextln: srlk %r2, %r2, 3
|
||||
; nextln: ork %r2, %r3, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ROTL
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %rotl_i64_reg(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = rotl.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: rllg %r2, %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %rotl_i64_imm(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i32 17
|
||||
v2 = rotl.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: rllg %r2, %r2, 17
|
||||
; nextln: br %r14
|
||||
|
||||
function %rotl_i32_reg(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = rotl.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: rll %r2, %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %rotl_i32_imm(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 17
|
||||
v2 = rotl.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: rll %r2, %r2, 17
|
||||
; nextln: br %r14
|
||||
|
||||
function %rotl_i16_reg(i16, i16) -> i16 {
|
||||
block0(v0: i16, v1: i16):
|
||||
v2 = rotl.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: llhr %r2, %r2
|
||||
; nextln: lr %r4, %r3
|
||||
; nextln: lcr %r3, %r3
|
||||
; nextln: nill %r4, 15
|
||||
; nextln: nill %r3, 15
|
||||
; nextln: sllk %r3, %r2, 0(%r3)
|
||||
; nextln: srlk %r2, %r2, 0(%r4)
|
||||
; nextln: ork %r2, %r3, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %rotl_i16_imm(i16) -> i16 {
|
||||
block0(v0: i16):
|
||||
v1 = iconst.i32 10
|
||||
v2 = rotl.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: llhr %r2, %r2
|
||||
; nextln: sllk %r3, %r2, 10
|
||||
; nextln: srlk %r2, %r2, 6
|
||||
; nextln: ork %r2, %r3, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %rotl_i8_reg(i8, i8) -> i8 {
|
||||
block0(v0: i8, v1: i8):
|
||||
v2 = rotl.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: llcr %r2, %r2
|
||||
; nextln: lr %r4, %r3
|
||||
; nextln: lcr %r3, %r3
|
||||
; nextln: nill %r4, 7
|
||||
; nextln: nill %r3, 7
|
||||
; nextln: sllk %r3, %r2, 0(%r3)
|
||||
; nextln: srlk %r2, %r2, 0(%r4)
|
||||
; nextln: ork %r2, %r3, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
function %rotr_i8_imm(i8) -> i8 {
|
||||
block0(v0: i8):
|
||||
v1 = iconst.i32 3
|
||||
v2 = rotl.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: llcr %r2, %r2
|
||||
; nextln: sllk %r3, %r2, 3
|
||||
; nextln: srlk %r2, %r2, 5
|
||||
; nextln: ork %r2, %r3, %r2
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; USHR
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %ushr_i64_reg(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = ushr.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: srlg %r2, %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %ushr_i64_imm(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i32 17
|
||||
v2 = ushr.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: srlg %r2, %r2, 17
|
||||
; nextln: br %r14
|
||||
|
||||
function %ushr_i32_reg(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = ushr.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: srlk %r2, %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %ushr_i32_imm(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 17
|
||||
v2 = ushr.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: srlk %r2, %r2, 17
|
||||
; nextln: br %r14
|
||||
|
||||
function %ushr_i16_reg(i16, i16) -> i16 {
|
||||
block0(v0: i16, v1: i16):
|
||||
v2 = ushr.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; FIXME: check shift count ?
|
||||
|
||||
; check: llhr %r2, %r2
|
||||
; nextln: nill %r3, 31
|
||||
; nextln: srlk %r2, %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %ushr_i16_imm(i16) -> i16 {
|
||||
block0(v0: i16):
|
||||
v1 = iconst.i32 10
|
||||
v2 = ushr.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: llhr %r2, %r2
|
||||
; nextln: srlk %r2, %r2, 10
|
||||
; nextln: br %r14
|
||||
|
||||
function %ushr_i8_reg(i8, i8) -> i8 {
|
||||
block0(v0: i8, v1: i8):
|
||||
v2 = ushr.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: llcr %r2, %r2
|
||||
; nextln: nill %r3, 31
|
||||
; nextln: srlk %r2, %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %ushr_i8_imm(i8) -> i8 {
|
||||
block0(v0: i8):
|
||||
v1 = iconst.i32 3
|
||||
v2 = ushr.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: llcr %r2, %r2
|
||||
; nextln: srlk %r2, %r2, 3
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ISHL
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %ishl_i64_reg(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = ishl.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: sllg %r2, %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %ishl_i64_imm(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i32 17
|
||||
v2 = ishl.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: sllg %r2, %r2, 17
|
||||
; nextln: br %r14
|
||||
|
||||
function %ishl_i32_reg(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = ishl.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: sllk %r2, %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %ishl_i32_imm(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 17
|
||||
v2 = ishl.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: sllk %r2, %r2, 17
|
||||
; nextln: br %r14
|
||||
|
||||
function %ishl_i16_reg(i16, i16) -> i16 {
|
||||
block0(v0: i16, v1: i16):
|
||||
v2 = ishl.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: nill %r3, 31
|
||||
; nextln: sllk %r2, %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %ishl_i16_imm(i16) -> i16 {
|
||||
block0(v0: i16):
|
||||
v1 = iconst.i32 10
|
||||
v2 = ishl.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: sllk %r2, %r2, 10
|
||||
; nextln: br %r14
|
||||
|
||||
function %ishl_i8_reg(i8, i8) -> i8 {
|
||||
block0(v0: i8, v1: i8):
|
||||
v2 = ishl.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: nill %r3, 31
|
||||
; nextln: sllk %r2, %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %ishl_i8_imm(i8) -> i8 {
|
||||
block0(v0: i8):
|
||||
v1 = iconst.i32 3
|
||||
v2 = ishl.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: sllk %r2, %r2, 3
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; SSHR
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %sshr_i64_reg(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = sshr.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: srag %r2, %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %sshr_i64_imm(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i32 17
|
||||
v2 = sshr.i64 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: srag %r2, %r2, 17
|
||||
; nextln: br %r14
|
||||
|
||||
function %sshr_i32_reg(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = sshr.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: srak %r2, %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %sshr_i32_imm(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 17
|
||||
v2 = sshr.i32 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: srak %r2, %r2, 17
|
||||
; nextln: br %r14
|
||||
|
||||
function %sshr_i16_reg(i16, i16) -> i16 {
|
||||
block0(v0: i16, v1: i16):
|
||||
v2 = sshr.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lhr %r2, %r2
|
||||
; nextln: nill %r3, 31
|
||||
; nextln: srak %r2, %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %sshr_i16_imm(i16) -> i16 {
|
||||
block0(v0: i16):
|
||||
v1 = iconst.i32 10
|
||||
v2 = sshr.i16 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lhr %r2, %r2
|
||||
; nextln: srak %r2, %r2, 10
|
||||
; nextln: br %r14
|
||||
|
||||
function %sshr_i8_reg(i8, i8) -> i8 {
|
||||
block0(v0: i8, v1: i8):
|
||||
v2 = sshr.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lbr %r2, %r2
|
||||
; nextln: nill %r3, 31
|
||||
; nextln: srak %r2, %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %sshr_i8_imm(i8) -> i8 {
|
||||
block0(v0: i8):
|
||||
v1 = iconst.i32 3
|
||||
v2 = sshr.i8 v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; check: lbr %r2, %r2
|
||||
; nextln: srak %r2, %r2, 3
|
||||
; nextln: br %r14
|
||||
|
||||
175
cranelift/filetests/filetests/isa/s390x/stack-limit.clif
Normal file
175
cranelift/filetests/filetests/isa/s390x/stack-limit.clif
Normal file
@@ -0,0 +1,175 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
function %foo() {
|
||||
block0:
|
||||
return
|
||||
}
|
||||
|
||||
function %stack_limit_leaf_zero(i64 stack_limit) {
|
||||
block0(v0: i64):
|
||||
return
|
||||
}
|
||||
|
||||
; check: br %r14
|
||||
|
||||
function %stack_limit_gv_leaf_zero(i64 vmctx) {
|
||||
gv0 = vmctx
|
||||
gv1 = load.i64 notrap aligned gv0
|
||||
gv2 = load.i64 notrap aligned gv1+4
|
||||
stack_limit = gv2
|
||||
block0(v0: i64):
|
||||
return
|
||||
}
|
||||
|
||||
; check: br %r14
|
||||
|
||||
|
||||
function %stack_limit_call_zero(i64 stack_limit) {
|
||||
fn0 = %foo()
|
||||
block0(v0: i64):
|
||||
call fn0()
|
||||
return
|
||||
}
|
||||
|
||||
; check: clgrtle %r15, %r2
|
||||
; nextln: stmg %r14, %r15, 112(%r15)
|
||||
; nextln: aghi %r15, -160
|
||||
; nextln: virtual_sp_offset_adjust 160
|
||||
; nextln: bras %r1, 12 ; data %foo + 0 ; lg %r2, 0(%r1)
|
||||
; nextln: basr %r14, %r2
|
||||
; nextln: lmg %r14, %r15, 272(%r15)
|
||||
; nextln: br %r14
|
||||
|
||||
function %stack_limit_gv_call_zero(i64 vmctx) {
|
||||
gv0 = vmctx
|
||||
gv1 = load.i64 notrap aligned gv0
|
||||
gv2 = load.i64 notrap aligned gv1+4
|
||||
stack_limit = gv2
|
||||
fn0 = %foo()
|
||||
block0(v0: i64):
|
||||
call fn0()
|
||||
return
|
||||
}
|
||||
|
||||
; check: lg %r1, 0(%r2)
|
||||
; nextln: lg %r1, 4(%r1)
|
||||
; nextln: clgrtle %r15, %r1
|
||||
; nextln: stmg %r14, %r15, 112(%r15)
|
||||
; nextln: aghi %r15, -160
|
||||
; nextln: virtual_sp_offset_adjust 160
|
||||
; nextln: bras %r1, 12 ; data %foo + 0 ; lg %r2, 0(%r1)
|
||||
; nextln: basr %r14, %r2
|
||||
; nextln: lmg %r14, %r15, 272(%r15)
|
||||
; nextln: br %r14
|
||||
|
||||
function %stack_limit(i64 stack_limit) {
|
||||
ss0 = explicit_slot 168
|
||||
block0(v0: i64):
|
||||
return
|
||||
}
|
||||
|
||||
; check: la %r1, 168(%r2)
|
||||
; nextln: clgrtle %r15, %r1
|
||||
; nextln: aghi %r15, -168
|
||||
; nextln: aghi %r15, 168
|
||||
; nextln: br %r14
|
||||
|
||||
function %large_stack_limit(i64 stack_limit) {
|
||||
ss0 = explicit_slot 400000
|
||||
block0(v0: i64):
|
||||
return
|
||||
}
|
||||
|
||||
; check: clgrtle %r15, %r2
|
||||
; nextln: lay %r1, 400000(%r2)
|
||||
; nextln: clgrtle %r15, %r1
|
||||
; nextln: agfi %r15, -400000
|
||||
; nextln: agfi %r15, 400000
|
||||
; nextln: br %r14
|
||||
|
||||
function %huge_stack_limit(i64 stack_limit) {
|
||||
ss0 = explicit_slot 4000000
|
||||
block0(v0: i64):
|
||||
return
|
||||
}
|
||||
|
||||
; check: clgrtle %r15, %r2
|
||||
; nextln: lgr %r1, %r2
|
||||
; nextln: algfi %r1, 4000000
|
||||
; nextln: clgrtle %r15, %r1
|
||||
; nextln: agfi %r15, -4000000
|
||||
; nextln: agfi %r15, 4000000
|
||||
; nextln: br %r14
|
||||
|
||||
function %limit_preamble(i64 vmctx) {
|
||||
gv0 = vmctx
|
||||
gv1 = load.i64 notrap aligned gv0
|
||||
gv2 = load.i64 notrap aligned gv1+4
|
||||
stack_limit = gv2
|
||||
ss0 = explicit_slot 20
|
||||
block0(v0: i64):
|
||||
return
|
||||
}
|
||||
|
||||
; check: lg %r1, 0(%r2)
|
||||
; nextln: lg %r1, 4(%r1)
|
||||
; nextln: la %r1, 24(%r1)
|
||||
; nextln: clgrtle %r15, %r1
|
||||
; nextln: aghi %r15, -24
|
||||
; nextln: aghi %r15, 24
|
||||
; nextln: br %r14
|
||||
|
||||
function %limit_preamble_large(i64 vmctx) {
|
||||
gv0 = vmctx
|
||||
gv1 = load.i64 notrap aligned gv0
|
||||
gv2 = load.i64 notrap aligned gv1+4
|
||||
stack_limit = gv2
|
||||
ss0 = explicit_slot 400000
|
||||
block0(v0: i64):
|
||||
return
|
||||
}
|
||||
|
||||
; check: lg %r1, 0(%r2)
|
||||
; nextln: lg %r1, 4(%r1)
|
||||
; nextln: clgrtle %r15, %r1
|
||||
; nextln: lay %r1, 400000(%r1)
|
||||
; nextln: clgrtle %r15, %r1
|
||||
; nextln: agfi %r15, -400000
|
||||
; nextln: agfi %r15, 400000
|
||||
; nextln: br %r14
|
||||
|
||||
function %limit_preamble_huge(i64 vmctx) {
|
||||
gv0 = vmctx
|
||||
gv1 = load.i64 notrap aligned gv0
|
||||
gv2 = load.i64 notrap aligned gv1+4
|
||||
stack_limit = gv2
|
||||
ss0 = explicit_slot 4000000
|
||||
block0(v0: i64):
|
||||
return
|
||||
}
|
||||
|
||||
; check: lg %r1, 0(%r2)
|
||||
; nextln: lg %r1, 4(%r1)
|
||||
; nextln: clgrtle %r15, %r1
|
||||
; nextln: algfi %r1, 4000000
|
||||
; nextln: clgrtle %r15, %r1
|
||||
; nextln: agfi %r15, -4000000
|
||||
; nextln: agfi %r15, 4000000
|
||||
; nextln: br %r14
|
||||
|
||||
function %limit_preamble_huge_offset(i64 vmctx) {
|
||||
gv0 = vmctx
|
||||
gv1 = load.i64 notrap aligned gv0+1000000
|
||||
stack_limit = gv1
|
||||
ss0 = explicit_slot 20
|
||||
block0(v0: i64):
|
||||
return
|
||||
}
|
||||
|
||||
; check: lgfi %r1, 1000000 ; lg %r1, 0(%r1,%r2)
|
||||
; nextln: la %r1, 24(%r1)
|
||||
; nextln: clgrtle %r15, %r1
|
||||
; nextln: aghi %r15, -24
|
||||
; nextln: aghi %r15, 24
|
||||
; nextln: br %r14
|
||||
93
cranelift/filetests/filetests/isa/s390x/stack.clif
Normal file
93
cranelift/filetests/filetests/isa/s390x/stack.clif
Normal file
@@ -0,0 +1,93 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
; FIXME: Should allocate register save area.
|
||||
|
||||
function %stack_addr_small() -> i64 {
|
||||
ss0 = explicit_slot 8
|
||||
|
||||
block0:
|
||||
v0 = stack_addr.i64 ss0
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: aghi %r15, -8
|
||||
; nextln: la %r2, 0(%r15)
|
||||
; nextln: aghi %r15, 8
|
||||
; nextln: br %r14
|
||||
|
||||
function %stack_addr_big() -> i64 {
|
||||
ss0 = explicit_slot 100000
|
||||
ss1 = explicit_slot 8
|
||||
|
||||
block0:
|
||||
v0 = stack_addr.i64 ss0
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: agfi %r15, -100008
|
||||
; nextln: la %r2, 0(%r15)
|
||||
; nextln: agfi %r15, 100008
|
||||
; nextln: br %r14
|
||||
|
||||
; FIXME: don't use stack_addr legalization for stack_load and stack_store
|
||||
|
||||
function %stack_load_small() -> i64 {
|
||||
ss0 = explicit_slot 8
|
||||
|
||||
block0:
|
||||
v0 = stack_load.i64 ss0
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: aghi %r15, -8
|
||||
; nextln: la %r2, 0(%r15)
|
||||
; nextln: lg %r2, 0(%r2)
|
||||
; nextln: aghi %r15, 8
|
||||
; nextln: br %r14
|
||||
|
||||
function %stack_load_big() -> i64 {
|
||||
ss0 = explicit_slot 100000
|
||||
ss1 = explicit_slot 8
|
||||
|
||||
block0:
|
||||
v0 = stack_load.i64 ss0
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: agfi %r15, -100008
|
||||
; nextln: la %r2, 0(%r15)
|
||||
; nextln: lg %r2, 0(%r2)
|
||||
; nextln: agfi %r15, 100008
|
||||
; nextln: br %r14
|
||||
|
||||
|
||||
function %stack_store_small(i64) {
|
||||
ss0 = explicit_slot 8
|
||||
|
||||
block0(v0: i64):
|
||||
stack_store.i64 v0, ss0
|
||||
return
|
||||
}
|
||||
|
||||
; check: aghi %r15, -8
|
||||
; nextln: la %r3, 0(%r15)
|
||||
; nextln: stg %r2, 0(%r3)
|
||||
; nextln: aghi %r15, 8
|
||||
; nextln: br %r14
|
||||
|
||||
function %stack_store_big(i64) {
|
||||
ss0 = explicit_slot 100000
|
||||
ss1 = explicit_slot 8
|
||||
|
||||
block0(v0: i64):
|
||||
stack_store.i64 v0, ss0
|
||||
return
|
||||
}
|
||||
|
||||
; check: agfi %r15, -100008
|
||||
; nextln: la %r3, 0(%r15)
|
||||
; nextln: stg %r2, 0(%r3)
|
||||
; nextln: agfi %r15, 100008
|
||||
; nextln: br %r14
|
||||
|
||||
281
cranelift/filetests/filetests/isa/s390x/store-little.clif
Normal file
281
cranelift/filetests/filetests/isa/s390x/store-little.clif
Normal file
@@ -0,0 +1,281 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
function %store_i64(i64, i64) {
|
||||
block0(v0: i64, v1: i64):
|
||||
store.i64 little v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: strvg %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_i64_sym(i64) {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i64):
|
||||
v1 = symbol_value.i64 gv0
|
||||
store.i64 little v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: larl %r1, %sym + 0 ; strvg %r2, 0(%r1)
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_imm_i64(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 12345
|
||||
store.i64 little v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: lghi %r3, 12345
|
||||
; nextln: strvg %r3, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore8_i64(i64, i64) {
|
||||
block0(v0: i64, v1: i64):
|
||||
istore8.i64 little v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: stc %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore8_imm_i64(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 123
|
||||
istore8.i64 little v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: mvi 0(%r2), 123
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore16_i64(i64, i64) {
|
||||
block0(v0: i64, v1: i64):
|
||||
istore16.i64 little v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: strvh %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore16_i64_sym(i64) {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i64):
|
||||
v1 = symbol_value.i64 gv0
|
||||
istore16.i64 little v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: larl %r1, %sym + 0 ; strvh %r2, 0(%r1)
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore16_imm_i64(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 12345
|
||||
istore16.i64 little v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: mvhhi 0(%r2), 14640
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore32_i64(i64, i64) {
|
||||
block0(v0: i64, v1: i64):
|
||||
istore32.i64 little v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: strv %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore32_i64_sym(i64) {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i64):
|
||||
v1 = symbol_value.i64 gv0
|
||||
istore32.i64 little v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: larl %r1, %sym + 0 ; strv %r2, 0(%r1)
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore32_imm_i64(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 12345
|
||||
istore32.i64 little v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: lghi %r3, 12345
|
||||
; nextln: strv %r3, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_i32(i32, i64) {
|
||||
block0(v0: i32, v1: i64):
|
||||
store.i32 little v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: strv %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_i32_sym(i32) {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i32):
|
||||
v1 = symbol_value.i64 gv0
|
||||
store.i32 little v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: larl %r1, %sym + 0 ; strv %r2, 0(%r1)
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_imm_i32(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i32 12345
|
||||
store.i32 little v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: lhi %r3, 12345
|
||||
; nextln: strv %r3, 0(%r2)
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore8_i32(i32, i64) {
|
||||
block0(v0: i32, v1: i64):
|
||||
istore8.i32 little v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: stc %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore8_imm_i32(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i32 123
|
||||
istore8.i32 little v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: mvi 0(%r2), 123
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore16_i32(i32, i64) {
|
||||
block0(v0: i32, v1: i64):
|
||||
istore16.i32 little v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: strvh %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore16_i32_sym(i32) {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i32):
|
||||
v1 = symbol_value.i64 gv0
|
||||
istore16.i32 little v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: larl %r1, %sym + 0 ; strvh %r2, 0(%r1)
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore16_imm_i32(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i32 12345
|
||||
istore16.i32 little v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: mvhhi 0(%r2), 14640
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_i16(i16, i64) {
|
||||
block0(v0: i16, v1: i64):
|
||||
store.i16 little v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: strvh %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_i16_sym(i16) {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i16):
|
||||
v1 = symbol_value.i64 gv0
|
||||
store.i16 little v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: larl %r1, %sym + 0 ; strvh %r2, 0(%r1)
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_imm_i16(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i16 12345
|
||||
store.i16 little v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: mvhhi 0(%r2), 14640
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore8_i16(i16, i64) {
|
||||
block0(v0: i16, v1: i64):
|
||||
istore8.i16 little v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: stc %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore8_imm_i16(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i16 123
|
||||
istore8.i16 little v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: mvi 0(%r2), 123
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_i8(i8, i64) {
|
||||
block0(v0: i8, v1: i64):
|
||||
store.i8 little v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: stc %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_i8_off(i8, i64) {
|
||||
block0(v0: i8, v1: i64):
|
||||
store.i8 little v0, v1+4096
|
||||
return
|
||||
}
|
||||
|
||||
; check: stcy %r2, 4096(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_imm_i8(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i8 123
|
||||
store.i8 little v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: mvi 0(%r2), 123
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_imm_i8_off(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i8 123
|
||||
store.i8 little v1, v0+4096
|
||||
return
|
||||
}
|
||||
|
||||
; check: mviy 4096(%r2), 123
|
||||
; nextln: br %r14
|
||||
|
||||
296
cranelift/filetests/filetests/isa/s390x/store.clif
Normal file
296
cranelift/filetests/filetests/isa/s390x/store.clif
Normal file
@@ -0,0 +1,296 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
function %store_i64(i64, i64) {
|
||||
block0(v0: i64, v1: i64):
|
||||
store.i64 v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: stg %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_i64_sym(i64) {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i64):
|
||||
v1 = symbol_value.i64 gv0
|
||||
store.i64 v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: stgrl %r2, %sym + 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_imm_i64(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 12345
|
||||
store.i64 v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: mvghi 0(%r2), 12345
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore8_i64(i64, i64) {
|
||||
block0(v0: i64, v1: i64):
|
||||
istore8.i64 v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: stc %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore8_imm_i64(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 123
|
||||
istore8.i64 v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: mvi 0(%r2), 123
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore16_i64(i64, i64) {
|
||||
block0(v0: i64, v1: i64):
|
||||
istore16.i64 v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: sth %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore16_i64_sym(i64) {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i64):
|
||||
v1 = symbol_value.i64 gv0
|
||||
istore16.i64 v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: sthrl %r2, %sym + 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore16_imm_i64(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 12345
|
||||
istore16.i64 v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: mvhhi 0(%r2), 12345
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore32_i64(i64, i64) {
|
||||
block0(v0: i64, v1: i64):
|
||||
istore32.i64 v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: st %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore32_i64_sym(i64) {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i64):
|
||||
v1 = symbol_value.i64 gv0
|
||||
istore32.i64 v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: strl %r2, %sym + 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore32_imm_i64(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 12345
|
||||
istore32.i64 v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: mvhi 0(%r2), 12345
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_i32(i32, i64) {
|
||||
block0(v0: i32, v1: i64):
|
||||
store.i32 v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: st %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_i32_sym(i32) {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i32):
|
||||
v1 = symbol_value.i64 gv0
|
||||
store.i32 v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: strl %r2, %sym + 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_i32_off(i32, i64) {
|
||||
block0(v0: i32, v1: i64):
|
||||
store.i32 v0, v1+4096
|
||||
return
|
||||
}
|
||||
|
||||
; check: sty %r2, 4096(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_imm_i32(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i32 12345
|
||||
store.i32 v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: mvhi 0(%r2), 12345
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore8_i32(i32, i64) {
|
||||
block0(v0: i32, v1: i64):
|
||||
istore8.i32 v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: stc %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore8_imm_i32(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i32 123
|
||||
istore8.i32 v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: mvi 0(%r2), 123
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore16_i32(i32, i64) {
|
||||
block0(v0: i32, v1: i64):
|
||||
istore16.i32 v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: sth %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore16_i32_sym(i32) {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i32):
|
||||
v1 = symbol_value.i64 gv0
|
||||
istore16.i32 v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: sthrl %r2, %sym + 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore16_imm_i32(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i32 12345
|
||||
istore16.i32 v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: mvhhi 0(%r2), 12345
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_i16(i16, i64) {
|
||||
block0(v0: i16, v1: i64):
|
||||
store.i16 v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: sth %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_i16_sym(i16) {
|
||||
gv0 = symbol colocated %sym
|
||||
block0(v0: i16):
|
||||
v1 = symbol_value.i64 gv0
|
||||
store.i16 v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: sthrl %r2, %sym + 0
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_i16_off(i16, i64) {
|
||||
block0(v0: i16, v1: i64):
|
||||
store.i16 v0, v1+4096
|
||||
return
|
||||
}
|
||||
|
||||
; check: sthy %r2, 4096(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_imm_i16(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i16 12345
|
||||
store.i16 v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: mvhhi 0(%r2), 12345
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore8_i16(i16, i64) {
|
||||
block0(v0: i16, v1: i64):
|
||||
istore8.i16 v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: stc %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %istore8_imm_i16(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i16 123
|
||||
istore8.i16 v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: mvi 0(%r2), 123
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_i8(i8, i64) {
|
||||
block0(v0: i8, v1: i64):
|
||||
store.i8 v0, v1
|
||||
return
|
||||
}
|
||||
|
||||
; check: stc %r2, 0(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_i8_off(i8, i64) {
|
||||
block0(v0: i8, v1: i64):
|
||||
store.i8 v0, v1+4096
|
||||
return
|
||||
}
|
||||
|
||||
; check: stcy %r2, 4096(%r3)
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_imm_i8(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i8 123
|
||||
store.i8 v1, v0
|
||||
return
|
||||
}
|
||||
|
||||
; check: mvi 0(%r2), 123
|
||||
; nextln: br %r14
|
||||
|
||||
function %store_imm_i8_off(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i8 123
|
||||
store.i8 v1, v0+4096
|
||||
return
|
||||
}
|
||||
|
||||
; check: mviy 4096(%r2), 123
|
||||
; nextln: br %r14
|
||||
|
||||
54
cranelift/filetests/filetests/isa/s390x/symbols.clif
Normal file
54
cranelift/filetests/filetests/isa/s390x/symbols.clif
Normal file
@@ -0,0 +1,54 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; SYMBOL_VALUE
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %symbol_value() -> i64 {
|
||||
gv0 = symbol %my_global
|
||||
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: bras %r1, 12 ; data %my_global + 0 ; lg %r2, 0(%r1)
|
||||
; nextln: br %r14
|
||||
|
||||
function %symbol_value_colocated() -> i64 {
|
||||
gv0 = symbol colocated %my_global_colo
|
||||
|
||||
block0:
|
||||
v0 = symbol_value.i64 gv0
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: larl %r2, %my_global_colo + 0
|
||||
; nextln: br %r14
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; FUNC_ADDR
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %func_addr() -> i64 {
|
||||
fn0 = %my_func(i64) -> i64
|
||||
|
||||
block0:
|
||||
v0 = func_addr.i64 fn0
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: bras %r1, 12 ; data %my_func + 0 ; lg %r2, 0(%r1)
|
||||
; nextln: br %r14
|
||||
|
||||
function %func_addr_colocated() -> i64 {
|
||||
fn0 = colocated %my_func_colo(i64) -> i64
|
||||
|
||||
block0:
|
||||
v0 = func_addr.i64 fn0
|
||||
return v0
|
||||
}
|
||||
|
||||
; check: larl %r2, %my_func_colo + 0
|
||||
; nextln: br %r14
|
||||
91
cranelift/filetests/filetests/isa/s390x/traps.clif
Normal file
91
cranelift/filetests/filetests/isa/s390x/traps.clif
Normal file
@@ -0,0 +1,91 @@
|
||||
test compile
|
||||
target s390x
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; TRAP/RESUMABLE_TRAP
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %trap() {
|
||||
block0:
|
||||
trap user0
|
||||
}
|
||||
|
||||
; check: trap
|
||||
|
||||
function %resumable_trap() {
|
||||
block0:
|
||||
trap user0
|
||||
}
|
||||
|
||||
; check: trap
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; TRAPZ
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %trapz(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 42
|
||||
v2 = icmp eq v0, v1
|
||||
trapz v2, user0
|
||||
return
|
||||
}
|
||||
|
||||
; FIXME: Does not use TrapIf internally as trapz is expanded.
|
||||
; check: Block 0
|
||||
; check: clgfi %r2, 42
|
||||
; nextln: jge label1 ; jg label2
|
||||
; check: Block 1:
|
||||
; check: br %r14
|
||||
; check: Block 2:
|
||||
; check: trap
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; TRAPNZ/RESUMABLE_TRAPNZ
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %trapnz(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 42
|
||||
v2 = icmp eq v0, v1
|
||||
trapnz v2, user0
|
||||
return
|
||||
}
|
||||
|
||||
; FIXME: Does not use TrapIf internally as trapnz is expanded.
|
||||
; check: Block 0
|
||||
; check: clgfi %r2, 42
|
||||
; nextln: jgne label1 ; jg label2
|
||||
; check: Block 1:
|
||||
; check: br %r14
|
||||
; check: Block 2:
|
||||
; check: trap
|
||||
|
||||
function %resumable_trapnz(i64) {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 42
|
||||
v2 = icmp eq v0, v1
|
||||
trapnz v2, user0
|
||||
return
|
||||
}
|
||||
|
||||
; FIXME: Does not use TrapIf internally as resumable_trapnz is expanded.
|
||||
; check: Block 0
|
||||
; check: clgfi %r2, 42
|
||||
; nextln: jgne label1 ; jg label2
|
||||
; check: Block 1:
|
||||
; check: br %r14
|
||||
; check: Block 2:
|
||||
; check: trap
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; DEBUGTRAP
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
function %h() {
|
||||
block0:
|
||||
debugtrap
|
||||
return
|
||||
}
|
||||
|
||||
; check: debugtrap
|
||||
Reference in New Issue
Block a user