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:
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,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user