///|
priv enum WgslIrEmitIntegerValue {
Signed(Int)
Unsigned(UInt)
Abstract(Int64)
}
///|
fn WgslIrEmitter::folded_constant_expression(
self : WgslIrEmitter,
constant : Constant,
) -> String? {
if !self.options.fold_numeric_constant_expressions() {
return None
}
match self.constant_type_integer_kind(constant) {
Some(kind) =>
match
self.eval_global_integer_expression_for_emit(constant.init, Set([])) {
Some(value) => return self.integer_value_literal_for_kind(value, kind)
None => ()
}
None => ()
}
match self.constant_type_float_width(constant) {
Some(width) =>
match self.eval_global_float_expression_for_emit(constant.init, Set([])) {
Some(value) => self.float_value_literal_for_width(value, width)
None => None
}
None => None
}
}
///|
fn WgslIrEmitter::constant_type_integer_kind(
self : WgslIrEmitter,
constant : Constant,
) -> ScalarKind? {
match self.shader_module.types.items.get(constant.ty.index()) {
Some(ty) =>
match ty.inner {
Scalar(scalar) =>
match scalar.kind {
Sint | Uint | AbstractInt => Some(scalar.kind)
_ => None
}
_ => None
}
None => None
}
}
///|
fn WgslIrEmitter::constant_type_float_width(
self : WgslIrEmitter,
constant : Constant,
) -> Int? {
match self.shader_module.types.items.get(constant.ty.index()) {
Some(ty) =>
match ty.inner {
Scalar(scalar) =>
match scalar.kind {
Float | AbstractFloat => Some(scalar.width)
_ => None
}
_ => None
}
None => None
}
}
///|
fn WgslIrEmitter::integer_value_literal_for_kind(
self : WgslIrEmitter,
value : WgslIrEmitIntegerValue,
kind : ScalarKind,
) -> String? {
let numeric_policy = self.options.numeric_literal_policy()
match kind {
Uint =>
match value.to_unsigned() {
Some(value) =>
Some(wgsl_ir_emit_unsigned_literal(value, numeric_policy))
None => None
}
Sint =>
match value.to_signed_int() {
Some(value) => Some(wgsl_ir_emit_signed_literal(value, numeric_policy))
None => None
}
AbstractInt =>
match value {
Abstract(value) => Some("\{value}")
Signed(value) => Some("\{value}")
Unsigned(value) => Some("\{value}")
}
_ => None
}
}
///|
fn WgslIrEmitter::float_value_literal_for_width(
self : WgslIrEmitter,
value : Double,
width : Int,
) -> String? {
let numeric_policy = self.options.numeric_literal_policy()
match width {
2 => Some(wgsl_ir_emit_f16_literal_text("\{value}"))
4 => Some(self.f32_literal(Float::from_double(value), numeric_policy))
8 => Some(wgsl_ir_emit_abstract_float_literal_text("\{value}"))
_ => None
}
}
///|
fn wgsl_ir_emit_unsigned_literal(
value : UInt,
policy : WgslIrNumericLiteralBytePolicy,
) -> String {
match policy {
CompatNumericLiteralSpelling | RuntimeNumericLiteralSpelling => "\{value}u"
}
}
///|
fn wgsl_ir_emit_signed_literal(
value : Int,
policy : WgslIrNumericLiteralBytePolicy,
) -> String {
match policy {
CompatNumericLiteralSpelling | RuntimeNumericLiteralSpelling => "\{value}i"
}
}
///|
fn WgslIrEmitter::eval_global_float_expression_for_emit(
self : WgslIrEmitter,
handle : Handle,
visiting_constants : @set.Set[Int],
) -> Double? {
match self.shader_module.global_expressions.items.get(handle.index()) {
Some(expression) =>
self.eval_global_float_expression_inner_for_emit(
expression, visiting_constants,
)
None => None
}
}
///|
fn WgslIrEmitter::eval_global_float_expression_inner_for_emit(
self : WgslIrEmitter,
expression : Expression,
visiting_constants : @set.Set[Int],
) -> Double? {
match expression {
Literal(F32(value) | F32Exact(value)) => wgsl_ir_emit_f32_to_double(value)
Literal(F16(value)) | Literal(F64(value)) | Literal(AbstractFloat(value)) =>
Some(value)
Constant(handle) =>
self.eval_constant_float_expression_for_emit(handle, visiting_constants)
Unary(Negate, inner) => {
guard self.eval_global_float_expression_for_emit(
inner, visiting_constants,
)
is Some(value) else {
return None
}
Some(-value)
}
Binary(op, left, right) => {
guard self.eval_global_float_expression_for_emit(left, visiting_constants)
is Some(left_value) else {
return None
}
guard self.eval_global_float_expression_for_emit(
right, visiting_constants,
)
is Some(right_value) else {
return None
}
wgsl_ir_emit_eval_float_binary(op, left_value, right_value)
}
_ => None
}
}
///|
fn WgslIrEmitter::eval_constant_float_expression_for_emit(
self : WgslIrEmitter,
handle : Handle,
visiting_constants : @set.Set[Int],
) -> Double? {
let index = handle.index()
if visiting_constants.contains(index) {
return None
}
match self.shader_module.constants.items.get(index) {
Some(constant) => {
visiting_constants.add(index)
let result = self.eval_global_float_expression_for_emit(
constant.init,
visiting_constants,
)
ignore(visiting_constants.remove(index))
result
}
None => None
}
}
///|
fn WgslIrEmitter::eval_constant_float_expression_for_writer(
self : WgslIrEmitter,
handle : Handle,
) -> Double? {
match self.shader_module.constants.items.get(handle.index()) {
Some(constant) if self.should_inline_constant_expression(constant) =>
self.eval_global_float_expression_for_emit(constant.init, Set([]))
_ => None
}
}
///|
fn wgsl_ir_emit_f32_to_double(value : Float) -> Double? {
Some(value.to_double())
}
///|
fn WgslIrEmitter::eval_global_integer_expression_for_emit(
self : WgslIrEmitter,
handle : Handle,
visiting_constants : @set.Set[Int],
) -> WgslIrEmitIntegerValue? {
match self.shader_module.global_expressions.items.get(handle.index()) {
Some(expression) =>
self.eval_global_integer_expression_inner_for_emit(
expression, visiting_constants,
)
None => None
}
}
///|
fn WgslIrEmitter::eval_global_integer_expression_inner_for_emit(
self : WgslIrEmitter,
expression : Expression,
visiting_constants : @set.Set[Int],
) -> WgslIrEmitIntegerValue? {
match expression {
Literal(I32(value)) => Some(Signed(value))
Literal(U32(value)) => Some(Unsigned(value))
Literal(AbstractInt(value)) => Some(Abstract(value))
Constant(handle) =>
self.eval_constant_integer_expression_for_emit(handle, visiting_constants)
Unary(Negate, inner) => {
guard self.eval_global_integer_expression_for_emit(
inner, visiting_constants,
)
is Some(value) else {
return None
}
match value.to_signed_int() {
Some(value) => Some(Signed(-value))
None => None
}
}
Unary(BitwiseNot, inner) =>
match
self.eval_global_integer_expression_for_emit(inner, visiting_constants) {
Some(Unsigned(value)) => Some(Unsigned(value.lnot()))
Some(Signed(value)) => Some(Signed(value.lnot()))
Some(Abstract(value)) => Some(Abstract(value.lnot()))
None => None
}
Binary(op, left, right) => {
guard self.eval_global_integer_expression_for_emit(
left, visiting_constants,
)
is Some(left_value) else {
return None
}
guard self.eval_global_integer_expression_for_emit(
right, visiting_constants,
)
is Some(right_value) else {
return None
}
wgsl_ir_emit_eval_integer_binary(op, left_value, right_value)
}
Math(Min, a, Some(b), None, None) => {
guard self.eval_global_integer_expression_for_emit(a, visiting_constants)
is Some(a_value) else {
return None
}
guard self.eval_global_integer_expression_for_emit(b, visiting_constants)
is Some(b_value) else {
return None
}
wgsl_ir_emit_eval_integer_min(a_value, b_value)
}
Math(Max, a, Some(b), None, None) => {
guard self.eval_global_integer_expression_for_emit(a, visiting_constants)
is Some(a_value) else {
return None
}
guard self.eval_global_integer_expression_for_emit(b, visiting_constants)
is Some(b_value) else {
return None
}
wgsl_ir_emit_eval_integer_max(a_value, b_value)
}
Math(Clamp, value, Some(low), Some(high), None) => {
guard self.eval_global_integer_expression_for_emit(
value, visiting_constants,
)
is Some(value) else {
return None
}
guard self.eval_global_integer_expression_for_emit(
low, visiting_constants,
)
is Some(low) else {
return None
}
guard self.eval_global_integer_expression_for_emit(
high, visiting_constants,
)
is Some(high) else {
return None
}
match wgsl_ir_emit_eval_integer_max(value, low) {
Some(value) => wgsl_ir_emit_eval_integer_min(value, high)
None => None
}
}
_ => None
}
}
///|
fn WgslIrEmitter::eval_constant_integer_expression_for_emit(
self : WgslIrEmitter,
handle : Handle,
visiting_constants : @set.Set[Int],
) -> WgslIrEmitIntegerValue? {
if visiting_constants.contains(handle.index()) {
return None
}
match self.shader_module.constants.items.get(handle.index()) {
Some(constant) => {
visiting_constants.add(handle.index())
let result = self.eval_global_integer_expression_for_emit(
constant.init,
visiting_constants,
)
ignore(visiting_constants.remove(handle.index()))
result
}
None => None
}
}
///|
fn WgslIrEmitter::eval_constant_integer_expression_for_writer(
self : WgslIrEmitter,
handle : Handle,
) -> WgslIrEmitIntegerValue? {
match self.shader_module.constants.items.get(handle.index()) {
Some(constant) if self.should_inline_constant_expression(constant) =>
self.eval_global_integer_expression_for_emit(constant.init, Set([]))
_ => None
}
}
///|
fn WgslIrEmitter::eval_constant_float_expression_for_constructor(
self : WgslIrEmitter,
handle : Handle,
) -> Double? {
match self.shader_module.constants.items.get(handle.index()) {
Some(constant) if !self.writer_module.compatibility.is_generated_import(
constant.name,
) => self.eval_global_float_expression_for_emit(constant.init, Set([]))
_ => None
}
}
///|
fn WgslIrEmitter::eval_constant_integer_expression_for_constructor(
self : WgslIrEmitter,
handle : Handle,
) -> WgslIrEmitIntegerValue? {
match self.shader_module.constants.items.get(handle.index()) {
Some(constant) if !self.writer_module.compatibility.is_generated_import(
constant.name,
) => self.eval_global_integer_expression_for_emit(constant.init, Set([]))
_ => None
}
}
///|
fn WgslIrEmitter::eval_float_expression_with_retained_constants(
self : WgslIrEmitter,
function : Function?,
handle : Handle,
) -> Double? raise WgslIrEmitError {
if !self.expression_tree_contains_constant_reference(function, handle) {
return None
}
self.eval_float_expression_with_retained_constants_inner(function, handle)
}
///|
fn WgslIrEmitter::eval_float_vector_binary_with_retained_constants(
self : WgslIrEmitter,
function : Function?,
op : BinaryOperator,
left : Handle,
right : Handle,
) -> Array[Double]? raise WgslIrEmitError {
if !self.expression_tree_contains_constant_reference(function, left) &&
!self.expression_tree_contains_constant_reference(function, right) {
return None
}
guard self.eval_float_vector_expression_with_retained_constants_inner(
function, left,
)
is Some(left_values) else {
return None
}
guard self.eval_float_vector_expression_with_retained_constants_inner(
function, right,
)
is Some(right_values) else {
return None
}
wgsl_ir_emit_eval_float_vector_binary(op, left_values, right_values)
}
///|
fn WgslIrEmitter::eval_float_vector_expression_with_retained_constants_inner(
self : WgslIrEmitter,
function : Function?,
handle : Handle,
) -> Array[Double]? raise WgslIrEmitError {
match self.required_expression(function, handle) {
Literal(literal) =>
match wgsl_ir_float_value_from_numeric_literal(literal) {
Some(value) => Some([value])
None => None
}
Constant(constant) =>
match self.eval_constant_float_expression_for_retained_context(constant) {
Some(value) => Some([value])
None =>
match
self.eval_constant_integer_expression_for_constructor(constant) {
Some(value) =>
match value.to_double() {
Some(value) => Some([value])
None => None
}
None => None
}
}
Splat(size, inner) =>
match
self.eval_float_expression_with_retained_constants_inner(
function, inner,
) {
Some(value) => {
let values : Array[Double] = []
for _ in 0.. None
}
Compose(ty, components) =>
match self.shader_module.types.items.get(ty.index()) {
Some({ inner: Vector(_, { kind: Float | AbstractFloat, .. }), .. }) => {
let values : Array[Double] = []
for component in components {
match
self.eval_float_expression_with_retained_constants_inner(
function, component,
) {
Some(value) => values.push(value)
None => return None
}
}
Some(values)
}
Some({ inner: Scalar({ kind: Float | AbstractFloat, .. }), .. }) =>
match components {
[component] =>
match
self.eval_float_expression_with_retained_constants_inner(
function, component,
) {
Some(value) => Some([value])
None => None
}
_ => None
}
_ => None
}
Unary(Negate, inner) =>
match
self.eval_float_vector_expression_with_retained_constants_inner(
function, inner,
) {
Some(values) => Some(values.map(fn(value) { -value }))
None => None
}
Binary(op, left, right) => {
if op == Divide &&
self.expression_is_generated_import_constant_reference(function, left) &&
wgsl_ir_expression_origin_is_source_local_const_initializer(
function, right,
) {
return None
}
guard self.eval_float_vector_expression_with_retained_constants_inner(
function, left,
)
is Some(left_values) else {
return None
}
guard self.eval_float_vector_expression_with_retained_constants_inner(
function, right,
)
is Some(right_values) else {
return None
}
wgsl_ir_emit_eval_float_vector_binary(op, left_values, right_values)
}
_ => None
}
}
///|
fn WgslIrEmitter::eval_float_expression_with_retained_constants_inner(
self : WgslIrEmitter,
function : Function?,
handle : Handle,
) -> Double? raise WgslIrEmitError {
match self.required_expression(function, handle) {
Literal(literal) => wgsl_ir_float_value_from_numeric_literal(literal)
Constant(constant) =>
match self.eval_constant_float_expression_for_retained_context(constant) {
Some(value) => Some(value)
None =>
match
self.eval_constant_integer_expression_for_constructor(constant) {
Some(value) => value.to_double()
None => None
}
}
Compose(ty, [component]) =>
match self.shader_module.types.items.get(ty.index()) {
Some({ inner: Scalar({ kind: Float | AbstractFloat, .. }), .. }) =>
self.eval_float_expression_with_retained_constants_inner(
function, component,
)
_ => None
}
Unary(Negate, inner) =>
match
self.eval_float_expression_with_retained_constants_inner(
function, inner,
) {
Some(value) => Some(-value)
None => None
}
Binary(op, left, right) => {
if op == Divide &&
self.expression_is_generated_import_constant_reference(function, left) &&
wgsl_ir_expression_origin_is_source_local_const_initializer(
function, right,
) {
return None
}
guard self.eval_float_expression_with_retained_constants_inner(
function, left,
)
is Some(left_value) else {
return None
}
guard self.eval_float_expression_with_retained_constants_inner(
function, right,
)
is Some(right_value) else {
return None
}
wgsl_ir_emit_eval_float_binary(op, left_value, right_value)
}
_ => None
}
}
///|
fn WgslIrEmitter::eval_constant_float_expression_for_retained_context(
self : WgslIrEmitter,
handle : Handle,
) -> Double? {
match self.shader_module.constants.items.get(handle.index()) {
Some(constant) =>
self.eval_global_float_expression_for_emit(constant.init, Set([]))
None => None
}
}
///|
fn wgsl_ir_emit_eval_float_vector_binary(
op : BinaryOperator,
left : Array[Double],
right : Array[Double],
) -> Array[Double]? {
let width = if left.length() == right.length() {
left.length()
} else if left.length() == 1 {
right.length()
} else if right.length() == 1 {
left.length()
} else {
return None
}
let values : Array[Double] = []
for index in 0.. values.push(value)
None => return None
}
}
Some(values)
}
///|
fn wgsl_ir_expression_origin_is_source_local_const_initializer(
function : Function?,
handle : Handle,
) -> Bool {
match function {
Some(function) =>
wgsl_naga_expression_origin_retains_generated_import_denominator(
function.expressions.origin(handle),
)
None => false
}
}
///|
fn wgsl_naga_expression_origin_retains_generated_import_denominator(
origin : ExpressionOrigin?,
) -> Bool {
match origin {
Some(SourceLocalConstInitializer | RetainedSourceLetExpression) => true
_ => false
}
}
///|
fn WgslIrEmitter::expression_is_generated_import_constant_reference(
self : WgslIrEmitter,
function : Function?,
handle : Handle,
) -> Bool {
match self.optional_expression(function, handle) {
Some(Constant(constant_handle)) =>
match self.shader_module.constants.items.get(constant_handle.index()) {
Some(constant) =>
self.writer_module.compatibility.is_generated_import(constant.name)
None => false
}
_ => false
}
}
///|
fn WgslIrEmitter::expression_tree_contains_constant_reference(
self : WgslIrEmitter,
function : Function?,
handle : Handle,
) -> Bool {
match self.optional_expression(function, handle) {
Some(expression) =>
self.expression_contains_constant_reference(function, expression)
None => false
}
}
///|
fn WgslIrEmitter::expression_contains_constant_reference(
self : WgslIrEmitter,
function : Function?,
expression : Expression,
) -> Bool {
match expression {
Constant(_) => true
Literal(_)
| Override(_)
| FunctionArgument(_)
| GlobalVariable(_)
| LocalVariable(_)
| Load(_)
| AddressOf(_, _)
| ZeroValue(_)
| FunctionCall(_, _)
| AtomicCall(_, _)
| ImageSample(_, _, _, _, _, _, _, _, _)
| ImageLoad(_, _, _, _, _)
| ImageQuery(_, _)
| CallResult(_)
| AtomicResult(_, _)
| WorkGroupUniformLoadResult(_)
| WorkGroupUniformLoad(_)
| ArrayLength(_)
| RayQueryInitialize(_, _, _)
| RayQueryProceed(_)
| RayQueryGenerateIntersection(_, _)
| RayQueryConfirmIntersection(_)
| RayQueryTerminate(_)
| RayQueryVertexPositions(_, _)
| RayQueryProceedResult
| RayQueryGetIntersection(_, _)
| SubgroupCall(_, _)
| SubgroupBallotResult
| SubgroupOperationResult(_)
| CooperativeLoad(_, _, _, _)
| CooperativeMultiplyAdd(_, _, _) => false
Unary(_, inner)
| Bitcast(_, inner)
| Relational(_, inner)
| As(inner, _, _)
| Splat(_, inner)
| Swizzle(_, inner, _)
| AccessIndex(inner, _)
| Component(inner, _)
| Derivative(_, _, inner) =>
self.expression_tree_contains_constant_reference(function, inner)
Access(base, index) | Binary(_, base, index) =>
self.expression_tree_contains_constant_reference(function, base) ||
self.expression_tree_contains_constant_reference(function, index)
Select(left, right, condition) =>
self.expression_tree_contains_constant_reference(function, left) ||
self.expression_tree_contains_constant_reference(function, right) ||
self.expression_tree_contains_constant_reference(function, condition)
Compose(_, components) =>
self.expression_list_contains_constant_reference(function, components)
Math(_, first, second, third, fourth) =>
self.expression_tree_contains_constant_reference(function, first) ||
self.optional_expression_contains_constant_reference(function, second) ||
self.optional_expression_contains_constant_reference(function, third) ||
self.optional_expression_contains_constant_reference(function, fourth)
}
}
///|
fn WgslIrEmitter::expression_list_contains_constant_reference(
self : WgslIrEmitter,
function : Function?,
expressions : Array[Handle],
) -> Bool {
for expression in expressions {
if self.expression_tree_contains_constant_reference(function, expression) {
return true
}
}
false
}
///|
fn WgslIrEmitter::optional_expression_contains_constant_reference(
self : WgslIrEmitter,
function : Function?,
expression : Handle?,
) -> Bool {
match expression {
Some(expression) =>
self.expression_tree_contains_constant_reference(function, expression)
None => false
}
}
///|
fn WgslIrEmitter::eval_integer_expression_for_writer(
self : WgslIrEmitter,
function : Function?,
handle : Handle,
) -> WgslIrEmitIntegerValue? raise WgslIrEmitError {
match self.required_expression(function, handle) {
Literal(I32(value)) => Some(Signed(value))
Literal(U32(value)) => Some(Unsigned(value))
Literal(AbstractInt(value)) => Some(Abstract(value))
Constant(handle) => self.eval_constant_integer_expression_for_writer(handle)
Unary(Negate, inner) => {
guard self.eval_integer_expression_for_writer(function, inner)
is Some(value) else {
return None
}
match value.to_signed_int() {
Some(value) => Some(Signed(-value))
None => None
}
}
Unary(BitwiseNot, inner) =>
match self.eval_integer_expression_for_writer(function, inner) {
Some(Unsigned(value)) => Some(Unsigned(value.lnot()))
Some(Signed(value)) => Some(Signed(value.lnot()))
Some(Abstract(value)) => Some(Abstract(value.lnot()))
None => None
}
Binary(op, left, right) => {
guard self.eval_integer_expression_for_writer(function, left)
is Some(left_value) else {
return None
}
guard self.eval_integer_expression_for_writer(function, right)
is Some(right_value) else {
return None
}
wgsl_ir_emit_eval_integer_binary(op, left_value, right_value)
}
Math(Min, a, Some(b), None, None) => {
guard self.eval_integer_expression_for_writer(function, a)
is Some(a_value) else {
return None
}
guard self.eval_integer_expression_for_writer(function, b)
is Some(b_value) else {
return None
}
wgsl_ir_emit_eval_integer_min(a_value, b_value)
}
Math(Max, a, Some(b), None, None) => {
guard self.eval_integer_expression_for_writer(function, a)
is Some(a_value) else {
return None
}
guard self.eval_integer_expression_for_writer(function, b)
is Some(b_value) else {
return None
}
wgsl_ir_emit_eval_integer_max(a_value, b_value)
}
Math(Clamp, value, Some(low), Some(high), None) => {
guard self.eval_integer_expression_for_writer(function, value)
is Some(value) else {
return None
}
guard self.eval_integer_expression_for_writer(function, low) is Some(low) else {
return None
}
guard self.eval_integer_expression_for_writer(function, high)
is Some(high) else {
return None
}
match wgsl_ir_emit_eval_integer_max(value, low) {
Some(value) => wgsl_ir_emit_eval_integer_min(value, high)
None => None
}
}
_ => None
}
}
///|
fn WgslIrEmitIntegerValue::is_unsigned(self : WgslIrEmitIntegerValue) -> Bool {
match self {
Unsigned(_) => true
Signed(_) | Abstract(_) => false
}
}
///|
fn WgslIrEmitIntegerValue::to_signed_int(self : WgslIrEmitIntegerValue) -> Int? {
match self {
Signed(value) => Some(value)
Abstract(value) =>
if value >= Int64::from_int(-2147483648) &&
value <= Int64::from_int(2147483647) {
Some(value.to_int())
} else {
None
}
Unsigned(value) => wgsl_ir_uint_literal_to_small_int(value)
}
}
///|
fn WgslIrEmitIntegerValue::to_unsigned(self : WgslIrEmitIntegerValue) -> UInt? {
match self {
Unsigned(value) => Some(value)
Signed(value) => wgsl_ir_emit_non_negative_int_to_uint(value)
Abstract(value) => wgsl_ir_emit_non_negative_int64_to_uint(value)
}
}
///|
fn wgsl_ir_emit_non_negative_int_to_uint(value : Int) -> UInt? {
if value < 0 {
return None
}
Some(value.reinterpret_as_uint())
}
///|
fn wgsl_ir_emit_non_negative_int64_to_uint(value : Int64) -> UInt? {
if value < Int64::from_int(0) {
return None
}
if value > 4294967295L {
return None
}
Some(value.reinterpret_as_uint64().to_uint())
}
///|
fn wgsl_ir_emit_eval_integer_binary(
op : BinaryOperator,
left : WgslIrEmitIntegerValue,
right : WgslIrEmitIntegerValue,
) -> WgslIrEmitIntegerValue? {
if left.is_unsigned() || right.is_unsigned() {
guard left.to_unsigned() is Some(left) else { return None }
guard right.to_unsigned() is Some(right) else { return None }
guard WgslIrEmitIntegerValue::Unsigned(right).to_signed_int()
is Some(right_shift) else {
return None
}
return match op {
Add => Some(Unsigned(left + right))
Subtract => Some(Unsigned(left - right))
Multiply => Some(Unsigned(left * right))
Divide => Some(Unsigned(left / right))
Modulo => Some(Unsigned(left % right))
And => Some(Unsigned(left & right))
ExclusiveOr => Some(Unsigned(left ^ right))
InclusiveOr => Some(Unsigned(left | right))
ShiftLeft => Some(Unsigned(left << right_shift))
ShiftRight => Some(Unsigned(left >> right_shift))
_ => None
}
}
guard left.to_signed_int() is Some(left) else { return None }
guard right.to_signed_int() is Some(right) else { return None }
match op {
Add => Some(Signed(left + right))
Subtract => Some(Signed(left - right))
Multiply => Some(Signed(left * right))
Divide => Some(Signed(left / right))
Modulo => Some(Signed(left % right))
And => Some(Signed(left & right))
ExclusiveOr => Some(Signed(left ^ right))
InclusiveOr => Some(Signed(left | right))
ShiftLeft => Some(Signed(left << right))
ShiftRight => Some(Signed(left >> right))
_ => None
}
}
///|
fn wgsl_ir_emit_eval_float_binary(
op : BinaryOperator,
left : Double,
right : Double,
) -> Double? {
match op {
Add => Some(left + right)
Subtract => Some(left - right)
Multiply => Some(left * right)
Divide => Some(left / right)
_ => None
}
}
///|
fn wgsl_ir_emit_eval_integer_min(
left : WgslIrEmitIntegerValue,
right : WgslIrEmitIntegerValue,
) -> WgslIrEmitIntegerValue? {
if left.is_unsigned() || right.is_unsigned() {
guard left.to_unsigned() is Some(left) else { return None }
guard right.to_unsigned() is Some(right) else { return None }
Some(Unsigned(if left < right { left } else { right }))
} else {
guard left.to_signed_int() is Some(left) else { return None }
guard right.to_signed_int() is Some(right) else { return None }
Some(Signed(if left < right { left } else { right }))
}
}
///|
fn wgsl_ir_emit_eval_integer_max(
left : WgslIrEmitIntegerValue,
right : WgslIrEmitIntegerValue,
) -> WgslIrEmitIntegerValue? {
if left.is_unsigned() || right.is_unsigned() {
guard left.to_unsigned() is Some(left) else { return None }
guard right.to_unsigned() is Some(right) else { return None }
Some(Unsigned(if left > right { left } else { right }))
} else {
guard left.to_signed_int() is Some(left) else { return None }
guard right.to_signed_int() is Some(right) else { return None }
Some(Signed(if left > right { left } else { right }))
}
}