cranelift_assembler_x64/
imm.rs

1//! Immediate operands to instructions.
2
3use crate::api::CodeSink;
4use 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`.
9macro_rules! hexify {
10    ($n:expr) => {
11        format!("$0x{:x}", $n)
12    };
13}
14
15/// Like `hexify!`, but this performs a sign extension.
16macro_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))]
27pub struct Imm8(u8);
28
29impl 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
45impl fmt::Display for Imm8 {
46    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
47        write!(f, "$0x{:x}", self.0)
48    }
49}
50
51/// A _signed_ 8-bit immediate operand (suitable for sign extension).
52#[derive(Clone, Copy, Debug)]
53#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
54pub struct Simm8(i8);
55
56impl Simm8 {
57    #[must_use]
58    pub fn new(value: i8) -> Self {
59        Self(value)
60    }
61
62    #[must_use]
63    pub fn value(&self) -> i8 {
64        self.0
65    }
66
67    pub fn encode(&self, sink: &mut impl CodeSink) {
68        sink.put1(self.0 as u8);
69    }
70
71    #[must_use]
72    pub fn to_string(&self, extend: Extension) -> String {
73        use Extension::{None, SignExtendLong, SignExtendQuad, SignExtendWord};
74        match extend {
75            None => hexify!(self.0),
76            SignExtendWord => hexify_sign_extend!(self.0, i8 => i16),
77            SignExtendLong => hexify_sign_extend!(self.0, i8 => i32),
78            SignExtendQuad => hexify_sign_extend!(self.0, i8 => i64),
79        }
80    }
81}
82
83/// A 16-bit immediate operand.
84#[derive(Clone, Debug)]
85#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
86pub struct Imm16(u16);
87
88impl Imm16 {
89    #[must_use]
90    pub fn new(value: u16) -> Self {
91        Self(value)
92    }
93
94    #[must_use]
95    pub fn value(&self) -> u16 {
96        self.0
97    }
98
99    pub fn encode(&self, sink: &mut impl CodeSink) {
100        sink.put2(self.0);
101    }
102}
103
104impl fmt::Display for Imm16 {
105    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106        write!(f, "$0x{:x}", self.0)
107    }
108}
109
110/// A _signed_ 16-bit immediate operand (suitable for sign extension).
111#[derive(Clone, Debug)]
112#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
113pub struct Simm16(i16);
114
115impl Simm16 {
116    #[must_use]
117    pub fn new(value: i16) -> Self {
118        Self(value)
119    }
120
121    #[must_use]
122    pub fn value(&self) -> i16 {
123        self.0
124    }
125
126    pub fn encode(&self, sink: &mut impl CodeSink) {
127        sink.put2(self.0 as u16);
128    }
129
130    #[must_use]
131    pub fn to_string(&self, extend: Extension) -> String {
132        use Extension::{None, SignExtendLong, SignExtendQuad, SignExtendWord};
133        match extend {
134            None => hexify!(self.0),
135            SignExtendWord => unreachable!("the 16-bit value is already 16 bits"),
136            SignExtendLong => hexify_sign_extend!(self.0, i16 => i32),
137            SignExtendQuad => hexify_sign_extend!(self.0, i16 => i64),
138        }
139    }
140}
141
142/// A 32-bit immediate operand.
143///
144/// Note that, "in 64-bit mode, the typical size of immediate operands remains
145/// 32 bits. When the operand size is 64 bits, the processor sign-extends all
146/// immediates to 64 bits prior to their use" (Intel SDM Vol. 2, 2.2.1.5).
147#[derive(Clone, Debug)]
148#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
149pub struct Imm32(u32);
150
151impl Imm32 {
152    #[must_use]
153    pub fn new(value: u32) -> Self {
154        Self(value)
155    }
156
157    #[must_use]
158    pub fn value(&self) -> u32 {
159        self.0
160    }
161
162    pub fn encode(&self, sink: &mut impl CodeSink) {
163        sink.put4(self.0);
164    }
165}
166
167impl fmt::Display for Imm32 {
168    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
169        write!(f, "$0x{:x}", self.0)
170    }
171}
172
173/// A _signed_ 32-bit immediate operand (suitable for sign extension).
174///
175/// Note that, "in 64-bit mode, the typical size of immediate operands remains
176/// 32 bits. When the operand size is 64 bits, the processor sign-extends all
177/// immediates to 64 bits prior to their use" (Intel SDM Vol. 2, 2.2.1.5).
178#[derive(Clone, Debug)]
179#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
180pub struct Simm32(i32);
181
182impl Simm32 {
183    #[must_use]
184    pub fn new(value: i32) -> Self {
185        Self(value)
186    }
187
188    #[must_use]
189    pub fn value(&self) -> i32 {
190        self.0
191    }
192
193    pub fn encode(&self, sink: &mut impl CodeSink) {
194        sink.put4(self.0 as u32);
195    }
196
197    #[must_use]
198    pub fn to_string(&self, extend: Extension) -> String {
199        use Extension::{None, SignExtendLong, SignExtendQuad, SignExtendWord};
200        match extend {
201            None => hexify!(self.0),
202            SignExtendWord => unreachable!("cannot sign extend a 32-bit value to 16 bits"),
203            SignExtendLong => unreachable!("the 32-bit value is already 32 bits"),
204            SignExtendQuad => hexify_sign_extend!(self.0, i32 => i64),
205        }
206    }
207}
208
209/// Define the ways an immediate may be sign- or zero-extended.
210#[derive(Clone, Copy, Debug)]
211pub enum Extension {
212    None,
213    SignExtendQuad,
214    SignExtendLong,
215    SignExtendWord,
216}