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