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