1use std::convert::TryFrom;
4
5use thiserror::Error;
6
7use crate::AddressSpace;
8
9#[repr(u64)]
16pub enum TypeId {
17 Half = 0,
19 BFloat,
21 Float,
23 Double,
25 X86Fp80,
27 Fp128,
29 PpcFp128,
31 Void,
33 Label,
35 Metadata,
37 X86Mmx,
39 X86Amx,
41 Token,
43 Integer,
45 Function,
47 Pointer,
49 Struct,
51 Array,
53 FixedVector,
55 ScalableVector,
57}
58
59#[allow(missing_docs)]
63#[derive(Clone, Debug, PartialEq)]
64pub enum Type {
65 Half,
66 BFloat,
67 Float,
68 Double,
69 Metadata,
70 X86Fp80,
71 Fp128,
72 PpcFp128,
73 Void,
74 Label,
75 X86Mmx,
76 X86Amx,
77 Token,
78 Integer(IntegerType),
79 Function(FunctionType),
80 Pointer(PointerType),
81 OpaquePointer(AddressSpace),
82 Struct(StructType),
83 Array(ArrayType),
84 FixedVector(VectorType),
85 ScalableVector(VectorType),
86}
87
88impl Type {
89 pub fn is_floating(&self) -> bool {
103 matches!(
104 self,
105 Type::Half
106 | Type::BFloat
107 | Type::Float
108 | Type::Double
109 | Type::X86Fp80
110 | Type::Fp128
111 | Type::PpcFp128
112 )
113 }
114
115 pub fn is_pointee(&self) -> bool {
118 !matches!(
119 self,
120 Type::Void | Type::Label | Type::Metadata | Type::Token | Type::X86Amx
121 )
122 }
123
124 pub fn is_array_element(&self) -> bool {
127 !matches!(
128 self,
129 Type::Void
130 | Type::Label
131 | Type::Metadata
132 | Type::Function(_)
133 | Type::Token
134 | Type::X86Amx
135 | Type::ScalableVector(_)
136 )
137 }
138
139 pub fn is_struct_element(&self) -> bool {
142 !matches!(
143 self,
144 Type::Void | Type::Label | Type::Metadata | Type::Function(_) | Type::Token
145 )
146 }
147
148 pub fn is_vector_element(&self) -> bool {
164 self.is_floating() || matches!(self, Type::Integer(_) | Type::Pointer(_))
165 }
166
167 fn is_first_class(&self) -> bool {
169 !matches!(self, Type::Function(_) | Type::Void)
170 }
171
172 pub fn is_argument(&self) -> bool {
182 self.is_first_class()
183 }
184
185 pub fn is_return(&self) -> bool {
188 !matches!(self, Type::Function(_) | Type::Label | Type::Metadata)
189 }
190
191 pub fn new_struct(
193 name: Option<String>,
194 fields: Vec<Type>,
195 is_packed: bool,
196 ) -> Result<Self, StructTypeError> {
197 let inner = StructType::new(name, fields, is_packed)?;
198
199 Ok(Type::Struct(inner))
200 }
201
202 pub fn new_integer(bit_width: u32) -> Result<Self, IntegerTypeError> {
204 let inner = IntegerType::try_from(bit_width)?;
205
206 Ok(Type::Integer(inner))
207 }
208
209 pub fn new_pointer(
211 pointee: Type,
212 address_space: AddressSpace,
213 ) -> Result<Self, PointerTypeError> {
214 let inner = PointerType::new(pointee, address_space)?;
215
216 Ok(Type::Pointer(inner))
217 }
218
219 pub fn new_array(num_elements: u64, element_type: Type) -> Result<Self, ArrayTypeError> {
221 let inner = ArrayType::new(num_elements, element_type)?;
222
223 Ok(Type::Array(inner))
224 }
225
226 pub fn new_scalable_vector(
228 num_elements: u64,
229 element_type: Type,
230 ) -> Result<Self, VectorTypeError> {
231 let inner = VectorType::new(num_elements, element_type)?;
232
233 Ok(Type::ScalableVector(inner))
234 }
235
236 pub fn new_vector(num_elements: u64, element_type: Type) -> Result<Self, VectorTypeError> {
238 let inner = VectorType::new(num_elements, element_type)?;
239
240 Ok(Type::FixedVector(inner))
241 }
242
243 pub fn new_function(
245 return_type: Type,
246 param_types: Vec<Type>,
247 is_vararg: bool,
248 ) -> Result<Self, FunctionTypeError> {
249 let inner = FunctionType::new(return_type, param_types, is_vararg)?;
250
251 Ok(Type::Function(inner))
252 }
253}
254
255#[derive(Debug, Error)]
257pub enum StructTypeError {
258 #[error("invalid structure element type: {0:?}")]
260 BadElement(Type),
261}
262
263#[non_exhaustive]
265#[derive(Clone, Debug, PartialEq)]
266pub struct StructType {
267 pub name: Option<String>,
269 pub fields: Vec<Type>,
271 is_packed: bool,
273}
274
275impl StructType {
276 pub fn new(
278 name: Option<String>,
279 fields: Vec<Type>,
280 is_packed: bool,
281 ) -> Result<Self, StructTypeError> {
282 if let Some(bad) = fields.iter().find(|t| !t.is_struct_element()) {
283 Err(StructTypeError::BadElement(bad.clone()))
284 } else {
285 Ok(Self {
286 name,
287 fields,
288 is_packed,
289 })
290 }
291 }
292}
293
294#[derive(Debug, Error)]
296pub enum IntegerTypeError {
297 #[error(
299 "specified bit width is invalid (not in [{}, {}])",
300 IntegerType::MIN_INT_BITS,
301 IntegerType::MAX_INT_BITS
302 )]
303 BadWidth,
304}
305
306#[non_exhaustive]
310#[derive(Clone, Debug, PartialEq)]
311pub struct IntegerType {
312 bit_width: u32,
314}
315
316impl IntegerType {
317 pub const MIN_INT_BITS: u32 = 1;
319 pub const MAX_INT_BITS: u32 = (1 << 24) - 1;
321
322 pub fn bit_width(&self) -> u32 {
324 self.bit_width
325 }
326
327 pub fn byte_width(&self) -> u32 {
331 (self.bit_width + 7) / 8
332 }
333}
334
335impl TryFrom<u32> for IntegerType {
336 type Error = IntegerTypeError;
337
338 fn try_from(value: u32) -> Result<Self, Self::Error> {
339 if (IntegerType::MIN_INT_BITS..=IntegerType::MAX_INT_BITS).contains(&value) {
340 Ok(Self { bit_width: value })
341 } else {
342 Err(Self::Error::BadWidth)
343 }
344 }
345}
346
347#[derive(Debug, Error)]
349pub enum PointerTypeError {
350 #[error("invalid pointee type: {0:?}")]
352 BadPointee(Type),
353}
354
355#[non_exhaustive]
359#[derive(Clone, Debug, PartialEq)]
360pub struct PointerType {
361 pointee: Box<Type>,
362 address_space: AddressSpace,
363}
364
365impl PointerType {
366 pub fn new(pointee: Type, address_space: AddressSpace) -> Result<Self, PointerTypeError> {
368 if pointee.is_pointee() {
369 Ok(Self {
370 pointee: Box::new(pointee),
371 address_space,
372 })
373 } else {
374 Err(PointerTypeError::BadPointee(pointee))
375 }
376 }
377
378 pub fn pointee(&self) -> &Type {
380 self.pointee.as_ref()
381 }
382}
383
384#[derive(Debug, Error)]
386pub enum ArrayTypeError {
387 #[error("invalid array element type: {0:?}")]
389 BadElement(Type),
390}
391
392#[non_exhaustive]
394#[derive(Clone, Debug, PartialEq)]
395pub struct ArrayType {
396 num_elements: u64,
397 element_type: Box<Type>,
398}
399
400impl ArrayType {
401 pub fn new(num_elements: u64, element_type: Type) -> Result<Self, ArrayTypeError> {
403 if element_type.is_array_element() {
404 Ok(Self {
405 num_elements,
406 element_type: Box::new(element_type),
407 })
408 } else {
409 Err(ArrayTypeError::BadElement(element_type))
410 }
411 }
412
413 pub fn element(&self) -> &Type {
415 self.element_type.as_ref()
416 }
417}
418
419#[derive(Debug, Error)]
421pub enum VectorTypeError {
422 #[error("invalid vector element type: {0:?}")]
424 BadElement(Type),
425}
426
427#[non_exhaustive]
432#[derive(Clone, Debug, PartialEq)]
433pub struct VectorType {
434 num_elements: u64,
435 element_type: Box<Type>,
436}
437
438impl VectorType {
439 pub fn new(num_elements: u64, element_type: Type) -> Result<Self, VectorTypeError> {
441 if element_type.is_vector_element() {
442 Ok(Self {
443 num_elements,
444 element_type: Box::new(element_type),
445 })
446 } else {
447 Err(VectorTypeError::BadElement(element_type))
448 }
449 }
450
451 pub fn element(&self) -> &Type {
453 self.element_type.as_ref()
454 }
455}
456
457#[derive(Debug, Error)]
459pub enum FunctionTypeError {
460 #[error("invalid function return type: {0:?}")]
462 BadReturn(Type),
463 #[error("invalid function parameter type: {0:?}")]
465 BadParameter(Type),
466}
467
468#[non_exhaustive]
470#[derive(Clone, Debug, PartialEq)]
471pub struct FunctionType {
472 return_type: Box<Type>,
473 param_types: Vec<Type>,
474 is_vararg: bool,
475}
476
477impl FunctionType {
478 pub fn new(
480 return_type: Type,
481 param_types: Vec<Type>,
482 is_vararg: bool,
483 ) -> Result<Self, FunctionTypeError> {
484 if !return_type.is_return() {
485 Err(FunctionTypeError::BadReturn(return_type))
486 } else if let Some(bad) = param_types.iter().find(|ty| !ty.is_argument()) {
487 Err(FunctionTypeError::BadParameter(bad.clone()))
488 } else {
489 Ok(FunctionType {
490 return_type: Box::new(return_type),
491 param_types,
492 is_vararg,
493 })
494 }
495 }
496}
497
498#[cfg(test)]
499mod tests {
500 use super::*;
501
502 #[test]
503 fn test_integer_type() {
504 {
505 assert!(IntegerType::try_from(0).is_err());
507 assert!(IntegerType::try_from(IntegerType::MAX_INT_BITS + 1).is_err());
508 }
509
510 {
511 let ty = IntegerType::try_from(IntegerType::MIN_INT_BITS).unwrap();
513 assert_eq!(ty.bit_width(), 1);
514 assert_eq!(ty.byte_width(), 1);
515
516 let ty = IntegerType::try_from(IntegerType::MAX_INT_BITS).unwrap();
517 assert_eq!(ty.bit_width(), IntegerType::MAX_INT_BITS);
518 assert_eq!(ty.byte_width(), 2097152);
519
520 let ty = IntegerType::try_from(31).unwrap();
521 assert_eq!(ty.bit_width(), 31);
522 assert_eq!(ty.byte_width(), 4);
523
524 let ty = IntegerType::try_from(32).unwrap();
525 assert_eq!(ty.bit_width(), 32);
526 assert_eq!(ty.byte_width(), 4);
527
528 for i in 1..=8 {
529 let ty = IntegerType::try_from(i).unwrap();
530 assert_eq!(ty.bit_width(), i);
531 assert_eq!(ty.byte_width(), 1);
532 }
533 }
534 }
535
536 #[test]
537 fn test_pointer_type() {
538 {
539 assert!(PointerType::new(Type::Void, AddressSpace::default()).is_err());
541 assert!(PointerType::new(Type::Label, AddressSpace::default()).is_err());
542 assert!(PointerType::new(Type::Metadata, AddressSpace::default()).is_err());
543 assert!(PointerType::new(Type::Token, AddressSpace::default()).is_err());
544 assert!(PointerType::new(Type::X86Amx, AddressSpace::default()).is_err());
545 }
546
547 {
548 let ty = PointerType::new(Type::Double, AddressSpace::default()).unwrap();
550 assert_eq!(ty.pointee(), &Type::Double);
551
552 let ty =
553 PointerType::new(Type::new_integer(32).unwrap(), AddressSpace::default()).unwrap();
554 assert_eq!(ty.pointee(), &Type::new_integer(32).unwrap());
555 }
556 }
557}