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