Skip to main content

melior/ir/
type.rs

1//! Types and type IDs.
2
3#[macro_use]
4mod r#macro;
5mod function;
6pub mod id;
7mod integer;
8mod mem_ref;
9mod ranked_tensor;
10mod shaped_type_like;
11mod tuple;
12mod type_like;
13
14pub use self::{
15    function::FunctionType, id::TypeId, integer::IntegerType, mem_ref::MemRefType,
16    ranked_tensor::RankedTensorType, shaped_type_like::ShapedTypeLike, tuple::TupleType,
17    type_like::TypeLike,
18};
19use super::Location;
20use crate::{context::Context, string_ref::StringRef, utility::print_callback};
21use mlir_sys::{
22    mlirBF16TypeGet, mlirF16TypeGet, mlirF32TypeGet, mlirF64TypeGet, mlirIndexTypeGet,
23    mlirNoneTypeGet, mlirTypeEqual, mlirTypeParseGet, mlirTypePrint, mlirVectorTypeGet,
24    mlirVectorTypeGetChecked, MlirType,
25};
26use std::{
27    ffi::c_void,
28    fmt::{self, Debug, Display, Formatter},
29    marker::PhantomData,
30};
31
32/// A type.
33// Types are always values but their internal storage is owned by contexts.
34#[derive(Clone, Copy)]
35pub struct Type<'c> {
36    raw: MlirType,
37    _context: PhantomData<&'c Context>,
38}
39
40impl<'c> Type<'c> {
41    /// Parses a type.
42    pub fn parse(context: &'c Context, source: &str) -> Option<Self> {
43        unsafe {
44            Self::from_option_raw(mlirTypeParseGet(
45                context.to_raw(),
46                StringRef::new(source).to_raw(),
47            ))
48        }
49    }
50
51    /// Creates a bfloat16 type.
52    pub fn bfloat16(context: &'c Context) -> Self {
53        unsafe { Self::from_raw(mlirBF16TypeGet(context.to_raw())) }
54    }
55
56    /// Creates a float16 type.
57    pub fn float16(context: &'c Context) -> Self {
58        unsafe { Self::from_raw(mlirF16TypeGet(context.to_raw())) }
59    }
60
61    /// Creates a float32 type.
62    pub fn float32(context: &'c Context) -> Self {
63        unsafe { Self::from_raw(mlirF32TypeGet(context.to_raw())) }
64    }
65
66    /// Creates a float64 type.
67    pub fn float64(context: &'c Context) -> Self {
68        unsafe { Self::from_raw(mlirF64TypeGet(context.to_raw())) }
69    }
70
71    /// Creates an index type.
72    pub fn index(context: &'c Context) -> Self {
73        unsafe { Self::from_raw(mlirIndexTypeGet(context.to_raw())) }
74    }
75
76    /// Creates a none type.
77    pub fn none(context: &'c Context) -> Self {
78        unsafe { Self::from_raw(mlirNoneTypeGet(context.to_raw())) }
79    }
80
81    /// Creates a vector type.
82    pub fn vector(dimensions: &[u64], r#type: Self) -> Self {
83        unsafe {
84            Self::from_raw(mlirVectorTypeGet(
85                dimensions.len() as isize,
86                dimensions.as_ptr() as *const i64,
87                r#type.raw,
88            ))
89        }
90    }
91
92    /// Creates a vector type with diagnostics.
93    pub fn vector_checked(
94        location: Location<'c>,
95        dimensions: &[u64],
96        r#type: Self,
97    ) -> Option<Self> {
98        unsafe {
99            Self::from_option_raw(mlirVectorTypeGetChecked(
100                location.to_raw(),
101                dimensions.len() as isize,
102                dimensions.as_ptr() as *const i64,
103                r#type.raw,
104            ))
105        }
106    }
107
108    /// Creates a type from a raw object.
109    ///
110    /// # Safety
111    ///
112    /// A raw object must be valid.
113    pub unsafe fn from_raw(raw: MlirType) -> Self {
114        Self {
115            raw,
116            _context: Default::default(),
117        }
118    }
119
120    /// Creates an optional type from a raw object.
121    ///
122    /// # Safety
123    ///
124    /// A raw object must be valid.
125    pub unsafe fn from_option_raw(raw: MlirType) -> Option<Self> {
126        if raw.ptr.is_null() {
127            None
128        } else {
129            Some(Self::from_raw(raw))
130        }
131    }
132}
133
134impl<'c> TypeLike<'c> for Type<'c> {
135    fn to_raw(&self) -> MlirType {
136        self.raw
137    }
138}
139
140impl PartialEq for Type<'_> {
141    fn eq(&self, other: &Self) -> bool {
142        unsafe { mlirTypeEqual(self.raw, other.raw) }
143    }
144}
145
146impl Eq for Type<'_> {}
147
148impl Display for Type<'_> {
149    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
150        let mut data = (formatter, Ok(()));
151
152        unsafe {
153            mlirTypePrint(
154                self.raw,
155                Some(print_callback),
156                &mut data as *mut _ as *mut c_void,
157            );
158        }
159
160        data.1
161    }
162}
163
164impl Debug for Type<'_> {
165    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
166        write!(formatter, "Type(")?;
167        Display::fmt(self, formatter)?;
168        write!(formatter, ")")
169    }
170}
171
172from_subtypes!(
173    Type,
174    FunctionType,
175    IntegerType,
176    MemRefType,
177    RankedTensorType,
178    TupleType
179);
180
181#[cfg(test)]
182mod tests {
183    use crate::test::create_test_context;
184
185    use super::*;
186
187    #[test]
188    fn new() {
189        let context = create_test_context();
190        Type::parse(&context, "f32");
191    }
192
193    #[test]
194    fn integer() {
195        let context = create_test_context();
196
197        assert_eq!(
198            Type::from(IntegerType::new(&context, 42)),
199            Type::parse(&context, "i42").unwrap()
200        );
201    }
202
203    #[test]
204    fn index() {
205        let context = create_test_context();
206
207        assert_eq!(
208            Type::index(&context),
209            Type::parse(&context, "index").unwrap()
210        );
211    }
212
213    #[test]
214    fn vector() {
215        let context = create_test_context();
216
217        assert_eq!(
218            Type::vector(&[42], Type::float64(&context)),
219            Type::parse(&context, "vector<42xf64>").unwrap()
220        );
221    }
222
223    #[test]
224    #[ignore = "SIGABRT on llvm with assertions on"]
225    fn vector_with_invalid_dimension() {
226        let context = create_test_context();
227
228        assert_eq!(
229            Type::vector(&[0], IntegerType::new(&context, 32).into()).to_string(),
230            "vector<0xi32>"
231        );
232    }
233
234    #[test]
235    fn vector_checked() {
236        let context = create_test_context();
237
238        assert_eq!(
239            Type::vector_checked(
240                Location::unknown(&context),
241                &[42],
242                IntegerType::new(&context, 32).into()
243            ),
244            Type::parse(&context, "vector<42xi32>")
245        );
246    }
247
248    #[test]
249    fn vector_checked_fail() {
250        let context = create_test_context();
251
252        assert_eq!(
253            Type::vector_checked(Location::unknown(&context), &[0], Type::index(&context)),
254            None
255        );
256    }
257
258    #[test]
259    fn equal() {
260        let context = create_test_context();
261
262        assert_eq!(Type::index(&context), Type::index(&context));
263    }
264
265    #[test]
266    fn not_equal() {
267        let context = create_test_context();
268
269        assert_ne!(Type::index(&context), Type::float64(&context));
270    }
271
272    #[test]
273    fn display() {
274        let context = create_test_context();
275
276        assert_eq!(Type::index(&context).to_string(), "index");
277    }
278
279    #[test]
280    fn debug() {
281        let context = create_test_context();
282
283        assert_eq!(format!("{:?}", Type::index(&context)), "Type(index)");
284    }
285}