1 //! Pure register operands; see [`Gpr`]. 2 3 use crate::AsReg; 4 use alloc::string::String; 5 6 /// A general purpose x64 register (e.g., `%rax`). 7 /// 8 /// This container wraps true register type `R` to allow users to specify their 9 /// own; by default this will use `u8`. 10 #[derive(Clone, Copy, Debug, PartialEq)] 11 pub struct Gpr<R: AsReg = u8>(pub(crate) R); 12 13 impl<R: AsReg> Gpr<R> { 14 /// Create a [`Gpr`] that may be real (immediately emit-able in machine 15 /// code) or virtual (waiting for register allocation). new(reg: R) -> Self16 pub fn new(reg: R) -> Self { 17 Self(reg) 18 } 19 20 /// Return the register's hardware encoding; the underlying type `R` _must_ 21 /// be a real register at this point. 22 /// 23 /// # Panics 24 /// 25 /// Panics if the register is not a valid x64 register. enc(&self) -> u826 pub fn enc(&self) -> u8 { 27 let enc = self.0.enc(); 28 assert!(enc < 16, "invalid register: {enc}"); 29 enc 30 } 31 32 /// Return the register name at the given `size`. to_string(&self, size: Size) -> String33 pub fn to_string(&self, size: Size) -> String { 34 self.0.to_string(Some(size)) 35 } 36 } 37 38 impl<R: AsReg> AsRef<R> for Gpr<R> { as_ref(&self) -> &R39 fn as_ref(&self) -> &R { 40 &self.0 41 } 42 } 43 44 impl<R: AsReg> AsMut<R> for Gpr<R> { as_mut(&mut self) -> &mut R45 fn as_mut(&mut self) -> &mut R { 46 &mut self.0 47 } 48 } 49 50 impl<R: AsReg> From<R> for Gpr<R> { from(reg: R) -> Gpr<R>51 fn from(reg: R) -> Gpr<R> { 52 Gpr(reg) 53 } 54 } 55 56 /// A single x64 register encoding can access a different number of bits. 57 #[derive(Copy, Clone, Debug)] 58 pub enum Size { 59 /// An 8-bit access. 60 Byte, 61 /// A 16-bit access. 62 Word, 63 /// A 32-bit access. 64 Doubleword, 65 /// A 64-bit access. 66 Quadword, 67 } 68 69 /// Like [`Gpr`], but with `%rsp` disallowed. 70 /// 71 /// This is due to avoid special cases of REX encodings, see Intel SDM Vol. 2A, 72 /// table 2-5. 73 #[derive(Clone, Copy, Debug, PartialEq)] 74 pub struct NonRspGpr<R: AsReg>(R); 75 76 impl<R: AsReg> NonRspGpr<R> { 77 /// See [`Gpr::new`]. new(reg: R) -> Self78 pub fn new(reg: R) -> Self { 79 Self(reg) 80 } 81 82 /// See [`Gpr::to_string`]. to_string(&self, size: Size) -> String83 pub fn to_string(&self, size: Size) -> String { 84 self.0.to_string(Some(size)) 85 } 86 87 /// See [`Gpr::enc`]. 88 /// 89 /// # Panics 90 /// 91 /// Panics if the register is invalid or `%rsp`. enc(&self) -> u892 pub fn enc(&self) -> u8 { 93 let enc = self.0.enc(); 94 assert!(enc < 16, "invalid register: {enc}"); 95 assert_ne!(enc, enc::RSP, "invalid register: %rsp"); 96 enc 97 } 98 } 99 100 impl<R: AsReg> AsRef<R> for NonRspGpr<R> { as_ref(&self) -> &R101 fn as_ref(&self) -> &R { 102 &self.0 103 } 104 } 105 106 impl<R: AsReg> AsMut<R> for NonRspGpr<R> { as_mut(&mut self) -> &mut R107 fn as_mut(&mut self) -> &mut R { 108 &mut self.0 109 } 110 } 111 112 impl<R: AsReg> From<R> for NonRspGpr<R> { from(reg: R) -> NonRspGpr<R>113 fn from(reg: R) -> NonRspGpr<R> { 114 NonRspGpr(reg) 115 } 116 } 117 118 /// Encode x64 registers. 119 pub mod enc { 120 use super::Size; 121 122 pub const RAX: u8 = 0; 123 pub const RCX: u8 = 1; 124 pub const RDX: u8 = 2; 125 pub const RBX: u8 = 3; 126 pub const RSP: u8 = 4; 127 pub const RBP: u8 = 5; 128 pub const RSI: u8 = 6; 129 pub const RDI: u8 = 7; 130 pub const R8: u8 = 8; 131 pub const R9: u8 = 9; 132 pub const R10: u8 = 10; 133 pub const R11: u8 = 11; 134 pub const R12: u8 = 12; 135 pub const R13: u8 = 13; 136 pub const R14: u8 = 14; 137 pub const R15: u8 = 15; 138 139 /// Return the name of a GPR encoding (`enc`) at the given `size`. 140 /// 141 /// # Panics 142 /// 143 /// This function will panic if the encoding is not a valid x64 register. to_string(enc: u8, size: Size) -> &'static str144 pub fn to_string(enc: u8, size: Size) -> &'static str { 145 use Size::{Byte, Doubleword, Quadword, Word}; 146 match enc { 147 RAX => match size { 148 Byte => "%al", 149 Word => "%ax", 150 Doubleword => "%eax", 151 Quadword => "%rax", 152 }, 153 RBX => match size { 154 Byte => "%bl", 155 Word => "%bx", 156 Doubleword => "%ebx", 157 Quadword => "%rbx", 158 }, 159 RCX => match size { 160 Byte => "%cl", 161 Word => "%cx", 162 Doubleword => "%ecx", 163 Quadword => "%rcx", 164 }, 165 RDX => match size { 166 Byte => "%dl", 167 Word => "%dx", 168 Doubleword => "%edx", 169 Quadword => "%rdx", 170 }, 171 RSI => match size { 172 Byte => "%sil", 173 Word => "%si", 174 Doubleword => "%esi", 175 Quadword => "%rsi", 176 }, 177 RDI => match size { 178 Byte => "%dil", 179 Word => "%di", 180 Doubleword => "%edi", 181 Quadword => "%rdi", 182 }, 183 RBP => match size { 184 Byte => "%bpl", 185 Word => "%bp", 186 Doubleword => "%ebp", 187 Quadword => "%rbp", 188 }, 189 RSP => match size { 190 Byte => "%spl", 191 Word => "%sp", 192 Doubleword => "%esp", 193 Quadword => "%rsp", 194 }, 195 R8 => match size { 196 Byte => "%r8b", 197 Word => "%r8w", 198 Doubleword => "%r8d", 199 Quadword => "%r8", 200 }, 201 R9 => match size { 202 Byte => "%r9b", 203 Word => "%r9w", 204 Doubleword => "%r9d", 205 Quadword => "%r9", 206 }, 207 R10 => match size { 208 Byte => "%r10b", 209 Word => "%r10w", 210 Doubleword => "%r10d", 211 Quadword => "%r10", 212 }, 213 R11 => match size { 214 Byte => "%r11b", 215 Word => "%r11w", 216 Doubleword => "%r11d", 217 Quadword => "%r11", 218 }, 219 R12 => match size { 220 Byte => "%r12b", 221 Word => "%r12w", 222 Doubleword => "%r12d", 223 Quadword => "%r12", 224 }, 225 R13 => match size { 226 Byte => "%r13b", 227 Word => "%r13w", 228 Doubleword => "%r13d", 229 Quadword => "%r13", 230 }, 231 R14 => match size { 232 Byte => "%r14b", 233 Word => "%r14w", 234 Doubleword => "%r14d", 235 Quadword => "%r14", 236 }, 237 R15 => match size { 238 Byte => "%r15b", 239 Word => "%r15w", 240 Doubleword => "%r15d", 241 Quadword => "%r15", 242 }, 243 _ => panic!("%invalid{enc}"), 244 } 245 } 246 } 247