use crate::systemz::systemz_register_info::SystemzRegister;
pub struct SystemzCallingConvention {
pub arg_regs: Vec<SystemzRegister>,
pub ret_regs: Vec<SystemzRegister>,
pub fp_arg_regs: Vec<SystemzRegister>,
pub fp_ret_regs: Vec<SystemzRegister>,
pub callee_saved: Vec<SystemzRegister>,
pub caller_saved: Vec<SystemzRegister>,
pub sp: SystemzRegister,
pub fp: SystemzRegister,
pub ra: SystemzRegister,
}
impl SystemzCallingConvention {
pub fn new() -> Self {
SystemzCallingConvention {
arg_regs: vec![
SystemzRegister::R2,
SystemzRegister::R3,
SystemzRegister::R4,
SystemzRegister::R5,
SystemzRegister::R6,
],
ret_regs: vec![SystemzRegister::R2, SystemzRegister::R3],
fp_arg_regs: vec![
SystemzRegister::F0,
SystemzRegister::F2,
SystemzRegister::F4,
SystemzRegister::F6,
],
fp_ret_regs: vec![SystemzRegister::F0],
callee_saved: vec![
SystemzRegister::R6,
SystemzRegister::R7,
SystemzRegister::R8,
SystemzRegister::R9,
SystemzRegister::R10,
SystemzRegister::R11,
SystemzRegister::R12,
SystemzRegister::R13,
SystemzRegister::R14,
SystemzRegister::R15,
SystemzRegister::F8,
SystemzRegister::F9,
SystemzRegister::F10,
SystemzRegister::F11,
SystemzRegister::F12,
SystemzRegister::F13,
SystemzRegister::F14,
SystemzRegister::F15,
],
caller_saved: vec![
SystemzRegister::R0,
SystemzRegister::R1,
SystemzRegister::R2,
SystemzRegister::R3,
SystemzRegister::R4,
SystemzRegister::R5,
SystemzRegister::F0,
SystemzRegister::F1,
SystemzRegister::F2,
SystemzRegister::F3,
SystemzRegister::F4,
SystemzRegister::F5,
SystemzRegister::F6,
SystemzRegister::F7,
],
sp: SystemzRegister::R15,
fp: SystemzRegister::R11,
ra: SystemzRegister::R14,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SystemzArchLevel {
Z10, Z196, ZEC12, Z13, Z14, Z15, Z16, }
pub struct SystemzTargetMachine {
pub cpu: String,
pub arch_level: SystemzArchLevel,
pub has_vector: bool,
pub has_dfp: bool,
pub has_tx: bool,
pub calling_conv: SystemzCallingConvention,
}
impl SystemzTargetMachine {
pub fn new(arch: SystemzArchLevel) -> Self {
let (cpu, has_vector, has_dfp, has_tx) = match arch {
SystemzArchLevel::Z10 => ("z10", false, false, false),
SystemzArchLevel::Z196 => ("z196", false, true, false),
SystemzArchLevel::ZEC12 => ("zEC12", false, true, true),
SystemzArchLevel::Z13 => ("z13", true, true, true),
SystemzArchLevel::Z14 => ("z14", true, true, true),
SystemzArchLevel::Z15 => ("z15", true, true, true),
SystemzArchLevel::Z16 => ("z16", true, true, true),
};
SystemzTargetMachine {
cpu: cpu.to_string(),
arch_level: arch,
has_vector,
has_dfp,
has_tx,
calling_conv: SystemzCallingConvention::new(),
}
}
pub fn default_target() -> Self {
Self::new(SystemzArchLevel::Z14)
}
pub fn get_target_triple(&self) -> String {
"s390x-ibm-linux-gnu".to_string()
}
pub fn get_data_layout(&self) -> String {
"E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64".to_string()
}
pub fn get_pointer_size(&self) -> u32 {
64
}
pub fn get_register_width(&self) -> u32 {
64
}
pub fn get_stack_alignment(&self) -> u32 {
8
}
pub fn get_red_zone_size(&self) -> u32 {
160
}
pub fn has_vector_facility(&self) -> bool {
self.has_vector
}
pub fn has_dfp_facility(&self) -> bool {
self.has_dfp
}
pub fn has_tx_facility(&self) -> bool {
self.has_tx
}
pub fn get_cpu(&self) -> &str {
&self.cpu
}
pub fn get_arch_level(&self) -> SystemzArchLevel {
self.arch_level
}
pub fn get_page_size(&self) -> u32 {
4096
}
pub fn get_min_stack_size(&self) -> u32 {
8192 }
pub fn get_max_alignment(&self) -> u32 {
8
}
pub fn supports_unaligned_access(&self) -> bool {
true
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_z14_config() {
let tm = SystemzTargetMachine::new(SystemzArchLevel::Z14);
assert!(tm.has_vector);
assert!(tm.has_dfp);
assert!(tm.has_tx);
assert_eq!(tm.cpu, "z14");
}
#[test]
fn test_z10_config() {
let tm = SystemzTargetMachine::new(SystemzArchLevel::Z10);
assert!(!tm.has_vector);
assert!(!tm.has_tx);
}
#[test]
fn test_z196_has_dfp() {
let tm = SystemzTargetMachine::new(SystemzArchLevel::Z196);
assert!(tm.has_dfp);
assert!(!tm.has_vector);
}
#[test]
fn test_zec12_has_tx() {
let tm = SystemzTargetMachine::new(SystemzArchLevel::ZEC12);
assert!(tm.has_tx);
}
#[test]
fn test_target_triple() {
let tm = SystemzTargetMachine::default_target();
assert_eq!(tm.get_target_triple(), "s390x-ibm-linux-gnu");
}
#[test]
fn test_data_layout() {
let tm = SystemzTargetMachine::default_target();
let layout = tm.get_data_layout();
assert!(layout.starts_with("E"));
assert!(layout.contains("i64:64"));
}
#[test]
fn test_pointer_size() {
let tm = SystemzTargetMachine::default_target();
assert_eq!(tm.get_pointer_size(), 64);
}
#[test]
fn test_register_width() {
let tm = SystemzTargetMachine::default_target();
assert_eq!(tm.get_register_width(), 64);
}
#[test]
fn test_stack_alignment() {
let tm = SystemzTargetMachine::default_target();
assert_eq!(tm.get_stack_alignment(), 8);
}
#[test]
fn test_red_zone_size() {
let tm = SystemzTargetMachine::default_target();
assert_eq!(tm.get_red_zone_size(), 160);
}
#[test]
fn test_page_size() {
let tm = SystemzTargetMachine::default_target();
assert_eq!(tm.get_page_size(), 4096);
}
#[test]
fn test_min_stack_size() {
let tm = SystemzTargetMachine::default_target();
assert_eq!(tm.get_min_stack_size(), 8192);
}
#[test]
fn test_supports_unaligned_access() {
let tm = SystemzTargetMachine::default_target();
assert!(tm.supports_unaligned_access());
}
#[test]
fn test_calling_convention_arg_regs() {
let cc = SystemzCallingConvention::new();
assert_eq!(cc.arg_regs.len(), 5);
assert_eq!(cc.arg_regs[0], SystemzRegister::R2);
}
#[test]
fn test_calling_convention_ret_regs() {
let cc = SystemzCallingConvention::new();
assert_eq!(cc.ret_regs, vec![SystemzRegister::R2, SystemzRegister::R3]);
}
#[test]
fn test_calling_convention_fp_arg_regs() {
let cc = SystemzCallingConvention::new();
assert_eq!(cc.fp_arg_regs[0], SystemzRegister::F0);
assert_eq!(cc.fp_arg_regs[2], SystemzRegister::F4);
}
#[test]
fn test_calling_convention_fp_ret_regs() {
let cc = SystemzCallingConvention::new();
assert_eq!(cc.fp_ret_regs, vec![SystemzRegister::F0]);
}
#[test]
fn test_calling_convention_callee_saved() {
let cc = SystemzCallingConvention::new();
assert!(cc.callee_saved.contains(&SystemzRegister::R15));
assert!(cc.callee_saved.contains(&SystemzRegister::F15));
assert!(!cc.callee_saved.contains(&SystemzRegister::R0));
}
#[test]
fn test_calling_convention_sp_fp_ra() {
let cc = SystemzCallingConvention::new();
assert_eq!(cc.sp, SystemzRegister::R15);
assert_eq!(cc.fp, SystemzRegister::R11);
assert_eq!(cc.ra, SystemzRegister::R14);
}
#[test]
fn test_default_target_is_z14() {
let tm = SystemzTargetMachine::default_target();
assert_eq!(tm.cpu, "z14");
assert!(tm.has_vector);
}
#[test]
fn test_arch_level_enum_variants() {
let levels = [
SystemzArchLevel::Z10,
SystemzArchLevel::Z196,
SystemzArchLevel::ZEC12,
SystemzArchLevel::Z13,
SystemzArchLevel::Z14,
SystemzArchLevel::Z15,
SystemzArchLevel::Z16,
];
for l in &levels {
let tm = SystemzTargetMachine::new(*l);
assert!(!tm.cpu.is_empty());
}
}
#[test]
fn test_max_alignment() {
let tm = SystemzTargetMachine::default_target();
assert_eq!(tm.get_max_alignment(), 8);
}
}