1 //! 32-bit ARM ISA definitions: registers.
2
3 use regalloc::{RealRegUniverse, Reg, RegClass, RegClassInfo, Writable, NUM_REG_CLASSES};
4
5 use std::string::ToString;
6
7 /// Get a reference to a GPR.
rreg(num: u8) -> Reg8 pub fn rreg(num: u8) -> Reg {
9 assert!(num < 16);
10 Reg::new_real(RegClass::I32, num, num)
11 }
12
13 /// Get a writable reference to a GPR.
writable_rreg(num: u8) -> Writable<Reg>14 pub fn writable_rreg(num: u8) -> Writable<Reg> {
15 Writable::from_reg(rreg(num))
16 }
17
18 /// Get a reference to the program counter (r15).
pc_reg() -> Reg19 pub fn pc_reg() -> Reg {
20 rreg(15)
21 }
22
23 /// Get a writable reference to the program counter.
writable_pc_reg() -> Writable<Reg>24 pub fn writable_pc_reg() -> Writable<Reg> {
25 Writable::from_reg(pc_reg())
26 }
27
28 /// Get a reference to the link register (r14).
lr_reg() -> Reg29 pub fn lr_reg() -> Reg {
30 rreg(14)
31 }
32
33 /// Get a writable reference to the link register.
writable_lr_reg() -> Writable<Reg>34 pub fn writable_lr_reg() -> Writable<Reg> {
35 Writable::from_reg(lr_reg())
36 }
37
38 /// Get a reference to the stack pointer (r13).
sp_reg() -> Reg39 pub fn sp_reg() -> Reg {
40 rreg(13)
41 }
42
43 /// Get a writable reference to the stack pointer.
writable_sp_reg() -> Writable<Reg>44 pub fn writable_sp_reg() -> Writable<Reg> {
45 Writable::from_reg(sp_reg())
46 }
47
48 /// Get a reference to the intra-procedure-call scratch register (r12),
49 /// which is used as a temporary register.
ip_reg() -> Reg50 pub fn ip_reg() -> Reg {
51 rreg(12)
52 }
53
54 /// Get a writable reference to the Intra-Procedure-call scratch register.
writable_ip_reg() -> Writable<Reg>55 pub fn writable_ip_reg() -> Writable<Reg> {
56 Writable::from_reg(ip_reg())
57 }
58
59 /// Get a reference to the frame pointer register (r11).
fp_reg() -> Reg60 pub fn fp_reg() -> Reg {
61 rreg(11)
62 }
63
64 /// Get a writable reference to the frame-pointer register.
writable_fp_reg() -> Writable<Reg>65 pub fn writable_fp_reg() -> Writable<Reg> {
66 Writable::from_reg(fp_reg())
67 }
68
69 /// Get a reference to the second temp register. We need this in some edge cases
70 /// where we need both the ip and another temporary.
71 ///
72 /// We use r10 for this role.
tmp2_reg() -> Reg73 pub fn tmp2_reg() -> Reg {
74 rreg(10)
75 }
76
77 /// Get a writable reference to the tmp2 reg.
writable_tmp2_reg() -> Writable<Reg>78 pub fn writable_tmp2_reg() -> Writable<Reg> {
79 Writable::from_reg(tmp2_reg())
80 }
81
82 /// Create the register universe.
83 /// Use only GPR for now.
create_reg_universe() -> RealRegUniverse84 pub fn create_reg_universe() -> RealRegUniverse {
85 let mut regs = vec![];
86 let mut allocable_by_class = [None; NUM_REG_CLASSES];
87
88 let r_reg_base = 0u8;
89 let r_reg_count = 10; // to exclude r10, fp, ip, sp, lr and pc.
90 for i in 0..r_reg_count {
91 let reg = Reg::new_real(
92 RegClass::I32,
93 /* enc = */ i,
94 /* index = */ r_reg_base + i,
95 )
96 .to_real_reg();
97 let name = format!("r{}", i);
98 regs.push((reg, name));
99 }
100 let r_reg_last = r_reg_base + r_reg_count - 1;
101
102 allocable_by_class[RegClass::I32.rc_to_usize()] = Some(RegClassInfo {
103 first: r_reg_base as usize,
104 last: r_reg_last as usize,
105 suggested_scratch: None,
106 });
107
108 // Other regs, not available to the allocator.
109 let allocable = regs.len();
110 regs.push((tmp2_reg().to_real_reg(), "r10".to_string()));
111 regs.push((fp_reg().to_real_reg(), "fp".to_string()));
112 regs.push((ip_reg().to_real_reg(), "ip".to_string()));
113 regs.push((sp_reg().to_real_reg(), "sp".to_string()));
114 regs.push((lr_reg().to_real_reg(), "lr".to_string()));
115 regs.push((pc_reg().to_real_reg(), "pc".to_string()));
116
117 // The indices in the register structs must match their
118 // actual indices in the array.
119 for (i, reg) in regs.iter().enumerate() {
120 assert_eq!(i, reg.0.get_index());
121 }
122
123 RealRegUniverse {
124 regs,
125 allocable,
126 allocable_by_class,
127 }
128 }
129