1mod branch_point;
2mod interfaces;
3mod invocation_bounds;
4mod kind;
5mod successor;
6mod transforms;
7
8use smallvec::{smallvec, SmallVec};
9
10pub use self::{
11 branch_point::RegionBranchPoint,
12 interfaces::{
13 LoopLikeOpInterface, RegionBranchOpInterface, RegionBranchTerminatorOpInterface,
14 RegionKindInterface,
15 },
16 invocation_bounds::InvocationBounds,
17 kind::RegionKind,
18 successor::{RegionSuccessor, RegionSuccessorInfo, RegionSuccessorIter},
19 transforms::RegionTransformFailed,
20};
21use super::*;
22use crate::{
23 adt::SmallSet,
24 patterns::RegionSimplificationLevel,
25 traits::{SingleBlock, SingleRegion},
26 Forward,
27};
28
29pub type RegionRef = UnsafeIntrusiveEntityRef<Region>;
30pub type RegionList = EntityList<Region>;
32pub type RegionCursor<'a> = EntityCursor<'a, Region>;
34pub type RegionCursorMut<'a> = EntityCursorMut<'a, Region>;
36
37#[derive(Default)]
53pub struct Region {
54 body: BlockList,
56}
57
58impl Entity for Region {}
59
60impl EntityWithParent for Region {
61 type Parent = Operation;
62}
63
64impl EntityListItem for Region {}
65
66impl EntityParent<Block> for Region {
67 fn offset() -> usize {
68 core::mem::offset_of!(Region, body)
69 }
70}
71
72impl core::fmt::Debug for Region {
73 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
74 core::fmt::Display::fmt(self, f)
75 }
76}
77impl core::fmt::Display for Region {
78 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
79 let region_number = self.region_number();
80 write!(f, "region({region_number})")
81 }
82}
83
84impl cfg::Graph for Region {
85 type ChildEdgeIter = block::BlockSuccessorEdgesIter;
86 type ChildIter = block::BlockSuccessorIter;
87 type Edge = BlockOperandRef;
88 type Node = BlockRef;
89
90 fn is_empty(&self) -> bool {
91 self.body.is_empty()
92 }
93
94 fn size(&self) -> usize {
95 self.body.len()
96 }
97
98 fn children(parent: Self::Node) -> Self::ChildIter {
99 block::BlockSuccessorIter::new(parent)
100 }
101
102 fn children_edges(parent: Self::Node) -> Self::ChildEdgeIter {
103 block::BlockSuccessorEdgesIter::new(parent)
104 }
105
106 fn edge_dest(edge: Self::Edge) -> Self::Node {
107 edge.parent().unwrap()
108 }
109
110 fn entry_node(&self) -> Self::Node {
111 self.body.front().as_pointer().expect("empty region")
112 }
113}
114
115impl<'a> cfg::InvertibleGraph for &'a Region {
116 type Inverse = cfg::Inverse<&'a Region>;
117 type InvertibleChildEdgeIter = block::BlockPredecessorEdgesIter;
118 type InvertibleChildIter = block::BlockPredecessorIter;
119
120 fn inverse(self) -> Self::Inverse {
121 cfg::Inverse::new(self)
122 }
123
124 fn inverse_children(parent: Self::Node) -> Self::InvertibleChildIter {
125 block::BlockPredecessorIter::new(parent)
126 }
127
128 fn inverse_children_edges(parent: Self::Node) -> Self::InvertibleChildEdgeIter {
129 block::BlockPredecessorEdgesIter::new(parent)
130 }
131}
132
133impl Region {
135 pub fn is_empty(&self) -> bool {
137 self.body.is_empty()
138 }
139
140 pub fn entry(&self) -> EntityRef<'_, Block> {
142 self.body.front().into_borrow().unwrap()
143 }
144
145 pub fn entry_mut(&mut self) -> EntityMut<'_, Block> {
147 self.body.front_mut().into_borrow_mut().unwrap()
148 }
149
150 #[inline]
152 pub fn entry_block_ref(&self) -> Option<BlockRef> {
153 self.body.front().as_pointer()
154 }
155
156 pub fn body(&self) -> &BlockList {
158 &self.body
159 }
160
161 pub fn body_mut(&mut self) -> &mut BlockList {
163 &mut self.body
164 }
165}
166
167impl Region {
169 pub fn prewalk_all<F>(&self, callback: F)
170 where
171 F: FnMut(&Operation),
172 {
173 Walk::<Operation>::prewalk_all::<Forward, _>(self, callback);
174 }
175
176 pub fn prewalk<F, B>(&self, callback: F) -> WalkResult<B>
177 where
178 F: FnMut(&Operation) -> WalkResult<B>,
179 {
180 Walk::<Operation>::prewalk::<Forward, _, _>(self, callback)
181 }
182
183 pub fn postwalk_all<F>(&self, callback: F)
184 where
185 F: FnMut(&Operation),
186 {
187 Walk::<Operation>::postwalk_all::<Forward, _>(self, callback);
188 }
189
190 pub fn postwalk<F, B>(&self, callback: F) -> WalkResult<B>
191 where
192 F: FnMut(&Operation) -> WalkResult<B>,
193 {
194 Walk::<Operation>::postwalk::<Forward, _, _>(self, callback)
195 }
196}
197
198impl Region {
200 #[inline]
201 pub fn as_region_ref(&self) -> RegionRef {
202 unsafe { RegionRef::from_raw(self) }
203 }
204
205 pub fn region_number(&self) -> usize {
206 let op = self.parent().unwrap().borrow();
207 op.regions()
208 .iter()
209 .position(|r| core::ptr::addr_eq(self, &*r))
210 .expect("invalid region parent")
211 }
212
213 pub fn is_ancestor(&self, other: &RegionRef) -> bool {
218 let this = self.as_region_ref();
219 &this == other || Self::is_proper_ancestor_of(&this, other)
220 }
221
222 pub fn is_proper_ancestor(&self, other: &RegionRef) -> bool {
227 let this = self.as_region_ref();
228 Self::is_proper_ancestor_of(&this, other)
229 }
230
231 fn is_proper_ancestor_of(this: &RegionRef, other: &RegionRef) -> bool {
232 if this == other {
233 return false;
234 }
235
236 let mut parent = other.borrow().parent_region();
237 while let Some(parent_region) = parent.take() {
238 if this == &parent_region {
239 return true;
240 }
241 parent = parent_region.borrow().parent_region();
242 }
243
244 false
245 }
246
247 pub fn may_be_graph_region(&self) -> bool {
249 if let Some(owner) = self.parent() {
250 owner
251 .borrow()
252 .as_trait::<dyn RegionKindInterface>()
253 .is_some_and(|rki| rki.has_graph_regions())
254 } else {
255 true
256 }
257 }
258
259 pub fn has_one_block(&self) -> bool {
261 !self.body.is_empty()
262 && BlockRef::ptr_eq(
263 &self.body.front().as_pointer().unwrap(),
264 &self.body.back().as_pointer().unwrap(),
265 )
266 }
267
268 pub fn parent(&self) -> Option<OperationRef> {
270 self.as_region_ref().parent()
271 }
272
273 pub fn parent_region(&self) -> Option<RegionRef> {
275 self.parent().and_then(|op| op.grandparent())
276 }
277}
278
279impl Region {
281 pub fn traverse_region_graph<F>(begin: &Self, mut stop: F) -> bool
294 where
295 F: FnMut(&Region, &SmallSet<RegionRef, 4>) -> bool,
296 {
297 let op = begin.parent().expect("cannot traverse an orphaned region");
298 let op = op.borrow();
299 let branch = op
300 .as_trait::<dyn RegionBranchOpInterface>()
301 .expect("expected parent op to implement RegionBranchOpInterface");
302
303 let mut visited = SmallSet::<RegionRef, 4>::default();
304 visited.insert(begin.as_region_ref());
305
306 let mut worklist = SmallVec::<[RegionRef; 4]>::default();
307 for successor in
308 branch.get_successor_regions(RegionBranchPoint::Child(begin.as_region_ref()))
309 {
310 if let Some(successor) = successor.into_successor() {
311 worklist.push(successor);
312 }
313 }
314
315 while let Some(next_region_ref) = worklist.pop() {
316 let next_region = next_region_ref.borrow();
317
318 if stop(&next_region, &visited) {
319 return true;
320 }
321
322 if visited.insert(next_region_ref) {
323 for successor in
324 branch.get_successor_regions(RegionBranchPoint::Child(next_region_ref))
325 {
326 if let Some(successor) = successor.into_successor() {
327 worklist.push(successor);
328 }
329 }
330 }
331 }
332
333 false
334 }
335
336 pub fn is_reachable_from(&self, begin: &Region) -> bool {
339 assert_eq!(self.parent(), begin.parent(), "expected both regions to belong to the same op");
340 Self::traverse_region_graph(begin, |region, _| core::ptr::addr_eq(self, region))
342 }
343
344 pub fn is_repetitive_region(&self) -> bool {
350 Self::traverse_region_graph(self, |region, _| core::ptr::addr_eq(self, region))
351 }
352
353 pub fn postorder_region_graph(begin: &Self) -> SmallVec<[RegionRef; 4]> {
361 struct RegionNode {
362 region: RegionRef,
363 children: SmallVec<[RegionRef; 2]>,
364 }
365 impl RegionNode {
366 pub fn new(region: RegionRef, branch: &dyn RegionBranchOpInterface) -> Self {
367 let children = branch
369 .get_successor_regions(RegionBranchPoint::Child(region))
370 .filter_map(|s| s.into_successor())
371 .collect();
372 Self { region, children }
373 }
374 }
375
376 let op = begin.parent().expect("cannot traverse an orphaned region");
377 let op = op.borrow();
378 let branch = op
379 .as_trait::<dyn RegionBranchOpInterface>()
380 .expect("expected parent op to implement RegionBranchOpInterface");
381
382 let mut postorder = SmallVec::<[RegionRef; 4]>::default();
383 let mut visited = SmallSet::<RegionRef, 4>::default();
384 let mut worklist = SmallVec::<[(RegionNode, usize); 4]>::default();
385
386 let root = begin.as_region_ref();
387 visited.insert(root);
388 let root = RegionNode::new(root, branch);
389 worklist.push((root, 0));
390
391 while let Some((node, child_index)) = worklist.last_mut() {
392 if *child_index >= node.children.len() {
394 postorder.push(node.region);
395 worklist.pop();
396 } else {
397 let index = *child_index;
399 *child_index += 1;
400 let child = RegionNode::new(node.children[index], branch);
401 if worklist.iter().any(|(node, _)| node.region == child.region) {
402 continue;
404 } else if visited.insert(child.region) {
405 worklist.push((child, 0));
406 }
407 }
408 }
409
410 postorder
411 }
412
413 pub fn postorder_region_graph_for(
418 root: &dyn RegionBranchOpInterface,
419 ) -> SmallVec<[RegionRef; 4]> {
420 struct RegionNode {
421 region: RegionRef,
422 children: SmallVec<[RegionRef; 2]>,
423 }
424 impl RegionNode {
425 pub fn new(region: RegionRef, branch: &dyn RegionBranchOpInterface) -> Self {
426 let children = branch
428 .get_successor_regions(RegionBranchPoint::Child(region))
429 .filter_map(|s| s.into_successor())
430 .collect();
431 Self { region, children }
432 }
433 }
434
435 let mut postorder = SmallVec::<[RegionRef; 4]>::default();
436 let mut visited = SmallSet::<RegionRef, 4>::default();
437 let mut worklist = SmallVec::<[(RegionNode, usize); 4]>::default();
438
439 for succ in root.get_successor_regions(RegionBranchPoint::Parent) {
440 let Some(region) = succ.into_successor() else {
441 continue;
442 };
443
444 if visited.insert(region) {
445 worklist.push((RegionNode::new(region, root), 0));
446 }
447 }
448
449 while let Some((node, child_index)) = worklist.last_mut() {
450 if *child_index >= node.children.len() {
452 postorder.push(node.region);
453 worklist.pop();
454 } else {
455 let index = *child_index;
457 *child_index += 1;
458 let child = RegionNode::new(node.children[index], root);
459 if worklist.iter().any(|(node, _)| node.region == child.region) {
460 continue;
462 } else if visited.insert(child.region) {
463 worklist.push((child, 0));
464 }
465 }
466 }
467
468 postorder
469 }
470}
471
472impl Region {
474 #[inline]
476 pub fn push_front(&mut self, block: BlockRef) {
477 self.body.push_front(block);
478 }
479
480 #[inline]
482 pub fn push_back(&mut self, block: BlockRef) {
483 self.body.push_back(block);
484 }
485
486 pub fn take_body(&mut self, mut from_region: RegionRef) {
487 self.drop_all_references();
488 self.body.clear();
489
490 let blocks = from_region.borrow_mut().body_mut().take();
493 self.body.back_mut().splice_after(blocks);
494 }
495
496 pub fn drop_all_references(&mut self) {
499 let mut cursor = self.body_mut().front_mut();
500 while let Some(mut op) = cursor.as_pointer() {
501 op.borrow_mut().drop_all_references();
502 cursor.move_next();
503 }
504 }
505}
506
507impl Region {
509 pub fn values_are_defined_above(&self, values: &[ValueRef]) -> bool {
512 let this = self.as_region_ref();
513 for value in values {
514 if !value
515 .borrow()
516 .parent_region()
517 .is_some_and(|value_region| Self::is_proper_ancestor_of(&value_region, &this))
518 {
519 return false;
520 }
521 }
522 true
523 }
524
525 pub fn replace_all_uses_in_region_with(&mut self, _value: ValueRef, _replacement: ValueRef) {
527 todo!("RegionUtils.h")
528 }
529
530 pub fn visit_used_values_defined_above<F>(&self, _limit: &RegionRef, _callback: F)
533 where
534 F: FnMut(OpOperand),
535 {
536 todo!("RegionUtils.h")
537 }
538
539 pub fn visit_used_values_defined_above_any<F>(_regions: &[RegionRef], _callback: F)
542 where
543 F: FnMut(OpOperand),
544 {
545 todo!("RegionUtils.h")
546 }
547
548 pub fn get_used_values_defined_above(&self, _limit: &RegionRef) -> SmallVec<[ValueRef; 1]> {
551 todo!("RegionUtils.h")
552 }
553
554 pub fn get_used_values_defined_above_any(_regions: &[RegionRef]) -> SmallVec<[ValueRef; 1]> {
556 todo!("RegionUtils.h")
557 }
558
559 pub fn make_isolated_from_above<R, F>(
572 &mut self,
573 _rewriter: &mut R,
574 _clone_into_region: F,
575 ) -> SmallVec<[ValueRef; 1]>
576 where
577 R: crate::Rewriter,
578 F: Fn(&Operation) -> bool,
579 {
580 todo!("RegionUtils.h")
581 }
582}
583
584impl Region {
586 pub fn find_common_ancestor(ops: &[OperationRef]) -> Option<RegionRef> {
587 use bitvec::prelude::*;
588
589 match ops.len() {
590 0 => None,
591 1 => unsafe { ops.get_unchecked(0) }.borrow().parent_region(),
592 num_ops => {
593 let (first, rest) = unsafe { ops.split_first().unwrap_unchecked() };
594 let mut region = first.borrow().parent_region();
595 let mut remaining_ops = bitvec![1; num_ops - 1];
596 while let Some(r) = region.take() {
597 while let Some(index) = remaining_ops.first_one() {
598 if r.borrow().find_ancestor_op(rest[index]).is_some() {
600 unsafe {
601 remaining_ops.set_unchecked(index, false);
602 }
603 }
604 }
605 if remaining_ops.not_any() {
606 break;
607 }
608 region = r.borrow().parent_region();
609 }
610 region
611 }
612 }
613 }
614
615 pub fn find_ancestor_block(&self, block: BlockRef) -> Option<BlockRef> {
620 let this = self.as_region_ref();
621 let mut current = Some(block);
622 while let Some(current_block) = current.take() {
623 let parent = current_block.parent()?;
624 if parent == this {
625 return Some(current_block);
626 }
627 current = parent.grandparent();
628 }
629 current
630 }
631
632 pub fn find_ancestor_op(&self, op: OperationRef) -> Option<OperationRef> {
637 let this = self.as_region_ref();
638 let mut current = Some(op);
639 while let Some(current_op) = current.take() {
640 let parent = current_op.borrow().parent_region()?;
641 if parent == this {
642 return Some(current_op);
643 }
644 current = parent.parent();
645 }
646 current
647 }
648}
649
650impl Region {
652 pub fn simplify_all(
665 regions: &[RegionRef],
666 rewriter: &mut dyn crate::Rewriter,
667 simplification_level: RegionSimplificationLevel,
668 ) -> Result<(), RegionTransformFailed> {
669 let merge_blocks = matches!(simplification_level, RegionSimplificationLevel::Aggressive);
670
671 log::debug!(target: "region-simplify", "running region simplification on {} regions", regions.len());
672 log::debug!(target: "region-simplify", " simplification level = {simplification_level:?}");
673 log::debug!(target: "region-simplify", " merge_blocks = {merge_blocks}");
674
675 let eliminated_blocks = Self::erase_unreachable_blocks(regions, rewriter).is_ok();
676 let eliminated_ops_or_args = Self::dead_code_elimination(regions, rewriter).is_ok();
677
678 let mut merged_identical_blocks = false;
679 let mut dropped_redundant_arguments = false;
680 if merge_blocks {
681 merged_identical_blocks = Self::merge_identical_blocks(regions, rewriter).is_ok();
682 dropped_redundant_arguments = Self::drop_redundant_arguments(regions, rewriter).is_ok();
683 }
684
685 if eliminated_blocks
686 || eliminated_ops_or_args
687 || merged_identical_blocks
688 || dropped_redundant_arguments
689 {
690 Ok(())
691 } else {
692 Err(RegionTransformFailed)
693 }
694 }
695}
696
697impl Region {
699 pub fn print(&self, flags: &OpPrintingFlags) -> crate::formatter::Document {
700 use crate::formatter::PrettyPrint;
701
702 let printer = RegionPrinter {
703 region: self,
704 flags,
705 };
706 printer.render()
707 }
708}
709
710struct RegionPrinter<'a> {
711 region: &'a Region,
712 flags: &'a OpPrintingFlags,
713}
714
715impl crate::formatter::PrettyPrint for RegionPrinter<'_> {
716 fn render(&self) -> crate::formatter::Document {
717 use crate::formatter::*;
718
719 if self.region.is_empty() {
720 return const_text("{ }");
721 }
722
723 let is_parent_op_single_block_single_region = self.region.parent().is_some_and(|op| {
724 let op = op.borrow();
725 op.implements::<dyn SingleBlock>() && op.implements::<dyn SingleRegion>()
726 });
727 self.region.body.iter().fold(Document::Empty, |acc, block| {
728 if acc.is_empty() {
729 if is_parent_op_single_block_single_region || !self.flags.print_entry_block_headers
730 {
731 const_text("{") + indent(4, nl() + block.print(self.flags))
732 } else {
733 const_text("{") + nl() + block.print(self.flags)
734 }
735 } else {
736 acc + nl() + block.print(self.flags)
737 }
738 }) + nl()
739 + const_text("}")
740 }
741}
742
743impl crate::formatter::PrettyPrint for Region {
744 fn render(&self) -> crate::formatter::Document {
745 let flags = OpPrintingFlags::default();
746
747 self.print(&flags)
748 }
749}