1 //! 32-bit ARM ISA definitions: instruction arguments.
2 
3 use crate::isa::arm32::inst::*;
4 
5 use regalloc::{PrettyPrint, RealRegUniverse, Reg};
6 
7 use std::string::String;
8 
9 /// A shift operator for a register or immediate.
10 #[derive(Clone, Copy, Debug)]
11 #[repr(u8)]
12 pub enum ShiftOp {
13     LSL = 0b00,
14     LSR = 0b01,
15     ASR = 0b10,
16     ROR = 0b11,
17 }
18 
19 impl ShiftOp {
20     /// Get the encoding of this shift op.
bits(self) -> u821     pub fn bits(self) -> u8 {
22         self as u8
23     }
24 }
25 
26 /// A shift operator amount.
27 #[derive(Clone, Copy, Debug)]
28 pub struct ShiftOpShiftImm(u8);
29 
30 impl ShiftOpShiftImm {
31     /// Maximum shift for shifted-register operands.
32     pub const MAX_SHIFT: u32 = 31;
33 
34     /// Create a new shiftop shift amount, if possible.
maybe_from_shift(shift: u32) -> Option<ShiftOpShiftImm>35     pub fn maybe_from_shift(shift: u32) -> Option<ShiftOpShiftImm> {
36         if shift <= Self::MAX_SHIFT {
37             Some(ShiftOpShiftImm(shift as u8))
38         } else {
39             None
40         }
41     }
42 
43     /// Return the shift amount.
value(self) -> u844     pub fn value(self) -> u8 {
45         self.0
46     }
47 }
48 
49 /// A shift operator with an amount, guaranteed to be within range.
50 #[derive(Clone, Debug)]
51 pub struct ShiftOpAndAmt {
52     op: ShiftOp,
53     shift: ShiftOpShiftImm,
54 }
55 
56 impl ShiftOpAndAmt {
new(op: ShiftOp, shift: ShiftOpShiftImm) -> ShiftOpAndAmt57     pub fn new(op: ShiftOp, shift: ShiftOpShiftImm) -> ShiftOpAndAmt {
58         ShiftOpAndAmt { op, shift }
59     }
60 
61     /// Get the shift op.
op(&self) -> ShiftOp62     pub fn op(&self) -> ShiftOp {
63         self.op
64     }
65 
66     /// Get the shift amount.
amt(&self) -> ShiftOpShiftImm67     pub fn amt(&self) -> ShiftOpShiftImm {
68         self.shift
69     }
70 }
71 
72 // An unsigned 8-bit immediate.
73 #[derive(Clone, Copy, Debug)]
74 pub struct UImm8 {
75     /// The value.
76     value: u8,
77 }
78 
79 impl UImm8 {
maybe_from_i64(value: i64) -> Option<UImm8>80     pub fn maybe_from_i64(value: i64) -> Option<UImm8> {
81         if 0 <= value && value < (1 << 8) {
82             Some(UImm8 { value: value as u8 })
83         } else {
84             None
85         }
86     }
87 
88     /// Bits for encoding.
bits(&self) -> u3289     pub fn bits(&self) -> u32 {
90         u32::from(self.value)
91     }
92 }
93 
94 /// An unsigned 12-bit immediate.
95 #[derive(Clone, Copy, Debug)]
96 pub struct UImm12 {
97     /// The value.
98     value: u16,
99 }
100 
101 impl UImm12 {
maybe_from_i64(value: i64) -> Option<UImm12>102     pub fn maybe_from_i64(value: i64) -> Option<UImm12> {
103         if 0 <= value && value < (1 << 12) {
104             Some(UImm12 {
105                 value: value as u16,
106             })
107         } else {
108             None
109         }
110     }
111 
112     /// Bits for encoding.
bits(&self) -> u32113     pub fn bits(&self) -> u32 {
114         u32::from(self.value)
115     }
116 }
117 
118 /// An addressing mode specified for a load/store operation.
119 #[derive(Clone, Debug)]
120 pub enum AMode {
121     // Real addressing modes
122     /// Register plus register offset, which can be shifted left by imm2.
123     RegReg(Reg, Reg, u8),
124 
125     /// Unsigned 12-bit immediate offset from reg.
126     RegOffset12(Reg, UImm12),
127 
128     /// Immediate offset from program counter aligned to 4.
129     /// Cannot be used by store instructions.
130     PCRel(i32),
131 
132     // Virtual addressing modes that are lowered at emission time:
133     /// Immediate offset from reg.
134     RegOffset(Reg, i64),
135 
136     /// Signed immediate offset from stack pointer.
137     SPOffset(i64, Type),
138 
139     /// Offset from the frame pointer.
140     FPOffset(i64, Type),
141 
142     /// Signed immediate offset from "nominal stack pointer".
143     NominalSPOffset(i64, Type),
144 }
145 
146 impl AMode {
147     /// Memory reference using the sum of two registers as an address.
reg_plus_reg(reg1: Reg, reg2: Reg, shift_amt: u8) -> AMode148     pub fn reg_plus_reg(reg1: Reg, reg2: Reg, shift_amt: u8) -> AMode {
149         assert!(shift_amt <= 3);
150         AMode::RegReg(reg1, reg2, shift_amt)
151     }
152 
153     /// Memory reference using the sum of a register and an immediate offset
154     /// as an address.
reg_plus_imm(reg: Reg, offset: i64) -> AMode155     pub fn reg_plus_imm(reg: Reg, offset: i64) -> AMode {
156         AMode::RegOffset(reg, offset)
157     }
158 }
159 
160 /// Condition for conditional branches.
161 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
162 #[repr(u8)]
163 pub enum Cond {
164     Eq = 0,
165     Ne = 1,
166     Hs = 2,
167     Lo = 3,
168     Mi = 4,
169     Pl = 5,
170     Vs = 6,
171     Vc = 7,
172     Hi = 8,
173     Ls = 9,
174     Ge = 10,
175     Lt = 11,
176     Gt = 12,
177     Le = 13,
178     Al = 14,
179 }
180 
181 impl Cond {
182     /// Return the inverted condition.
invert(self) -> Cond183     pub fn invert(self) -> Cond {
184         match self {
185             Cond::Eq => Cond::Ne,
186             Cond::Ne => Cond::Eq,
187 
188             Cond::Hs => Cond::Lo,
189             Cond::Lo => Cond::Hs,
190 
191             Cond::Mi => Cond::Pl,
192             Cond::Pl => Cond::Mi,
193 
194             Cond::Vs => Cond::Vc,
195             Cond::Vc => Cond::Vs,
196 
197             Cond::Hi => Cond::Ls,
198             Cond::Ls => Cond::Hi,
199 
200             Cond::Ge => Cond::Lt,
201             Cond::Lt => Cond::Ge,
202 
203             Cond::Gt => Cond::Le,
204             Cond::Le => Cond::Gt,
205 
206             Cond::Al => panic!("Cannot inverse {:?} condition", self),
207         }
208     }
209 
210     /// Return the machine encoding of this condition.
bits(self) -> u16211     pub fn bits(self) -> u16 {
212         self as u16
213     }
214 }
215 
216 /// A branch target. Either unresolved (basic-block index) or resolved (offset
217 /// from end of current instruction).
218 #[derive(Clone, Copy, Debug)]
219 pub enum BranchTarget {
220     /// An unresolved reference to a Label.
221     Label(MachLabel),
222     /// A fixed PC offset.
223     ResolvedOffset(i32),
224 }
225 
226 impl BranchTarget {
227     /// Return the target's label, if it is a label-based target.
as_label(self) -> Option<MachLabel>228     pub fn as_label(self) -> Option<MachLabel> {
229         match self {
230             BranchTarget::Label(l) => Some(l),
231             _ => None,
232         }
233     }
234 
235     // Ready for embedding in instruction.
as_offset(self, inst_16_bit: bool) -> i32236     fn as_offset(self, inst_16_bit: bool) -> i32 {
237         match self {
238             BranchTarget::ResolvedOffset(off) => {
239                 if inst_16_bit {
240                     // pc is equal to end of the current inst + 2.
241                     (off - 2) >> 1
242                 } else {
243                     // pc points to end of the current inst.
244                     off >> 1
245                 }
246             }
247             _ => 0,
248         }
249     }
250 
251     // For 32-bit unconditional jump.
as_off24(self) -> u32252     pub fn as_off24(self) -> u32 {
253         let off = self.as_offset(false);
254         assert!(off < (1 << 24));
255         assert!(off >= -(1 << 24));
256         (off as u32) & ((1 << 24) - 1)
257     }
258 
259     // For 32-bit conditional jump.
as_off20(self) -> u32260     pub fn as_off20(self) -> u32 {
261         let off = self.as_offset(false);
262         assert!(off < (1 << 20));
263         assert!(off >= -(1 << 20));
264         (off as u32) & ((1 << 20) - 1)
265     }
266 }
267 
268 impl PrettyPrint for ShiftOpAndAmt {
show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String269     fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
270         let op = match self.op() {
271             ShiftOp::LSL => "lsl",
272             ShiftOp::LSR => "lsr",
273             ShiftOp::ASR => "asr",
274             ShiftOp::ROR => "ror",
275         };
276         format!("{} #{}", op, self.amt().value())
277     }
278 }
279 
280 impl PrettyPrint for UImm8 {
show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String281     fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
282         format!("#{}", self.value)
283     }
284 }
285 
286 impl PrettyPrint for UImm12 {
show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String287     fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
288         format!("#{}", self.value)
289     }
290 }
291 
292 impl PrettyPrint for AMode {
show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String293     fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String {
294         match self {
295             &AMode::RegReg(rn, rm, imm2) => {
296                 let shift = if imm2 != 0 {
297                     format!(", lsl #{}", imm2)
298                 } else {
299                     "".to_string()
300                 };
301                 format!(
302                     "[{}, {}{}]",
303                     rn.show_rru(mb_rru),
304                     rm.show_rru(mb_rru),
305                     shift
306                 )
307             }
308             &AMode::RegOffset12(rn, off) => {
309                 format!("[{}, {}]", rn.show_rru(mb_rru), off.show_rru(mb_rru))
310             }
311             &AMode::PCRel(off) => format!("[pc, #{}]", off),
312             &AMode::RegOffset(..)
313             | &AMode::SPOffset(..)
314             | &AMode::FPOffset(..)
315             | &AMode::NominalSPOffset(..) => panic!("unexpected mem mode"),
316         }
317     }
318 }
319 
320 impl PrettyPrint for Cond {
show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String321     fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
322         let mut s = format!("{:?}", self);
323         s.make_ascii_lowercase();
324         s
325     }
326 }
327 
328 impl PrettyPrint for BranchTarget {
show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String329     fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
330         match self {
331             &BranchTarget::Label(label) => format!("label{:?}", label.get()),
332             &BranchTarget::ResolvedOffset(off) => format!("{}", off),
333         }
334     }
335 }
336