1mod argument;
4
5pub use self::argument::BlockArgument;
6use super::{
7 operation::OperationRefMut, Location, Operation, OperationRef, RegionRef, Type, TypeLike, Value,
8};
9use crate::{context::Context, utility::print_callback, Error};
10use mlir_sys::{
11 mlirBlockAddArgument, mlirBlockAppendOwnedOperation, mlirBlockCreate, mlirBlockDestroy,
12 mlirBlockDetach, mlirBlockEqual, mlirBlockGetArgument, mlirBlockGetFirstOperation,
13 mlirBlockGetNextInRegion, mlirBlockGetNumArguments, mlirBlockGetParentOperation,
14 mlirBlockGetParentRegion, mlirBlockGetTerminator, mlirBlockInsertOwnedOperation,
15 mlirBlockInsertOwnedOperationAfter, mlirBlockInsertOwnedOperationBefore, mlirBlockPrint,
16 MlirBlock,
17};
18use std::{
19 ffi::c_void,
20 fmt::{self, Debug, Display, Formatter},
21 marker::PhantomData,
22 mem::{forget, transmute},
23 ops::Deref,
24};
25
26pub struct Block<'c> {
28 raw: MlirBlock,
29 _context: PhantomData<&'c Context>,
30}
31
32impl<'c> Block<'c> {
33 pub fn new(arguments: &[(Type<'c>, Location<'c>)]) -> Self {
36 unsafe {
37 Self::from_raw(mlirBlockCreate(
38 arguments.len() as isize,
39 arguments
40 .iter()
41 .map(|(argument, _)| argument.to_raw())
42 .collect::<Vec<_>>()
43 .as_ptr() as *const _,
44 arguments
45 .iter()
46 .map(|(_, location)| location.to_raw())
47 .collect::<Vec<_>>()
48 .as_ptr() as *const _,
49 ))
50 }
51 }
52
53 pub fn argument(&self, index: usize) -> Result<BlockArgument<'c, '_>, Error> {
55 unsafe {
56 if index < self.argument_count() {
57 Ok(BlockArgument::from_raw(mlirBlockGetArgument(
58 self.raw,
59 index as isize,
60 )))
61 } else {
62 Err(Error::PositionOutOfBounds {
63 name: "block argument",
64 value: self.to_string(),
65 index,
66 })
67 }
68 }
69 }
70
71 pub fn argument_count(&self) -> usize {
73 unsafe { mlirBlockGetNumArguments(self.raw) as usize }
74 }
75
76 pub fn first_operation(&self) -> Option<OperationRef<'c, '_>> {
78 unsafe { OperationRef::from_option_raw(mlirBlockGetFirstOperation(self.raw)) }
79 }
80
81 pub fn first_operation_mut(&mut self) -> Option<OperationRefMut<'c, '_>> {
83 unsafe { OperationRefMut::from_option_raw(mlirBlockGetFirstOperation(self.raw)) }
84 }
85
86 pub fn terminator(&self) -> Option<OperationRef<'c, '_>> {
88 unsafe { OperationRef::from_option_raw(mlirBlockGetTerminator(self.raw)) }
89 }
90
91 pub fn terminator_mut(&mut self) -> Option<OperationRefMut<'c, '_>> {
93 unsafe { OperationRefMut::from_option_raw(mlirBlockGetTerminator(self.raw)) }
94 }
95
96 pub fn parent_region(&self) -> Option<RegionRef<'c, '_>> {
100 unsafe { RegionRef::from_option_raw(mlirBlockGetParentRegion(self.raw)) }
101 }
102
103 pub fn parent_operation(&self) -> Option<OperationRef<'c, '_>> {
105 unsafe { OperationRef::from_option_raw(mlirBlockGetParentOperation(self.raw)) }
106 }
107
108 pub fn add_argument(&self, r#type: Type<'c>, location: Location<'c>) -> Value<'c, '_> {
110 unsafe {
111 Value::from_raw(mlirBlockAddArgument(
112 self.raw,
113 r#type.to_raw(),
114 location.to_raw(),
115 ))
116 }
117 }
118
119 pub fn append_operation(&self, operation: Operation<'c>) -> OperationRef<'c, '_> {
121 unsafe {
122 let operation = operation.into_raw();
123
124 mlirBlockAppendOwnedOperation(self.raw, operation);
125
126 OperationRef::from_raw(operation)
127 }
128 }
129
130 pub fn insert_operation(
134 &self,
135 position: usize,
136 operation: Operation<'c>,
137 ) -> OperationRef<'c, '_> {
138 unsafe {
139 let operation = operation.into_raw();
140
141 mlirBlockInsertOwnedOperation(self.raw, position as isize, operation);
142
143 OperationRef::from_raw(operation)
144 }
145 }
146
147 pub fn insert_operation_after(
149 &self,
150 one: OperationRef<'c, '_>,
151 other: Operation<'c>,
152 ) -> OperationRef<'c, '_> {
153 unsafe {
154 let other = other.into_raw();
155
156 mlirBlockInsertOwnedOperationAfter(self.raw, one.to_raw(), other);
157
158 OperationRef::from_raw(other)
159 }
160 }
161
162 pub fn insert_operation_before(
164 &self,
165 one: OperationRef<'c, '_>,
166 other: Operation<'c>,
167 ) -> OperationRef<'c, '_> {
168 unsafe {
169 let other = other.into_raw();
170
171 mlirBlockInsertOwnedOperationBefore(self.raw, one.to_raw(), other);
172
173 OperationRef::from_raw(other)
174 }
175 }
176
177 pub unsafe fn detach(&self) -> Option<Block<'c>> {
185 if self.parent_region().is_some() {
186 mlirBlockDetach(self.raw);
187
188 Some(Block::from_raw(self.raw))
189 } else {
190 None
191 }
192 }
193
194 pub fn next_in_region(&self) -> Option<BlockRef<'c, '_>> {
196 unsafe { BlockRef::from_option_raw(mlirBlockGetNextInRegion(self.raw)) }
197 }
198
199 pub unsafe fn from_raw(raw: MlirBlock) -> Self {
205 Self {
206 raw,
207 _context: Default::default(),
208 }
209 }
210
211 pub const fn into_raw(self) -> MlirBlock {
213 let block = self.raw;
214
215 forget(self);
216
217 block
218 }
219
220 pub const fn to_raw(&self) -> MlirBlock {
222 self.raw
223 }
224}
225
226impl Drop for Block<'_> {
227 fn drop(&mut self) {
228 unsafe { mlirBlockDestroy(self.raw) };
229 }
230}
231
232impl PartialEq for Block<'_> {
233 fn eq(&self, other: &Self) -> bool {
234 unsafe { mlirBlockEqual(self.raw, other.raw) }
235 }
236}
237
238impl Eq for Block<'_> {}
239
240impl Display for Block<'_> {
241 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
242 let mut data = (formatter, Ok(()));
243
244 unsafe {
245 mlirBlockPrint(
246 self.raw,
247 Some(print_callback),
248 &mut data as *mut _ as *mut c_void,
249 );
250 }
251
252 data.1
253 }
254}
255
256impl Debug for Block<'_> {
257 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
258 writeln!(formatter, "Block(")?;
259 Display::fmt(self, formatter)?;
260 write!(formatter, ")")
261 }
262}
263
264#[derive(Clone, Copy)]
266pub struct BlockRef<'c, 'a> {
267 raw: MlirBlock,
268 _reference: PhantomData<&'a Block<'c>>,
269}
270
271impl BlockRef<'_, '_> {
272 pub unsafe fn from_raw(raw: MlirBlock) -> Self {
278 Self {
279 raw,
280 _reference: Default::default(),
281 }
282 }
283
284 pub unsafe fn from_option_raw(raw: MlirBlock) -> Option<Self> {
290 if raw.ptr.is_null() {
291 None
292 } else {
293 Some(Self::from_raw(raw))
294 }
295 }
296}
297
298impl<'a> Deref for BlockRef<'_, 'a> {
299 type Target = Block<'a>;
300
301 fn deref(&self) -> &Self::Target {
302 unsafe { transmute(self) }
303 }
304}
305
306impl PartialEq for BlockRef<'_, '_> {
307 fn eq(&self, other: &Self) -> bool {
308 unsafe { mlirBlockEqual(self.raw, other.raw) }
309 }
310}
311
312impl Eq for BlockRef<'_, '_> {}
313
314impl Display for BlockRef<'_, '_> {
315 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
316 Display::fmt(self.deref(), formatter)
317 }
318}
319
320impl Debug for BlockRef<'_, '_> {
321 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
322 Debug::fmt(self.deref(), formatter)
323 }
324}
325
326#[cfg(test)]
327mod tests {
328 use super::*;
329 use crate::{
330 ir::{operation::OperationBuilder, r#type::IntegerType, Module, Region, ValueLike},
331 test::create_test_context,
332 };
333 use pretty_assertions::assert_eq;
334
335 #[test]
336 fn new() {
337 Block::new(&[]);
338 }
339
340 #[test]
341 fn argument() {
342 let context = create_test_context();
343 let r#type = IntegerType::new(&context, 64).into();
344
345 assert_eq!(
346 Block::new(&[(r#type, Location::unknown(&context))])
347 .argument(0)
348 .unwrap()
349 .r#type(),
350 r#type
351 );
352 }
353
354 #[test]
355 fn argument_error() {
356 assert_eq!(
357 Block::new(&[]).argument(0).unwrap_err(),
358 Error::PositionOutOfBounds {
359 name: "block argument",
360 value: "<<UNLINKED BLOCK>>\n".into(),
361 index: 0,
362 }
363 );
364 }
365
366 #[test]
367 fn argument_count() {
368 assert_eq!(Block::new(&[]).argument_count(), 0);
369 }
370
371 #[test]
372 fn parent_region() {
373 let region = Region::new();
374 let block = region.append_block(Block::new(&[]));
375
376 assert_eq!(block.parent_region().as_deref(), Some(®ion));
377 }
378
379 #[test]
380 fn parent_region_none() {
381 let block = Block::new(&[]);
382
383 assert_eq!(block.parent_region(), None);
384 }
385
386 #[test]
387 fn parent_operation() {
388 let context = create_test_context();
389 let module = Module::new(Location::unknown(&context));
390
391 assert_eq!(
392 module.body().parent_operation(),
393 Some(module.as_operation())
394 );
395 }
396
397 #[test]
398 fn parent_operation_none() {
399 let block = Block::new(&[]);
400
401 assert_eq!(block.parent_operation(), None);
402 }
403
404 #[test]
405 fn terminator() {
406 let context = create_test_context();
407
408 let block = Block::new(&[]);
409
410 let operation = block.append_operation(
411 OperationBuilder::new("func.return", Location::unknown(&context))
412 .build()
413 .unwrap(),
414 );
415
416 assert_eq!(block.terminator(), Some(operation));
417 }
418
419 #[test]
420 fn terminator_none() {
421 assert_eq!(Block::new(&[]).terminator(), None);
422 }
423
424 #[test]
425 fn first_operation() {
426 let context = create_test_context();
427 context.set_allow_unregistered_dialects(true);
428 let block = Block::new(&[]);
429
430 let operation = block.append_operation(
431 OperationBuilder::new("foo", Location::unknown(&context))
432 .build()
433 .unwrap(),
434 );
435
436 assert_eq!(block.first_operation(), Some(operation));
437 }
438
439 #[test]
440 fn first_operation_none() {
441 let block = Block::new(&[]);
442
443 assert_eq!(block.first_operation(), None);
444 }
445
446 #[test]
447 fn append_operation() {
448 let context = create_test_context();
449 context.set_allow_unregistered_dialects(true);
450 let block = Block::new(&[]);
451
452 block.append_operation(
453 OperationBuilder::new("foo", Location::unknown(&context))
454 .build()
455 .unwrap(),
456 );
457 }
458
459 #[test]
460 fn insert_operation() {
461 let context = create_test_context();
462 context.set_allow_unregistered_dialects(true);
463 let block = Block::new(&[]);
464
465 block.insert_operation(
466 0,
467 OperationBuilder::new("foo", Location::unknown(&context))
468 .build()
469 .unwrap(),
470 );
471 }
472
473 #[test]
474 fn insert_operation_after() {
475 let context = create_test_context();
476 context.set_allow_unregistered_dialects(true);
477 let block = Block::new(&[]);
478
479 let first_operation = block.append_operation(
480 OperationBuilder::new("foo", Location::unknown(&context))
481 .build()
482 .unwrap(),
483 );
484 let second_operation = block.insert_operation_after(
485 first_operation,
486 OperationBuilder::new("foo", Location::unknown(&context))
487 .build()
488 .unwrap(),
489 );
490
491 assert_eq!(block.first_operation(), Some(first_operation));
492 assert_eq!(
493 block.first_operation().unwrap().next_in_block(),
494 Some(second_operation)
495 );
496 }
497
498 #[test]
499 fn insert_operation_before() {
500 let context = create_test_context();
501 context.set_allow_unregistered_dialects(true);
502 let block = Block::new(&[]);
503
504 let second_operation = block.append_operation(
505 OperationBuilder::new("foo", Location::unknown(&context))
506 .build()
507 .unwrap(),
508 );
509 let first_operation = block.insert_operation_before(
510 second_operation,
511 OperationBuilder::new("foo", Location::unknown(&context))
512 .build()
513 .unwrap(),
514 );
515
516 assert_eq!(block.first_operation(), Some(first_operation));
517 assert_eq!(
518 block.first_operation().unwrap().next_in_block(),
519 Some(second_operation)
520 );
521 }
522
523 #[test]
524 fn next_in_region() {
525 let region = Region::new();
526
527 let first_block = region.append_block(Block::new(&[]));
528 let second_block = region.append_block(Block::new(&[]));
529
530 assert_eq!(first_block.next_in_region(), Some(second_block));
531 }
532
533 #[test]
534 fn detach() {
535 let region = Region::new();
536 let block = region.append_block(Block::new(&[]));
537
538 assert_eq!(
539 unsafe { block.detach() }.unwrap().to_string(),
540 "<<UNLINKED BLOCK>>\n"
541 );
542 }
543
544 #[test]
545 fn detach_detached() {
546 let block = Block::new(&[]);
547
548 assert!(unsafe { block.detach() }.is_none());
549 }
550
551 #[test]
552 fn display() {
553 assert_eq!(Block::new(&[]).to_string(), "<<UNLINKED BLOCK>>\n");
554 }
555
556 #[test]
557 fn debug() {
558 assert_eq!(
559 format!("{:?}", &Block::new(&[])),
560 "Block(\n<<UNLINKED BLOCK>>\n)"
561 );
562 }
563}