///|
fn wgsl_ir_function_expression_should_use_named_let(
function : Function,
handle : Handle,
) -> Bool {
match function.expressions.items.get(handle.index()) {
Some(Literal(_))
| Some(Constant(_))
| Some(Override(_))
| Some(ZeroValue(_))
| Some(FunctionArgument(_))
| Some(GlobalVariable(_))
| Some(LocalVariable(_))
| Some(AddressOf(_, _))
| Some(FunctionCall(_, _))
| Some(AtomicCall(_, _))
| Some(WorkGroupUniformLoad(_)) => false
Some(_) => true
None => false
}
}
///|
fn wgsl_ir_function_expression_is_materialized_temporary(
function : Function,
handle : Handle,
) -> Bool {
match function.expressions.items.get(handle.index()) {
Some(CallResult(_)) => true
_ => false
}
}
///|
fn wgsl_ir_max_handle(left : Handle, right : Handle) -> Handle {
if left.index() >= right.index() {
left
} else {
right
}
}
///|
fn wgsl_ir_function_expression_is_emit_leaf(
function : Function,
handle : Handle,
) -> Bool {
match function.expressions.items.get(handle.index()) {
Some(expression) => wgsl_ir_expression_is_emit_leaf(expression)
None => false
}
}
///|
fn wgsl_ir_return_expression_should_emit_before_return(
function : Function,
expression_mark : Int32,
value : Handle,
) -> Bool {
if wgsl_ir_function_expression_has_arena_name(function, value) {
return false
}
for index in expression_mark..<=value.index() {
match function.expressions.items.get(index) {
Some(FunctionCall(_, _))
| Some(CallResult(_))
| Some(AtomicCall(_, _))
| Some(ImageSample(_, _, _, _, _, _, _, _, _))
| Some(ImageLoad(_, _, _, _, _))
| Some(ImageQuery(_, _))
| Some(WorkGroupUniformLoad(_)) => return false
_ => ()
}
}
match function.expressions.items.get(value.index()) {
Some(expression) => !wgsl_ir_expression_is_emit_leaf(expression)
None => false
}
}
///|
fn wgsl_ir_expression_is_emit_leaf(expression : Expression) -> Bool {
match expression {
Literal(_)
| Constant(_)
| Override(_)
| FunctionArgument(_)
| CallResult(_)
| AtomicResult(_, _)
| GlobalVariable(_)
| LocalVariable(_) => true
_ => false
}
}
///|
fn WgslIrLowerer::function_expression_should_materialize_as_let_initializer(
self : WgslIrLowerer,
function : Function,
value : Handle,
) -> Bool {
ignore(self)
match function.expressions.items.get(value.index()) {
Some(FunctionCall(_, _))
| Some(AtomicCall(_, _))
| Some(WorkGroupUniformLoad(_)) => true
_ => false
}
}
///|
fn WgslIrLowerer::lower_local_const_declaration(
self : WgslIrLowerer,
local_decl : @ast.WgslLocalDeclaration,
function : Function,
scope : WgslIrFunctionScope,
local_constant_placement : WgslIrLocalConstantArenaPlacement,
) -> Unit raise WgslIrLowerError {
let expression_mark = function.expressions.items.length()
let local_constant_snapshot = wgsl_ir_snapshot_local_constant_values(
scope.local_constants,
)
let explicit_ty = match local_decl.ty_ref() {
Some(ty_ref) => Some(self.lower_function_type_ref(ty_ref, function, scope))
None => None
}
let init = match local_decl.initializer_ref() {
Some(expr_ref) =>
self.lower_function_expression_ref_with_expected(
expr_ref, function, scope, explicit_ty,
)
None => raise MissingType(local_decl.name().name())
}
if !self.function_expression_is_const_expression(function, init) {
raise UnsupportedExpression(
"local const initializer is not a const expression",
)
}
let const_ty = match explicit_ty {
Some(ty) => ty
None =>
match self.function_expression_type(function, init) {
Some(ty) => ty
None =>
self.infer_local_type_from_initializer(
local_decl.name().name(),
local_decl.initializer_ref(),
)
}
}
let normalized = self.normalized_local_constant_initializer(
function,
init,
Some(const_ty),
)
function.expressions.set_origin(normalized, FoldedLocalConstant)
ignore(scope.locals.remove(local_decl.name().name()))
match local_constant_placement {
DeclarationArenaLocalConstant =>
scope.local_constants.set(
local_decl.name().name(),
wgsl_ir_local_const_value_cell(ExpressionAlias(normalized, None)),
)
UseSiteLazyLocalConstant => {
let normalized_expression = wgsl_ir_lazy_local_constant_expression(
function, normalized,
)
wgsl_ir_rewind_function_expressions_and_local_constant_values(
function, expression_mark, scope, local_constant_snapshot,
)
match local_decl.initializer_ref() {
Some(expr_ref) =>
scope.local_constants.set(
local_decl.name().name(),
wgsl_ir_local_const_value_cell(
LazyConstant({
expr_ref,
explicit_ty,
normalized: normalized_expression,
}),
),
)
None => ()
}
}
}
}
///|
fn wgsl_ir_lazy_local_constant_expression(
function : Function,
handle : Handle,
) -> WgslIrLazyLocalConstantExpression? {
match function.expressions.items.get(handle.index()) {
Some(Literal(literal)) =>
Some({ expression: Literal(literal), origin: FoldedLocalConstant, })
_ => None
}
}
///|
fn wgsl_ir_rewind_function_expressions(
function : Function,
length : Int32,
) -> Unit {
function.expressions.truncate(length)
}
///|
fn wgsl_ir_rewind_function_expressions_and_local_constant_values(
function : Function,
length : Int32,
scope : WgslIrFunctionScope,
local_constant_snapshot : Map[String, WgslIrLocalValue],
) -> Unit {
wgsl_ir_rewind_function_expressions(function, length)
wgsl_ir_restore_local_constant_values(
scope.local_constants,
local_constant_snapshot,
)
wgsl_ir_invalidate_local_constant_aliases_after_expression_rewind(
scope.local_constants,
length,
)
}
///|
fn WgslIrLowerer::local_let_const_scalar_initializer_should_fold(
self : WgslIrLowerer,
local_decl : @ast.WgslLocalDeclaration,
init_handle : Handle,
function : Function,
scope : WgslIrFunctionScope,
) -> Bool {
if !self.function_expression_is_const_expression(function, init_handle) ||
!self.function_expression_has_scalar_type(function, init_handle) {
return false
}
if wgsl_ir_function_expression_should_use_named_let(function, init_handle) {
match local_decl.initializer_ref() {
Some(expr_ref) =>
match expr_ref.root() {
Some(root) =>
if wgsl_ir_expr_node_references_local_let_constant(root, scope) {
return false
}
None => ()
}
None => ()
}
}
true
}
///|
fn WgslIrLowerer::function_expression_has_scalar_type(
self : WgslIrLowerer,
function : Function,
handle : Handle,
) -> Bool {
match self.function_expression_type(function, handle) {
Some(ty_handle) =>
match self.shader_module.types.get(ty_handle) {
Some(type_) =>
match type_.inner {
Scalar(_) => true
_ => false
}
None => false
}
None => false
}
}
///|
fn WgslIrLowerer::function_expression_is_handle_resource_value(
self : WgslIrLowerer,
function : Function,
handle : Handle,
) -> Bool {
match self.function_expression_type(function, handle) {
Some(ty) => self.type_is_global_handle_value(ty)
None => false
}
}
///|
fn WgslIrLowerer::function_expression_is_const_expression(
self : WgslIrLowerer,
function : Function,
handle : Handle,
) -> Bool {
match function.expressions.items.get(handle.index()) {
Some(expression) =>
self.function_expression_inner_is_const_expression(function, expression)
None => false
}
}
///|
fn WgslIrLowerer::function_expression_inner_is_const_expression(
self : WgslIrLowerer,
function : Function,
expression : Expression,
) -> Bool {
match expression {
Literal(_) | Constant(_) | ZeroValue(_) => true
Override(_)
| FunctionArgument(_)
| GlobalVariable(_)
| LocalVariable(_)
| Load(_)
| AddressOf(_, _)
| FunctionCall(_, _)
| AtomicCall(_, _)
| ImageSample(_, _, _, _, _, _, _, _, _)
| ImageLoad(_, _, _, _, _)
| ImageQuery(_, _)
| CallResult(_)
| AtomicResult(_, _)
| WorkGroupUniformLoadResult(_)
| WorkGroupUniformLoad(_)
| ArrayLength(_)
| RayQueryInitialize(_, _, _)
| RayQueryProceed(_)
| RayQueryGenerateIntersection(_, _)
| RayQueryConfirmIntersection(_)
| RayQueryTerminate(_)
| RayQueryVertexPositions(_, _)
| RayQueryProceedResult
| RayQueryGetIntersection(_, _)
| SubgroupCall(_, _)
| SubgroupBallotResult
| SubgroupOperationResult(_)
| CooperativeLoad(_, _, _, _)
| CooperativeMultiplyAdd(_, _, _) => false
Compose(_, components) =>
self.function_expression_list_is_const_expression(function, components)
Access(base, index) =>
self.function_expression_is_const_expression(function, base) &&
self.function_expression_is_const_expression(function, index)
AccessIndex(base, _)
| Component(base, _)
| Splat(_, base)
| Swizzle(_, base, _) =>
self.function_expression_is_const_expression(function, base)
Unary(_, inner)
| Bitcast(_, inner)
| Relational(_, inner)
| As(inner, _, _) =>
self.function_expression_is_const_expression(function, inner)
Binary(_, left, right) =>
self.function_expression_is_const_expression(function, left) &&
self.function_expression_is_const_expression(function, right)
Select(left, right, condition) =>
self.function_expression_is_const_expression(function, left) &&
self.function_expression_is_const_expression(function, right) &&
self.function_expression_is_const_expression(function, condition)
Derivative(_, _, _) => false
Math(_, first, second, third, fourth) =>
self.function_expression_is_const_expression(function, first) &&
self.optional_function_expression_is_const_expression(function, second) &&
self.optional_function_expression_is_const_expression(function, third) &&
self.optional_function_expression_is_const_expression(function, fourth)
}
}
///|
fn WgslIrLowerer::function_expression_list_is_const_expression(
self : WgslIrLowerer,
function : Function,
handles : Array[Handle],
) -> Bool {
for handle in handles {
if !self.function_expression_is_const_expression(function, handle) {
return false
}
}
true
}
///|
fn WgslIrLowerer::optional_function_expression_is_const_expression(
self : WgslIrLowerer,
function : Function,
handle : Handle?,
) -> Bool {
match handle {
Some(value) => self.function_expression_is_const_expression(function, value)
None => true
}
}