1 //! Immediate operands to instructions.
2 
3 use crate::api::CodeSink;
4 use std::fmt;
5 
6 /// This helper function prints the unsigned hexadecimal representation of the
7 /// immediate value: e.g., this prints `$0xfe` to represent both the signed `-2`
8 /// and the unsigned `254`.
9 macro_rules! hexify {
10     ($n:expr) => {
11         format!("$0x{:x}", $n)
12     };
13 }
14 
15 /// Like `hexify!`, but this performs a sign extension.
16 macro_rules! hexify_sign_extend {
17     ($n:expr, $from:ty => $to:ty) => {{
18         let from: $from = $n; // Assert the type we expect.
19         let to = <$to>::from(from);
20         format!("$0x{:x}", to)
21     }};
22 }
23 
24 /// An 8-bit immediate operand.
25 #[derive(Clone, Copy, Debug)]
26 #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
27 pub struct Imm8(u8);
28 
29 impl Imm8 {
30     #[must_use]
31     pub fn new(value: u8) -> Self {
32         Self(value)
33     }
34 
35     #[must_use]
36     pub fn value(&self) -> u8 {
37         self.0
38     }
39 
40     pub fn encode(&self, sink: &mut impl CodeSink) {
41         sink.put1(self.0);
42     }
43 }
44 
45 impl From<u8> for Imm8 {
46     fn from(imm8: u8) -> Self {
47         Self(imm8)
48     }
49 }
50 
51 impl TryFrom<i32> for Imm8 {
52     type Error = std::num::TryFromIntError;
53     fn try_from(simm32: i32) -> Result<Self, Self::Error> {
54         Ok(Self(u8::try_from(simm32)?))
55     }
56 }
57 
58 impl fmt::Display for Imm8 {
59     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
60         write!(f, "$0x{:x}", self.0)
61     }
62 }
63 
64 /// A _signed_ 8-bit immediate operand (suitable for sign extension).
65 #[derive(Clone, Copy, Debug)]
66 #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
67 pub struct Simm8(i8);
68 
69 impl Simm8 {
70     #[must_use]
71     pub fn new(value: i8) -> Self {
72         Self(value)
73     }
74 
75     #[must_use]
76     pub fn value(&self) -> i8 {
77         self.0
78     }
79 
80     pub fn encode(&self, sink: &mut impl CodeSink) {
81         sink.put1(self.0 as u8);
82     }
83 
84     #[must_use]
85     pub fn to_string(&self, extend: Extension) -> String {
86         use Extension::{None, SignExtendLong, SignExtendQuad, SignExtendWord};
87         match extend {
88             None => hexify!(self.0),
89             SignExtendWord => hexify_sign_extend!(self.0, i8 => i16),
90             SignExtendLong => hexify_sign_extend!(self.0, i8 => i32),
91             SignExtendQuad => hexify_sign_extend!(self.0, i8 => i64),
92         }
93     }
94 }
95 
96 impl From<i8> for Simm8 {
97     fn from(simm8: i8) -> Self {
98         Self(simm8)
99     }
100 }
101 
102 impl TryFrom<i32> for Simm8 {
103     type Error = std::num::TryFromIntError;
104     fn try_from(simm32: i32) -> Result<Self, Self::Error> {
105         Ok(Self(i8::try_from(simm32)?))
106     }
107 }
108 
109 /// A 16-bit immediate operand.
110 #[derive(Copy, Clone, Debug)]
111 #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
112 pub struct Imm16(u16);
113 
114 impl Imm16 {
115     #[must_use]
116     pub fn new(value: u16) -> Self {
117         Self(value)
118     }
119 
120     #[must_use]
121     pub fn value(&self) -> u16 {
122         self.0
123     }
124 
125     pub fn encode(&self, sink: &mut impl CodeSink) {
126         sink.put2(self.0);
127     }
128 }
129 
130 impl From<u16> for Imm16 {
131     fn from(imm16: u16) -> Self {
132         Self(imm16)
133     }
134 }
135 
136 impl TryFrom<i32> for Imm16 {
137     type Error = std::num::TryFromIntError;
138     fn try_from(simm32: i32) -> Result<Self, Self::Error> {
139         Ok(Self(u16::try_from(simm32)?))
140     }
141 }
142 
143 impl fmt::Display for Imm16 {
144     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145         write!(f, "$0x{:x}", self.0)
146     }
147 }
148 
149 /// A _signed_ 16-bit immediate operand (suitable for sign extension).
150 #[derive(Copy, Clone, Debug)]
151 #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
152 pub struct Simm16(i16);
153 
154 impl Simm16 {
155     #[must_use]
156     pub fn new(value: i16) -> Self {
157         Self(value)
158     }
159 
160     #[must_use]
161     pub fn value(&self) -> i16 {
162         self.0
163     }
164 
165     pub fn encode(&self, sink: &mut impl CodeSink) {
166         sink.put2(self.0 as u16);
167     }
168 
169     #[must_use]
170     pub fn to_string(&self, extend: Extension) -> String {
171         use Extension::{None, SignExtendLong, SignExtendQuad, SignExtendWord};
172         match extend {
173             None => hexify!(self.0),
174             SignExtendWord => unreachable!("the 16-bit value is already 16 bits"),
175             SignExtendLong => hexify_sign_extend!(self.0, i16 => i32),
176             SignExtendQuad => hexify_sign_extend!(self.0, i16 => i64),
177         }
178     }
179 }
180 
181 impl From<i16> for Simm16 {
182     fn from(simm16: i16) -> Self {
183         Self(simm16)
184     }
185 }
186 
187 impl TryFrom<i32> for Simm16 {
188     type Error = std::num::TryFromIntError;
189     fn try_from(simm32: i32) -> Result<Self, Self::Error> {
190         Ok(Self(i16::try_from(simm32)?))
191     }
192 }
193 
194 /// A 32-bit immediate operand.
195 ///
196 /// Note that, "in 64-bit mode, the typical size of immediate operands remains
197 /// 32 bits. When the operand size is 64 bits, the processor sign-extends all
198 /// immediates to 64 bits prior to their use" (Intel SDM Vol. 2, 2.2.1.5).
199 #[derive(Copy, Clone, Debug)]
200 #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
201 pub struct Imm32(u32);
202 
203 impl Imm32 {
204     #[must_use]
205     pub fn new(value: u32) -> Self {
206         Self(value)
207     }
208 
209     #[must_use]
210     pub fn value(&self) -> u32 {
211         self.0
212     }
213 
214     pub fn encode(&self, sink: &mut impl CodeSink) {
215         sink.put4(self.0);
216     }
217 }
218 
219 impl From<u32> for Imm32 {
220     fn from(imm32: u32) -> Self {
221         Self(imm32)
222     }
223 }
224 
225 impl From<i32> for Imm32 {
226     fn from(simm32: i32) -> Self {
227         // TODO: should this be a `TryFrom`?
228         Self(simm32 as u32)
229     }
230 }
231 
232 impl fmt::Display for Imm32 {
233     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
234         write!(f, "$0x{:x}", self.0)
235     }
236 }
237 
238 /// A _signed_ 32-bit immediate operand (suitable for sign extension).
239 ///
240 /// Note that, "in 64-bit mode, the typical size of immediate operands remains
241 /// 32 bits. When the operand size is 64 bits, the processor sign-extends all
242 /// immediates to 64 bits prior to their use" (Intel SDM Vol. 2, 2.2.1.5).
243 #[derive(Copy, Clone, Debug)]
244 #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
245 pub struct Simm32(i32);
246 
247 impl Simm32 {
248     #[must_use]
249     pub fn new(value: i32) -> Self {
250         Self(value)
251     }
252 
253     #[must_use]
254     pub fn value(&self) -> i32 {
255         self.0
256     }
257 
258     pub fn encode(&self, sink: &mut impl CodeSink) {
259         sink.put4(self.0 as u32);
260     }
261 
262     #[must_use]
263     pub fn to_string(&self, extend: Extension) -> String {
264         use Extension::{None, SignExtendLong, SignExtendQuad, SignExtendWord};
265         match extend {
266             None => hexify!(self.0),
267             SignExtendWord => unreachable!("cannot sign extend a 32-bit value to 16 bits"),
268             SignExtendLong => unreachable!("the 32-bit value is already 32 bits"),
269             SignExtendQuad => hexify_sign_extend!(self.0, i32 => i64),
270         }
271     }
272 }
273 
274 impl From<i32> for Simm32 {
275     fn from(simm32: i32) -> Self {
276         Self(simm32)
277     }
278 }
279 
280 /// A 64-bit immediate operand.
281 ///
282 /// This form is quite rare; see certain `mov` instructions.
283 #[derive(Copy, Clone, Debug)]
284 #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
285 pub struct Imm64(u64);
286 
287 impl Imm64 {
288     #[must_use]
289     pub fn new(value: u64) -> Self {
290         Self(value)
291     }
292 
293     #[must_use]
294     pub fn value(&self) -> u64 {
295         self.0
296     }
297 
298     pub fn encode(&self, sink: &mut impl CodeSink) {
299         sink.put8(self.0);
300     }
301 }
302 
303 impl From<u64> for Imm64 {
304     fn from(imm64: u64) -> Self {
305         Self(imm64)
306     }
307 }
308 
309 impl fmt::Display for Imm64 {
310     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
311         write!(f, "$0x{:x}", self.0)
312     }
313 }
314 
315 /// Define the ways an immediate may be sign- or zero-extended.
316 #[derive(Clone, Copy, Debug)]
317 pub enum Extension {
318     None,
319     SignExtendQuad,
320     SignExtendLong,
321     SignExtendWord,
322 }
323