use super::*;
use crate::{
AttributeRef, Op, SuccessorOperandRange, SuccessorOperandRangeMut, Type, traits::Terminator,
};
pub trait RegionKindInterface {
fn kind(&self) -> RegionKind;
#[inline]
fn has_ssa_dominance(&self) -> bool {
matches!(self.kind(), RegionKind::SSA)
}
#[inline]
fn has_graph_regions(&self) -> bool {
matches!(self.kind(), RegionKind::Graph)
}
}
pub trait RegionBranchOpInterface: Op {
#[inline]
#[allow(unused_variables)]
fn get_entry_successor_operands(&self, point: RegionBranchPoint) -> SuccessorOperandRange<'_> {
crate::SuccessorOperandRange::empty()
}
#[inline]
#[allow(unused_variables)]
fn get_entry_successor_regions(
&self,
operands: &[Option<AttributeRef>],
) -> RegionSuccessorIter<'_> {
self.get_successor_regions(RegionBranchPoint::Parent)
}
fn get_successor_regions(&self, point: RegionBranchPoint) -> RegionSuccessorIter<'_>;
#[inline]
#[allow(unused_variables)]
fn get_region_invocation_bounds(
&self,
operands: &[Option<AttributeRef>],
) -> SmallVec<[InvocationBounds; 1]> {
use smallvec::smallvec;
smallvec![InvocationBounds::Unknown; self.num_regions()]
}
#[inline]
fn are_types_compatible(&self, lhs: &Type, rhs: &Type) -> bool {
lhs == rhs
}
fn is_repetitive_region(&self, index: usize) -> bool {
self.region(index).is_repetitive_region()
}
fn has_loop(&self) -> bool {
self.get_successor_regions(RegionBranchPoint::Parent)
.filter_map(|entry| entry.into_successor())
.any(|region| {
Region::traverse_region_graph(®ion.borrow(), |r, visited| {
visited.contains(&r.as_region_ref())
})
})
}
}
pub trait RegionBranchTerminatorOpInterface: Op + Terminator {
fn get_successor_operands(&self, point: RegionBranchPoint) -> SuccessorOperandRange<'_>;
fn get_mutable_successor_operands(
&mut self,
point: RegionBranchPoint,
) -> SuccessorOperandRangeMut<'_>;
#[allow(unused_variables)]
fn get_successor_regions(
&self,
operands: &[Option<AttributeRef>],
) -> SmallVec<[RegionSuccessorInfo; 2]> {
let parent_region =
self.parent_region().expect("expected operation to have a parent region");
let parent_op = parent_region.parent().expect("expected operation to have a parent op");
parent_op
.borrow()
.as_trait::<dyn RegionBranchOpInterface>()
.expect("invalid region terminator parent: must implement RegionBranchOpInterface")
.get_successor_regions(RegionBranchPoint::Child(parent_region))
.into_successor_infos()
}
}
#[allow(unused_variables)]
#[allow(clippy::result_unit_err)]
pub trait LoopLikeOpInterface: Op {
fn is_defined_outside_of_loop(&self, value: ValueRef) -> bool {
let value = value.borrow();
if let Some(defining_op) = value.get_defining_op() {
self.as_operation().is_ancestor_of(&defining_op.borrow())
} else {
let block_arg = value
.downcast_ref::<BlockArgument>()
.expect("invalid value reference: defining op is orphaned");
let defining_region = block_arg.parent_region().unwrap();
let defining_op = defining_region.parent().unwrap();
self.as_operation().is_ancestor_of(&defining_op.borrow())
}
}
fn get_loop_header_region(&self) -> RegionRef;
fn get_loop_regions(&self) -> SmallVec<[RegionRef; 2]>;
fn move_out_of_loop(&mut self, mut op: OperationRef) {
op.borrow_mut().move_to(crate::ProgramPoint::before(self.as_operation()));
}
fn promote_if_single_iteration(
&mut self,
rewriter: &mut dyn crate::Rewriter,
) -> Result<(), ()> {
Err(())
}
fn get_loop_induction_vars(&self) -> Option<SmallVec<[ValueRef; 2]>> {
None
}
fn get_loop_lower_bounds(&self) -> Option<SmallVec<[OpFoldResult; 2]>> {
None
}
fn get_loop_upper_bounds(&self) -> Option<SmallVec<[OpFoldResult; 2]>> {
None
}
fn get_loop_steps(&self) -> Option<SmallVec<[OpFoldResult; 2]>> {
None
}
fn get_inits_mut(&mut self) -> OpOperandRangeMut<'_> {
self.operands_mut().empty_mut()
}
fn get_region_iter_args(&self) -> Option<EntityRef<'_, [BlockArgumentRef]>> {
None
}
fn get_yielded_values_mut(&mut self) -> Option<EntityProjectionMut<'_, OpOperandRangeMut<'_>>> {
None
}
fn get_loop_results(&self) -> Option<OpResultRange<'_>> {
None
}
}
impl dyn LoopLikeOpInterface {
pub fn get_single_induction_var(&self) -> Option<ValueRef> {
let vars = self.get_loop_induction_vars();
if let Some([var]) = vars.as_deref() {
return Some(*var);
}
None
}
pub fn get_single_lower_bound(&self) -> Option<OpFoldResult> {
let mut lower_bounds = self.get_loop_lower_bounds()?;
if lower_bounds.len() == 1 {
lower_bounds.pop()
} else {
None
}
}
pub fn get_single_upper_bound(&self) -> Option<OpFoldResult> {
let mut upper_bounds = self.get_loop_upper_bounds()?;
if upper_bounds.len() == 1 {
upper_bounds.pop()
} else {
None
}
}
pub fn get_single_step(&self) -> Option<OpFoldResult> {
let mut steps = self.get_loop_steps()?;
if steps.len() == 1 { steps.pop() } else { None }
}
}