use naga::{AtomicFunction, Expression, Handle, Scalar, Statement};
use super::{Builder, Kind, Val, Width};
impl Builder {
pub fn atomic_kind(scalar: Scalar) -> Kind {
if scalar == Scalar::I32 { Kind::I } else { Kind::U }
}
pub fn atomic(
&mut self,
pointer: Handle<Expression>,
fun: AtomicFunction,
value: Val,
scalar: Scalar,
) -> Val {
let kind = Self::atomic_kind(scalar);
let value = self.bitcast_to(value, kind);
let ty = self.ty_of(kind, Width::One);
let result = self.result_expr(Expression::AtomicResult {
ty,
comparison: false,
});
self.push(Statement::Atomic {
pointer,
fun,
value: value.expr,
result: Some(result),
});
Val {
expr: result,
kind,
width: Width::One,
}
}
pub fn image_atomic_result(&mut self, kind: Kind) -> Val {
let ty = self.ty_of(kind, Width::One);
let expr = self.result_expr(Expression::AtomicResult {
ty,
comparison: false,
});
Val {
expr,
kind,
width: Width::One,
}
}
pub fn compare_exchange(
&mut self,
pointer: Handle<Expression>,
compare: Val,
value: Val,
scalar: Scalar,
) -> (Val, Val) {
let kind = Self::atomic_kind(scalar);
let compare = self.bitcast_to(compare, kind);
let value = self.bitcast_to(value, kind);
let ty = self
.module
.generate_predeclared_type(naga::PredeclaredType::AtomicCompareExchangeWeakResult(scalar));
let result = self.result_expr(Expression::AtomicResult { ty, comparison: true });
self.push(Statement::Atomic {
pointer,
fun: AtomicFunction::Exchange {
compare: Some(compare.expr),
},
value: value.expr,
result: Some(result),
});
let old = Val {
expr: self.app(Expression::AccessIndex {
base: result,
index: 0,
}),
kind,
width: Width::One,
};
let exchanged = Val {
expr: self.app(Expression::AccessIndex {
base: result,
index: 1,
}),
kind: Kind::B,
width: Width::One,
};
(old, exchanged)
}
pub fn buffer_word(&mut self, words: Handle<Expression>, word: Val, typed: bool) -> Handle<Expression> {
let element = self.app(Expression::Access {
base: words,
index: word.expr,
});
if typed {
self.app(Expression::AccessIndex {
base: element,
index: 0,
})
} else {
element
}
}
pub fn atomic_inside(&mut self, inside: Val, kind: Kind, body: impl FnOnce(&mut Self) -> Val) -> Val {
let ty = self.ty_of(kind, Width::One);
let local = self.local("old", ty);
let zero = self.lit_bits(kind, 0);
let pointer = self.local_ptr(local);
self.store(pointer, zero);
self.when(inside, |b| {
let old = body(b);
let old = b.bitcast_to(old, kind);
let pointer = b.local_ptr(local);
b.store(pointer, old);
});
let pointer = self.local_ptr(local);
self.load(pointer, kind, Width::One)
}
}