cranelift_codegen/isa/s390x/inst/
regs.rs

1//! S390x ISA definitions: registers.
2
3use alloc::string::String;
4use regalloc2::PReg;
5
6use crate::isa::s390x::inst::{RegPair, WritableRegPair};
7use crate::machinst::*;
8
9//=============================================================================
10// Registers, the Universe thereof, and printing
11
12/// Get a reference to a GPR (integer register).
13pub fn gpr(num: u8) -> Reg {
14    Reg::from(gpr_preg(num))
15}
16
17pub(crate) const fn gpr_preg(num: u8) -> PReg {
18    assert!(num < 16);
19    PReg::new(num as usize, RegClass::Int)
20}
21
22/// Get a writable reference to a GPR.
23pub fn writable_gpr(num: u8) -> Writable<Reg> {
24    Writable::from_reg(gpr(num))
25}
26
27/// Get a reference to a VR (vector register).
28pub fn vr(num: u8) -> Reg {
29    Reg::from(vr_preg(num))
30}
31
32pub(crate) const fn vr_preg(num: u8) -> PReg {
33    assert!(num < 32);
34    PReg::new(num as usize, RegClass::Float)
35}
36
37/// Get a writable reference to a VR.
38#[allow(dead_code)] // used by tests.
39pub fn writable_vr(num: u8) -> Writable<Reg> {
40    Writable::from_reg(vr(num))
41}
42
43/// Test whether a vector register is overlapping an FPR.
44pub fn is_fpr(r: Reg) -> bool {
45    let r = r.to_real_reg().unwrap();
46    assert!(r.class() == RegClass::Float);
47    return r.hw_enc() < 16;
48}
49
50/// Get a reference to the stack-pointer register.
51pub fn stack_reg() -> Reg {
52    gpr(15)
53}
54
55/// Get a writable reference to the stack-pointer register.
56pub fn writable_stack_reg() -> Writable<Reg> {
57    Writable::from_reg(stack_reg())
58}
59
60/// Get a reference to the first temporary, sometimes "spill temporary", register. This register is
61/// used to compute the address of a spill slot when a direct offset addressing mode from FP is not
62/// sufficient (+/- 2^11 words). We exclude this register from regalloc and reserve it for this
63/// purpose for simplicity; otherwise we need a multi-stage analysis where we first determine how
64/// many spill slots we have, then perhaps remove the reg from the pool and recompute regalloc.
65///
66/// We use r1 for this because it's a scratch register but is slightly special (used for linker
67/// veneers). We're free to use it as long as we don't expect it to live through call instructions.
68pub fn spilltmp_reg() -> Reg {
69    gpr(1)
70}
71
72/// Get a writable reference to the spilltmp reg.
73pub fn writable_spilltmp_reg() -> Writable<Reg> {
74    Writable::from_reg(spilltmp_reg())
75}
76
77pub fn zero_reg() -> Reg {
78    gpr(0)
79}
80
81pub fn show_reg(reg: Reg) -> String {
82    if let Some(rreg) = reg.to_real_reg() {
83        match rreg.class() {
84            RegClass::Int => format!("%r{}", rreg.hw_enc()),
85            RegClass::Float => format!("%v{}", rreg.hw_enc()),
86            RegClass::Vector => unreachable!(),
87        }
88    } else {
89        format!("%{reg:?}")
90    }
91}
92
93pub fn maybe_show_fpr(reg: Reg) -> Option<String> {
94    if let Some(rreg) = reg.to_real_reg() {
95        if is_fpr(reg) {
96            return Some(format!("%f{}", rreg.hw_enc()));
97        }
98    }
99    None
100}
101
102pub fn pretty_print_reg(reg: Reg) -> String {
103    show_reg(reg)
104}
105
106pub fn pretty_print_regpair(pair: RegPair) -> String {
107    let hi = pair.hi;
108    let lo = pair.lo;
109    if let Some(hi_reg) = hi.to_real_reg() {
110        if let Some(lo_reg) = lo.to_real_reg() {
111            assert!(
112                hi_reg.hw_enc() + 1 == lo_reg.hw_enc(),
113                "Invalid regpair: {} {}",
114                show_reg(hi),
115                show_reg(lo)
116            );
117            return show_reg(hi);
118        }
119    }
120
121    format!("{}/{}", show_reg(hi), show_reg(lo))
122}
123
124pub fn pretty_print_reg_mod(rd: Writable<Reg>, ri: Reg) -> String {
125    let output = rd.to_reg();
126    let input = ri;
127    if output == input {
128        show_reg(output)
129    } else {
130        format!("{}<-{}", show_reg(output), show_reg(input))
131    }
132}
133
134pub fn pretty_print_regpair_mod(rd: WritableRegPair, ri: RegPair) -> String {
135    let rd_hi = rd.hi.to_reg();
136    let rd_lo = rd.lo.to_reg();
137    let ri_hi = ri.hi;
138    let ri_lo = ri.lo;
139    if rd_hi == ri_hi {
140        show_reg(rd_hi)
141    } else {
142        format!(
143            "{}/{}<-{}/{}",
144            show_reg(rd_hi),
145            show_reg(rd_lo),
146            show_reg(ri_hi),
147            show_reg(ri_lo)
148        )
149    }
150}
151
152pub fn pretty_print_regpair_mod_lo(rd: WritableRegPair, ri: Reg) -> String {
153    let rd_hi = rd.hi.to_reg();
154    let rd_lo = rd.lo.to_reg();
155    if rd_lo == ri {
156        show_reg(rd_hi)
157    } else {
158        format!(
159            "{}/{}<-_/{}",
160            show_reg(rd_hi),
161            show_reg(rd_lo),
162            show_reg(ri),
163        )
164    }
165}
166
167pub fn pretty_print_fpr(reg: Reg) -> (String, Option<String>) {
168    (show_reg(reg), maybe_show_fpr(reg))
169}