///|
fn WgslIrEmitter::eval_float_expression_for_writer(
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) =>
self.eval_constant_float_expression_for_writer(constant)
Compose(ty, [component]) =>
match self.shader_module.types.items.get(ty.index()) {
Some({ inner: Scalar({ kind: Float | AbstractFloat, .. }), .. }) =>
self.eval_float_expression_for_writer(function, component)
_ => None
}
Unary(Negate, inner) =>
match self.eval_float_expression_for_writer(function, inner) {
Some(value) => Some(-value)
None => None
}
Binary(op, left, right) => {
guard self.eval_float_expression_for_writer(function, left)
is Some(left_value) else {
return None
}
guard self.eval_float_expression_for_writer(function, right)
is Some(right_value) else {
return None
}
wgsl_ir_emit_eval_float_binary(op, left_value, right_value)
}
_ => None
}
}
///|
fn WgslIrEmitter::expression_tree_contains_folded_local_constant(
self : WgslIrEmitter,
function : Function?,
handle : Handle,
) -> Bool raise WgslIrEmitError {
match function {
Some(function) =>
match function.expressions.origin(handle) {
Some(
FoldedLocalConstant
| RetainedSourceLetExpression
| SourceLocalConstInitializer
) => return true
_ => ()
}
None => ()
}
match self.required_expression(function, handle) {
Compose(_, components) => {
for component in components {
if self.expression_tree_contains_folded_local_constant(
function, component,
) {
return true
}
}
false
}
Splat(_, inner)
| Swizzle(_, inner, _)
| Unary(_, inner)
| As(inner, _, _)
| Bitcast(_, inner) =>
self.expression_tree_contains_folded_local_constant(function, inner)
Binary(_, left, right) =>
self.expression_tree_contains_folded_local_constant(function, left) ||
self.expression_tree_contains_folded_local_constant(function, right)
_ => false
}
}
///|
fn WgslIrEmitter::folded_scalar_constructor_expression(
self : WgslIrEmitter,
ty : Handle,
components : Array[Handle],
function : Function?,
) -> String? raise WgslIrEmitError {
if !self.options.fold_numeric_constant_expressions() ||
components.length() != 1 {
return None
}
guard self.shader_module.types.items.get(ty.index()) is Some(type_) else {
raise MissingHandle("type \{ty.index()}")
}
guard type_.inner is Scalar(target) else { return None }
guard target.kind == Float else { return None }
let expression = self.required_expression(function, components[0])
match expression {
Literal(literal) =>
match wgsl_ir_float_value_from_numeric_literal(literal) {
Some(value) => self.float_value_literal_for_width(value, target.width)
None => None
}
Constant(handle) =>
match self.eval_constant_float_expression_for_constructor(handle) {
Some(value) => self.float_value_literal_for_width(value, target.width)
None =>
match self.eval_constant_integer_expression_for_constructor(handle) {
Some(value) =>
match value.to_double() {
Some(value) =>
self.float_value_literal_for_width(value, target.width)
None => None
}
None => None
}
}
_ =>
match
self.eval_float_expression_with_retained_constants(
function,
components[0],
) {
Some(value) => self.float_value_literal_for_width(value, target.width)
None => None
}
}
}
///|
fn wgsl_ir_float_value_from_numeric_literal(literal : Literal) -> Double? {
match literal {
F16(value) | F64(value) | AbstractFloat(value) => Some(value)
F32(value) | F32Exact(value) => Some(value.to_double())
I32(value) => Some(Double::from_int(value))
U32(value) => Some(value.to_double())
AbstractInt(value) => Some(value.to_double())
_ => None
}
}
///|
fn WgslIrEmitIntegerValue::to_double(self : WgslIrEmitIntegerValue) -> Double? {
match self {
Signed(value) => Some(Double::from_int(value))
Unsigned(value) => Some(value.to_double())
Abstract(value) => Some(value.to_double())
}
}
///|
fn WgslIrEmitter::compose_component_scalar_context(
self : WgslIrEmitter,
ty : Handle,
components : Array[Handle],
function : Function?,
) -> Scalar? {
guard self.shader_module.types.items.get(ty.index()) is Some(type_) else {
return None
}
match type_.inner {
Scalar(scalar) => Some(scalar)
Vector(_, scalar) => {
let scalar = if wgsl_ir_scalar_kind_is_abstract(scalar.kind) {
match self.concrete_component_scalar_context(function, components) {
Some(value) => value
None => scalar
}
} else {
scalar
}
for component in components {
if !self.expression_is_scalar_type(function, component, scalar) {
return None
}
}
Some(scalar)
}
_ => None
}
}
///|
fn WgslIrEmitter::concrete_component_scalar_context(
self : WgslIrEmitter,
function : Function?,
components : Array[Handle],
) -> Scalar? {
let mut scalar : Scalar? = None
for component in components {
guard self.expression_component_scalar(function, component) is Some(value) else {
return None
}
if wgsl_ir_scalar_kind_is_abstract(value.kind) {
return None
}
match scalar {
Some(existing) => if existing != value { return None }
None => scalar = Some(value)
}
}
scalar
}
///|
fn WgslIrEmitter::compose_component_expression(
self : WgslIrEmitter,
function : Function?,
component : Handle,
scalar_context : Scalar?,
) -> String raise WgslIrEmitError {
match scalar_context {
Some(scalar) =>
match self.contextual_scalar_literal(function, component, scalar) {
Some(value) => value
None =>
match
self.constructor_scalar_folded_expression(
function, component, scalar,
) {
Some(value) => value
None => self.required_function_expression(function, component)
}
}
None =>
match self.constructor_component_folded_expression(function, component) {
Some(value) => value
None => self.required_function_expression(function, component)
}
}
}
///|
fn WgslIrEmitter::constructor_component_folded_expression(
self : WgslIrEmitter,
function : Function?,
operand : Handle,
) -> String? raise WgslIrEmitError {
match self.expression_component_scalar(function, operand) {
Some({ kind: AbstractFloat, .. }) =>
self.constructor_scalar_folded_expression(function, operand, {
kind: Float,
width: 4,
})
Some(scalar) if !wgsl_ir_scalar_kind_is_abstract(scalar.kind) =>
self.constructor_scalar_folded_expression(function, operand, scalar)
_ =>
self.constructor_scalar_folded_expression(function, operand, {
kind: Float,
width: 4,
})
}
}
///|
fn WgslIrEmitter::constructor_scalar_folded_expression(
self : WgslIrEmitter,
function : Function?,
operand : Handle,
scalar : Scalar,
) -> String? raise WgslIrEmitError {
guard self.options.fold_numeric_constant_expressions() else { return None }
if self.expression_tree_contains_folded_local_constant(function, operand) {
return None
}
match scalar.kind {
Float | AbstractFloat =>
match self.eval_float_expression_for_writer(function, operand) {
Some(value) => self.float_value_literal_for_width(value, scalar.width)
None =>
match
self.eval_float_expression_with_retained_constants(
function, operand,
) {
Some(value) =>
self.float_value_literal_for_width(value, scalar.width)
None => None
}
}
_ => None
}
}