pub(super) use crate::transform::subst::{substitute_node, substitute_nodes};
use crate::ir::{Expr, Ident, Node};
pub(super) fn expr_contains_opaque(expr: &Expr) -> bool {
match expr {
Expr::Opaque(_) => true,
Expr::Load { index, .. } => expr_contains_opaque(index),
Expr::BufLen { .. } => false,
Expr::Atomic {
index,
expected,
value,
..
} => {
expr_contains_opaque(index)
|| expr_contains_opaque(value)
|| matches!(expected.as_deref(), Some(e) if expr_contains_opaque(e))
}
Expr::BinOp { left, right, .. } => {
expr_contains_opaque(left) || expr_contains_opaque(right)
}
Expr::UnOp { operand, .. } => expr_contains_opaque(operand),
Expr::Select {
cond,
true_val,
false_val,
} => {
expr_contains_opaque(cond)
|| expr_contains_opaque(true_val)
|| expr_contains_opaque(false_val)
}
Expr::Cast { value, .. } | Expr::SubgroupReduce { value, .. } => {
expr_contains_opaque(value)
}
Expr::Fma { a, b, c } => {
expr_contains_opaque(a) || expr_contains_opaque(b) || expr_contains_opaque(c)
}
Expr::Call { args, .. } => args.iter().any(expr_contains_opaque),
Expr::SubgroupBallot { cond } => expr_contains_opaque(cond),
Expr::SubgroupShuffle { value, lane } => {
expr_contains_opaque(value) || expr_contains_opaque(lane)
}
Expr::LitU32(_)
| Expr::LitI32(_)
| Expr::LitF32(_)
| Expr::LitBool(_)
| Expr::Var(_)
| Expr::InvocationId { .. }
| Expr::WorkgroupId { .. }
| Expr::LocalId { .. }
| Expr::SubgroupLocalId
| Expr::SubgroupSize => false,
}
}
pub(super) fn body_writes_loop_var(nodes: &[Node], var: &Ident) -> bool {
nodes.iter().any(|node| match node {
Node::Let { name, .. } | Node::Assign { name, .. } => name == var,
Node::If {
then, otherwise, ..
} => body_writes_loop_var(then, var) || body_writes_loop_var(otherwise, var),
Node::Loop {
var: inner, body, ..
} => inner != var && body_writes_loop_var(body, var),
Node::Block(body) => body_writes_loop_var(body, var),
Node::Region { body, .. } => body_writes_loop_var(body, var),
_ => false,
})
}
pub(super) fn body_rebinds_var(body: &[Node], var: &Ident) -> bool {
body.iter().any(|node| match node {
Node::Let { name, .. } | Node::Assign { name, .. } => name == var,
Node::Loop {
var: inner, body, ..
} => inner == var || body_rebinds_var(body, var),
Node::If {
then, otherwise, ..
} => body_rebinds_var(then, var) || body_rebinds_var(otherwise, var),
Node::Block(body) => body_rebinds_var(body, var),
Node::Region { body, .. } => body_rebinds_var(body, var),
_ => false,
})
}