melior/ir/operation/
builder.rs1use super::Operation;
2use crate::{
3 context::Context,
4 ir::{Attribute, AttributeLike, Block, Identifier, Location, Region, Type, Value},
5 string_ref::StringRef,
6 Error,
7};
8use mlir_sys::{
9 mlirNamedAttributeGet, mlirOperationCreate, mlirOperationStateAddAttributes,
10 mlirOperationStateAddOperands, mlirOperationStateAddOwnedRegions, mlirOperationStateAddResults,
11 mlirOperationStateAddSuccessors, mlirOperationStateEnableResultTypeInference,
12 mlirOperationStateGet, MlirOperationState,
13};
14use std::{
15 marker::PhantomData,
16 mem::{forget, transmute, ManuallyDrop},
17};
18
19pub struct OperationBuilder<'c> {
21 raw: MlirOperationState,
22 _context: PhantomData<&'c Context>,
23}
24
25impl<'c> OperationBuilder<'c> {
26 pub fn new(name: &str, location: Location<'c>) -> Self {
28 Self {
29 raw: unsafe { mlirOperationStateGet(StringRef::new(name).to_raw(), location.to_raw()) },
30 _context: Default::default(),
31 }
32 }
33
34 pub fn add_results(mut self, results: &[Type<'c>]) -> Self {
36 unsafe {
37 mlirOperationStateAddResults(
38 &mut self.raw,
39 results.len() as isize,
40 results.as_ptr() as *const _,
41 )
42 }
43
44 self
45 }
46
47 pub fn add_operands(mut self, operands: &[Value<'c, '_>]) -> Self {
49 unsafe {
50 mlirOperationStateAddOperands(
51 &mut self.raw,
52 operands.len() as isize,
53 operands.as_ptr() as *const _,
54 )
55 }
56
57 self
58 }
59
60 pub fn add_regions<const N: usize>(mut self, regions: [Region<'c>; N]) -> Self {
62 unsafe {
63 mlirOperationStateAddOwnedRegions(
64 &mut self.raw,
65 regions.len() as isize,
66 regions.as_ptr() as *const _,
67 )
68 }
69
70 forget(regions);
71
72 self
73 }
74
75 pub fn add_regions_vec(mut self, regions: Vec<Region<'c>>) -> Self {
77 unsafe {
78 #[allow(clippy::transmute_undefined_repr)]
81 mlirOperationStateAddOwnedRegions(
82 &mut self.raw,
83 regions.len() as isize,
84 transmute::<Vec<Region>, Vec<ManuallyDrop<Region>>>(regions).as_ptr() as *const _,
85 )
86 }
87
88 self
89 }
90
91 pub fn add_successors(mut self, successors: &[&Block<'c>]) -> Self {
95 for block in successors {
96 unsafe {
97 mlirOperationStateAddSuccessors(&mut self.raw, 1, &[block.to_raw()] as *const _)
98 }
99 }
100
101 self
102 }
103
104 pub fn add_attributes(mut self, attributes: &[(Identifier<'c>, Attribute<'c>)]) -> Self {
106 for (identifier, attribute) in attributes {
107 unsafe {
108 mlirOperationStateAddAttributes(
109 &mut self.raw,
110 1,
111 &[mlirNamedAttributeGet(
112 identifier.to_raw(),
113 attribute.to_raw(),
114 )] as *const _,
115 )
116 }
117 }
118
119 self
120 }
121
122 pub fn enable_result_type_inference(mut self) -> Self {
124 unsafe { mlirOperationStateEnableResultTypeInference(&mut self.raw) }
125
126 self
127 }
128
129 pub fn build(mut self) -> Result<Operation<'c>, Error> {
131 unsafe { Operation::from_option_raw(mlirOperationCreate(&mut self.raw)) }
132 .ok_or(Error::OperationBuild)
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139 use crate::{
140 ir::{Block, ValueLike},
141 test::create_test_context,
142 };
143
144 #[test]
145 fn new() {
146 let context = create_test_context();
147 context.set_allow_unregistered_dialects(true);
148
149 OperationBuilder::new("foo", Location::unknown(&context))
150 .build()
151 .unwrap();
152 }
153
154 #[test]
155 fn add_operands() {
156 let context = create_test_context();
157 context.set_allow_unregistered_dialects(true);
158
159 let location = Location::unknown(&context);
160 let r#type = Type::index(&context);
161 let block = Block::new(&[(r#type, location)]);
162 let argument = block.argument(0).unwrap().into();
163
164 OperationBuilder::new("foo", Location::unknown(&context))
165 .add_operands(&[argument])
166 .build()
167 .unwrap();
168 }
169
170 #[test]
171 fn add_results() {
172 let context = create_test_context();
173 context.set_allow_unregistered_dialects(true);
174
175 OperationBuilder::new("foo", Location::unknown(&context))
176 .add_results(&[Type::parse(&context, "i1").unwrap()])
177 .build()
178 .unwrap();
179 }
180
181 #[test]
182 fn add_regions() {
183 let context = create_test_context();
184 context.set_allow_unregistered_dialects(true);
185
186 OperationBuilder::new("foo", Location::unknown(&context))
187 .add_regions([Region::new()])
188 .build()
189 .unwrap();
190 }
191
192 #[test]
193 fn add_successors() {
194 let context = create_test_context();
195 context.set_allow_unregistered_dialects(true);
196
197 OperationBuilder::new("foo", Location::unknown(&context))
198 .add_successors(&[&Block::new(&[])])
199 .build()
200 .unwrap();
201 }
202
203 #[test]
204 fn add_attributes() {
205 let context = create_test_context();
206 context.set_allow_unregistered_dialects(true);
207
208 OperationBuilder::new("foo", Location::unknown(&context))
209 .add_attributes(&[(
210 Identifier::new(&context, "foo"),
211 Attribute::parse(&context, "unit").unwrap(),
212 )])
213 .build()
214 .unwrap();
215 }
216
217 #[test]
218 fn enable_result_type_inference() {
219 let context = create_test_context();
220 context.set_allow_unregistered_dialects(true);
221
222 let location = Location::unknown(&context);
223 let r#type = Type::index(&context);
224 let block = Block::new(&[(r#type, location)]);
225 let argument = block.argument(0).unwrap().into();
226
227 assert_eq!(
228 OperationBuilder::new("arith.addi", location)
229 .add_operands(&[argument, argument])
230 .enable_result_type_inference()
231 .build()
232 .unwrap()
233 .result(0)
234 .unwrap()
235 .r#type(),
236 r#type,
237 );
238 }
239}