use crate::ir_inner::model::expr::{Expr, ExprNode, Ident};
use crate::ir_inner::model::types::{AtomicOp, BinOp, DataType, UnOp};
use crate::visit::VisitOrder;
use std::ops::ControlFlow;
pub trait ExprVisitor {
type Break;
fn visit_lit_u32(&mut self, _expr: &Expr, _value: u32) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_lit_i32(&mut self, _expr: &Expr, _value: i32) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_lit_f32(&mut self, _expr: &Expr, _value: f32) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_lit_bool(&mut self, _expr: &Expr, _value: bool) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_var(&mut self, _expr: &Expr, _name: &Ident) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_load(
&mut self,
_expr: &Expr,
_buffer: &Ident,
_index: &Expr,
) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_buf_len(&mut self, _expr: &Expr, _buffer: &Ident) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_buffer_ref(&mut self, _expr: &Expr, _buffer: &Ident) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_invocation_id(&mut self, _expr: &Expr, _axis: u32) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_workgroup_id(&mut self, _expr: &Expr, _axis: u32) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_local_id(&mut self, _expr: &Expr, _axis: u32) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_subgroup_local_id(&mut self, _expr: &Expr) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_subgroup_size(&mut self, _expr: &Expr) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_bin_op(
&mut self,
_expr: &Expr,
_op: &BinOp,
_left: &Expr,
_right: &Expr,
) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_un_op(
&mut self,
_expr: &Expr,
_op: &UnOp,
_operand: &Expr,
) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_call(
&mut self,
_expr: &Expr,
_op_id: &str,
_args: &[Expr],
) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_sequence(&mut self, _parts: &[Expr]) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_fma(
&mut self,
_expr: &Expr,
_a: &Expr,
_b: &Expr,
_c: &Expr,
) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_select(
&mut self,
_expr: &Expr,
_cond: &Expr,
_true_val: &Expr,
_false_val: &Expr,
) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_cast(
&mut self,
_expr: &Expr,
_target: &DataType,
_value: &Expr,
) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_atomic(
&mut self,
_expr: &Expr,
_op: &AtomicOp,
_buffer: &Ident,
_index: &Expr,
_expected: Option<&Expr>,
_value: &Expr,
) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_subgroup_ballot(&mut self, _expr: &Expr, _cond: &Expr) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_subgroup_shuffle(
&mut self,
_expr: &Expr,
_value: &Expr,
_lane: &Expr,
) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_subgroup_add(&mut self, _expr: &Expr, _value: &Expr) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn visit_opaque_expr(
&mut self,
_expr: &Expr,
_extension: &dyn ExprNode,
) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
fn walk_children_default(&mut self, expr: &Expr, order: VisitOrder) -> ControlFlow<Self::Break>
where
Self: Sized,
{
walk_expr_children_default(self, expr, order)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExprBufferAccess {
Load,
Atomic,
}
struct ExprBufferAccessVisitor<F> {
visitor: F,
}
impl<F> ExprVisitor for ExprBufferAccessVisitor<F>
where
F: FnMut(ExprBufferAccess, &Ident),
{
type Break = std::convert::Infallible;
fn visit_load(
&mut self,
_expr: &Expr,
buffer: &Ident,
_index: &Expr,
) -> ControlFlow<Self::Break> {
(self.visitor)(ExprBufferAccess::Load, buffer);
ControlFlow::Continue(())
}
fn visit_buf_len(&mut self, _expr: &Expr, buffer: &Ident) -> ControlFlow<Self::Break> {
(self.visitor)(ExprBufferAccess::Load, buffer);
ControlFlow::Continue(())
}
fn visit_buffer_ref(&mut self, _expr: &Expr, buffer: &Ident) -> ControlFlow<Self::Break> {
(self.visitor)(ExprBufferAccess::Load, buffer);
ControlFlow::Continue(())
}
fn visit_atomic(
&mut self,
_expr: &Expr,
_op: &AtomicOp,
buffer: &Ident,
_index: &Expr,
_expected: Option<&Expr>,
_value: &Expr,
) -> ControlFlow<Self::Break> {
(self.visitor)(ExprBufferAccess::Atomic, buffer);
ControlFlow::Continue(())
}
}
pub fn visit_expr_buffer_accesses(expr: &Expr, visitor: impl FnMut(ExprBufferAccess, &Ident)) {
let mut visitor = ExprBufferAccessVisitor { visitor };
let _ = visit_preorder(&mut visitor, expr);
}
mod traversal;
pub use traversal::{visit_expr, visit_postorder, visit_preorder, walk_expr_children_default};