///|
fn WgslIrLowerer::lower_function_expression_ref(
self : WgslIrLowerer,
expr_ref : @ast.WgslExprRef,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
self.lower_function_expression_ref_with_expected(
expr_ref,
function,
scope,
None,
)
}
///|
fn WgslIrLowerer::lower_function_expression_ref_with_expected(
self : WgslIrLowerer,
expr_ref : @ast.WgslExprRef,
function : Function,
scope : WgslIrFunctionScope,
expected_ty : Handle?,
) -> Handle raise WgslIrLowerError {
guard expr_ref.root() is Some(root) else {
raise UnsupportedExpression("empty function expression")
}
self.lower_function_expression_node_with_expected(
root, function, scope, expected_ty,
) catch {
UnsupportedExpression(message) =>
raise UnsupportedExpression(
"\{message} at \{expr_ref.start()}..\{expr_ref.end()}: \{wgsl_ir_expr_ref_token_text(expr_ref)}",
)
error => raise error
}
}
///|
fn wgsl_ir_expr_ref_token_text(expr_ref : @ast.WgslExprRef) -> String {
let parts : Array[String] = []
for token in expr_ref.tokens() {
parts.push(token.text())
}
parts.join(" ")
}
///|
fn WgslIrLowerer::lower_function_lvalue_ref(
self : WgslIrLowerer,
expr_ref : @ast.WgslExprRef,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
guard expr_ref.root() is Some(root) else {
raise UnsupportedExpression("empty lvalue")
}
self.lower_function_lvalue_node(root, function, scope)
}
///|
fn WgslIrLowerer::append_foldable_function_binary_expression(
self : WgslIrLowerer,
function : Function,
scope : WgslIrFunctionScope,
local_constant_snapshot : Map[String, WgslIrLocalValue],
expression_mark : Int32,
op : BinaryOperator,
left : Handle,
right : Handle,
allow_fold : Bool,
) -> Handle raise WgslIrLowerError {
let handle = function.expressions.append(Binary(op, left, right))
if !allow_fold {
return handle
}
self.fold_function_binary_expression_at_mark(
function, scope, local_constant_snapshot, expression_mark, handle,
)
}
///|
fn WgslIrLowerer::fold_function_binary_expression_at_mark(
self : WgslIrLowerer,
function : Function,
scope : WgslIrFunctionScope,
local_constant_snapshot : Map[String, WgslIrLocalValue],
expression_mark : Int32,
handle : Handle,
) -> Handle raise WgslIrLowerError {
if self.function_binary_expression_should_retain_named_constant(
function, handle,
) {
return handle
}
match self.fold_function_constant_typed_literal_expression(function, handle) {
Some(literal) => {
wgsl_ir_rewind_function_expressions_and_local_constant_values(
function, expression_mark, scope, local_constant_snapshot,
)
function.expressions.append_with_origin(
Literal(literal),
FoldedLocalConstant,
)
}
None => handle
}
}
///|
fn WgslIrLowerer::function_argument_is_pointer(
self : WgslIrLowerer,
function : Function,
index : Int32,
) -> Bool {
match function.arguments.get(index) {
Some(argument) =>
match self.shader_module.types.get(argument.ty) {
Some(type_) =>
match type_.inner {
Pointer(_, _) => true
_ => false
}
None => false
}
None => false
}
}
///|
fn WgslIrLowerer::lower_function_lvalue_node(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
match node.kind() {
Identifier(name) => {
match scope.local_constants.get(name.name()) {
Some(_) => raise UnsupportedExpression("local const is not assignable")
None => ()
}
match scope.locals.get(name.name()) {
Some(handle) => {
match function.local_variables.items.get(handle.index()) {
Some(local_var) =>
if local_var.kind == Let {
raise UnsupportedExpression("local let is not assignable")
}
None => ()
}
return scope.local_pointer_expression(name.name(), handle, function)
}
None => ()
}
match scope.arguments.get(name.name()) {
Some(index) =>
if self.function_argument_is_pointer(function, index) {
return scope.argument_pointer_expression(
name.name(),
index,
function,
)
} else {
raise UnsupportedExpression("function argument is not assignable")
}
None => ()
}
match self.global_names.get(name.name()) {
Some(handle) =>
match scope.consume_pending_global_pointer_expression(name.name()) {
Some(predeclared) => predeclared
None =>
scope.global_pointer_expression(
name.name(),
handle,
function,
self.global_variable_reuses_pointer_expression(handle),
)
}
None => raise UnknownIdentifier(name.name())
}
}
Group(inner) => self.lower_function_lvalue_node(inner, function, scope)
Unary(op, expr) =>
if op == Multiply {
self.lower_function_expression_node(expr, function, scope)
} else {
raise UnsupportedExpression("unsupported lvalue shape")
}
Member(base, member_name) => {
let base_handle = self.lower_function_member_lvalue_base(
base, function, scope,
)
function.expressions.append(
AccessIndex(
base_handle,
self.member_index_for_expression(
function,
base_handle,
member_name.name(),
),
),
)
}
Index(base, index) => {
match
self.lower_function_direct_addressable_lvalue_binary_index(
base, index, function, scope,
) {
Some(handle) => return handle
None => ()
}
match
self.lower_function_dynamic_member_index_access(
base, index, function, scope,
) {
Some(handle) => return handle
None => ()
}
match self.static_index_value_from_expr_node(index) {
Some(_) => ()
None => {
if wgsl_ir_expr_node_contains_member_access(base) {
self.predeclare_function_member_root_expression(
base, function, scope,
)
self.predeclare_function_argument_values_in_source_order(
index, function, scope,
)
} else {
self.predeclare_function_reference_roots_in_source_order(
index, function, scope,
)
}
let base_handle = self.lower_function_lvalue_node(
base, function, scope,
)
let index_handle = self.lower_function_expression_node(
index, function, scope,
)
return function.expressions.append(Access(base_handle, index_handle))
}
}
let base_handle = self.lower_function_lvalue_node(base, function, scope)
self.lower_function_static_or_dynamic_index(
base_handle, index, function, scope,
)
}
_ => raise UnsupportedExpression("unsupported lvalue shape")
}
}
///|
fn WgslIrLowerer::lower_function_direct_addressable_lvalue_binary_index(
self : WgslIrLowerer,
base : @ast.WgslExprNode,
index : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle? raise WgslIrLowerError {
match self.static_index_value_from_expr_node(index) {
Some(_) => return None
None => ()
}
guard !wgsl_ir_expr_node_contains_member_access(index) else { return None }
let name = match base.kind() {
Identifier(name) => name.name()
_ => return None
}
guard !self.expression_node_contains_mutable_local_reference(
index, function, scope,
) ||
self.expression_identifier_is_direct_local_var_base(name, function, scope) else {
return None
}
guard self.expression_identifier_is_direct_addressable_base(
name, function, scope,
) else {
return None
}
let (op, left, right) = match index.kind() {
Binary(_, _, _) =>
self.lower_binary_expression_children(index, function, scope)
_ => return None
}
let base_handle = self.lower_function_lvalue_node(base, function, scope)
let binary_op = wgsl_ir_binary_operator(op)
let (left, right) = self.normalize_function_binary_operands(
function, binary_op, left, right,
)
let index_handle = function.expressions.append(Binary(binary_op, left, right))
Some(function.expressions.append(Access(base_handle, index_handle)))
}
///|
fn WgslIrLowerer::lower_function_direct_addressable_value_binary_index(
self : WgslIrLowerer,
base : @ast.WgslExprNode,
index : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle? raise WgslIrLowerError {
match self.static_index_value_from_expr_node(index) {
Some(_) => return None
None => ()
}
guard !wgsl_ir_expr_node_contains_member_access(index) else { return None }
let name = match base.kind() {
Identifier(name) => name.name()
_ => return None
}
guard !self.expression_node_contains_mutable_local_reference(
index, function, scope,
) ||
self.expression_identifier_is_direct_local_var_base(name, function, scope) else {
return None
}
guard self.expression_identifier_is_direct_addressable_base(
name, function, scope,
) else {
return None
}
let (op, left, right) = match index.kind() {
Binary(_, _, _) =>
self.lower_binary_expression_children(index, function, scope)
_ => return None
}
let base_handle = self.lower_function_index_value_base(base, function, scope)
let binary_op = wgsl_ir_binary_operator(op)
let (left, right) = self.normalize_function_binary_operands(
function, binary_op, left, right,
)
let index_handle = function.expressions.append(Binary(binary_op, left, right))
Some(
self.apply_function_load_rule(
function,
function.expressions.append(Access(base_handle, index_handle)),
),
)
}
///|
fn WgslIrLowerer::expression_identifier_is_direct_addressable_base(
self : WgslIrLowerer,
name : String,
function : Function,
scope : WgslIrFunctionScope,
) -> Bool {
match scope.locals.get(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 =>
match self.global_names.get(name) {
Some(_) => true
None => false
}
}
}
///|
fn WgslIrLowerer::expression_identifier_is_direct_local_var_base(
self : WgslIrLowerer,
name : String,
function : Function,
scope : WgslIrFunctionScope,
) -> Bool {
match scope.locals.get(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
}
}
///|
fn WgslIrLowerer::lower_function_member_lvalue_base(
self : WgslIrLowerer,
base : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
match wgsl_ir_deref_operand(base) {
Some(operand) =>
self.lower_function_expression_node(operand, function, scope)
None => self.lower_function_lvalue_node(base, function, scope)
}
}
///|
fn WgslIrLowerer::lower_function_member_value_base(
self : WgslIrLowerer,
base : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
match wgsl_ir_deref_operand(base) {
Some(operand) =>
self.lower_function_expression_node(operand, function, scope)
None =>
if self.function_access_base_is_addressable(base, function, scope) {
self.lower_function_access_base_pointer_node(base, function, scope)
} else {
self.lower_function_expression_node(base, function, scope)
}
}
}
///|
fn wgsl_ir_deref_operand(node : @ast.WgslExprNode) -> @ast.WgslExprNode? {
match node.kind() {
Group(inner) => wgsl_ir_deref_operand(inner)
Unary(op, expr) => if op == Multiply { Some(expr) } else { None }
_ => None
}
}
///|
fn WgslIrLowerer::lower_function_expression_node(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Handle raise WgslIrLowerError {
self.lower_function_expression_node_with_expected(node, function, scope, None)
}
///|
fn WgslIrLowerer::lower_function_expression_node_with_expected(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
expected_ty : Handle?,
) -> Handle raise WgslIrLowerError {
match node.kind() {
Literal(token) =>
self.lower_function_literal_node_with_expected(
token, function, scope, expected_ty,
)
ShaderDefTemplate(text) =>
raise UnsupportedExpression(
"shader-def template expression requires preprocessing: \{text}",
)
Identifier(name) =>
self.lower_identifier_expression(name.name(), function, scope)
PostfixUpdate(_, _) =>
raise UnsupportedExpression("update expression outside statement context")
Assignment(_, _, _) =>
raise UnsupportedExpression(
"assignment expression outside statement context",
)
Unary(op, expr) =>
if op == BitAnd {
let target = self.lower_function_lvalue_node(expr, function, scope)
function.expressions.append(
AddressOf(self.pointer_type_for_lvalue(function, target), target),
)
} else if op == Multiply {
function.expressions.append(
Load(self.lower_function_expression_node(expr, function, scope)),
)
} else if op == Subtract {
match expr.kind() {
Literal(token) =>
match
self.negated_literal_from_token_with_expected(token, expected_ty) {
Some(literal) => function.expressions.append(Literal(literal))
None =>
function.expressions.append(
Unary(
wgsl_ir_unary_operator(op),
self.lower_function_expression_node(expr, function, scope),
),
)
}
_ =>
function.expressions.append(
Unary(
wgsl_ir_unary_operator(op),
self.lower_function_expression_node(expr, function, scope),
),
)
}
} else {
function.expressions.append(
Unary(
wgsl_ir_unary_operator(op),
self.lower_function_expression_node(expr, function, scope),
),
)
}
Binary(op, left, right) => {
let scheduler = self.expression_arena_scheduler(function, scope)
let expression_mark = function.expressions.items.length()
let local_constant_snapshot = wgsl_ir_snapshot_local_constant_values(
scope.local_constants,
)
if scheduler.binary_predeclares_left_associative_reference_roots(
op, left, right,
) {
self.predeclare_function_binary_chain_reference_roots_in_source_order(
node, function, scope,
)
}
match
self.plan_binary_sibling_arguments_before_parent(
op, left, right, function, scope,
) {
Some(handle) => return handle
None => ()
}
match
self.plan_binary_const_left_before_math_parent(
op, left, right, function, scope,
) {
Some(handle) => return handle
None => ()
}
match
self.plan_binary_declared_constant_before_call_product(
op, left, right, function, scope,
) {
Some(handle) => return handle
None => ()
}
match
self.plan_binary_trailing_source_let_initializer(
op, left, right, function, scope,
) {
Some(handle) => return handle
None => ()
}
match
self.plan_binary_trailing_source_let_literal(
op, left, right, function, scope,
) {
Some(handle) => return handle
None => ()
}
match
self.plan_binary_folded_right_const_vector_operand(
op, left, right, function, scope,
) {
Some(handle) => return handle
None => ()
}
match
self.plan_binary_parent_argument_after_member_root(
op, left, right, function, scope,
) {
Some(handle) => return handle
None => ()
}
match
self.plan_binary_parent_argument_after_named_root(
op, left, right, function, scope,
) {
Some(handle) => return handle
None => ()
}
match
self.plan_binary_parent_argument_root_projection(
op, left, right, function, scope,
) {
Some(handle) => return handle
None => ()
}
match
self.plan_binary_left_argument_after_global_product(
op, left, right, function, scope,
) {
Some(handle) => return handle
None => ()
}
let member_bases_lower_in_source_order = scheduler.binary_predeclares_sibling_member_roots(
left, right,
)
if member_bases_lower_in_source_order {
self.predeclare_function_member_base_expressions(left, function, scope)
self.predeclare_function_member_base_expressions(right, function, scope)
} else if wgsl_ir_expr_node_is_function_argument_value(left, scope) &&
wgsl_ir_expr_node_is_direct_access_chain(right) {
self.predeclare_function_member_base_expressions(right, function, scope)
} else if wgsl_ir_expr_node_is_direct_access_chain(left) &&
wgsl_ir_expr_node_is_function_argument_value(right, scope) {
self.predeclare_function_reference_roots_in_source_order(
left, function, scope,
)
self.predeclare_function_argument_value(right, function, scope)
} else if scheduler.binary_predeclares_right_subtree_arguments_before_left_access_projection(
op, left, right,
) {
self.predeclare_function_reference_roots_in_source_order(
left, function, scope,
)
self.predeclare_function_argument_values_in_source_order(
right, function, scope,
)
} else if scheduler.binary_predeclares_right_subtree_arguments_before_left_associative_call_chain(
op, left, right,
) {
self.predeclare_function_argument_values_in_source_order(
right, function, scope,
)
} else if scheduler.binary_predeclares_right_constructor_argument_member_root(
left, right,
) {
self.predeclare_function_reference_roots_in_source_order(
left, function, scope,
)
self.predeclare_function_member_base_expressions(right, function, scope)
} else if wgsl_ir_expr_node_contains_member_access(left) &&
wgsl_ir_expr_node_contains_function_argument_math_call(right, scope) {
self.predeclare_function_reference_roots_in_source_order(
left, function, scope,
)
self.predeclare_function_reference_roots_in_source_order(
right, function, scope,
)
} else if scheduler.binary_right_subtree_has_higher_precedence(op, right) &&
!wgsl_ir_expr_node_is_function_argument_value(left, scope) &&
wgsl_ir_expr_node_is_direct_access_chain(left) &&
wgsl_ir_expr_node_contains_call(left) &&
!wgsl_ir_expr_node_contains_non_math_call(left) &&
!wgsl_ir_expr_node_contains_non_math_call(right) &&
wgsl_ir_expr_node_contains_function_argument_value(right, scope) {
self.predeclare_function_argument_values_in_source_order(
right, function, scope,
)
}
let (left_handle, right_handle) = if !member_bases_lower_in_source_order &&
(
scheduler.binary_right_subtree_has_higher_precedence(op, right) ||
scheduler.binary_lowers_right_children_before_left_access(
op, left, right,
)
) {
match
self.plan_binary_const_parent_with_right_local_reference(
op, left, right, function, scope,
) {
Some(result) => result
None =>
if scheduler.binary_preserves_left_first_across_higher_precedence_right(
op, left, right,
) {
let left_handle = self.lower_function_expression_node(
left, function, scope,
)
let right_mark = function.expressions.items.length()
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 right_handle = self.append_foldable_function_binary_expression(
function,
scope,
local_constant_snapshot,
right_mark,
right_binary_op,
right_left,
right_right,
!wgsl_ir_expr_node_references_local_let_constant(right, scope),
)
(left_handle, right_handle)
} else if scheduler.binary_lowers_right_children_before_left_access(
op, left, right,
) {
let right_mark = function.expressions.items.length()
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 = self.append_foldable_function_binary_expression(
function,
scope,
local_constant_snapshot,
right_mark,
right_binary_op,
right_left,
right_right,
!wgsl_ir_expr_node_references_local_let_constant(right, scope),
)
(left_handle, right_handle)
} else if wgsl_ir_expr_node_is_direct_access_chain(left) ||
self.expression_node_is_mutable_local_value(left, function, scope) {
let left_handle = self.lower_function_expression_node(
left, function, scope,
)
let right_mark = function.expressions.items.length()
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 right_handle = self.append_foldable_function_binary_expression(
function,
scope,
local_constant_snapshot,
right_mark,
right_binary_op,
right_left,
right_right,
!wgsl_ir_expr_node_references_local_let_constant(right, scope),
)
(left_handle, right_handle)
} else {
let right_binary_lowers_before_left = wgsl_ir_expr_node_contains_non_math_call(
right,
) ||
wgsl_ir_expr_node_is_literal_like(left)
let right_children_lower_before_left = wgsl_ir_expr_node_is_function_argument_value(
left, scope,
) &&
!wgsl_ir_expr_node_contains_call(right)
let (left_handle, right_handle) = if right_binary_lowers_before_left {
let right_mark = function.expressions.items.length()
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 right_handle = self.append_foldable_function_binary_expression(
function,
scope,
local_constant_snapshot,
right_mark,
right_binary_op,
right_left,
right_right,
!wgsl_ir_expr_node_references_local_let_constant(right, scope),
)
let left_handle = self.lower_function_expression_node(
left, function, scope,
)
(left_handle, right_handle)
} else if right_children_lower_before_left {
let right_mark = function.expressions.items.length()
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 = self.append_foldable_function_binary_expression(
function,
scope,
local_constant_snapshot,
right_mark,
right_binary_op,
right_left,
right_right,
!wgsl_ir_expr_node_references_local_let_constant(right, scope),
)
(left_handle, right_handle)
} else {
let left_handle = self.lower_function_expression_node(
left, function, scope,
)
let right_mark = function.expressions.items.length()
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 right_handle = self.append_foldable_function_binary_expression(
function,
scope,
local_constant_snapshot,
right_mark,
right_binary_op,
right_left,
right_right,
!wgsl_ir_expr_node_references_local_let_constant(right, scope),
)
(left_handle, right_handle)
}
(left_handle, right_handle)
}
}
} else if wgsl_ir_expr_node_is_binary_source_let_arithmetic(left, scope) &&
wgsl_ir_expr_node_is_direct_access_chain(right) &&
!wgsl_ir_expr_node_contains_call(left) &&
!wgsl_ir_expr_node_contains_call(right) {
let (left_op, left_left, left_right) = self.lower_binary_expression_children(
left, function, scope,
)
self.predeclare_function_member_root_expression(right, function, scope)
let left_binary_op = wgsl_ir_binary_operator(left_op)
let (left_left, left_right) = self.normalize_function_binary_operands(
function, left_binary_op, left_left, left_right,
)
let left_handle = function.expressions.append(
Binary(left_binary_op, left_left, left_right),
)
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 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 {
match
self.plan_binary_right_constructor_after_arguments_before_left(
op, left, right, function, scope,
) {
Some(result) => result
None =>
if op == Divide &&
wgsl_ir_expr_node_is_literal_like(left) &&
wgsl_ir_expr_node_contains_non_math_call(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 if scheduler.binary_lowers_right_before_left(op, left, right) {
self.lower_function_right_operand_before_left(
op, left, right, function, scope,
)
} 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)
}
}
}
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),
)
if wgsl_ir_expr_node_references_local_let_constant(node, scope) {
function.expressions.set_origin(handle, RetainedSourceLetExpression)
return handle
}
self.fold_function_binary_expression_at_mark(
function, scope, local_constant_snapshot, expression_mark, handle,
)
}
Group(expr) =>
self.lower_function_expression_node_with_expected(
expr, function, scope, expected_ty,
)
Sequence([single]) =>
self.lower_function_expression_node_with_expected(
single, function, scope, expected_ty,
)
Member(base, member_name) => {
let base_handle = self.lower_function_member_value_base(
base, function, scope,
)
self.apply_function_load_rule(
function,
self.lower_member_expression(function, base_handle, member_name.name()),
)
}
Index(base, index) => {
match
self.lower_function_const_array_static_index_value(
base, index, function,
) {
Some(handle) => return handle
None => ()
}
match
self.lower_function_direct_addressable_value_binary_index(
base, index, function, scope,
) {
Some(handle) => return handle
None => ()
}
match self.static_index_value_from_expr_node(index) {
Some(_) => ()
None => {
self.predeclare_function_reference_roots_in_source_order(
index, function, scope,
)
let base_handle = self.lower_function_index_value_base(
base, function, scope,
)
let index_handle = self.lower_function_expression_node(
index, function, scope,
)
return self.apply_function_load_rule(
function,
function.expressions.append(Access(base_handle, index_handle)),
)
}
}
let base_handle = self.lower_function_index_value_base(
base, function, scope,
)
self.apply_function_load_rule(
function,
self.lower_function_static_or_dynamic_index(
base_handle, index, function, scope,
),
)
}
Call(callee, arguments) => {
let arguments = wgsl_ir_call_arguments(arguments)
self.lower_function_call_expression(
callee, arguments, function, scope, expected_ty,
)
}
Template(base, _) =>
raise UnsupportedExpression(
"standalone template expression: \{wgsl_ir_expr_node_shape(base)}",
)
PathAccess(_, _) =>
raise UnsupportedExpression(
"unresolved qualified path expression: \{wgsl_ir_expr_node_shape(node)}",
)
Sequence(items) =>
raise UnsupportedExpression(
"expression sequence with \{items.length()} item(s) outside argument context: \{wgsl_ir_expr_node_shape(node)}",
)
}
}
///|
fn WgslIrLowerer::lower_function_literal_node_with_expected(
self : WgslIrLowerer,
token : @ast.WgslExprToken,
function : Function,
scope : WgslIrFunctionScope,
expected_ty : Handle?,
) -> Handle raise WgslIrLowerError {
let text_key = wgsl_ir_source_local_const_literal_key(token, expected_ty)
match scope.runtime_source_local_const_initializer_expressions.get(text_key) {
Some(handle) => return handle
None => ()
}
match scope.source_local_const_initializer_expressions.get(text_key) {
Some(handle) => return handle
None => ()
}
match self.source_local_const_literal_semantic_key(token, expected_ty) {
Some(semantic_key) => {
match
scope.runtime_source_local_const_initializer_expressions.get(
semantic_key,
) {
Some(handle) => return handle
None => ()
}
match scope.source_local_const_initializer_expressions.get(semantic_key) {
Some(handle) => return handle
None => ()
}
}
None => ()
}
match self.source_local_const_literal_concrete_storage_type(expected_ty) {
Some(concrete_ty) =>
match
self.source_local_const_literal_semantic_key(token, Some(concrete_ty)) {
Some(semantic_key) => {
match
scope.runtime_source_local_const_initializer_expressions.get(
semantic_key,
) {
Some(handle) => return handle
None => ()
}
match
scope.source_local_const_initializer_expressions.get(semantic_key) {
Some(handle) => return handle
None => ()
}
}
None => ()
}
None => ()
}
function.expressions.append(
Literal(self.literal_from_token_with_expected(token, expected_ty)),
)
}
///|
fn WgslIrLowerer::lower_function_fresh_literal_node_with_expected(
self : WgslIrLowerer,
token : @ast.WgslExprToken,
function : Function,
expected_ty : Handle?,
) -> Handle raise WgslIrLowerError {
function.expressions.append(
Literal(self.literal_from_token_with_expected(token, expected_ty)),
)
}
///|
fn WgslIrLowerer::source_local_const_literal_concrete_storage_type(
self : WgslIrLowerer,
expected_ty : Handle?,
) -> Handle? {
guard expected_ty is Some(ty) else { return None }
match self.shader_module.types.get(ty) {
Some({ inner: Scalar(scalar), .. })
| Some({ inner: Vector(_, scalar), .. })
| Some({ inner: Matrix(_, _, scalar), .. }) =>
match self.concretize_abstract_storage_scalar(scalar) {
Some(concrete) => Some(self.scalar_type_handle(concrete))
None => None
}
_ => None
}
}
///|
fn WgslIrLowerer::lower_function_const_array_static_index_value(
self : WgslIrLowerer,
base : @ast.WgslExprNode,
index : @ast.WgslExprNode,
function : Function,
) -> Handle? raise WgslIrLowerError {
let base = match base.kind() {
Group(inner) => inner
_ => base
}
guard base.kind() is Identifier(name) else { return None }
guard self.static_index_value_from_expr_node(index) is Some(static_index) else {
return None
}
guard static_index >= 0 else { return None }
guard self.ensure_constant_declaration_lowered(name.name())
is Some(constant_handle) else {
return None
}
guard self.shader_module.constants.items.get(constant_handle.index())
is Some(constant) else {
return None
}
guard self.shader_module.types.get(
self.deref_pointer_type_handle(constant.ty),
)
is Some(type_) else {
return None
}
match type_.inner {
Array(_, Constant(count), _) => if static_index >= count { return None }
_ => return None
}
guard self.shader_module.global_expressions.items.get(constant.init.index())
is Some(init) else {
return None
}
match init {
Compose(_, components) =>
match components.get(static_index) {
Some(component) =>
Some(
self.clone_global_const_expression_to_function(component, function),
)
None => None
}
_ => None
}
}
///|
fn WgslIrLowerer::clone_global_const_expression_to_function(
self : WgslIrLowerer,
handle : Handle,
function : Function,
) -> Handle raise WgslIrLowerError {
guard self.shader_module.global_expressions.items.get(handle.index())
is Some(expression) else {
raise UnsupportedExpression("missing global const expression")
}
match expression {
Literal(literal) => function.expressions.append(Literal(literal))
ZeroValue(ty) => function.expressions.append(ZeroValue(ty))
Constant(constant) =>
match self.shader_module.constants.items.get(constant.index()) {
Some(nested) =>
self.clone_global_const_expression_to_function(nested.init, function)
None => function.expressions.append(Constant(constant))
}
Compose(ty, components) => {
let cloned : Array[Handle] = []
for component in components {
cloned.push(
self.clone_global_const_expression_to_function(component, function),
)
}
function.expressions.append(Compose(ty, cloned))
}
Splat(size, inner) =>
function.expressions.append(
Splat(
size,
self.clone_global_const_expression_to_function(inner, function),
),
)
Unary(op, inner) =>
function.expressions.append(
Unary(
op,
self.clone_global_const_expression_to_function(inner, function),
),
)
Binary(op, left, right) => {
let left = self.clone_global_const_expression_to_function(left, function)
let right = self.clone_global_const_expression_to_function(
right, function,
)
function.expressions.append(Binary(op, left, right))
}
Select(condition, accept, reject) => {
let condition = self.clone_global_const_expression_to_function(
condition, function,
)
let accept = self.clone_global_const_expression_to_function(
accept, function,
)
let reject = self.clone_global_const_expression_to_function(
reject, function,
)
function.expressions.append(Select(condition, accept, reject))
}
Bitcast(ty, inner) =>
function.expressions.append(
Bitcast(
ty,
self.clone_global_const_expression_to_function(inner, function),
),
)
Relational(relational, inner) =>
function.expressions.append(
Relational(
relational,
self.clone_global_const_expression_to_function(inner, function),
),
)
Math(math, a, b, c, d) => {
let a = self.clone_global_const_expression_to_function(a, function)
let b = match b {
Some(handle) =>
Some(self.clone_global_const_expression_to_function(handle, function))
None => None
}
let c = match c {
Some(handle) =>
Some(self.clone_global_const_expression_to_function(handle, function))
None => None
}
let d = match d {
Some(handle) =>
Some(self.clone_global_const_expression_to_function(handle, function))
None => None
}
function.expressions.append(Math(math, a, b, c, d))
}
As(inner, kind, width) =>
function.expressions.append(
As(
self.clone_global_const_expression_to_function(inner, function),
kind,
width,
),
)
AccessIndex(base, index) =>
function.expressions.append(
AccessIndex(
self.clone_global_const_expression_to_function(base, function),
index,
),
)
Access(base, index) => {
let base = self.clone_global_const_expression_to_function(base, function)
let index = self.clone_global_const_expression_to_function(
index, function,
)
function.expressions.append(Access(base, index))
}
Swizzle(size, base, components) =>
function.expressions.append(
Swizzle(
size,
self.clone_global_const_expression_to_function(base, function),
components,
),
)
Component(base, component) =>
function.expressions.append(
Component(
self.clone_global_const_expression_to_function(base, function),
component,
),
)
_ =>
raise UnsupportedExpression(
"global const expression is not function-cloneable",
)
}
}