1use std::fmt;
19
20#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
23pub enum AddressSpace {
24 #[default]
25 Generic,
26 Global,
27 Region,
28 Local,
29 Constant,
30 Private,
31 Parameter,
32}
33
34#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
38pub enum Signedness {
39 #[default]
40 Signed,
41 Unsigned,
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
47pub enum AggregateClass {
48 Integer,
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
54pub struct Aggregate {
55 pub size: usize,
56 pub align: usize,
57 pub class: AggregateClass,
58}
59
60impl Aggregate {
61 pub fn words(&self) -> usize {
63 self.size.div_ceil(8)
64 }
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
70pub enum ScalarType {
71 I8,
72 I16,
73 I32,
74 I64,
75 F32,
76 F64,
77 Ptr,
78 PtrIn(AddressSpace),
79 I1,
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
84pub enum VectorLane {
85 I8,
86 I16,
87 I32,
88 I64,
89 F32,
90 F64,
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
95pub enum VectorType {
96 V128(VectorLane),
97 V256(VectorLane),
98}
99
100#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
104pub enum MirType {
105 Scalar(ScalarType),
106 Vector(VectorType),
107}
108
109impl MirType {
110 pub fn signed_integer(self, value: i64) -> i64 {
112 let shift = 64 - self.size_bytes() * 8;
113 (value << shift) >> shift
114 }
115
116 pub fn unsigned_integer(self, value: i64) -> u64 {
118 let shift = 64 - self.size_bytes() * 8;
119 ((value as u64) << shift) >> shift
120 }
121
122 pub fn size_bytes(&self) -> usize {
124 match self {
125 MirType::Scalar(s) => match s {
126 ScalarType::I1 | ScalarType::I8 => 1,
127 ScalarType::I16 => 2,
128 ScalarType::I32 | ScalarType::F32 => 4,
129 ScalarType::I64 | ScalarType::F64 | ScalarType::Ptr | ScalarType::PtrIn(_) => 8,
130 },
131 MirType::Vector(v) => match v {
132 VectorType::V128(_) => 16,
133 VectorType::V256(_) => 32,
134 },
135 }
136 }
137
138 pub fn alignment(&self) -> usize {
140 match self {
141 MirType::Scalar(s) => match s {
142 ScalarType::I1 | ScalarType::I8 => 1,
143 ScalarType::I16 => 2,
144 ScalarType::I32 | ScalarType::F32 => 4,
145 ScalarType::I64 | ScalarType::F64 | ScalarType::Ptr | ScalarType::PtrIn(_) => 8,
146 },
147 MirType::Vector(v) => match v {
148 VectorType::V128(_) => 16,
149 VectorType::V256(_) => 32,
150 },
151 }
152 }
153
154 pub fn is_float(&self) -> bool {
156 matches!(
157 self,
158 MirType::Scalar(ScalarType::F32 | ScalarType::F64)
159 | MirType::Vector(VectorType::V128(VectorLane::F32 | VectorLane::F64))
160 | MirType::Vector(VectorType::V256(VectorLane::F32 | VectorLane::F64))
161 )
162 }
163
164 pub fn is_vector(&self) -> bool {
166 matches!(self, MirType::Vector(_))
167 }
168
169 pub fn i1() -> Self {
171 MirType::Scalar(ScalarType::I1)
172 }
173
174 pub fn i8() -> Self {
176 MirType::Scalar(ScalarType::I8)
177 }
178
179 pub fn i16() -> Self {
181 MirType::Scalar(ScalarType::I16)
182 }
183
184 pub fn i32() -> Self {
186 MirType::Scalar(ScalarType::I32)
187 }
188
189 pub fn i64() -> Self {
191 MirType::Scalar(ScalarType::I64)
192 }
193
194 pub fn f32() -> Self {
196 MirType::Scalar(ScalarType::F32)
197 }
198
199 pub fn f64() -> Self {
201 MirType::Scalar(ScalarType::F64)
202 }
203
204 pub fn ptr_in(space: AddressSpace) -> Self {
206 Self::Scalar(ScalarType::PtrIn(space))
207 }
208
209 pub fn ptr() -> Self {
211 MirType::Scalar(ScalarType::Ptr)
212 }
213}
214
215impl fmt::Display for ScalarType {
216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217 match self {
218 ScalarType::I1 => write!(f, "i1"),
219 ScalarType::I8 => write!(f, "i8"),
220 ScalarType::I16 => write!(f, "i16"),
221 ScalarType::I32 => write!(f, "i32"),
222 ScalarType::I64 => write!(f, "i64"),
223 ScalarType::F32 => write!(f, "f32"),
224 ScalarType::F64 => write!(f, "f64"),
225 ScalarType::Ptr => write!(f, "ptr"),
226 ScalarType::PtrIn(space) => write!(f, "ptr<{space:?}>"),
227 }
228 }
229}
230
231impl fmt::Display for VectorLane {
232 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233 match self {
234 VectorLane::I8 => write!(f, "i8"),
235 VectorLane::I16 => write!(f, "i16"),
236 VectorLane::I32 => write!(f, "i32"),
237 VectorLane::I64 => write!(f, "i64"),
238 VectorLane::F32 => write!(f, "f32"),
239 VectorLane::F64 => write!(f, "f64"),
240 }
241 }
242}
243
244impl fmt::Display for VectorType {
245 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 match self {
247 VectorType::V128(lane) => write!(f, "v128<{lane}>"),
248 VectorType::V256(lane) => write!(f, "v256<{lane}>"),
249 }
250 }
251}
252
253impl fmt::Display for MirType {
254 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255 match self {
256 MirType::Scalar(s) => write!(f, "{s}"),
257 MirType::Vector(v) => write!(f, "{v}"),
258 }
259 }
260}
261
262#[cfg(test)]
263mod tests {
264 use super::*;
265
266 #[test]
267 fn pointer_spaces_preserve_layout() {
268 for space in [
269 AddressSpace::Generic,
270 AddressSpace::Global,
271 AddressSpace::Region,
272 AddressSpace::Local,
273 AddressSpace::Constant,
274 AddressSpace::Private,
275 AddressSpace::Parameter,
276 ] {
277 let ty = MirType::ptr_in(space);
278 assert_eq!(ty.size_bytes(), MirType::ptr().size_bytes());
279 assert_eq!(ty.alignment(), MirType::ptr().alignment());
280 }
281 assert_ne!(
282 MirType::ptr_in(AddressSpace::Global),
283 MirType::ptr_in(AddressSpace::Local)
284 );
285 }
286
287 #[test]
288 fn test_scalar_sizes() {
289 assert_eq!(MirType::Scalar(ScalarType::I8).size_bytes(), 1);
290 assert_eq!(MirType::Scalar(ScalarType::I32).size_bytes(), 4);
291 assert_eq!(MirType::Scalar(ScalarType::I64).size_bytes(), 8);
292 }
293
294 #[test]
295 fn test_vector_sizes() {
296 assert_eq!(
297 MirType::Vector(VectorType::V128(VectorLane::I32)).size_bytes(),
298 16
299 );
300 assert_eq!(
301 MirType::Vector(VectorType::V256(VectorLane::F64)).size_bytes(),
302 32
303 );
304 }
305
306 #[test]
307 fn test_float_detection() {
308 assert!(MirType::Scalar(ScalarType::F32).is_float());
309 assert!(MirType::Scalar(ScalarType::F64).is_float());
310 assert!(!MirType::Scalar(ScalarType::I32).is_float());
311 }
312}