Skip to main content

melior/ir/
value.rs

1mod value_like;
2
3pub use self::value_like::ValueLike;
4use super::{block::BlockArgument, operation::OperationResult, Type};
5use crate::{utility::print_callback, Context};
6use mlir_sys::{mlirValueEqual, mlirValuePrint, MlirValue};
7use std::{
8    ffi::c_void,
9    fmt::{self, Debug, Display, Formatter},
10    marker::PhantomData,
11};
12
13/// A value.
14// Values are always non-owning references to their parents, such as operations
15// and blocks. See the `Value` class in the MLIR C++ API.
16#[derive(Clone, Copy)]
17pub struct Value<'c, 'a> {
18    raw: MlirValue,
19    _context: PhantomData<&'c Context>,
20    _parent: PhantomData<&'a ()>,
21}
22
23impl Value<'_, '_> {
24    /// Creates a value from a raw object.
25    ///
26    /// # Safety
27    ///
28    /// A raw object must be valid.
29    pub unsafe fn from_raw(value: MlirValue) -> Self {
30        Self {
31            raw: value,
32            _context: Default::default(),
33            _parent: Default::default(),
34        }
35    }
36}
37
38impl<'c> ValueLike<'c> for Value<'c, '_> {
39    fn to_raw(&self) -> MlirValue {
40        self.raw
41    }
42}
43
44impl PartialEq for Value<'_, '_> {
45    fn eq(&self, other: &Self) -> bool {
46        unsafe { mlirValueEqual(self.raw, other.raw) }
47    }
48}
49
50impl Eq for Value<'_, '_> {}
51
52impl Display for Value<'_, '_> {
53    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
54        let mut data = (formatter, Ok(()));
55
56        unsafe {
57            mlirValuePrint(
58                self.raw,
59                Some(print_callback),
60                &mut data as *mut _ as *mut c_void,
61            );
62        }
63
64        data.1
65    }
66}
67
68impl Debug for Value<'_, '_> {
69    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
70        writeln!(formatter, "Value(")?;
71        Display::fmt(self, formatter)?;
72        write!(formatter, ")")
73    }
74}
75
76from_borrowed_subtypes!(Value, BlockArgument, OperationResult);
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81    use crate::{
82        ir::{operation::OperationBuilder, Attribute, Block, Identifier, Location},
83        test::create_test_context,
84        Context,
85    };
86
87    #[test]
88    fn r#type() {
89        let context = create_test_context();
90        let location = Location::unknown(&context);
91        let index_type = Type::index(&context);
92
93        let operation = OperationBuilder::new("arith.constant", location)
94            .add_results(&[index_type])
95            .add_attributes(&[(
96                Identifier::new(&context, "value"),
97                Attribute::parse(&context, "0 : index").unwrap(),
98            )])
99            .build()
100            .unwrap();
101
102        assert_eq!(operation.result(0).unwrap().r#type(), index_type);
103    }
104
105    #[test]
106    fn is_operation_result() {
107        let context = create_test_context();
108        let location = Location::unknown(&context);
109        let r#type = Type::index(&context);
110
111        let operation = OperationBuilder::new("arith.constant", location)
112            .add_results(&[r#type])
113            .add_attributes(&[(
114                Identifier::new(&context, "value"),
115                Attribute::parse(&context, "0 : index").unwrap(),
116            )])
117            .build()
118            .unwrap();
119
120        assert!(operation.result(0).unwrap().is_operation_result());
121    }
122
123    #[test]
124    fn is_block_argument() {
125        let context = create_test_context();
126        let r#type = Type::index(&context);
127        let block = Block::new(&[(r#type, Location::unknown(&context))]);
128
129        assert!(block.argument(0).unwrap().is_block_argument());
130    }
131
132    #[test]
133    fn dump() {
134        let context = create_test_context();
135        let location = Location::unknown(&context);
136        let index_type = Type::index(&context);
137
138        let value = OperationBuilder::new("arith.constant", location)
139            .add_results(&[index_type])
140            .add_attributes(&[(
141                Identifier::new(&context, "value"),
142                Attribute::parse(&context, "0 : index").unwrap(),
143            )])
144            .build()
145            .unwrap();
146
147        value.result(0).unwrap().dump();
148    }
149
150    #[test]
151    fn equal() {
152        let context = create_test_context();
153        let location = Location::unknown(&context);
154        let index_type = Type::index(&context);
155
156        let operation = OperationBuilder::new("arith.constant", location)
157            .add_results(&[index_type])
158            .add_attributes(&[(
159                Identifier::new(&context, "value"),
160                Attribute::parse(&context, "0 : index").unwrap(),
161            )])
162            .build()
163            .unwrap();
164        let result = Value::from(operation.result(0).unwrap());
165
166        assert_eq!(result, result);
167    }
168
169    #[test]
170    fn not_equal() {
171        let context = create_test_context();
172        let location = Location::unknown(&context);
173        let index_type = Type::index(&context);
174
175        let operation = || {
176            OperationBuilder::new("arith.constant", location)
177                .add_results(&[index_type])
178                .add_attributes(&[(
179                    Identifier::new(&context, "value"),
180                    Attribute::parse(&context, "0 : index").unwrap(),
181                )])
182                .build()
183                .unwrap()
184        };
185
186        assert_ne!(
187            Value::from(operation().result(0).unwrap()),
188            operation().result(0).unwrap().into()
189        );
190    }
191
192    #[test]
193    fn display_with_unregistered_dialect() {
194        let context = Context::new();
195        context.set_allow_unregistered_dialects(true);
196
197        let location = Location::unknown(&context);
198        let index_type = Type::index(&context);
199
200        let operation = OperationBuilder::new("arith.constant", location)
201            .add_results(&[index_type])
202            .add_attributes(&[(
203                Identifier::new(&context, "value"),
204                Attribute::parse(&context, "0 : index").unwrap(),
205            )])
206            .build()
207            .unwrap();
208
209        assert_eq!(
210            operation.result(0).unwrap().to_string(),
211            "%0 = \"arith.constant\"() {value = 0 : index} : () -> index\n"
212        );
213    }
214
215    #[test]
216    fn display_with_registered_dialect() {
217        let context = create_test_context();
218
219        let location = Location::unknown(&context);
220        let index_type = Type::index(&context);
221
222        let operation = OperationBuilder::new("arith.constant", location)
223            .add_results(&[index_type])
224            .add_attributes(&[(
225                Identifier::new(&context, "value"),
226                Attribute::parse(&context, "0 : index").unwrap(),
227            )])
228            .build()
229            .unwrap();
230
231        assert_eq!(
232            operation.result(0).unwrap().to_string(),
233            "%c0 = arith.constant 0 : index\n"
234        );
235    }
236
237    #[test]
238    fn debug() {
239        let context = create_test_context();
240
241        let location = Location::unknown(&context);
242        let index_type = Type::index(&context);
243
244        let operation = OperationBuilder::new("arith.constant", location)
245            .add_results(&[index_type])
246            .add_attributes(&[(
247                Identifier::new(&context, "value"),
248                Attribute::parse(&context, "0 : index").unwrap(),
249            )])
250            .build()
251            .unwrap();
252
253        assert_eq!(
254            format!("{:?}", Value::from(operation.result(0).unwrap())),
255            "Value(\n%c0 = arith.constant 0 : index\n)"
256        );
257    }
258}