///|
fn WgslIrLowerer::lower_function_relational_call(
self : WgslIrLowerer,
relational_function : RelationalFunction,
arguments : Array[@ast.WgslExprNode],
function : Function,
scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
let arguments = wgsl_ir_flatten_expression_arguments(arguments)
guard arguments is [expr] else {
raise UnsupportedExpression(
"\{wgsl_ir_relational_function_name(relational_function)} expects one argument",
)
}
let argument = self.lower_function_relational_argument(expr, function, scope)
function.expressions.append(
Relational(
relational_function,
self.apply_function_load_rule(function, argument),
),
)
}
///|
fn WgslIrLowerer::lower_function_relational_argument(
self : WgslIrLowerer,
expr : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
match wgsl_ir_expr_node_without_groups(expr).kind() {
Binary(op, left, right) if wgsl_ir_ast_binary_operator_is_comparison(op) => {
let expression_mark = function.expressions.items.length()
let local_constant_snapshot = wgsl_ir_snapshot_local_constant_values(
scope.local_constants,
)
let left_handle = self.lower_function_expression_node(
left, function, scope,
)
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,
)
let handle = function.expressions.append(
Binary(binary_op, left_handle, right_handle),
)
self.fold_function_binary_expression_at_mark(
function, scope, local_constant_snapshot, expression_mark, handle,
)
}
_ => self.lower_function_expression_node(expr, function, scope)
}
}
///|
fn WgslIrLowerer::lower_function_select_call(
self : WgslIrLowerer,
arguments : Array[@ast.WgslExprNode],
function : Function,
scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
let arguments = wgsl_ir_flatten_expression_arguments(arguments)
guard arguments is [reject, accept, condition] else {
raise UnsupportedExpression("select expects three arguments")
}
match
self.lower_function_select_with_splat_values_and_binary_splat_condition(
reject, accept, condition, function, scope,
) {
Some(handle) => return handle
None => ()
}
match
self.lower_function_select_with_constant_constructor_values_and_binary_condition(
reject, accept, condition, function, scope,
) {
Some(handle) => return handle
None => ()
}
match
self.lower_function_select_with_constant_values_and_binary_condition(
reject, accept, condition, function, scope,
) {
Some(handle) => return handle
None => ()
}
let (condition, accept, reject) = if wgsl_ir_expr_node_is_deferred_select_value(
reject,
) &&
wgsl_ir_expr_node_is_deferred_select_value(accept) {
let condition = self.lower_function_expression_node(
condition, function, scope,
)
let accept = self.lower_function_expression_node(accept, function, scope)
let reject = self.lower_function_expression_node(reject, function, scope)
(condition, accept, reject)
} else if self.select_accept_predeclares_reference_root(
accept, function, scope,
) {
self.predeclare_function_member_root_expression(accept, function, scope)
let condition = self.lower_function_expression_node(
condition, function, scope,
)
let reject = self.lower_function_expression_node(reject, function, scope)
let accept = self.lower_function_expression_node(accept, function, scope)
(condition, accept, reject)
} else {
let reject = self.lower_function_expression_node(reject, function, scope)
let accept = self.lower_function_expression_node(accept, function, scope)
let condition = self.lower_function_expression_node(
condition, function, scope,
)
(condition, accept, reject)
}
function.expressions.append(Select(condition, accept, reject))
}
///|
fn WgslIrLowerer::lower_function_select_with_splat_values_and_binary_splat_condition(
self : WgslIrLowerer,
reject : @ast.WgslExprNode,
accept : @ast.WgslExprNode,
condition : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle? raise WgslIrLowerError {
guard self.expression_node_is_select_constant_vector_splat_value(reject) else {
return None
}
guard self.expression_node_is_select_constant_vector_splat_value(accept) else {
return None
}
let (condition_op, condition_left, condition_right) = match condition.kind() {
Binary(op, left, right) => (op, left, right)
Group(inner) =>
match inner.kind() {
Binary(op, left, right) => (op, left, right)
_ => return None
}
_ => return None
}
guard self.expression_node_is_select_constant_vector_splat_value(
condition_right,
) else {
return None
}
let reject_handle = self.lower_function_expression_node(
reject, function, scope,
)
let accept_handle = self.lower_function_expression_node(
accept, function, scope,
)
guard self.prelower_select_constant_vector_splat_component(
condition_right, function, scope,
)
is Some(right_splat) else {
return None
}
let left_handle = self.lower_function_expression_node(
condition_left, function, scope,
)
let right_handle = self.lower_function_constructor_expression_from_handles(
right_splat.ty,
[right_splat.component],
function,
)
let binary_op = wgsl_ir_binary_operator(condition_op)
let (left_handle, right_handle) = self.normalize_function_binary_operands(
function, binary_op, left_handle, right_handle,
)
let condition_handle = function.expressions.append(
Binary(binary_op, left_handle, right_handle),
)
Some(
function.expressions.append(
Select(condition_handle, accept_handle, reject_handle),
),
)
}
///|
fn WgslIrLowerer::prelower_select_constant_vector_splat_component(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> WgslIrDeferredConstructorArgument? raise WgslIrLowerError {
match node.kind() {
Group(inner) =>
self.prelower_select_constant_vector_splat_component(
inner, function, scope,
)
Call(callee, constructor_arguments) => {
guard wgsl_ir_flatten_expression_arguments(
wgsl_ir_call_arguments(constructor_arguments),
)
is [component] else {
return None
}
guard self.expression_node_is_select_constant_value(component) else {
return None
}
guard self.lower_math_splat_constructor_callee_type(
callee, constructor_arguments,
)
is Some(ty) else {
return None
}
guard self.vector_size_from_type(ty) is Some(_) else { return None }
let expected_ty = self.constructor_component_expected_type(ty)
let component = self.lower_function_constructor_argument(
component, function, scope, expected_ty,
)
Some({ ty, component, })
}
_ => None
}
}
///|
fn WgslIrLowerer::lower_function_select_with_constant_constructor_values_and_binary_condition(
self : WgslIrLowerer,
reject : @ast.WgslExprNode,
accept : @ast.WgslExprNode,
condition : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle? raise WgslIrLowerError {
guard self.expression_node_is_select_constant_constructor_value(reject) else {
return None
}
guard self.expression_node_is_select_constant_constructor_value(accept) else {
return None
}
match condition.kind() {
Binary(_, _, _) => ()
Group(inner) =>
match inner.kind() {
Binary(_, _, _) => ()
_ => return None
}
_ => return None
}
let condition_handle = self.lower_function_expression_node(
condition, function, scope,
)
let reject_handle = self.lower_function_expression_node(
reject, function, scope,
)
let accept_handle = self.lower_function_expression_node(
accept, function, scope,
)
Some(
function.expressions.append(
Select(condition_handle, accept_handle, reject_handle),
),
)
}
///|
fn WgslIrLowerer::lower_function_select_with_constant_values_and_binary_condition(
self : WgslIrLowerer,
reject : @ast.WgslExprNode,
accept : @ast.WgslExprNode,
condition : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle? raise WgslIrLowerError {
guard self.expression_node_is_select_constant_value(reject) else {
return None
}
guard self.expression_node_is_select_constant_value(accept) else {
return None
}
let (condition_op, condition_left, condition_right) = match condition.kind() {
Binary(op, left, right) => (op, left, right)
Group(inner) =>
match inner.kind() {
Binary(op, left, right) => (op, left, right)
_ => return None
}
_ => return None
}
let left_handle = self.lower_function_expression_node(
condition_left, function, scope,
)
let right_handle = self.lower_function_expression_node(
condition_right, function, scope,
)
let binary_op = wgsl_ir_binary_operator(condition_op)
let (left_handle, right_handle) = self.normalize_function_binary_operands(
function, binary_op, left_handle, right_handle,
)
let condition_handle = function.expressions.append(
Binary(binary_op, left_handle, right_handle),
)
let accept_handle = self.lower_function_expression_node(
accept, function, scope,
)
let reject_handle = self.lower_function_expression_node(
reject, function, scope,
)
Some(
function.expressions.append(
Select(condition_handle, accept_handle, reject_handle),
),
)
}
///|
fn WgslIrLowerer::expression_node_is_select_constant_constructor_value(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
) -> Bool {
match node.kind() {
Group(inner) =>
self.expression_node_is_select_constant_constructor_value(inner)
Call(callee, arguments) => {
guard self.expression_callee_is_constructor_call_value(callee) else {
return false
}
let arguments = wgsl_ir_flatten_expression_arguments(
wgsl_ir_call_arguments(arguments),
)
arguments.all(fn(argument) {
self.expression_node_is_select_constant_value(argument)
})
}
_ => false
}
}
///|
fn WgslIrLowerer::expression_node_is_select_constant_vector_splat_value(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
) -> Bool {
match node.kind() {
Group(inner) =>
self.expression_node_is_select_constant_vector_splat_value(inner)
Call(callee, arguments) => {
guard wgsl_ir_flatten_expression_arguments(
wgsl_ir_call_arguments(arguments),
)
is [argument] else {
return false
}
guard self.expression_node_is_select_constant_value(argument) else {
return false
}
match callee.kind() {
Identifier(name) =>
wgsl_ir_vector_size_from_constructor_name(name.name()) != None
Template(base, _) =>
self.expression_node_is_select_constant_vector_splat_callee(base)
Group(inner) =>
self.expression_node_is_select_constant_vector_splat_callee(inner)
_ => false
}
}
_ => false
}
}
///|
fn WgslIrLowerer::expression_node_is_select_constant_vector_splat_callee(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
) -> Bool {
ignore(self)
match node.kind() {
Identifier(name) =>
wgsl_ir_vector_size_from_constructor_name(name.name()) != None
Template(base, _) =>
match base.kind() {
Identifier(name) =>
wgsl_ir_vector_size_from_constructor_name(name.name()) != None
_ => false
}
Group(inner) =>
match inner.kind() {
Identifier(name) =>
wgsl_ir_vector_size_from_constructor_name(name.name()) != None
_ => false
}
_ => false
}
}
///|
fn WgslIrLowerer::expression_node_is_select_constant_value(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
) -> Bool {
match node.kind() {
Literal(_) => return true
Group(inner) => return self.expression_node_is_select_constant_value(inner)
Unary(op, inner) =>
return op == Subtract &&
self.expression_node_is_select_constant_value(inner)
Identifier(name) =>
return self.constant_names.contains(name.name()) ||
wgsl_ir_predeclared_u32_constant_literal(name.name()) != None
_ => return false
}
}
///|
fn WgslIrLowerer::select_accept_predeclares_reference_root(
self : WgslIrLowerer,
accept : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Bool {
guard wgsl_ir_expr_node_is_direct_access_chain(accept) else { return false }
guard self.direct_access_chain_root_is_global_reference(accept) else {
return false
}
self.expression_node_contains_writer_reference_value(accept, function, scope) &&
!wgsl_ir_expr_node_is_function_argument_value(accept, scope)
}
///|
fn WgslIrLowerer::lower_function_bitcast_call(
self : WgslIrLowerer,
ty : Handle,
arguments : Array[@ast.WgslExprNode],
function : Function,
scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
let arguments = wgsl_ir_flatten_expression_arguments(arguments)
guard arguments is [expr] else {
raise UnsupportedExpression("bitcast expects one argument")
}
function.expressions.append(
Bitcast(ty, self.lower_function_expression_node(expr, function, scope)),
)
}