use crate::ir::model::expr::Expr;
use crate::ir::model::program::BufferDecl;
use crate::ir::model::types::{AtomicOp, BufferAccess, DataType};
use crate::ir::validate::typecheck::expr_type;
use crate::ir::validate::{err, Binding, ValidationError};
use rustc_hash::FxHashMap;
#[inline]
pub fn validate_atomic(
op: &AtomicOp,
buffer: &str,
_index: &Expr,
expected: Option<&Expr>,
value: &Expr,
buffers: &FxHashMap<&str, &BufferDecl>,
scope: &FxHashMap<String, Binding>,
errors: &mut Vec<ValidationError>,
) {
if let Some(buf) = buffers.get(buffer) {
match &buf.access {
BufferAccess::ReadWrite => {}
BufferAccess::Workgroup => {
errors.push(err(format!(
"V025: atomic on workgroup buffer `{buffer}` is not yet specified. Fix: use a storage ReadWrite buffer for atomics, or wait for the workgroup-atomic memory model to land."
)));
}
_ => {
errors.push(err(format!(
"V009: atomic on non-writable buffer `{buffer}`. Fix: declare it with BufferAccess::ReadWrite."
)));
}
}
if buf.element == DataType::Bytes {
errors.push(err(format!(
"V013: operation on buffer `{buffer}` with element type `bytes` is not supported. Fix: use a typed buffer."
)));
}
if buf.element != DataType::U32 {
errors.push(err(format!(
"V014: atomic on buffer `{buffer}` with non-u32 element type `{elem}`. Fix: atomics only support U32 elements.",
elem = buf.element
)));
}
if let Some(val_ty) = expr_type(value, buffers, scope) {
if val_ty != DataType::U32 {
errors.push(err(format!(
"atomic value type `{val_ty}` does not match required `u32`. Fix: ensure the atomic operand is U32."
)));
}
}
match (op, expected) {
(AtomicOp::CompareExchange, Some(expected_expr)) => {
if let Some(expected_ty) = expr_type(expected_expr, buffers, scope) {
if expected_ty != DataType::U32 {
errors.push(err(format!(
"compare-exchange expected type `{expected_ty}` does not match required `u32`. Fix: ensure Expr::Atomic.expected is U32."
)));
}
}
}
(AtomicOp::CompareExchange, None) => errors.push(err(
"compare-exchange atomic is missing expected value. Fix: set Expr::Atomic.expected for AtomicOp::CompareExchange."
.to_string(),
)),
(_, Some(_)) => errors.push(err(
"non-compare-exchange atomic includes an expected value. Fix: use Expr::Atomic.expected only with AtomicOp::CompareExchange."
.to_string(),
)),
(_, None) => {}
}
} else {
errors.push(err(format!(
"atomic on unknown buffer `{buffer}`. Fix: declare it in Program::buffers."
)));
}
}