///|
fn wgsl_ir_local_constant_arena_placement_for_statement(
statement : @ast.WgslStatement,
statements : Array[@ast.WgslStatement],
statement_index : Int32,
scope : WgslIrFunctionScope,
) -> WgslIrLocalConstantArenaPlacement {
match statement.payload() {
LocalDeclaration(locals) => {
for local_decl in locals {
if (local_decl.kind() == Let || local_decl.kind() == Const) &&
wgsl_ir_local_const_initializer_uses_declaration_arena(
local_decl, statements, statement_index, scope,
) &&
wgsl_ir_local_name_has_same_block_use_before_nested_flow(
local_decl.name().name(),
statements,
statement_index,
) {
return DeclarationArenaLocalConstant
}
}
UseSiteLazyLocalConstant
}
_ => UseSiteLazyLocalConstant
}
}
///|
fn wgsl_ir_source_var_store_initializers_for_statement(
locals : Array[@ast.WgslLocalDeclaration],
statements : Array[@ast.WgslStatement],
statement_index : Int32,
lowerer : WgslIrLowerer,
scope : WgslIrFunctionScope,
) -> Array[String] raise WgslIrLowerError {
let names : Array[String] = []
for local_decl in locals {
if wgsl_ir_source_var_initializer_uses_store_before_next_for(
local_decl, statements, statement_index, lowerer, scope,
) {
names.push(local_decl.name().name())
}
}
names
}
///|
fn wgsl_ir_source_var_initializer_uses_store_before_next_for(
local_decl : @ast.WgslLocalDeclaration,
statements : Array[@ast.WgslStatement],
statement_index : Int32,
lowerer : WgslIrLowerer,
scope : WgslIrFunctionScope,
) -> Bool raise WgslIrLowerError {
guard local_decl.kind() == Var else { return false }
guard local_decl.initializer_ref() is Some(expr_ref) else { return false }
guard expr_ref.root() is Some(root) else { return false }
guard lowerer.expression_node_is_const_initializer(root) else { return false }
let next_index = statement_index + 1
guard next_index < statements.length() else { return false }
guard statements[next_index].kind() == For else { return false }
ignore(scope)
wgsl_ir_statement_direct_expressions_mention_identifier(
statements[next_index],
local_decl.name().name(),
)
}
///|
fn wgsl_ir_local_const_initializer_uses_declaration_arena(
local_decl : @ast.WgslLocalDeclaration,
statements : Array[@ast.WgslStatement],
statement_index : Int32,
scope : WgslIrFunctionScope,
) -> Bool {
if wgsl_ir_local_const_initializer_references_local_let(local_decl, scope) {
return true
}
if wgsl_ir_local_const_initializer_is_literal(local_decl) &&
wgsl_ir_next_assignment_rhs_mentions_identifier(
local_decl.name().name(),
statements,
statement_index,
) {
return false
}
!wgsl_ir_local_const_initializer_is_bool_literal(local_decl) &&
wgsl_ir_next_statement_mentions_identifier(
local_decl.name().name(),
statements,
statement_index,
)
}
///|
fn wgsl_ir_local_const_initializer_references_local_let(
local_decl : @ast.WgslLocalDeclaration,
scope : WgslIrFunctionScope,
) -> Bool {
match local_decl.initializer_ref() {
Some(expr_ref) =>
match expr_ref.root() {
Some(root) =>
wgsl_ir_expr_node_references_local_let_constant(root, scope)
None => false
}
None => false
}
}
///|
fn wgsl_ir_local_const_initializer_is_literal(
local_decl : @ast.WgslLocalDeclaration,
) -> Bool {
match local_decl.initializer_ref() {
Some(expr_ref) =>
match expr_ref.root() {
Some(root) => wgsl_ir_expr_node_is_literal(root)
None => false
}
None => false
}
}
///|
fn wgsl_ir_local_const_initializer_is_bool_literal(
local_decl : @ast.WgslLocalDeclaration,
) -> Bool {
match local_decl.initializer_ref() {
Some(expr_ref) =>
match expr_ref.root() {
Some(root) => wgsl_ir_expr_node_is_bool_literal(root)
None => false
}
None => false
}
}
///|
fn wgsl_ir_expr_node_is_literal(node : @ast.WgslExprNode) -> Bool {
match node.kind() {
Literal(_) => true
Group(inner) => wgsl_ir_expr_node_is_literal(inner)
_ => false
}
}
///|
fn wgsl_ir_expr_node_is_bool_literal(node : @ast.WgslExprNode) -> Bool {
match node.kind() {
Literal(token) => token.text() == "true" || token.text() == "false"
Group(inner) => wgsl_ir_expr_node_is_bool_literal(inner)
_ => false
}
}
///|
fn wgsl_ir_next_assignment_rhs_mentions_identifier(
name : String,
statements : Array[@ast.WgslStatement],
statement_index : Int32,
) -> Bool {
let next_index = statement_index + 1
if next_index >= statements.length() {
return false
}
match statements[next_index].payload() {
Assignment(_, _, Some(rhs)) =>
wgsl_ir_expr_ref_mentions_identifier(rhs, name)
_ => false
}
}
///|
fn wgsl_ir_next_statement_mentions_identifier(
name : String,
statements : Array[@ast.WgslStatement],
statement_index : Int32,
) -> Bool {
let next_index = statement_index + 1
if next_index >= statements.length() {
return false
}
wgsl_ir_statement_direct_expressions_mention_identifier(
statements[next_index],
name,
)
}
///|
fn wgsl_ir_local_name_has_same_block_use_before_nested_flow(
name : String,
statements : Array[@ast.WgslStatement],
statement_index : Int32,
) -> Bool {
for index in (statement_index + 1).. 0 {
return false
}
}
false
}
///|
fn wgsl_ir_statement_direct_expressions_mention_identifier(
statement : @ast.WgslStatement,
name : String,
) -> Bool {
for local_decl in statement.local_bindings() {
match local_decl.initializer_ref() {
Some(expr_ref) =>
if wgsl_ir_expr_ref_mentions_identifier(expr_ref, name) {
return true
}
None => ()
}
}
for expr_ref in statement.expression_refs() {
if wgsl_ir_expr_ref_mentions_identifier(expr_ref, name) {
return true
}
}
false
}
///|
fn wgsl_ir_expr_ref_mentions_identifier(
expr_ref : @ast.WgslExprRef,
name : String,
) -> Bool {
match expr_ref.root() {
Some(root) => wgsl_ir_expr_node_mentions_identifier(root, name)
None => expr_ref.identifiers().any(fn(ident) { ident.name() == name })
}
}
///|
fn wgsl_ir_expr_node_mentions_identifier(
node : @ast.WgslExprNode,
name : String,
) -> Bool {
match node.kind() {
Identifier(ident) => ident.name() == name
Literal(_) | ShaderDefTemplate(_) => false
Unary(_, expr) | PostfixUpdate(_, expr) | Group(expr) =>
wgsl_ir_expr_node_mentions_identifier(expr, name)
Assignment(_, lhs, rhs) | Binary(_, lhs, rhs) | Index(lhs, rhs) =>
wgsl_ir_expr_node_mentions_identifier(lhs, name) ||
wgsl_ir_expr_node_mentions_identifier(rhs, name)
Call(callee, args) =>
wgsl_ir_expr_node_mentions_identifier(callee, name) ||
args.any(fn(arg) { wgsl_ir_expr_node_mentions_identifier(arg, name) })
Template(callee, args) =>
wgsl_ir_expr_node_mentions_identifier(callee, name) ||
args.any(fn(arg) {
match arg {
Expression(expr) => wgsl_ir_expr_ref_mentions_identifier(expr, name)
Type(_) => false
}
})
PathAccess(base, segment) =>
wgsl_ir_expr_node_mentions_identifier(base, name) ||
segment.name() == name
Member(base, _) => wgsl_ir_expr_node_mentions_identifier(base, name)
Sequence(items) =>
items.any(fn(item) { wgsl_ir_expr_node_mentions_identifier(item, name) })
}
}
///|
fn wgsl_ir_expr_ref_plain_local_identifier(
expr_ref : @ast.WgslExprRef,
scope : WgslIrFunctionScope,
) -> Bool {
match expr_ref.root() {
Some(root) => wgsl_ir_expr_node_plain_local_identifier(root, scope)
None => false
}
}
///|
fn WgslIrLowerer::wgsl_ir_expr_ref_is_function_argument_pointer_deref(
self : WgslIrLowerer,
expr_ref : @ast.WgslExprRef,
function : Function,
scope : WgslIrFunctionScope,
) -> Bool {
match expr_ref.root() {
Some(root) =>
self.wgsl_ir_expr_node_is_function_argument_pointer_deref(
root, function, scope,
)
None => false
}
}
///|
fn WgslIrLowerer::wgsl_ir_expr_node_is_function_argument_pointer_deref(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Bool {
match node.kind() {
Group(inner) =>
self.wgsl_ir_expr_node_is_function_argument_pointer_deref(
inner, function, scope,
)
Unary(op, inner) =>
if op == Multiply {
self.wgsl_ir_expr_node_is_function_argument_pointer(
inner, function, scope,
)
} else {
false
}
_ => false
}
}
///|
fn WgslIrLowerer::wgsl_ir_expr_node_is_function_argument_pointer(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
function : Function,
scope : WgslIrFunctionScope,
) -> Bool {
match node.kind() {
Group(inner) =>
self.wgsl_ir_expr_node_is_function_argument_pointer(
inner, function, scope,
)
Identifier(ident) =>
match scope.arguments.get(ident.name()) {
Some(index) =>
match function.arguments.get(index) {
Some(argument) => self.lowerer_type_is_pointer(argument.ty)
None => false
}
None => false
}
_ => false
}
}
///|
fn wgsl_ir_expr_node_plain_local_identifier(
node : @ast.WgslExprNode,
scope : WgslIrFunctionScope,
) -> Bool {
match node.kind() {
Identifier(ident) => scope.locals.contains(ident.name())
Group(inner) => wgsl_ir_expr_node_plain_local_identifier(inner, scope)
_ => false
}
}
///|
fn wgsl_ir_expr_node_references_local_let_constant(
node : @ast.WgslExprNode,
scope : WgslIrFunctionScope,
) -> Bool {
match node.kind() {
Identifier(name) =>
match scope.local_constants.get(name.name()) {
Some(cell) => cell.source == LocalLet
None => false
}
Literal(_) | ShaderDefTemplate(_) => false
Unary(_, inner) | PostfixUpdate(_, inner) | Group(inner) =>
wgsl_ir_expr_node_references_local_let_constant(inner, scope)
Assignment(_, left, right) | Binary(_, left, right) | Index(left, right) =>
wgsl_ir_expr_node_references_local_let_constant(left, scope) ||
wgsl_ir_expr_node_references_local_let_constant(right, scope)
Call(callee, arguments) => {
let arguments = wgsl_ir_call_arguments(arguments)
wgsl_ir_expr_node_references_local_let_constant(callee, scope) ||
wgsl_ir_expr_node_list_references_local_let_constant(arguments, scope)
}
Template(callee, arguments) =>
wgsl_ir_expr_node_references_local_let_constant(callee, scope) ||
arguments.any(fn(argument) {
match argument {
Expression(expr_ref) =>
match expr_ref.root() {
Some(root) =>
wgsl_ir_expr_node_references_local_let_constant(root, scope)
None => false
}
Type(_) => false
}
})
PathAccess(base, _) | Member(base, _) =>
wgsl_ir_expr_node_references_local_let_constant(base, scope)
Sequence(items) =>
wgsl_ir_expr_node_list_references_local_let_constant(items, scope)
}
}
///|
fn wgsl_ir_expr_node_list_references_local_let_constant(
items : Array[@ast.WgslExprNode],
scope : WgslIrFunctionScope,
) -> Bool {
for item in items {
if wgsl_ir_expr_node_references_local_let_constant(item, scope) {
return true
}
}
false
}
///|
fn wgsl_ir_expr_ref_references_local_let_constant(
expr_ref : @ast.WgslExprRef,
scope : WgslIrFunctionScope,
) -> Bool {
match expr_ref.root() {
Some(root) => wgsl_ir_expr_node_references_local_let_constant(root, scope)
None => false
}
}
///|
fn wgsl_ir_expr_node_plain_mutable_local_identifier_name(
node : @ast.WgslExprNode,
scope : WgslIrFunctionScope,
) -> String? {
match node.kind() {
Identifier(ident) =>
if scope.locals.contains(ident.name()) {
Some(ident.name())
} else {
None
}
Group(inner) =>
wgsl_ir_expr_node_plain_mutable_local_identifier_name(inner, scope)
_ => None
}
}