Skip to main content

melior/dialect/
index.rs

1//! `index` dialect.
2
3use super::arith::CmpiPredicate;
4use crate::{
5    ir::{
6        attribute::IntegerAttribute, operation::OperationBuilder, Attribute, Identifier, Location,
7        Operation, Value,
8    },
9    Context,
10};
11
12// spell-checker: disable
13
14/// Creates an `index.constant` operation.
15pub fn constant<'c>(
16    context: &'c Context,
17    value: IntegerAttribute<'c>,
18    location: Location<'c>,
19) -> Operation<'c> {
20    OperationBuilder::new("index.constant", location)
21        .add_attributes(&[(Identifier::new(context, "value"), value.into())])
22        .enable_result_type_inference()
23        .build()
24        .expect("valid operation")
25}
26
27/// Creates an `index.cmp` operation.
28pub fn cmp<'c>(
29    context: &'c Context,
30    predicate: CmpiPredicate,
31    lhs: Value<'c, '_>,
32    rhs: Value<'c, '_>,
33    location: Location<'c>,
34) -> Operation<'c> {
35    OperationBuilder::new("index.cmp", location)
36        .add_attributes(&[(
37            Identifier::new(context, "pred"),
38            Attribute::parse(
39                context,
40                match predicate {
41                    CmpiPredicate::Eq => "#index<cmp_predicate eq>",
42                    CmpiPredicate::Ne => "#index<cmp_predicate ne>",
43                    CmpiPredicate::Slt => "#index<cmp_predicate slt>",
44                    CmpiPredicate::Sle => "#index<cmp_predicate sle>",
45                    CmpiPredicate::Sgt => "#index<cmp_predicate sgt>",
46                    CmpiPredicate::Sge => "#index<cmp_predicate sge>",
47                    CmpiPredicate::Ult => "#index<cmp_predicate ult>",
48                    CmpiPredicate::Ule => "#index<cmp_predicate ule>",
49                    CmpiPredicate::Ugt => "#index<cmp_predicate ugt>",
50                    CmpiPredicate::Uge => "#index<cmp_predicate uge>",
51                },
52            )
53            .unwrap(),
54        )])
55        .add_operands(&[lhs, rhs])
56        .enable_result_type_inference()
57        .build()
58        .expect("valid operation")
59}
60
61melior_macro::binary_operations!(
62    index,
63    [
64        add, and, ceildivs, ceildivu, divs, divu, floordivs, maxs, maxu, mins, minu, mul, or, rems,
65        remu, shl, shrs, shru, sub, xor,
66    ]
67);
68
69melior_macro::typed_unary_operations!(index, [casts, castu]);
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74    use crate::{
75        dialect::func,
76        ir::{
77            attribute::{StringAttribute, TypeAttribute},
78            r#type::{FunctionType, IntegerType},
79            Block, Location, Module, Region, Type,
80        },
81        test::load_all_dialects,
82        Context,
83    };
84
85    fn create_context() -> Context {
86        let context = Context::new();
87        load_all_dialects(&context);
88        context
89    }
90
91    fn compile_operation<'c>(
92        context: &'c Context,
93        operation: impl Fn(&Block<'c>) -> Operation<'c>,
94        function_type: FunctionType<'c>,
95    ) {
96        let location = Location::unknown(context);
97        let module = Module::new(location);
98
99        let block = Block::new(
100            &(0..function_type.input_count())
101                .map(|index| (function_type.input(index).unwrap(), location))
102                .collect::<Vec<_>>(),
103        );
104
105        let operation = operation(&block);
106        let name = operation.name();
107        let name = name.as_string_ref().as_str().unwrap();
108
109        block.append_operation(func::r#return(
110            &[block.append_operation(operation).result(0).unwrap().into()],
111            location,
112        ));
113
114        let region = Region::new();
115        region.append_block(block);
116
117        let function = func::func(
118            context,
119            StringAttribute::new(context, "foo"),
120            TypeAttribute::new(function_type.into()),
121            region,
122            &[],
123            Location::unknown(context),
124        );
125
126        module.body().append_operation(function);
127
128        assert!(module.as_operation().verify());
129        insta::assert_snapshot!(name, module.as_operation());
130    }
131
132    #[test]
133    fn compile_constant() {
134        let context = create_context();
135        let index_type = Type::index(&context);
136
137        compile_operation(
138            &context,
139            |_| {
140                constant(
141                    &context,
142                    IntegerAttribute::new(index_type, 42),
143                    Location::unknown(&context),
144                )
145            },
146            FunctionType::new(&context, &[index_type], &[index_type]),
147        );
148    }
149
150    #[test]
151    fn compile_cmp() {
152        let context = create_context();
153        let index_type = Type::index(&context);
154
155        compile_operation(
156            &context,
157            |block| {
158                cmp(
159                    &context,
160                    CmpiPredicate::Eq,
161                    block.argument(0).unwrap().into(),
162                    block.argument(1).unwrap().into(),
163                    Location::unknown(&context),
164                )
165            },
166            FunctionType::new(
167                &context,
168                &[index_type, index_type],
169                &[IntegerType::new(&context, 1).into()],
170            ),
171        );
172    }
173
174    mod typed_unary {
175        use super::*;
176
177        #[test]
178        fn compile_casts() {
179            let context = create_context();
180
181            compile_operation(
182                &context,
183                |block| {
184                    casts(
185                        block.argument(0).unwrap().into(),
186                        IntegerType::new(&context, 64).into(),
187                        Location::unknown(&context),
188                    )
189                },
190                FunctionType::new(
191                    &context,
192                    &[Type::index(&context)],
193                    &[IntegerType::new(&context, 64).into()],
194                ),
195            );
196        }
197
198        #[test]
199        fn compile_castu() {
200            let context = create_context();
201
202            compile_operation(
203                &context,
204                |block| {
205                    castu(
206                        block.argument(0).unwrap().into(),
207                        IntegerType::new(&context, 64).into(),
208                        Location::unknown(&context),
209                    )
210                },
211                FunctionType::new(
212                    &context,
213                    &[Type::index(&context)],
214                    &[IntegerType::new(&context, 64).into()],
215                ),
216            );
217        }
218    }
219
220    #[test]
221    fn compile_add() {
222        let context = Context::new();
223        load_all_dialects(&context);
224
225        let location = Location::unknown(&context);
226        let module = Module::new(location);
227
228        let integer_type = Type::index(&context);
229
230        let function = {
231            let block = Block::new(&[(integer_type, location), (integer_type, location)]);
232
233            let sum = block.append_operation(add(
234                block.argument(0).unwrap().into(),
235                block.argument(1).unwrap().into(),
236                location,
237            ));
238
239            block.append_operation(func::r#return(&[sum.result(0).unwrap().into()], location));
240
241            let region = Region::new();
242            region.append_block(block);
243
244            func::func(
245                &context,
246                StringAttribute::new(&context, "foo"),
247                TypeAttribute::new(
248                    FunctionType::new(&context, &[integer_type, integer_type], &[integer_type])
249                        .into(),
250                ),
251                region,
252                &[],
253                Location::unknown(&context),
254            )
255        };
256
257        module.body().append_operation(function);
258
259        assert!(module.as_operation().verify());
260        insta::assert_snapshot!(module.as_operation());
261    }
262}