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 const fn gpr(num: u8) -> Reg {
14    Reg::from_real_reg(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 const fn vr(num: u8) -> Reg {
29    Reg::from_real_reg(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.
38pub fn writable_vr(num: u8) -> Writable<Reg> {
39    Writable::from_reg(vr(num))
40}
41
42/// Test whether a vector register is overlapping an FPR.
43pub fn is_fpr(r: Reg) -> bool {
44    let r = r.to_real_reg().unwrap();
45    assert!(r.class() == RegClass::Float);
46    return r.hw_enc() < 16;
47}
48
49/// Get a reference to the stack-pointer register.
50pub fn stack_reg() -> Reg {
51    gpr(15)
52}
53
54/// Get a writable reference to the stack-pointer register.
55pub fn writable_stack_reg() -> Writable<Reg> {
56    Writable::from_reg(stack_reg())
57}
58
59/// Get a reference to the first temporary, sometimes "spill temporary", register. This register is
60/// used to compute the address of a spill slot when a direct offset addressing mode from FP is not
61/// sufficient (+/- 2^11 words). We exclude this register from regalloc and reserve it for this
62/// purpose for simplicity; otherwise we need a multi-stage analysis where we first determine how
63/// many spill slots we have, then perhaps remove the reg from the pool and recompute regalloc.
64///
65/// We use r1 for this because it's a scratch register but is slightly special (used for linker
66/// veneers). We're free to use it as long as we don't expect it to live through call instructions.
67pub fn spilltmp_reg() -> Reg {
68    gpr(1)
69}
70
71/// Get a writable reference to the spilltmp reg.
72pub fn writable_spilltmp_reg() -> Writable<Reg> {
73    Writable::from_reg(spilltmp_reg())
74}
75
76pub fn zero_reg() -> Reg {
77    gpr(0)
78}
79
80pub fn show_reg(reg: Reg) -> String {
81    if let Some(rreg) = reg.to_real_reg() {
82        match rreg.class() {
83            RegClass::Int => format!("%r{}", rreg.hw_enc()),
84            RegClass::Float => format!("%v{}", rreg.hw_enc()),
85            RegClass::Vector => unreachable!(),
86        }
87    } else {
88        format!("%{reg:?}")
89    }
90}
91
92pub fn maybe_show_fpr(reg: Reg) -> Option<String> {
93    if let Some(rreg) = reg.to_real_reg() {
94        if is_fpr(reg) {
95            return Some(format!("%f{}", rreg.hw_enc()));
96        }
97    }
98    None
99}
100
101pub fn pretty_print_reg(reg: Reg) -> String {
102    show_reg(reg)
103}
104
105pub fn pretty_print_regpair(pair: RegPair) -> String {
106    let hi = pair.hi;
107    let lo = pair.lo;
108    if let Some(hi_reg) = hi.to_real_reg() {
109        if let Some(lo_reg) = lo.to_real_reg() {
110            assert!(
111                hi_reg.hw_enc() + 1 == lo_reg.hw_enc(),
112                "Invalid regpair: {} {}",
113                show_reg(hi),
114                show_reg(lo)
115            );
116            return show_reg(hi);
117        }
118    }
119
120    format!("{}/{}", show_reg(hi), show_reg(lo))
121}
122
123pub fn pretty_print_fp_regpair(pair: RegPair) -> String {
124    let hi = pair.hi;
125    let lo = pair.lo;
126    if let Some(hi_reg) = hi.to_real_reg() {
127        if let Some(lo_reg) = lo.to_real_reg() {
128            assert!(
129                hi_reg.hw_enc() + 2 == lo_reg.hw_enc(),
130                "Invalid regpair: {} {}",
131                show_reg(hi),
132                show_reg(lo)
133            );
134            return maybe_show_fpr(hi).unwrap();
135        }
136    }
137
138    format!("{}/{}", show_reg(hi), show_reg(lo))
139}
140
141pub fn pretty_print_reg_mod(rd: Writable<Reg>, ri: Reg) -> String {
142    let output = rd.to_reg();
143    let input = ri;
144    if output == input {
145        show_reg(output)
146    } else {
147        format!("{}<-{}", show_reg(output), show_reg(input))
148    }
149}
150
151pub fn pretty_print_regpair_mod(rd: WritableRegPair, ri: RegPair) -> String {
152    let rd_hi = rd.hi.to_reg();
153    let rd_lo = rd.lo.to_reg();
154    let ri_hi = ri.hi;
155    let ri_lo = ri.lo;
156    if rd_hi == ri_hi {
157        show_reg(rd_hi)
158    } else {
159        format!(
160            "{}/{}<-{}/{}",
161            show_reg(rd_hi),
162            show_reg(rd_lo),
163            show_reg(ri_hi),
164            show_reg(ri_lo)
165        )
166    }
167}
168
169pub fn pretty_print_regpair_mod_lo(rd: WritableRegPair, ri: Reg) -> String {
170    let rd_hi = rd.hi.to_reg();
171    let rd_lo = rd.lo.to_reg();
172    if rd_lo == ri {
173        show_reg(rd_hi)
174    } else {
175        format!(
176            "{}/{}<-_/{}",
177            show_reg(rd_hi),
178            show_reg(rd_lo),
179            show_reg(ri),
180        )
181    }
182}
183
184pub fn pretty_print_fpr(reg: Reg) -> (String, Option<String>) {
185    (show_reg(reg), maybe_show_fpr(reg))
186}