///|
fn WgslIrLowerer::plan_binary_const_parent_with_right_local_reference(
self : WgslIrLowerer,
parent_op : @ast.WgslExprOperator,
left : @ast.WgslExprNode,
right : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> (Handle, Handle)? raise WgslIrLowerError {
match parent_op {
Add | Subtract => ()
_ => return None
}
guard self.expression_node_is_writer_deferred_const_like(left, scope) else {
return None
}
guard wgsl_ir_expr_node_without_groups(left).kind() is Binary(_, _, _) else {
return None
}
guard !wgsl_ir_expr_node_contains_non_math_call(right) else { return None }
let (right_op, right_left_node, right_right_node) = match
wgsl_ir_expr_node_without_groups(right).kind() {
Binary(op, right_left, right_right) => (op, right_left, right_right)
_ => return None
}
guard wgsl_ir_ast_binary_operator_is_multiplicative(right_op) else {
return None
}
guard self.expression_node_is_writer_deferred_const_like(
right_left_node, scope,
) else {
return None
}
guard wgsl_ir_expr_node_without_groups(right_left_node).kind()
is Binary(_, _, _) else {
return None
}
guard self.expression_node_contains_mutable_local_reference(
right_right_node, function, scope,
) else {
return None
}
let right_left = self.lower_function_expression_node(
right_left_node, function, scope,
)
let left_handle = self.lower_function_expression_node(left, function, scope)
let right_right = self.lower_function_expression_node(
right_right_node, function, scope,
)
let right_binary_op = wgsl_ir_binary_operator(right_op)
let (right_left, right_right) = self.normalize_function_binary_operands(
function, right_binary_op, right_left, right_right,
)
let right_handle = function.expressions.append(
Binary(right_binary_op, right_left, right_right),
)
Some((left_handle, right_handle))
}
///|
fn WgslIrLowerer::plan_binary_declared_constant_before_call_product(
self : WgslIrLowerer,
op : @ast.WgslExprOperator,
left : @ast.WgslExprNode,
right : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle? raise WgslIrLowerError {
guard op == Subtract else { return None }
guard self.expr_node_is_declared_or_generated_constant_reference(left) else {
return None
}
guard wgsl_ir_expr_node_without_groups(right).kind()
is Binary(right_op, right_left, right_right) else {
return None
}
guard wgsl_ir_ast_binary_operator_is_multiplicative(right_op) else {
return None
}
guard wgsl_ir_expr_node_contains_call(right) else { return None }
let right_left_handle = self.lower_function_expression_node(
right_left, function, scope,
)
let right_right_handle = self.lower_function_expression_node(
right_right, function, scope,
)
let left_handle = self.lower_function_expression_node(left, function, scope)
let right_binary_op = wgsl_ir_binary_operator(right_op)
let (right_left_handle, right_right_handle) = self.normalize_function_binary_operands(
function, right_binary_op, right_left_handle, right_right_handle,
)
let right_handle = function.expressions.append(
Binary(right_binary_op, right_left_handle, right_right_handle),
)
let binary_op = wgsl_ir_binary_operator(op)
let (left_handle, right_handle) = self.normalize_function_binary_operands(
function, binary_op, left_handle, right_handle,
)
Some(
function.expressions.append(Binary(binary_op, left_handle, right_handle)),
)
}
///|
fn WgslIrLowerer::expr_node_is_declared_or_generated_constant_reference(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
) -> Bool {
match node.kind() {
Group(inner) =>
self.expr_node_is_declared_or_generated_constant_reference(inner)
Identifier(name) =>
self.constant_declarations.contains(name.name()) ||
self.constant_names.contains(name.name())
_ => false
}
}
///|
fn WgslIrLowerer::plan_binary_parent_argument_after_member_root(
self : WgslIrLowerer,
op : @ast.WgslExprOperator,
left : @ast.WgslExprNode,
right : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle? raise WgslIrLowerError {
guard wgsl_ir_expr_node_is_function_argument_value(right, scope) else {
return None
}
guard left.kind() is Binary(left_op, left_left, left_right) else {
return None
}
guard wgsl_ir_expr_node_is_direct_access_chain(left_right) else {
return None
}
let left_left_handle = self.lower_function_expression_node(
left_left, function, scope,
)
self.predeclare_function_member_base_expressions(left_right, function, scope)
self.predeclare_function_argument_value(right, function, scope)
let left_right_handle = self.lower_function_expression_node(
left_right, function, scope,
)
let left_binary_op = wgsl_ir_binary_operator(left_op)
let (left_left_handle, left_right_handle) = self.normalize_function_binary_operands(
function, left_binary_op, left_left_handle, left_right_handle,
)
let left_handle = function.expressions.append(
Binary(left_binary_op, left_left_handle, left_right_handle),
)
let right_handle = self.lower_function_expression_node(right, function, scope)
let binary_op = wgsl_ir_binary_operator(op)
let (left_handle, right_handle) = self.normalize_function_binary_operands(
function, binary_op, left_handle, right_handle,
)
Some(
function.expressions.append(Binary(binary_op, left_handle, right_handle)),
)
}
///|
fn WgslIrLowerer::plan_binary_const_left_before_math_parent(
self : WgslIrLowerer,
op : @ast.WgslExprOperator,
left : @ast.WgslExprNode,
right : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle? raise WgslIrLowerError {
guard wgsl_ir_ast_binary_operator_is_multiplicative(op) else { return None }
guard self.expression_node_is_foldable_math_const_like(left, scope) else {
return None
}
guard !wgsl_ir_expr_node_references_local_let_constant(left, scope) else {
return None
}
let (math_function, argument) = match
wgsl_ir_expr_node_without_groups(right).kind() {
Call(callee, arguments) =>
match callee.kind() {
Identifier(name) =>
match wgsl_ir_math_function_from_name(name.name()) {
Some(math_function) => {
let arguments = wgsl_ir_call_arguments(arguments)
guard arguments is [argument] else { return None }
(math_function, argument)
}
None => return None
}
_ => return None
}
_ => return None
}
guard wgsl_ir_expr_node_without_groups(argument).kind() is Binary(_, _, _) else {
return None
}
let (argument_op, argument_left, argument_right) = self.lower_binary_expression_children_for_const_left_math_argument(
argument, function, scope,
)
let left_handle = self.lower_function_expression_node(left, function, scope)
let argument_binary_op = wgsl_ir_binary_operator(argument_op)
let (argument_left, argument_right) = self.normalize_function_binary_operands(
function, argument_binary_op, argument_left, argument_right,
)
let argument_handle = function.expressions.append(
Binary(argument_binary_op, argument_left, argument_right),
)
let right_handle = function.expressions.append(
Math(math_function, argument_handle, None, None, None),
)
let binary_op = wgsl_ir_binary_operator(op)
let (left_handle, right_handle) = self.normalize_function_binary_operands(
function, binary_op, left_handle, right_handle,
)
Some(
function.expressions.append(Binary(binary_op, left_handle, right_handle)),
)
}
///|
fn WgslIrLowerer::plan_binary_folded_right_const_vector_operand(
self : WgslIrLowerer,
op : @ast.WgslExprOperator,
left : @ast.WgslExprNode,
right : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle? raise WgslIrLowerError {
match op {
Add | Subtract => ()
_ => return None
}
guard self.expression_node_is_float_vector_const_fold_candidate(right, scope) else {
return None
}
guard self.expression_node_contains_constructor_call_value(right) else {
return None
}
let mark = function.expressions.items.length()
let lowered_right = self.lower_function_expression_node(
right, function, scope,
)
let folded = self.fold_function_constant_float_vector_expression(
function, lowered_right,
)
function.expressions.truncate(mark)
guard folded is Some((right_ty, values)) else { return None }
let right_handle = self.append_function_float_vector_literal_compose(
function, right_ty, values,
)
let left_handle = self.lower_function_expression_node(left, function, scope)
let binary_op = wgsl_ir_binary_operator(op)
let (left_handle, right_handle) = self.normalize_function_binary_operands(
function, binary_op, left_handle, right_handle,
)
Some(
function.expressions.append(Binary(binary_op, left_handle, right_handle)),
)
}
///|
fn WgslIrLowerer::lower_binary_expression_children_for_const_left_math_argument(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> (@ast.WgslExprOperator, Handle, Handle) raise WgslIrLowerError {
match wgsl_ir_expr_node_without_groups(node).kind() {
Binary(op, left, right) =>
if wgsl_ir_expr_node_is_literal_like(left) &&
wgsl_ir_expr_node_without_groups(right).kind() is Binary(_, _, _) {
let right_handle = self.lower_function_expression_node(
right, function, scope,
)
let left_handle = self.lower_function_expression_node(
left, function, scope,
)
(op, left_handle, right_handle)
} else {
self.lower_binary_expression_children(node, function, scope)
}
_ => self.lower_binary_expression_children(node, function, scope)
}
}
///|
fn WgslIrLowerer::plan_binary_trailing_source_let_initializer(
self : WgslIrLowerer,
op : @ast.WgslExprOperator,
left : @ast.WgslExprNode,
right : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle? raise WgslIrLowerError {
guard wgsl_ir_ast_binary_operator_is_multiplicative(op) else { return None }
guard wgsl_ir_expr_node_without_groups(left).kind() is Binary(_, _, _) else {
return None
}
guard wgsl_ir_expr_node_without_groups(right).kind() is Identifier(name) else {
return None
}
guard self.local_let_identifier_has_literal_initializer(name.name(), scope) else {
return None
}
guard self.expression_node_contains_mutable_local_reference(
left, function, scope,
) else {
return None
}
let right_handle = self.lower_identifier_expression(
name.name(),
function,
scope,
)
let left_handle = self.lower_function_expression_node(left, function, scope)
let binary_op = wgsl_ir_binary_operator(op)
let (left_handle, right_handle) = self.normalize_function_binary_operands(
function, binary_op, left_handle, right_handle,
)
Some(
function.expressions.append(Binary(binary_op, left_handle, right_handle)),
)
}
///|
fn WgslIrLowerer::plan_binary_trailing_source_let_literal(
self : WgslIrLowerer,
op : @ast.WgslExprOperator,
left : @ast.WgslExprNode,
right : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle? raise WgslIrLowerError {
guard wgsl_ir_ast_binary_operator_is_multiplicative(op) else { return None }
guard wgsl_ir_expr_node_without_groups(right).kind() is Identifier(name) else {
return None
}
guard self.local_let_identifier_has_literal_initializer(name.name(), scope) else {
return None
}
guard self.expression_node_is_mutable_local_value(left, function, scope) else {
return None
}
guard !wgsl_ir_expr_node_contains_call(left) else { return None }
let right_handle = self.lower_identifier_expression(
name.name(),
function,
scope,
)
let left_handle = self.lower_function_expression_node(left, function, scope)
let binary_op = wgsl_ir_binary_operator(op)
let (left_handle, right_handle) = self.normalize_function_binary_operands(
function, binary_op, left_handle, right_handle,
)
let handle = function.expressions.append(
Binary(binary_op, left_handle, right_handle),
)
function.expressions.set_origin(handle, RetainedSourceLetExpression)
Some(handle)
}
///|
fn WgslIrLowerer::local_let_identifier_has_literal_initializer(
self : WgslIrLowerer,
name : String,
scope : WgslIrFunctionScope,
) -> Bool {
ignore(self)
match scope.local_constants.get(name) {
Some({ value: LazyConstant(local_constant), source: LocalLet, }) =>
match local_constant.expr_ref.root() {
Some(root) => wgsl_ir_expr_node_is_literal_like(root)
None => false
}
_ => false
}
}
///|
fn WgslIrLowerer::plan_binary_sibling_arguments_before_parent(
self : WgslIrLowerer,
op : @ast.WgslExprOperator,
left : @ast.WgslExprNode,
right : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle? raise WgslIrLowerError {
guard wgsl_ir_expr_node_is_function_argument_value(right, scope) else {
return None
}
let left = wgsl_ir_expr_node_without_groups(left)
guard left.kind() is Binary(left_op, left_left, left_right) else {
return None
}
guard wgsl_ir_expr_node_is_function_argument_value(left_right, scope) else {
return None
}
let left_left_handle = self.lower_function_expression_node(
left_left, function, scope,
)
self.predeclare_function_argument_value(left_right, function, scope)
self.predeclare_function_argument_value(right, function, scope)
let left_right_handle = self.lower_function_expression_node(
left_right, function, scope,
)
let left_binary_op = wgsl_ir_binary_operator(left_op)
let (left_left_handle, left_right_handle) = self.normalize_function_binary_operands(
function, left_binary_op, left_left_handle, left_right_handle,
)
let left_handle = function.expressions.append(
Binary(left_binary_op, left_left_handle, left_right_handle),
)
let right_handle = self.lower_function_expression_node(right, function, scope)
let binary_op = wgsl_ir_binary_operator(op)
let (left_handle, right_handle) = self.normalize_function_binary_operands(
function, binary_op, left_handle, right_handle,
)
Some(
function.expressions.append(Binary(binary_op, left_handle, right_handle)),
)
}
///|
fn WgslIrLowerer::plan_binary_parent_argument_after_named_root(
self : WgslIrLowerer,
op : @ast.WgslExprOperator,
left : @ast.WgslExprNode,
right : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle? raise WgslIrLowerError {
guard wgsl_ir_expr_node_is_function_argument_value(right, scope) else {
return None
}
let left = wgsl_ir_expr_node_without_groups(left)
guard left.kind() is Binary(left_op, left_left, left_right) else {
return None
}
guard self.expression_node_is_named_expression_alias(
left_left, function, scope,
) else {
return None
}
let left_left_handle = self.lower_function_expression_node(
left_left, function, scope,
)
let left_right_handle = self.lower_function_expression_node(
left_right, function, scope,
)
self.predeclare_function_argument_value(right, function, scope)
let left_binary_op = wgsl_ir_binary_operator(left_op)
let (left_left_handle, left_right_handle) = self.normalize_function_binary_operands(
function, left_binary_op, left_left_handle, left_right_handle,
)
let left_handle = function.expressions.append(
Binary(left_binary_op, left_left_handle, left_right_handle),
)
let right_handle = self.lower_function_expression_node(right, function, scope)
let binary_op = wgsl_ir_binary_operator(op)
let (left_handle, right_handle) = self.normalize_function_binary_operands(
function, binary_op, left_handle, right_handle,
)
Some(
function.expressions.append(Binary(binary_op, left_handle, right_handle)),
)
}
///|
fn WgslIrLowerer::plan_binary_parent_argument_root_projection(
self : WgslIrLowerer,
op : @ast.WgslExprOperator,
left : @ast.WgslExprNode,
right : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle? raise WgslIrLowerError {
guard wgsl_ir_direct_access_chain_root_is_function_argument(right, scope) else {
return None
}
guard !wgsl_ir_expr_node_is_function_argument_value(right, scope) else {
return None
}
let left = wgsl_ir_expr_node_without_groups(left)
guard left.kind() is Binary(left_op, left_left, left_right) else {
return None
}
guard wgsl_ir_expr_node_is_direct_access_chain(left_left) else { return None }
guard self.expression_node_is_named_expression_alias(
left_right, function, scope,
) else {
return None
}
self.predeclare_function_argument_values_in_source_order(
right, function, scope,
)
let left_left_handle = self.lower_function_expression_node(
left_left, function, scope,
)
let left_right_handle = self.lower_function_expression_node(
left_right, function, scope,
)
let left_binary_op = wgsl_ir_binary_operator(left_op)
let (left_left_handle, left_right_handle) = self.normalize_function_binary_operands(
function, left_binary_op, left_left_handle, left_right_handle,
)
let left_handle = function.expressions.append(
Binary(left_binary_op, left_left_handle, left_right_handle),
)
let right_handle = self.lower_function_expression_node(right, function, scope)
let binary_op = wgsl_ir_binary_operator(op)
let (left_handle, right_handle) = self.normalize_function_binary_operands(
function, binary_op, left_handle, right_handle,
)
Some(
function.expressions.append(Binary(binary_op, left_handle, right_handle)),
)
}
///|
fn wgsl_ir_expr_node_without_groups(
node : @ast.WgslExprNode,
) -> @ast.WgslExprNode {
match node.kind() {
Group(inner) => wgsl_ir_expr_node_without_groups(inner)
_ => node
}
}
///|
fn WgslIrLowerer::predeclare_function_argument_value(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Unit raise WgslIrLowerError {
ignore(self)
match node.kind() {
Identifier(name) =>
match scope.arguments.get(name.name()) {
Some(index) =>
ignore(scope.argument_expression(name.name(), index, function))
None => ()
}
Group(inner) =>
self.predeclare_function_argument_value(inner, function, scope)
_ => ()
}
}
///|
fn WgslIrLowerer::expression_node_is_named_expression_alias(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Bool {
match node.kind() {
Group(inner) =>
self.expression_node_is_named_expression_alias(inner, function, scope)
Identifier(name) =>
match scope.local_constants.get(name.name()) {
Some({ value: ExpressionAlias(handle, _), .. }) =>
wgsl_ir_function_expression_has_arena_name(function, handle)
_ => false
}
_ => false
}
}
///|
fn WgslIrLowerer::predeclare_function_member_base_expressions(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Unit raise WgslIrLowerError {
match node.kind() {
Member(base, _) =>
self.predeclare_function_member_root_expression(base, function, scope)
Group(inner) =>
self.predeclare_function_member_base_expressions(inner, function, scope)
Unary(_, expr) =>
self.predeclare_function_member_base_expressions(expr, function, scope)
Binary(_, left, right) => {
self.predeclare_function_member_base_expressions(left, function, scope)
self.predeclare_function_member_base_expressions(right, function, scope)
}
Call(_, arguments) | Sequence(arguments) =>
for argument in arguments {
self.predeclare_function_member_base_expressions(
argument, function, scope,
)
}
Index(base, index) => {
self.predeclare_function_member_base_expressions(base, function, scope)
self.predeclare_function_member_base_expressions(index, function, scope)
}
Template(base, _) =>
self.predeclare_function_member_base_expressions(base, function, scope)
_ => ()
}
}
///|
fn WgslIrLowerer::predeclare_function_reference_roots_in_source_order(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Unit raise WgslIrLowerError {
match node.kind() {
Identifier(_) =>
self.predeclare_function_argument_value(node, function, scope)
Group(inner) =>
self.predeclare_function_reference_roots_in_source_order(
inner, function, scope,
)
Member(base, _) =>
self.predeclare_function_member_root_expression(base, function, scope)
Unary(_, expr) | PostfixUpdate(_, expr) =>
self.predeclare_function_reference_roots_in_source_order(
expr, function, scope,
)
Assignment(_, left, right) => {
self.predeclare_function_reference_roots_in_source_order(
left, function, scope,
)
self.predeclare_function_reference_roots_in_source_order(
right, function, scope,
)
}
Binary(_, left, right) => {
self.predeclare_function_reference_roots_in_source_order(
left, function, scope,
)
self.predeclare_function_reference_roots_in_source_order(
right, function, scope,
)
}
Call(_, arguments) | Sequence(arguments) =>
for argument in arguments {
self.predeclare_function_reference_roots_in_source_order(
argument, function, scope,
)
}
Index(base, index) => {
self.predeclare_function_reference_roots_in_source_order(
base, function, scope,
)
self.predeclare_function_reference_roots_in_source_order(
index, function, scope,
)
}
Template(base, _) =>
self.predeclare_function_reference_roots_in_source_order(
base, function, scope,
)
Literal(_) | ShaderDefTemplate(_) | PathAccess(_, _) => ()
}
}
///|
fn WgslIrLowerer::plan_binary_left_argument_after_global_product(
self : WgslIrLowerer,
op : @ast.WgslExprOperator,
left : @ast.WgslExprNode,
right : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle? raise WgslIrLowerError {
guard op == Subtract else { return None }
guard wgsl_ir_expr_node_is_function_argument_value(left, scope) else {
return None
}
guard wgsl_ir_expr_node_without_groups(right).kind()
is Binary(right_op, right_left, right_right) else {
return None
}
guard wgsl_ir_ast_binary_operator_is_multiplicative(right_op) else {
return None
}
guard wgsl_ir_expr_node_is_function_argument_value(right_left, scope) else {
return None
}
guard wgsl_ir_expr_node_without_groups(right_right).kind()
is Identifier(global_name) else {
return None
}
let global_handle = match self.global_names.get(global_name.name()) {
Some(handle) => handle
None => return None
}
guard !self.global_variable_is_handle_value(global_handle) else {
return None
}
let global_pointer = function.expressions.append(
GlobalVariable(global_handle),
)
let right_left_handle = self.lower_function_expression_node(
right_left, function, scope,
)
let left_handle = self.lower_function_expression_node(left, function, scope)
let right_right_handle = function.expressions.append(Load(global_pointer))
let right_binary_op = wgsl_ir_binary_operator(right_op)
let (right_left_handle, right_right_handle) = self.normalize_function_binary_operands(
function, right_binary_op, right_left_handle, right_right_handle,
)
let right_handle = function.expressions.append(
Binary(right_binary_op, right_left_handle, right_right_handle),
)
let binary_op = wgsl_ir_binary_operator(op)
let (left_handle, right_handle) = self.normalize_function_binary_operands(
function, binary_op, left_handle, right_handle,
)
Some(
function.expressions.append(Binary(binary_op, left_handle, right_handle)),
)
}
///|
fn WgslIrLowerer::predeclare_function_binary_chain_reference_roots_in_source_order(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Unit raise WgslIrLowerError {
match node.kind() {
Identifier(name) =>
self.predeclare_identifier_reference_root(name.name(), function, scope)
Group(inner) =>
self.predeclare_function_binary_chain_reference_roots_in_source_order(
inner, function, scope,
)
Member(base, _) =>
self.predeclare_function_member_root_expression(base, function, scope)
Unary(_, expr) | PostfixUpdate(_, expr) =>
self.predeclare_function_binary_chain_reference_roots_in_source_order(
expr, function, scope,
)
Assignment(_, left, right) | Binary(_, left, right) => {
self.predeclare_function_binary_chain_reference_roots_in_source_order(
left, function, scope,
)
self.predeclare_function_binary_chain_reference_roots_in_source_order(
right, function, scope,
)
}
Index(base, index) => {
self.predeclare_function_binary_chain_reference_roots_in_source_order(
base, function, scope,
)
self.predeclare_function_binary_chain_reference_roots_in_source_order(
index, function, scope,
)
}
Template(base, _) =>
self.predeclare_function_binary_chain_reference_roots_in_source_order(
base, function, scope,
)
Call(_, arguments) =>
match wgsl_ir_call_arguments(arguments) {
[first, ..] =>
self.predeclare_function_binary_chain_reference_roots_in_source_order(
first, function, scope,
)
[] => ()
}
Sequence(arguments) =>
for argument in arguments {
self.predeclare_function_binary_chain_reference_roots_in_source_order(
argument, function, scope,
)
}
Literal(_) | ShaderDefTemplate(_) | PathAccess(_, _) => ()
}
}
///|
fn WgslIrLowerer::predeclare_identifier_reference_root(
self : WgslIrLowerer,
name : String,
function : Function,
scope : WgslIrFunctionScope,
) -> Unit raise WgslIrLowerError {
match scope.local_constants.get(name) {
Some(_) => {
ignore(self.lower_identifier_expression(name, function, scope))
return
}
None => ()
}
match scope.locals.get(name) {
Some(handle) => {
ignore(scope.local_pointer_expression(name, handle, function))
return
}
None => ()
}
match scope.arguments.get(name) {
Some(index) => {
ignore(scope.argument_expression(name, index, function))
return
}
None => ()
}
match self.global_names.get(name) {
Some(handle) => {
ignore(scope.predeclare_global_pointer_expression(name, handle, function))
return
}
None => ()
}
}
///|
fn WgslIrLowerer::predeclare_function_member_root_expression(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Unit raise WgslIrLowerError {
match node.kind() {
Identifier(name) =>
self.predeclare_identifier_named_expression(name.name(), function, scope)
Group(inner) =>
self.predeclare_function_member_root_expression(inner, function, scope)
Member(base, _) =>
self.predeclare_function_member_root_expression(base, function, scope)
Index(base, _) =>
self.predeclare_function_member_root_expression(base, function, scope)
_ => ()
}
}
///|
fn WgslIrLowerer::lower_function_right_operand_before_left(
self : WgslIrLowerer,
parent_op : @ast.WgslExprOperator,
left : @ast.WgslExprNode,
right : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> (Handle, Handle) raise WgslIrLowerError {
let scheduler = self.expression_arena_scheduler(function, scope)
if scheduler.binary_right_root_is_delayed_after_parent_left(parent_op, right) &&
!wgsl_ir_expr_node_contains_call(right) {
if (parent_op == Divide || parent_op == Subtract) &&
(
wgsl_ir_expr_node_is_literal_like(left) ||
wgsl_ir_expr_node_is_negative_literal_like(left)
) {
let right_handle = self.lower_function_expression_node(
right, function, scope,
)
let left_handle = self.lower_function_expression_node(
left, function, scope,
)
return (left_handle, right_handle)
}
let (right_op, right_left, right_right) = self.lower_binary_expression_children(
right, function, scope,
)
let right_binary_op = wgsl_ir_binary_operator(right_op)
let (right_left, right_right) = self.normalize_function_binary_operands(
function, right_binary_op, right_left, right_right,
)
let left_handle = self.lower_function_expression_node(left, function, scope)
let right_handle = function.expressions.append(
Binary(right_binary_op, right_left, right_right),
)
return (left_handle, right_handle)
}
let right_handle = self.lower_function_expression_node(right, function, scope)
let left_handle = self.lower_function_expression_node(left, function, scope)
(left_handle, right_handle)
}
///|
fn WgslIrLowerer::predeclare_identifier_named_expression(
self : WgslIrLowerer,
name : String,
function : Function,
scope : WgslIrFunctionScope,
) -> Unit raise WgslIrLowerError {
match scope.arguments.get(name) {
Some(index) => {
ignore(scope.argument_expression(name, index, function))
return
}
None => ()
}
match scope.local_constants.get(name) {
Some(_) => {
ignore(self.lower_identifier_expression(name, function, scope))
return
}
None => ()
}
match self.global_names.get(name) {
Some(handle) => {
ignore(scope.predeclare_global_pointer_expression(name, handle, function))
return
}
None => ()
}
}
///|
fn WgslIrLowerer::lower_binary_expression_children(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> (@ast.WgslExprOperator, Handle, Handle) raise WgslIrLowerError {
match node.kind() {
Binary(op, left, right) => {
let scheduler = self.expression_arena_scheduler(function, scope)
match
self.lower_binary_expression_children_with_parent_argument_after_child(
op, left, right, function, scope,
) {
Some(result) => return result
None => ()
}
if scheduler.binary_lowers_right_argument_before_left_access(left, right) {
self.predeclare_function_reference_roots_in_source_order(
left, function, scope,
)
self.predeclare_function_argument_value(right, function, scope)
}
let (left_handle, right_handle) = if scheduler.binary_lowers_right_before_left(
op, left, right,
) {
self.lower_function_right_operand_before_left(
op, left, right, function, scope,
)
} else if scheduler.binary_delays_left_constructor_commit_until_right_argument(
left, right,
) {
match
self.plan_binary_left_constructor_after_right_argument_root(
left, right, function, scope,
) {
Some(result) => result
None => {
let left_handle = self.lower_function_expression_node(
left, function, scope,
)
let right_handle = self.lower_function_expression_node(
right, function, scope,
)
(left_handle, right_handle)
}
}
} else if scheduler.binary_lowers_right_argument_before_left_access(
left, right,
) {
let right_handle = self.lower_function_expression_node(
right, function, scope,
)
let left_handle = self.lower_function_expression_node(
left, function, scope,
)
(left_handle, right_handle)
} else {
let left_handle = self.lower_function_expression_node(
left, function, scope,
)
let right_handle = self.lower_function_expression_node(
right, function, scope,
)
(left_handle, right_handle)
}
(op, left_handle, right_handle)
}
Group(inner) =>
self.lower_binary_expression_children(inner, function, scope)
_ => raise UnsupportedExpression("expected binary expression subtree")
}
}
///|
fn WgslIrLowerer::lower_binary_expression_children_with_parent_argument_after_child(
self : WgslIrLowerer,
op : @ast.WgslExprOperator,
left : @ast.WgslExprNode,
right : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> (@ast.WgslExprOperator, Handle, Handle)? raise WgslIrLowerError {
guard wgsl_ir_expr_node_is_function_argument_value(right, scope) else {
return None
}
let left = wgsl_ir_expr_node_without_groups(left)
guard left.kind() is Binary(left_op, left_left, left_right) else {
return None
}
let left_left_handle = self.lower_function_expression_node(
left_left, function, scope,
)
let left_right_handle = self.lower_function_expression_node(
left_right, function, scope,
)
self.predeclare_function_argument_value(right, function, scope)
let left_binary_op = wgsl_ir_binary_operator(left_op)
let (left_left_handle, left_right_handle) = self.normalize_function_binary_operands(
function, left_binary_op, left_left_handle, left_right_handle,
)
let left_handle = function.expressions.append(
Binary(left_binary_op, left_left_handle, left_right_handle),
)
let right_handle = self.lower_function_expression_node(right, function, scope)
Some((op, left_handle, right_handle))
}
///|
fn WgslIrLowerer::plan_binary_left_constructor_after_right_argument_root(
self : WgslIrLowerer,
left : @ast.WgslExprNode,
right : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> (Handle, Handle)? raise WgslIrLowerError {
let left_handle = match
self.lower_function_constructor_call_after_predeclared_argument(
left, right, function, scope,
) {
Some(handle) => handle
None => return None
}
let right_handle = self.lower_function_expression_node(right, function, scope)
Some((left_handle, right_handle))
}
///|
fn WgslIrLowerer::plan_binary_right_constructor_after_arguments_before_left(
self : WgslIrLowerer,
op : @ast.WgslExprOperator,
left : @ast.WgslExprNode,
right : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> (Handle, Handle)? raise WgslIrLowerError {
guard op == Multiply else { return None }
guard wgsl_ir_expr_node_is_function_argument_value(left, scope) else {
return None
}
match wgsl_ir_expr_node_without_groups(right).kind() {
Call(callee, arguments) => {
let arguments = wgsl_ir_call_arguments(arguments)
guard self.expression_callee_is_constructor_call_value(callee) else {
return None
}
let flattened = wgsl_ir_flatten_expression_arguments(arguments)
guard !flattened.is_empty() else { return None }
let scheduler = self.expression_arena_scheduler(function, scope)
for argument in flattened {
if scheduler.constructor_argument_has_ordered_effect(argument) {
return None
}
}
let expression_mark = function.expressions.items.length()
let lowered_arguments = self.lower_function_constructor_arguments_with_expected(
arguments,
function,
scope,
None,
)
let left_handle = self.lower_function_expression_node(
left, function, scope,
)
let right_handle = match callee.kind() {
Identifier(name) => {
guard wgsl_ir_vector_size_from_constructor_name(name.name()) != None else {
return None
}
self.finish_function_constructor_call(
name.name(),
arguments,
lowered_arguments,
function,
scope,
None,
expression_mark,
)
}
Template(_, _) =>
match self.lower_templated_callee_type(callee) {
Some(ty) =>
self.lower_function_constructor_expression_from_handles(
ty, lowered_arguments, function,
)
None => return None
}
_ => return None
}
Some((left_handle, right_handle))
}
_ => None
}
}
///|
fn WgslIrLowerer::lower_function_constructor_call_after_predeclared_argument(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
sibling_argument : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle? raise WgslIrLowerError {
match node.kind() {
Group(inner) =>
self.lower_function_constructor_call_after_predeclared_argument(
inner, sibling_argument, function, scope,
)
Call(callee, arguments) => {
let arguments = wgsl_ir_call_arguments(arguments)
match callee.kind() {
Identifier(name) => {
guard self.expression_callee_is_constructor_call_value(callee) else {
return None
}
let expression_mark = function.expressions.items.length()
let lowered_arguments = self.lower_function_constructor_arguments_with_expected(
arguments,
function,
scope,
None,
)
self.predeclare_function_argument_value(
sibling_argument, function, scope,
)
Some(
self.finish_function_constructor_call(
name.name(),
arguments,
lowered_arguments,
function,
scope,
None,
expression_mark,
),
)
}
_ =>
match self.lower_templated_callee_type(callee) {
Some(ty) => {
let lowered_arguments = self.lower_function_constructor_arguments(
ty, arguments, function, scope,
)
self.predeclare_function_argument_value(
sibling_argument, function, scope,
)
Some(
self.lower_function_constructor_expression_from_handles(
ty, lowered_arguments, function,
),
)
}
None => None
}
}
}
_ => None
}
}
///|
fn WgslIrLowerer::expression_node_is_writer_deferred_const_like(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
scope : WgslIrFunctionScope,
) -> Bool {
match node.kind() {
Group(inner) =>
self.expression_node_is_writer_deferred_const_like(inner, scope)
Literal(_) => true
Identifier(_) =>
self.expression_node_is_inline_constant_reference(node, scope)
Binary(_, left, right) =>
self.expression_node_is_writer_deferred_const_like(left, scope) &&
self.expression_node_is_writer_deferred_const_like(right, scope)
_ => false
}
}
///|
fn WgslIrLowerer::expression_node_is_foldable_math_const_like(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
scope : WgslIrFunctionScope,
) -> Bool {
match node.kind() {
Group(inner) =>
self.expression_node_is_foldable_math_const_like(inner, scope)
Unary(_, inner) =>
self.expression_node_is_foldable_math_const_like(inner, scope)
Binary(_, left, right) =>
self.expression_node_is_foldable_math_const_like(left, scope) &&
self.expression_node_is_foldable_math_const_like(right, scope)
_ => self.expression_node_is_writer_deferred_const_like(node, scope)
}
}
///|
fn WgslIrLowerer::expression_node_is_float_vector_const_fold_candidate(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
scope : WgslIrFunctionScope,
) -> Bool {
match node.kind() {
Group(inner) =>
self.expression_node_is_float_vector_const_fold_candidate(inner, scope)
Literal(_) => true
Identifier(_) =>
self.expression_node_is_inline_constant_reference(node, scope)
Unary(op, inner) =>
op == Subtract &&
self.expression_node_is_float_vector_const_fold_candidate(inner, scope)
Binary(_, left, right) =>
self.expression_node_is_float_vector_const_fold_candidate(left, scope) &&
self.expression_node_is_float_vector_const_fold_candidate(right, scope)
Call(callee, arguments) =>
self.expression_callee_is_constructor_call_value(callee) &&
wgsl_ir_call_arguments(arguments).all(fn(argument) {
self.expression_node_is_float_vector_const_fold_candidate(
argument, scope,
)
})
_ => false
}
}
///|
fn WgslIrLowerer::expression_node_contains_constructor_call_value(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
) -> Bool {
match node.kind() {
Group(inner) | Unary(_, inner) =>
self.expression_node_contains_constructor_call_value(inner)
Binary(_, left, right) =>
self.expression_node_contains_constructor_call_value(left) ||
self.expression_node_contains_constructor_call_value(right)
Call(callee, arguments) =>
self.expression_callee_is_constructor_call_value(callee) ||
wgsl_ir_call_arguments(arguments).any(fn(argument) {
self.expression_node_contains_constructor_call_value(argument)
})
_ => false
}
}
///|
fn WgslIrLowerer::expression_node_is_inline_constant_reference(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
scope : WgslIrFunctionScope,
) -> Bool {
match node.kind() {
Group(inner) =>
self.expression_node_is_inline_constant_reference(inner, scope)
Identifier(name) =>
scope.local_constants.contains(name.name()) ||
self.constant_declarations.contains(name.name()) ||
self.constant_names.contains(name.name())
_ => false
}
}
///|
fn wgsl_ir_ast_binary_operator_is_multiplicative(
op : @ast.WgslExprOperator,
) -> Bool {
match op {
Multiply | Divide | Modulo => true
_ => false
}
}
///|
fn wgsl_ir_ast_binary_operator_is_comparison(
op : @ast.WgslExprOperator,
) -> Bool {
match op {
Equal | NotEqual | Less | LessEqual | Greater | GreaterEqual => true
_ => false
}
}
///|
fn wgsl_ir_direct_access_chain_root_is_function_argument(
node : @ast.WgslExprNode,
scope : WgslIrFunctionScope,
) -> Bool {
match node.kind() {
Group(inner) =>
wgsl_ir_direct_access_chain_root_is_function_argument(inner, scope)
Member(base, _) | Index(base, _) =>
wgsl_ir_direct_access_chain_root_is_function_argument(base, scope)
Identifier(name) => scope.arguments.contains(name.name())
_ => false
}
}
///|
fn WgslIrLowerer::direct_access_chain_root_is_global_reference(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
) -> Bool {
match node.kind() {
Group(inner) => self.direct_access_chain_root_is_global_reference(inner)
Member(base, _) | Index(base, _) =>
self.direct_access_chain_root_is_global_reference(base)
Identifier(name) => self.global_names.get(name.name()) != None
_ => false
}
}
///|
fn wgsl_ir_expr_node_contains_call_member_access(
node : @ast.WgslExprNode,
) -> Bool {
match node.kind() {
Group(inner) | Unary(_, inner) | PostfixUpdate(_, inner) =>
wgsl_ir_expr_node_contains_call_member_access(inner)
Binary(_, left, right) | Assignment(_, left, right) | Index(left, right) =>
wgsl_ir_expr_node_contains_call_member_access(left) ||
wgsl_ir_expr_node_contains_call_member_access(right)
Member(base, _) | PathAccess(base, _) | Template(base, _) =>
wgsl_ir_expr_node_contains_call_member_access(base)
Call(callee, arguments) => {
let arguments = wgsl_ir_call_arguments(arguments)
wgsl_ir_expr_node_contains_member_access(callee) ||
arguments.any(fn(argument) {
wgsl_ir_expr_node_contains_member_access(argument)
})
}
Sequence(items) =>
items.any(fn(item) { wgsl_ir_expr_node_contains_call_member_access(item) })
Identifier(_) | Literal(_) | ShaderDefTemplate(_) => false
}
}
///|
fn WgslIrLowerer::expression_node_is_constructor_call_value(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
) -> Bool {
match node.kind() {
Group(inner) => self.expression_node_is_constructor_call_value(inner)
Call(callee, _) => self.expression_callee_is_constructor_call_value(callee)
_ => false
}
}
///|
fn WgslIrLowerer::expression_callee_is_constructor_call_value(
self : WgslIrLowerer,
callee : @ast.WgslExprNode,
) -> Bool {
match callee.kind() {
Group(inner) => self.expression_callee_is_constructor_call_value(inner)
Identifier(name) =>
self.type_cache.contains(name.name()) ||
wgsl_ir_untemplated_constructor_name_is_const(name.name())
Template(base, _) => self.expression_callee_is_constructor_call_value(base)
_ => false
}
}
///|
fn wgsl_ir_expr_node_contains_member_access(node : @ast.WgslExprNode) -> Bool {
match node.kind() {
Member(_, _) => true
Group(inner) => wgsl_ir_expr_node_contains_member_access(inner)
Unary(_, expr) => wgsl_ir_expr_node_contains_member_access(expr)
Binary(_, left, right) =>
wgsl_ir_expr_node_contains_member_access(left) ||
wgsl_ir_expr_node_contains_member_access(right)
Call(_, arguments) | Sequence(arguments) =>
arguments.any(fn(argument) {
wgsl_ir_expr_node_contains_member_access(argument)
})
Index(base, index) =>
wgsl_ir_expr_node_contains_member_access(base) ||
wgsl_ir_expr_node_contains_member_access(index)
Template(base, _) => wgsl_ir_expr_node_contains_member_access(base)
_ => false
}
}
///|
fn wgsl_ir_expr_node_contains_function_argument_value(
node : @ast.WgslExprNode,
scope : WgslIrFunctionScope,
) -> Bool {
match node.kind() {
Identifier(name) => scope.arguments.contains(name.name())
Group(inner) =>
wgsl_ir_expr_node_contains_function_argument_value(inner, scope)
Unary(_, expr) | PostfixUpdate(_, expr) =>
wgsl_ir_expr_node_contains_function_argument_value(expr, scope)
Binary(_, left, right) | Assignment(_, left, right) | Index(left, right) =>
wgsl_ir_expr_node_contains_function_argument_value(left, scope) ||
wgsl_ir_expr_node_contains_function_argument_value(right, scope)
Member(base, _) | PathAccess(base, _) | Template(base, _) =>
wgsl_ir_expr_node_contains_function_argument_value(base, scope)
Call(_, arguments) | Sequence(arguments) =>
arguments.any(fn(argument) {
wgsl_ir_expr_node_contains_function_argument_value(argument, scope)
})
Literal(_) | ShaderDefTemplate(_) => false
}
}
///|
fn wgsl_ir_expr_node_contains_function_argument_math_call(
node : @ast.WgslExprNode,
scope : WgslIrFunctionScope,
) -> Bool {
match node.kind() {
Call(callee, arguments) => {
let arguments = wgsl_ir_call_arguments(arguments)
match callee.kind() {
Identifier(name) if wgsl_ir_math_function_from_name(name.name()) != None =>
arguments.any(fn(argument) {
wgsl_ir_expr_node_contains_function_argument_value(argument, scope)
})
_ =>
arguments.any(fn(argument) {
wgsl_ir_expr_node_contains_function_argument_math_call(
argument, scope,
)
})
}
}
Group(inner) | Unary(_, inner) | PostfixUpdate(_, inner) =>
wgsl_ir_expr_node_contains_function_argument_math_call(inner, scope)
Binary(_, left, right) | Assignment(_, left, right) | Index(left, right) =>
wgsl_ir_expr_node_contains_function_argument_math_call(left, scope) ||
wgsl_ir_expr_node_contains_function_argument_math_call(right, scope)
Member(base, _) | PathAccess(base, _) | Template(base, _) =>
wgsl_ir_expr_node_contains_function_argument_math_call(base, scope)
Sequence(items) =>
items.any(fn(item) {
wgsl_ir_expr_node_contains_function_argument_math_call(item, scope)
})
Identifier(_) | Literal(_) | ShaderDefTemplate(_) => false
}
}
///|
fn wgsl_ir_expr_node_contains_call(node : @ast.WgslExprNode) -> Bool {
match node.kind() {
Call(_, _) => true
Group(inner) | Unary(_, inner) | PostfixUpdate(_, inner) =>
wgsl_ir_expr_node_contains_call(inner)
Binary(_, left, right) | Assignment(_, left, right) | Index(left, right) =>
wgsl_ir_expr_node_contains_call(left) ||
wgsl_ir_expr_node_contains_call(right)
Member(base, _) | PathAccess(base, _) | Template(base, _) =>
wgsl_ir_expr_node_contains_call(base)
Sequence(items) =>
items.any(fn(item) { wgsl_ir_expr_node_contains_call(item) })
Identifier(_) | Literal(_) | ShaderDefTemplate(_) => false
}
}
///|
fn wgsl_ir_expr_node_contains_non_math_call(node : @ast.WgslExprNode) -> Bool {
match node.kind() {
Call(callee, arguments) => {
let arguments = wgsl_ir_call_arguments(arguments)
let callee_is_math = match callee.kind() {
Identifier(name) => wgsl_ir_math_function_from_name(name.name()) != None
_ => false
}
!callee_is_math ||
arguments.any(fn(argument) {
wgsl_ir_expr_node_contains_non_math_call(argument)
})
}
Group(inner) | Unary(_, inner) | PostfixUpdate(_, inner) =>
wgsl_ir_expr_node_contains_non_math_call(inner)
Binary(_, left, right) | Assignment(_, left, right) | Index(left, right) =>
wgsl_ir_expr_node_contains_non_math_call(left) ||
wgsl_ir_expr_node_contains_non_math_call(right)
Member(base, _) | PathAccess(base, _) | Template(base, _) =>
wgsl_ir_expr_node_contains_non_math_call(base)
Sequence(items) =>
items.any(fn(item) { wgsl_ir_expr_node_contains_non_math_call(item) })
Identifier(_) | Literal(_) | ShaderDefTemplate(_) => false
}
}
///|
fn wgsl_ir_expr_node_is_direct_access_chain(node : @ast.WgslExprNode) -> Bool {
match node.kind() {
Group(inner) => wgsl_ir_expr_node_is_direct_access_chain(inner)
Member(_, _) | Index(_, _) => true
_ => false
}
}
///|
fn WgslIrLowerer::expression_node_contains_writer_reference_value(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Bool {
if self.expression_node_is_mutable_local_value(node, function, scope) ||
self.expression_node_is_global_reference_value(node) {
return true
}
match node.kind() {
Group(inner) | Unary(_, inner) | PostfixUpdate(_, inner) =>
self.expression_node_contains_writer_reference_value(
inner, function, scope,
)
Identifier(name) =>
scope.arguments.contains(name.name()) ||
scope.local_constants.contains(name.name())
Binary(_, left, right) | Assignment(_, left, right) | Index(left, right) =>
self.expression_node_contains_writer_reference_value(
left, function, scope,
) ||
self.expression_node_contains_writer_reference_value(
right, function, scope,
)
Member(base, _) | PathAccess(base, _) | Template(base, _) =>
self.expression_node_contains_writer_reference_value(
base, function, scope,
)
Call(callee, arguments) => {
let arguments = wgsl_ir_call_arguments(arguments)
self.expression_node_contains_writer_reference_value(
callee, function, scope,
) ||
arguments.any(fn(argument) {
self.expression_node_contains_writer_reference_value(
argument, function, scope,
)
})
}
Sequence(items) =>
items.any(fn(item) {
self.expression_node_contains_writer_reference_value(
item, function, scope,
)
})
Literal(_) | ShaderDefTemplate(_) => false
}
}
///|
fn WgslIrLowerer::expression_node_is_global_reference_value(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
) -> Bool {
match node.kind() {
Group(inner) => self.expression_node_is_global_reference_value(inner)
Identifier(name) => self.global_names.get(name.name()) != None
_ => false
}
}
///|
fn wgsl_ir_expr_node_is_literal_like(node : @ast.WgslExprNode) -> Bool {
match node.kind() {
Literal(_) => true
Group(inner) => wgsl_ir_expr_node_is_literal_like(inner)
Sequence([single]) => wgsl_ir_expr_node_is_literal_like(single)
_ => false
}
}
///|
fn wgsl_ir_expr_node_is_negative_literal_like(node : @ast.WgslExprNode) -> Bool {
match node.kind() {
Group(inner) | Sequence([inner]) =>
wgsl_ir_expr_node_is_negative_literal_like(inner)
Unary(Subtract, inner) => wgsl_ir_expr_node_is_literal_like(inner)
_ => false
}
}
///|
fn wgsl_ir_expr_node_is_binary_source_let_arithmetic(
node : @ast.WgslExprNode,
scope : WgslIrFunctionScope,
) -> Bool {
match wgsl_ir_expr_node_without_groups(node).kind() {
Binary(_, _, _) =>
wgsl_ir_expr_node_references_local_let_constant(node, scope)
_ => false
}
}
///|
fn wgsl_ir_expr_node_is_deferred_select_value(node : @ast.WgslExprNode) -> Bool {
match node.kind() {
Literal(_) => true
Group(inner) => wgsl_ir_expr_node_is_deferred_select_value(inner)
Unary(op, inner) =>
op == Subtract && wgsl_ir_expr_node_is_deferred_select_value(inner)
_ => false
}
}
///|
fn WgslIrLowerer::expression_node_is_mutable_local_value(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Bool {
match node.kind() {
Group(inner) =>
self.expression_node_is_mutable_local_value(inner, function, scope)
Identifier(name) =>
match scope.locals.get(name.name()) {
Some(handle) =>
match function.local_variables.items.get(handle.index()) {
Some(local_var) =>
local_var.kind == Var &&
!self.local_variable_is_handle_value(function, handle)
None => false
}
None => false
}
_ => false
}
}
///|
fn WgslIrLowerer::expression_node_contains_mutable_local_reference(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Bool {
if self.expression_node_is_mutable_local_value(node, function, scope) {
return true
}
match node.kind() {
Group(inner) | Unary(_, inner) | PostfixUpdate(_, inner) =>
self.expression_node_contains_mutable_local_reference(
inner, function, scope,
)
Binary(_, left, right) | Assignment(_, left, right) | Index(left, right) =>
self.expression_node_contains_mutable_local_reference(
left, function, scope,
) ||
self.expression_node_contains_mutable_local_reference(
right, function, scope,
)
Member(base, _) | PathAccess(base, _) | Template(base, _) =>
self.expression_node_contains_mutable_local_reference(
base, function, scope,
)
Call(callee, arguments) => {
if self.expression_node_contains_mutable_local_reference(
callee, function, scope,
) {
return true
}
for argument in wgsl_ir_call_arguments(arguments) {
if self.expression_node_contains_mutable_local_reference(
argument, function, scope,
) {
return true
}
}
false
}
Sequence(items) => {
for item in items {
if self.expression_node_contains_mutable_local_reference(
item, function, scope,
) {
return true
}
}
false
}
Identifier(_) | Literal(_) | ShaderDefTemplate(_) => false
}
}
///|
fn wgsl_ir_expr_node_is_function_argument_value(
node : @ast.WgslExprNode,
scope : WgslIrFunctionScope,
) -> Bool {
match node.kind() {
Group(inner) => wgsl_ir_expr_node_is_function_argument_value(inner, scope)
Identifier(name) => scope.arguments.contains(name.name())
_ => false
}
}
///|
fn WgslIrLowerer::normalize_function_binary_operands(
self : WgslIrLowerer,
function : Function,
op : BinaryOperator,
left : Handle,
right : Handle,
) -> (Handle, Handle) raise WgslIrLowerError {
guard self.function_expression_type(function, left) is Some(left_ty) else {
return (left, right)
}
guard self.function_expression_type(function, right) is Some(right_ty) else {
return (left, right)
}
match self.shift_amount_expected_type(op, left_ty) {
Some(expected_ty) =>
self.contextualize_function_expression_for_type(
function, right, expected_ty,
)
None => ()
}
self.contextualize_function_binary_operand_pair(
function, op, left, left_ty, right, right_ty,
)
guard wgsl_ir_binary_operator_requires_vector_splat(op) else {
return (left, right)
}
match self.vector_size_from_type(left_ty) {
Some(size) if self.type_is_scalar(right_ty) =>
(left, function.expressions.append(Splat(size, right)))
_ =>
match self.vector_size_from_type(right_ty) {
Some(size) if self.type_is_scalar(left_ty) =>
(function.expressions.append(Splat(size, left)), right)
_ => (left, right)
}
}
}
///|
fn WgslIrLowerer::contextualize_function_binary_operand_pair(
self : WgslIrLowerer,
function : Function,
op : BinaryOperator,
left : Handle,
left_ty : Handle,
right : Handle,
right_ty : Handle,
) -> Unit raise WgslIrLowerError {
if wgsl_ir_binary_operator_has_asymmetric_integer_context(op) {
return
}
if op == Multiply {
match self.matrix_multiply_operand_context(left_ty, right_ty) {
Some((left_expected, right_expected)) => {
match left_expected {
Some(ty) =>
self.contextualize_function_expression_for_type(function, left, ty)
None => ()
}
match right_expected {
Some(ty) =>
self.contextualize_function_expression_for_type(function, right, ty)
None => ()
}
}
None => ()
}
}
match self.contextualized_constructor_type(right_ty, left_ty) {
Some(_) =>
self.contextualize_function_expression_for_type(function, right, left_ty)
None => ()
}
match self.contextualized_constructor_type(left_ty, right_ty) {
Some(_) =>
self.contextualize_function_expression_for_type(function, left, right_ty)
None => ()
}
}
///|
fn WgslIrLowerer::shift_amount_expected_type(
self : WgslIrLowerer,
op : BinaryOperator,
left_ty : Handle,
) -> Handle? {
match op {
ShiftLeft | ShiftRight => {
let u32_ty = match self.type_cache.get("u32") {
Some(ty) => ty
None => return None
}
match self.vector_size_from_type(left_ty) {
Some(size) => self.vector_type_from_scalar_type_handle(size, u32_ty)
None => Some(u32_ty)
}
}
_ => None
}
}
///|
fn wgsl_ir_binary_operator_has_asymmetric_integer_context(
op : BinaryOperator,
) -> Bool {
match op {
ShiftLeft | ShiftRight => true
_ => false
}
}