// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
fn wgsl_ir_emit_expression_temporary_name_key(
origin : WgslIrEmitFunctionOrigin,
handle : Handle,
) -> String {
match origin {
UserFunction(function_index) =>
wgsl_ir_emit_name_key2("fn_expr", function_index, handle.index())
EntryPointFunction(entry_point_index) =>
wgsl_ir_emit_name_key2("ep_expr", entry_point_index, handle.index())
}
}
///|
fn wgsl_ir_emit_local_name_key(
origin : WgslIrEmitFunctionOrigin,
handle : Handle,
) -> String {
match origin {
UserFunction(function_index) =>
wgsl_ir_emit_name_key2("fn_local", function_index, handle.index())
EntryPointFunction(entry_point_index) =>
wgsl_ir_emit_name_key2("ep_local", entry_point_index, handle.index())
}
}
///|
fn wgsl_ir_emit_named_expression_name_key(
origin : WgslIrEmitFunctionOrigin,
handle : Handle,
) -> String {
match origin {
UserFunction(function_index) =>
wgsl_ir_emit_name_key2("fn_named_expr", function_index, handle.index())
EntryPointFunction(entry_point_index) =>
wgsl_ir_emit_name_key2("ep_named_expr", entry_point_index, handle.index())
}
}
///|
priv struct WgslIrFunctionBodyWriterPlan {
materialized_expressions : @set.Set[Int]
temporary_initializer_expressions : @set.Set[Int]
elided_local_alias_targets : Map[Int, Handle]
local_variable_declarations : Array[Int]
has_body_after_hoisted_declarations : Bool
implicit_expression_slots_before : Array[Int]
body_emission : BodyEmissionPlanner
}
///|
priv struct WgslIrTemporaryIndexTrace {
skipped : Int
base_index : Int
adjusted_base_index : Int
implicit_expression_slots_before : Int
prior_call_projection_argument_slots : Int
implicit_load_slots : Int
reused_resource_operand_slots : Int
projected_temporary_slots : Int
final_index : Int
}
///|
fn WgslIrFunctionBodyWriterPlan::from_function(
shader_module : Module,
function : Function,
projection_aliases : Bool,
) -> WgslIrFunctionBodyWriterPlan {
let materialized_expressions = wgsl_ir_function_materialized_expression_indices(
function,
)
let elided_local_alias_targets = wgsl_ir_writer_function_elided_local_alias_targets(
shader_module, function, materialized_expressions, projection_aliases,
)
{
materialized_expressions,
temporary_initializer_expressions: wgsl_ir_writer_function_temporary_initializer_expression_indices(
function,
),
elided_local_alias_targets,
local_variable_declarations: wgsl_ir_writer_function_body_local_declarations(
function, elided_local_alias_targets,
),
has_body_after_hoisted_declarations: wgsl_ir_writer_function_body_has_non_hoisted_statement(
function, elided_local_alias_targets,
),
implicit_expression_slots_before: wgsl_ir_writer_function_implicit_expression_slots_before(
shader_module, function,
),
body_emission: BodyEmissionPlanner::from_function(
elided_local_alias_targets,
),
}
}
///|
fn WgslIrFunctionBodyWriterPlan::implicit_expression_slot_offset(
self : WgslIrFunctionBodyWriterPlan,
handle : Handle,
) -> Int {
match self.implicit_expression_slots_before.get(handle.index()) {
Some(value) => value
None => 0
}
}
///|
fn WgslIrFunctionBodyWriterPlan::local_declaration_order(
self : WgslIrFunctionBodyWriterPlan,
) -> Array[Int] {
self.local_variable_declarations
}
///|
fn WgslIrFunctionBodyWriterPlan::needs_blank_after_local_declarations(
self : WgslIrFunctionBodyWriterPlan,
) -> Bool {
self.local_variable_declarations.length() > 0 &&
self.has_body_after_hoisted_declarations
}
///|
fn WgslIrFunctionBodyWriterPlan::statement_plan(
self : WgslIrFunctionBodyWriterPlan,
function : Function,
block : Block,
) -> Array[WgslIrStatementWriterPlanItem] {
self.body_emission.statement_plan(function, block)
}
///|
fn wgsl_ir_writer_function_body_local_declarations(
function : Function,
elided_local_alias_targets : Map[Int, Handle],
) -> Array[Int] {
let order : Array[Int] = []
let seen : @set.Set[Int] = Set([])
wgsl_ir_writer_collect_body_local_declarations(
function.body,
function,
elided_local_alias_targets,
order,
seen,
)
for index in 0.. Unit {
for statement in block.statements {
match statement {
Declare(handle) => {
let index = handle.index()
if !seen.contains(index) &&
wgsl_ir_writer_local_declaration_is_hoistable(
function, elided_local_alias_targets, index,
) {
seen.add(index)
order.push(index)
}
}
Block(child) =>
wgsl_ir_writer_collect_body_local_declarations(
child, function, elided_local_alias_targets, order, seen,
)
If(_, accept, reject) => {
wgsl_ir_writer_collect_body_local_declarations(
accept, function, elided_local_alias_targets, order, seen,
)
wgsl_ir_writer_collect_body_local_declarations(
reject, function, elided_local_alias_targets, order, seen,
)
}
Switch(_, cases) =>
for case in cases {
wgsl_ir_writer_collect_body_local_declarations(
case.body,
function,
elided_local_alias_targets,
order,
seen,
)
}
Loop(body, continuing, _) => {
wgsl_ir_writer_collect_body_local_declarations(
body, function, elided_local_alias_targets, order, seen,
)
wgsl_ir_writer_collect_body_local_declarations(
continuing, function, elided_local_alias_targets, order, seen,
)
}
_ => ()
}
}
}
///|
fn wgsl_ir_writer_local_declaration_is_hoistable(
function : Function,
elided_local_alias_targets : Map[Int, Handle],
index : Int,
) -> Bool {
if elided_local_alias_targets.get(index) != None {
return false
}
match function.local_variables.items.get(index) {
Some(local_var) => local_var.kind == Var && !local_var.generated_temporary
None => false
}
}
///|
fn wgsl_ir_writer_function_temporary_initializer_expression_indices(
function : Function,
) -> @set.Set[Int] {
let indices : @set.Set[Int] = Set([])
for local_var in function.local_variables.items {
if local_var.generated_temporary {
match local_var.init {
Some(init) => indices.add(init.index())
None => ()
}
}
}
indices
}
///|
fn wgsl_ir_writer_function_body_has_non_hoisted_statement(
function : Function,
elided_local_alias_targets : Map[Int, Handle],
) -> Bool {
for statement in function.body.statements {
if !wgsl_ir_statement_is_writer_elided_local_alias_declaration(
elided_local_alias_targets, statement,
) &&
!wgsl_ir_body_statement_is_hoisted_local_var_declaration(
function, statement,
) {
return true
}
}
false
}
///|
fn wgsl_ir_statement_is_writer_elided_local_alias_declaration(
elided_local_alias_targets : Map[Int, Handle],
statement : Statement,
) -> Bool {
match statement {
Declare(handle) => elided_local_alias_targets.get(handle.index()) != None
_ => false
}
}
///|
fn WgslIrFinalNamePlan::allocate_function_body_names_from_arena(
self : WgslIrFinalNamePlan,
shader_module : Module,
origin : WgslIrEmitFunctionOrigin,
function : Function,
function_plan : WgslIrFunctionWriterPlan,
namer : WgslIrWriterNamer,
compatibility : WgslNagaCompatibilityView,
local_spelling_mode : WgslNagaLocalSpellingMode,
) -> Unit {
let temp_namer = WgslIrWriterNamer::WgslIrWriterNamer()
self.allocate_function_expression_temporary_names(
origin, function, function_plan, temp_namer,
)
for named in function.named_expressions {
let key = wgsl_ir_emit_named_expression_name_key(origin, named.handle)
if self.names.get(key) == None {
self.names.set(
key,
namer.local_call(
temp_namer,
compatibility.spelling_for_mode(named.name, local_spelling_mode),
),
)
}
}
for local_index in 0..
self.expression_alias_name(
shader_module, origin, function, function_plan, target,
)
None =>
if local_var.generated_temporary {
match local_var.init {
Some(init) =>
self.names.get(
wgsl_ir_emit_expression_temporary_name_key(origin, init),
)
None => None
}
} else {
let raw_name = match local_var.name {
Some(name) =>
Some(compatibility.spelling_for_mode(name, local_spelling_mode))
None => None
}
Some(namer.local_call_or(temp_namer, raw_name, "local"))
}
}
match local_name {
Some(name) => self.names.set(local_key, name)
None => ()
}
}
}
///|
fn WgslIrFinalNamePlan::expression_alias_name(
self : WgslIrFinalNamePlan,
shader_module : Module,
origin : WgslIrEmitFunctionOrigin,
function : Function,
function_plan : WgslIrFunctionWriterPlan,
handle : Handle,
) -> String? {
match function.expressions.items.get(handle.index()) {
Some(FunctionArgument(index)) =>
match origin {
UserFunction(function_index) =>
self.names.get(
wgsl_ir_emit_name_key2("fn_arg", function_index, index),
)
EntryPointFunction(entry_point_index) =>
self.names.get(
wgsl_ir_emit_name_key2("ep_arg", entry_point_index, index),
)
}
Some(LocalVariable(local_handle)) =>
match function_plan.elided_local_alias_target(local_handle) {
Some(target) =>
self.expression_alias_name(
shader_module, origin, function, function_plan, target,
)
None =>
self.names.get(wgsl_ir_emit_local_name_key(origin, local_handle))
}
Some(Swizzle(_, base, components)) =>
match
self.expression_alias_name(
shader_module, origin, function, function_plan, base,
) {
Some(base_name) =>
Some("\{base_name}.\{wgsl_ir_writer_swizzle_components(components)}")
None => None
}
Some(Component(base, component)) =>
match
self.expression_alias_name(
shader_module, origin, function, function_plan, base,
) {
Some(base_name) =>
Some("\{base_name}.\{wgsl_ir_swizzle_component_name(component)}")
None => None
}
Some(AccessIndex(base, index)) =>
match
self.expression_alias_name(
shader_module, origin, function, function_plan, base,
) {
Some(base_name) =>
match
wgsl_ir_writer_access_index_alias_suffix(
shader_module, function, base, index,
) {
Some(suffix) => Some("\{base_name}\{suffix}")
None => None
}
None => None
}
_ =>
self.names.get(wgsl_ir_emit_expression_temporary_name_key(origin, handle))
}
}
///|
fn wgsl_ir_writer_swizzle_components(
components : Array[SwizzleComponent],
) -> String {
let out = StringBuilder::new()
for component in components {
out.write_string(wgsl_ir_swizzle_component_name(component))
}
out.to_string()
}
///|
fn wgsl_ir_writer_access_index_alias_suffix(
shader_module : Module,
function : Function,
base : Handle,
index : Int,
) -> String? {
guard wgsl_ir_writer_alias_expression_is_vector(shader_module, function, base) else {
return None
}
match index {
0 => Some(".x")
1 => Some(".y")
2 => Some(".z")
3 => Some(".w")
_ => None
}
}
///|
fn WgslIrFinalNamePlan::reserve_function_var_local_names_from_arena(
self : WgslIrFinalNamePlan,
origin : WgslIrEmitFunctionOrigin,
function : Function,
function_plan : WgslIrFunctionWriterPlan,
namer : WgslIrWriterNamer,
compatibility : WgslNagaCompatibilityView,
local_spelling_mode : WgslNagaLocalSpellingMode,
) -> Unit {
let temp_namer = WgslIrWriterNamer::WgslIrWriterNamer()
for local_index in function_plan.local_declaration_order() {
let local_handle = Handle::Handle(local_index)
let local_var = function.local_variables.items[local_index]
if local_var.kind == Var && !local_var.generated_temporary {
let key = wgsl_ir_emit_local_name_key(origin, local_handle)
if self.names.get(key) == None {
let raw_name = match local_var.name {
Some(name) =>
Some(compatibility.spelling_for_mode(name, local_spelling_mode))
None => None
}
self.names.set(key, namer.local_call_or(temp_namer, raw_name, "local"))
}
}
}
}
///|
fn WgslIrFinalNamePlan::allocate_function_expression_temporary_names(
self : WgslIrFinalNamePlan,
origin : WgslIrEmitFunctionOrigin,
function : Function,
function_plan : WgslIrFunctionWriterPlan,
temp_namer : WgslIrWriterNamer,
) -> Unit {
for expr_index in 0.. Map[Int, Handle] {
let targets : Map[Int, Handle] = Map([])
let mut changed = true
while changed {
changed = false
for local_index in 0.. {
targets.set(local_index, target)
changed = true
}
None => ()
}
}
}
}
targets
}
///|
fn wgsl_ir_writer_local_alias_target_expression(
function : Function,
shader_module : Module,
materialized_expressions : @set.Set[Int],
known_targets : Map[Int, Handle],
projection_aliases : Bool,
local_handle : Handle,
) -> Handle? {
guard function.local_variables.items.get(local_handle.index())
is Some(local_var) else {
return None
}
guard local_var.kind == Let else { return None }
guard !local_var.generated_temporary else { return None }
guard local_var.init is Some(init) else { return None }
wgsl_ir_writer_expression_alias_target(
function, shader_module, materialized_expressions, known_targets, projection_aliases,
local_handle, init,
)
}
///|
fn wgsl_ir_writer_expression_alias_target(
function : Function,
shader_module : Module,
materialized_expressions : @set.Set[Int],
known_targets : Map[Int, Handle],
projection_aliases : Bool,
local_handle : Handle,
expression_handle : Handle,
) -> Handle? {
if materialized_expressions.contains(expression_handle.index()) {
return Some(expression_handle)
}
match function.expressions.items.get(expression_handle.index()) {
Some(Swizzle(_, base, _)) if projection_aliases =>
if wgsl_ir_writer_local_alias_is_forwarded_by_local_declaration(
function, local_handle,
) &&
wgsl_ir_writer_expression_projection_base_has_alias_target(
function, materialized_expressions, known_targets, base,
) {
Some(expression_handle)
} else {
None
}
Some(Component(base, _)) if projection_aliases =>
if wgsl_ir_writer_local_alias_is_forwarded_by_local_declaration(
function, local_handle,
) &&
wgsl_ir_writer_expression_projection_base_has_alias_target(
function, materialized_expressions, known_targets, base,
) {
Some(expression_handle)
} else {
None
}
Some(AccessIndex(base, index)) if projection_aliases =>
if wgsl_ir_writer_local_alias_is_forwarded_by_local_declaration(
function, local_handle,
) &&
wgsl_ir_writer_expression_projection_base_has_alias_target(
function, materialized_expressions, known_targets, base,
) &&
wgsl_ir_writer_access_index_alias_suffix(
shader_module, function, base, index,
) !=
None {
Some(expression_handle)
} else {
None
}
Some(FunctionArgument(_)) => Some(expression_handle)
Some(LocalVariable(local_handle)) =>
match known_targets.get(local_handle.index()) {
Some(target) =>
if projection_aliases &&
wgsl_ir_writer_expression_is_projection(function, target) {
None
} else {
Some(target)
}
None =>
match function.local_variables.items.get(local_handle.index()) {
Some(local_var) =>
if local_var.generated_temporary {
match local_var.init {
Some(init) =>
if materialized_expressions.contains(init.index()) {
Some(init)
} else {
None
}
None => None
}
} else {
None
}
None => None
}
}
_ => None
}
}
///|
fn wgsl_ir_writer_expression_is_projection(
function : Function,
handle : Handle,
) -> Bool {
match function.expressions.items.get(handle.index()) {
Some(Swizzle(_, _, _)) | Some(Component(_, _)) | Some(AccessIndex(_, _)) =>
true
_ => false
}
}
///|
fn wgsl_ir_writer_local_alias_is_forwarded_by_local_declaration(
function : Function,
local_handle : Handle,
) -> Bool {
let mut reference_count = 0
for expression in function.expressions.items {
if expression == LocalVariable(local_handle) {
reference_count += 1
}
}
if reference_count != 1 {
return false
}
for local_var in function.local_variables.items {
match local_var.init {
Some(init) =>
if wgsl_ir_expression_graph_contains_local_variable(
function, init, local_handle,
) {
return true
}
None => ()
}
}
false
}
///|
fn wgsl_ir_expression_graph_contains_local_variable(
function : Function,
root : Handle,
local_handle : Handle,
) -> Bool {
match function.expressions.items.get(root.index()) {
Some(LocalVariable(handle)) => handle == local_handle
Some(Load(inner))
| Some(AddressOf(_, inner))
| Some(Splat(_, inner))
| Some(Swizzle(_, inner, _))
| Some(Component(inner, _))
| Some(AccessIndex(inner, _)) =>
wgsl_ir_expression_graph_contains_local_variable(
function, inner, local_handle,
)
Some(Access(base, index)) =>
wgsl_ir_expression_graph_contains_local_variable(
function, base, local_handle,
) ||
wgsl_ir_expression_graph_contains_local_variable(
function, index, local_handle,
)
Some(Unary(_, inner)) =>
wgsl_ir_expression_graph_contains_local_variable(
function, inner, local_handle,
)
Some(Binary(_, left, right)) =>
wgsl_ir_expression_graph_contains_local_variable(
function, left, local_handle,
) ||
wgsl_ir_expression_graph_contains_local_variable(
function, right, local_handle,
)
_ => false
}
}
///|
fn wgsl_ir_writer_expression_projection_base_has_alias_target(
function : Function,
materialized_expressions : @set.Set[Int],
known_targets : Map[Int, Handle],
base : Handle,
) -> Bool {
if materialized_expressions.contains(base.index()) {
return true
}
match function.expressions.items.get(base.index()) {
Some(Swizzle(_, inner, _)) =>
wgsl_ir_writer_expression_projection_base_has_alias_target(
function, materialized_expressions, known_targets, inner,
)
Some(Component(inner, _)) =>
wgsl_ir_writer_expression_projection_base_has_alias_target(
function, materialized_expressions, known_targets, inner,
)
Some(AccessIndex(inner, _)) =>
wgsl_ir_writer_expression_projection_base_has_alias_target(
function, materialized_expressions, known_targets, inner,
)
_ => false
}
}
///|
fn wgsl_ir_writer_alias_expression_is_vector(
shader_module : Module,
function : Function,
handle : Handle,
) -> Bool {
match function.expressions.items.get(handle.index()) {
Some(FunctionArgument(index)) =>
match function.arguments.get(index) {
Some(argument) =>
wgsl_ir_writer_type_handle_is_vector(shader_module, argument.ty)
None => false
}
Some(LocalVariable(local_handle)) =>
match function.local_variables.items.get(local_handle.index()) {
Some(local_var) =>
wgsl_ir_writer_type_handle_is_vector(shader_module, local_var.ty)
None => false
}
Some(Load(pointer)) =>
match
wgsl_ir_writer_expression_type_handle(shader_module, function, pointer) {
Some(ty) =>
wgsl_ir_writer_type_handle_is_vector(
shader_module,
wgsl_ir_writer_deref_pointer_type_handle(shader_module, ty),
)
None => false
}
Some(ImageLoad(image, _, _, _, _)) =>
wgsl_ir_writer_image_load_result_is_vector(shader_module, function, image)
Some(Swizzle(size, _, _)) => size.width() > 1
_ => false
}
}
///|
fn wgsl_ir_writer_expression_type_handle(
shader_module : Module,
function : Function,
handle : Handle,
) -> Handle? {
match function.expressions.items.get(handle.index()) {
Some(FunctionArgument(index)) =>
match function.arguments.get(index) {
Some(argument) => Some(argument.ty)
None => None
}
Some(LocalVariable(local_handle)) =>
match function.local_variables.items.get(local_handle.index()) {
Some(local_var) => Some(local_var.ty)
None => None
}
Some(GlobalVariable(global_handle)) =>
match shader_module.global_variables.items.get(global_handle.index()) {
Some(global) => Some(global.ty)
None => None
}
Some(Load(pointer)) =>
match
wgsl_ir_writer_expression_type_handle(shader_module, function, pointer) {
Some(ty) =>
Some(wgsl_ir_writer_deref_pointer_type_handle(shader_module, ty))
None => None
}
_ => None
}
}
///|
fn wgsl_ir_writer_type_handle_is_vector(
shader_module : Module,
ty : Handle,
) -> Bool {
match shader_module.types.items.get(ty.index()) {
Some({ inner: Vector(_, _), .. }) => true
_ => false
}
}
///|
fn wgsl_ir_writer_deref_pointer_type_handle(
shader_module : Module,
ty : Handle,
) -> Handle {
match shader_module.types.items.get(ty.index()) {
Some({ inner: Pointer(inner, _) | BindingArray(inner, _), .. }) => inner
_ => ty
}
}
///|
fn wgsl_ir_writer_image_load_result_is_vector(
shader_module : Module,
function : Function,
image : Handle,
) -> Bool {
match wgsl_ir_writer_expression_type_handle(shader_module, function, image) {
Some(image_ty) =>
match shader_module.types.items.get(image_ty.index()) {
Some({ inner: Image(_, _, _), .. }) => true
_ => false
}
None => false
}
}
///|
fn wgsl_ir_function_materialized_expression_indices(
function : Function,
) -> @set.Set[Int] {
let indices : @set.Set[Int] = Set([])
for local_var in function.local_variables.items {
if local_var.generated_temporary {
match local_var.init {
Some(init) => indices.add(init.index())
None => ()
}
}
}
wgsl_ir_collect_statement_materialized_expression_indices(
function.body,
indices,
)
for expr_index in 0.. indices.add(expr_index)
_ => ()
}
}
indices
}
///|
fn wgsl_ir_collect_statement_materialized_expression_indices(
block : Block,
indices : @set.Set[Int],
) -> Unit {
for statement in block.statements {
match statement {
Block(child) =>
wgsl_ir_collect_statement_materialized_expression_indices(
child, indices,
)
If(_, accept, reject) => {
wgsl_ir_collect_statement_materialized_expression_indices(
accept, indices,
)
wgsl_ir_collect_statement_materialized_expression_indices(
reject, indices,
)
}
Switch(_, cases) =>
for case in cases {
wgsl_ir_collect_statement_materialized_expression_indices(
case.body,
indices,
)
}
Loop(body, continuing, _) => {
wgsl_ir_collect_statement_materialized_expression_indices(body, indices)
wgsl_ir_collect_statement_materialized_expression_indices(
continuing, indices,
)
}
Call(_, _, Some(result)) | Atomic(_, _, _, _, Some(result)) =>
indices.add(result.index())
_ => ()
}
}
}
///|
fn wgsl_ir_emit_expression_temporary_index(
function : Function,
function_plan : WgslIrFunctionWriterPlan,
handle : Handle,
) -> Int {
wgsl_ir_emit_expression_temporary_index_trace(function, function_plan, handle).final_index
}
///|
fn wgsl_ir_emit_expression_temporary_index_trace(
function : Function,
function_plan : WgslIrFunctionWriterPlan,
handle : Handle,
) -> WgslIrTemporaryIndexTrace {
let mut skipped = 0
for index in 0.. 0 {
reused_resource_operand_slots
} else {
0
}
let final_index = adjusted_base_index +
implicit_expression_slots_before +
prior_call_projection_argument_slots +
implicit_load_slots +
reused_resource_operand_slots +
projected_temporary_slots
{
skipped,
base_index,
adjusted_base_index,
implicit_expression_slots_before,
prior_call_projection_argument_slots,
implicit_load_slots,
reused_resource_operand_slots,
projected_temporary_slots,
final_index,
}
}
///|
fn wgsl_naga_function_expression_is_synthetic_local_reference(
function : Function,
handle : Handle,
) -> Bool {
match function.expressions.items.get(handle.index()) {
Some(Load(inner)) =>
wgsl_naga_function_expression_is_synthetic_local_reference(
function, inner,
)
Some(LocalVariable(local_handle)) =>
match function.local_variables.items.get(local_handle.index()) {
Some(local_var) =>
if local_var.kind != Let {
false
} else if local_var.generated_temporary {
true
} else {
true
}
None => false
}
_ => false
}
}
///|
fn wgsl_ir_emit_atomic_value_operand_slot_adjustment(
function : Function,
handle : Handle,
) -> Int {
guard function.expressions.items.get(handle.index()) is Some(Load(_)) else {
return 0
}
guard wgsl_ir_function_materialized_expression_indices(function).contains(
handle.index(),
) else {
return 0
}
for statement in function.body.statements {
if wgsl_ir_statement_uses_handle_as_atomic_value(
function, statement, handle,
) {
return 1
}
}
0
}
///|
fn wgsl_ir_statement_uses_handle_as_atomic_value(
function : Function,
statement : Statement,
handle : Handle,
) -> Bool {
match statement {
Atomic(_, _, value, _, result) =>
value == handle && result == Some(Handle(handle.index() + 1))
Block(block) =>
wgsl_ir_block_uses_handle_as_atomic_value(function, block, handle)
If(_, accept, reject) =>
wgsl_ir_block_uses_handle_as_atomic_value(function, accept, handle) ||
wgsl_ir_block_uses_handle_as_atomic_value(function, reject, handle)
Switch(_, cases) => {
for case in cases {
if wgsl_ir_block_uses_handle_as_atomic_value(
function,
case.body,
handle,
) {
return true
}
}
false
}
Loop(body, continuing, _) =>
wgsl_ir_block_uses_handle_as_atomic_value(function, body, handle) ||
wgsl_ir_block_uses_handle_as_atomic_value(function, continuing, handle)
_ => false
}
}
///|
fn wgsl_ir_block_uses_handle_as_atomic_value(
function : Function,
block : Block,
handle : Handle,
) -> Bool {
for statement in block.statements {
if wgsl_ir_statement_uses_handle_as_atomic_value(
function, statement, handle,
) {
return true
}
}
false
}
///|
fn wgsl_ir_writer_function_implicit_expression_slots_before(
shader_module : Module,
function : Function,
) -> Array[Int] {
let offsets : Array[Int] = []
let mut offset = 0
for index in 0..
offset += wgsl_ir_writer_compose_implicit_expression_slots(
shader_module, ty, components,
)
_ => ()
}
}
offsets
}
///|
fn wgsl_ir_writer_compose_implicit_expression_slots(
shader_module : Module,
ty : Handle,
components : Array[Handle],
) -> Int {
match shader_module.types.items.get(ty.index()) {
Some(type_) =>
match type_.inner {
Matrix(columns, rows, _) =>
if components.length() == columns.width() * rows.width() {
columns.width()
} else {
0
}
_ => 0
}
None => 0
}
}
///|
fn wgsl_ir_function_expression_is_projection_graph_node(
function : Function,
handle : Handle,
) -> Bool {
match function.expressions.items.get(handle.index()) {
Some(Load(_))
| Some(Access(_, _))
| Some(AccessIndex(_, _))
| Some(Component(_, _))
| Some(Swizzle(_, _, _)) => true
_ => false
}
}
///|
fn wgsl_ir_emit_implicit_load_slot_offset(
function : Function,
function_plan : WgslIrFunctionWriterPlan,
limit : Handle,
) -> Int {
let mut offset = 0
for index in 0..<=limit.index() {
let handle = Handle::Handle(index)
if function_plan.contains_materialized_expression(handle) &&
wgsl_ir_emit_expression_has_implicit_load_slot(function, handle) {
offset += 1
}
}
offset
}
///|
fn wgsl_ir_emit_expression_has_implicit_load_slot(
function : Function,
handle : Handle,
) -> Bool {
match function.expressions.items.get(handle.index()) {
Some(AccessIndex(base, _)) | Some(Component(base, _)) =>
wgsl_ir_emit_expression_is_dynamic_pointer_access(function, base)
_ => false
}
}
///|
fn wgsl_ir_emit_expression_is_dynamic_pointer_access(
function : Function,
handle : Handle,
) -> Bool {
match function.expressions.items.get(handle.index()) {
Some(Access(_, _)) => true
Some(AccessIndex(base, _)) | Some(Component(base, _)) =>
wgsl_ir_emit_expression_is_dynamic_pointer_access(function, base)
_ => false
}
}
///|
fn wgsl_ir_emit_reused_resource_operand_slot_offset(
function : Function,
limit : Handle,
) -> Int {
let seen : Map[Int, Int] = Map([])
let mut offset = 0
for index in 0..<=limit.index() {
match function.expressions.items.get(index) {
Some(ImageSample(image, sampler, _, _, _, _, _, _, _)) => {
let sample_depth = wgsl_ir_function_expression_statement_depth(
function,
Handle(index),
)
offset += wgsl_ir_emit_reused_resource_operand_slot(
function, seen, sample_depth, image,
)
offset += wgsl_ir_emit_reused_resource_operand_slot(
function, seen, sample_depth, sampler,
)
}
_ => ()
}
}
offset
}
///|
fn wgsl_ir_emit_reused_resource_operand_slot(
function : Function,
seen : Map[Int, Int],
sample_depth : Int,
handle : Handle,
) -> Int {
guard wgsl_ir_emit_expression_is_global_resource(function, handle) else {
return 0
}
let index = handle.index()
match seen.get(index) {
Some(first_depth) => if first_depth == sample_depth { 0 } else { 1 }
None => {
seen.set(index, sample_depth)
0
}
}
}
///|
fn wgsl_ir_function_expression_statement_depth(
function : Function,
handle : Handle,
) -> Int {
match wgsl_ir_block_expression_statement_depth(function.body, handle, 0) {
Some(depth) => depth
None => -1
}
}
///|
fn wgsl_ir_block_expression_statement_depth(
block : Block,
handle : Handle,
depth : Int,
) -> Int? {
for statement in block.statements {
match wgsl_ir_statement_expression_depth(statement, handle, depth) {
Some(found) => return Some(found)
None => ()
}
}
None
}
///|
fn wgsl_ir_statement_expression_depth(
statement : Statement,
handle : Handle,
depth : Int,
) -> Int? {
match statement {
Emit(range) =>
if range.start.index() <= handle.index() &&
handle.index() <= range.end.index() {
Some(depth)
} else {
None
}
Store(target, value) =>
if target == handle || value == handle {
Some(depth)
} else {
None
}
Phony(value) | Return(Some(value)) | ConstAssert(value) =>
if value == handle {
Some(depth)
} else {
None
}
If(condition, accept, reject) =>
if condition == handle {
Some(depth)
} else {
match
wgsl_ir_block_expression_statement_depth(accept, handle, depth + 1) {
Some(found) => Some(found)
None =>
wgsl_ir_block_expression_statement_depth(reject, handle, depth + 1)
}
}
Loop(body, continuing, break_if) =>
match break_if {
Some(value) if value == handle => Some(depth)
_ =>
match
wgsl_ir_block_expression_statement_depth(body, handle, depth + 1) {
Some(found) => Some(found)
None =>
wgsl_ir_block_expression_statement_depth(
continuing,
handle,
depth + 1,
)
}
}
Block(child) =>
wgsl_ir_block_expression_statement_depth(child, handle, depth + 1)
Switch(selector, cases) =>
if selector == handle {
Some(depth)
} else {
for case in cases {
match
wgsl_ir_block_expression_statement_depth(
case.body,
handle,
depth + 1,
) {
Some(found) => return Some(found)
None => ()
}
}
None
}
ImageStore(image, coordinate, array_index, value) =>
if image == handle ||
coordinate == handle ||
value == handle ||
array_index == Some(handle) {
Some(depth)
} else {
None
}
ImageAtomic(image, coordinate, array_index, _, value) =>
if image == handle ||
coordinate == handle ||
value == handle ||
array_index == Some(handle) {
Some(depth)
} else {
None
}
Atomic(pointer, _, value, compare, result) =>
if pointer == handle ||
value == handle ||
compare == Some(handle) ||
result == Some(handle) {
Some(depth)
} else {
None
}
WorkGroupUniformLoad(pointer, result) =>
if pointer == handle || result == handle {
Some(depth)
} else {
None
}
Call(callee, arguments, result) =>
if callee == handle ||
arguments.any(fn(argument) { argument == handle }) ||
result == Some(handle) {
Some(depth)
} else {
None
}
RayQuery(query, ray_function) =>
if query == handle ||
wgsl_ir_ray_query_statement_function_contains_handle(
ray_function, handle,
) {
Some(depth)
} else {
None
}
RayPipelineFunction(ray_function) =>
if wgsl_ir_ray_pipeline_statement_function_contains_handle(
ray_function, handle,
) {
Some(depth)
} else {
None
}
SubgroupBallot(value, result) =>
if value == handle || result == Some(handle) {
Some(depth)
} else {
None
}
SubgroupGather(_, value, result) =>
if value == handle || result == handle {
Some(depth)
} else {
None
}
SubgroupCollectiveOperation(_, _, value, result) =>
if value == handle || result == handle {
Some(depth)
} else {
None
}
CooperativeStore(pointer, data) =>
if pointer == handle ||
wgsl_ir_cooperative_store_data_contains_handle(data, handle) {
Some(depth)
} else {
None
}
ControlBarrier(_)
| MemoryBarrier(_)
| Declare(_)
| Break
| Continue
| Kill
| Return(None)
| ImplicitReturn => None
}
}
///|
fn wgsl_ir_ray_query_statement_function_contains_handle(
ray_function : RayQueryFunction,
handle : Handle,
) -> Bool {
match ray_function {
Initialize(ray, flags) => ray == handle || flags == handle
Proceed(value) | GenerateIntersection(value) => value == handle
ConfirmIntersection | Terminate => false
}
}
///|
fn wgsl_ir_ray_pipeline_statement_function_contains_handle(
ray_function : RayPipelineFunction,
handle : Handle,
) -> Bool {
match ray_function {
TraceRay(a, b, c) => a == handle || b == handle || c == handle
}
}
///|
fn wgsl_ir_cooperative_store_data_contains_handle(
data : CooperativeData,
handle : Handle,
) -> Bool {
data.pointer == handle || data.stride == handle
}
///|
fn wgsl_ir_emit_expression_is_global_resource(
function : Function,
handle : Handle,
) -> Bool {
match function.expressions.items.get(handle.index()) {
Some(GlobalVariable(_)) => true
_ => false
}
}
///|