1use super::arith::CmpiPredicate;
4use crate::{
5 ir::{
6 attribute::IntegerAttribute, operation::OperationBuilder, Attribute, Identifier, Location,
7 Operation, Value,
8 },
9 Context,
10};
11
12pub 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
27pub 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}