///|
fn WgslIrLowerer::lower_global_expression_ref(
self : WgslIrLowerer,
expr_ref : @ast.WgslExprRef,
) -> Handle raise WgslIrLowerError {
self.lower_global_expression_ref_with_expected(expr_ref, None)
}
///|
fn WgslIrLowerer::lower_global_expression_ref_with_expected(
self : WgslIrLowerer,
expr_ref : @ast.WgslExprRef,
expected_ty : Handle?,
) -> Handle raise WgslIrLowerError {
guard expr_ref.root() is Some(root) else {
raise UnsupportedExpression("empty global expression")
}
self.lower_global_expression_node_with_expected(root, expected_ty)
}
///|
fn WgslIrLowerer::lower_global_expression_node(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
) -> Handle raise WgslIrLowerError {
self.lower_global_expression_node_with_expected(node, None)
}
///|
fn WgslIrLowerer::lower_global_expression_node_with_expected(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
expected_ty : Handle?,
) -> Handle raise WgslIrLowerError {
self.shader_module.append_global_expression(
self.lower_expression_node_to_global_expression_with_expected(
node, expected_ty,
),
)
}
///|
fn WgslIrLowerer::lower_expression_node_to_global_expression_with_expected(
self : WgslIrLowerer,
node : @ast.WgslExprNode,
expected_ty : Handle?,
) -> Expression raise WgslIrLowerError {
match node.kind() {
Literal(token) =>
Literal(self.literal_from_token_with_expected(token, expected_ty))
Identifier(name) => self.global_identifier_expression(name)
Unary(op, expr) =>
if op == Subtract {
match expr.kind() {
Literal(token) =>
match
self.negated_literal_from_token_with_expected(token, expected_ty) {
Some(literal) => Literal(literal)
None =>
Unary(
wgsl_ir_unary_operator(op),
self.lower_global_expression_node(expr),
)
}
_ =>
Unary(
wgsl_ir_unary_operator(op),
self.lower_global_expression_node(expr),
)
}
} else {
Unary(
wgsl_ir_unary_operator(op),
self.lower_global_expression_node(expr),
)
}
Binary(op, left, right) => {
let binary_op = wgsl_ir_binary_operator(op)
let left_handle = self.lower_global_expression_node(left)
let right_handle = self.lower_global_expression_node(right)
let (left_handle, right_handle) = self.normalize_global_binary_operands(
binary_op, left_handle, right_handle,
)
Binary(binary_op, left_handle, right_handle)
}
Group(expr) =>
self.lower_expression_node_to_global_expression_with_expected(
expr, expected_ty,
)
Sequence([single]) =>
self.lower_expression_node_to_global_expression_with_expected(
single, expected_ty,
)
Member(base, member_name) => {
let base_handle = self.lower_global_expression_node(base)
self.lower_global_member_expression(base_handle, member_name.name())
}
Index(base, index) =>
Access(
self.lower_global_expression_node(base),
self.lower_global_expression_node(index),
)
Call(callee, arguments) => {
let arguments = wgsl_ir_call_arguments(arguments)
match self.lower_bitcast_callee_type(callee) {
Some(ty) => self.lower_global_bitcast_call(ty, arguments)
None =>
match callee.kind() {
Identifier(name) =>
if name.name() == "select" {
self.lower_global_select_call(arguments)
} else if wgsl_ir_barrier_builtin_from_name(name.name())
is Some(_) {
raise wgsl_ir_barrier_value_error(name.name())
} else {
match wgsl_ir_math_function_from_name(name.name()) {
Some(math_function) =>
self.lower_global_math_call(math_function, arguments)
None =>
match wgsl_ir_relational_function_from_name(name.name()) {
Some(relational_function) =>
self.lower_global_relational_call(
relational_function, arguments,
)
None =>
if name.name() == "array" {
self.lower_global_array_constructor_call(
expected_ty, arguments,
)
} else {
let ty = match
self.expected_constructor_type(
name.name(),
expected_ty,
) {
Some(ty) => ty
None =>
self.lower_untemplated_constructor_type_from_ast(
name.name(),
arguments,
name.name(),
)
}
Compose(
ty,
self.lower_global_expression_arguments(arguments),
)
}
}
}
}
_ =>
match self.lower_templated_callee_type(callee) {
Some(ty) =>
Compose(
ty,
self.lower_global_constructor_arguments(ty, arguments),
)
None =>
raise UnsupportedExpression(
"non-identifier global call expression: \{wgsl_ir_expr_node_shape(callee)}",
)
}
}
}
}
_ =>
raise UnsupportedExpression(
"global expression kind is not constant-lowerable",
)
}
}
///|
fn WgslIrLowerer::lower_global_member_expression(
self : WgslIrLowerer,
base_handle : Handle,
member_name : String,
) -> Expression raise WgslIrLowerError {
match self.global_expression_type(base_handle) {
Some(ty_handle) =>
match
self.shader_module.types.get(self.deref_pointer_type_handle(ty_handle)) {
Some(ty) =>
match ty.inner {
Vector(_, _) =>
match wgsl_ir_swizzle_components(member_name) {
Some(components) =>
if components.length() == 1 {
AccessIndex(
base_handle,
wgsl_ir_gather_component_index(components[0]),
)
} else {
Swizzle(
wgsl_ir_vector_size_from_component_count(
components.length(),
),
base_handle,
components,
)
}
None =>
raise UnsupportedExpression(
"invalid vector swizzle: \{member_name}",
)
}
_ =>
AccessIndex(
base_handle,
self.member_index_for_global_expression(
base_handle, member_name,
),
)
}
None =>
AccessIndex(
base_handle,
self.member_index_for_global_expression(base_handle, member_name),
)
}
None =>
AccessIndex(
base_handle,
self.member_index_for_global_expression(base_handle, member_name),
)
}
}
///|
fn WgslIrLowerer::normalize_global_binary_operands(
self : WgslIrLowerer,
op : BinaryOperator,
left : Handle,
right : Handle,
) -> (Handle, Handle) {
guard wgsl_ir_binary_operator_requires_vector_splat(op) else {
return (left, right)
}
guard self.global_expression_type(left) is Some(left_ty) else {
return (left, right)
}
guard self.global_expression_type(right) is Some(right_ty) else {
return (left, right)
}
match self.vector_size_from_type(left_ty) {
Some(size) if self.type_is_scalar(right_ty) =>
(left, self.shader_module.global_expressions.append(Splat(size, right)))
_ =>
match self.vector_size_from_type(right_ty) {
Some(size) if self.type_is_scalar(left_ty) =>
(
self.shader_module.global_expressions.append(Splat(size, left)),
right,
)
_ => (left, right)
}
}
}
///|
fn WgslIrLowerer::lower_global_select_call(
self : WgslIrLowerer,
arguments : Array[@ast.WgslExprNode],
) -> Expression raise WgslIrLowerError {
let arguments = wgsl_ir_flatten_expression_arguments(arguments)
guard arguments is [reject, accept, condition] else {
raise UnsupportedExpression("select expects three arguments")
}
Select(
self.lower_global_expression_node(condition),
self.lower_global_expression_node(accept),
self.lower_global_expression_node(reject),
)
}
///|
fn WgslIrLowerer::lower_global_bitcast_call(
self : WgslIrLowerer,
ty : Handle,
arguments : Array[@ast.WgslExprNode],
) -> Expression raise WgslIrLowerError {
let arguments = wgsl_ir_flatten_expression_arguments(arguments)
guard arguments is [expr] else {
raise UnsupportedExpression("bitcast expects one argument")
}
Bitcast(ty, self.lower_global_expression_node(expr))
}
///|
fn WgslIrLowerer::lower_global_array_constructor_call(
self : WgslIrLowerer,
expected_ty : Handle?,
arguments : Array[@ast.WgslExprNode],
) -> Expression raise WgslIrLowerError {
let ty = match expected_ty {
Some(ty) => ty
None => self.infer_array_constructor_type_from_ast(arguments, "array")
}
guard self.array_element_type(ty) is Some(element_ty) else {
raise UnsupportedType("array")
}
Compose(
ty,
self.lower_global_expression_arguments_with_expected(
arguments,
Some(element_ty),
),
)
}
///|
fn WgslIrLowerer::lower_global_expression_arguments(
self : WgslIrLowerer,
arguments : Array[@ast.WgslExprNode],
) -> Array[Handle] raise WgslIrLowerError {
self.lower_global_expression_arguments_with_expected(arguments, None)
}
///|
fn WgslIrLowerer::lower_global_expression_arguments_with_expected(
self : WgslIrLowerer,
arguments : Array[@ast.WgslExprNode],
expected_ty : Handle?,
) -> Array[Handle] raise WgslIrLowerError {
let handles : Array[Handle] = []
for argument in wgsl_ir_flatten_expression_arguments(arguments) {
handles.push(
self.lower_global_expression_node_with_expected(argument, expected_ty),
)
}
handles
}
///|
fn WgslIrLowerer::lower_global_constructor_arguments(
self : WgslIrLowerer,
ty : Handle,
arguments : Array[@ast.WgslExprNode],
) -> Array[Handle] raise WgslIrLowerError {
let flattened = wgsl_ir_flatten_expression_arguments(arguments)
self.lower_global_expression_arguments_with_expected(
flattened,
self.constructor_argument_expected_type(ty, flattened.length()),
)
}
///|
fn WgslIrLowerer::lower_global_math_call(
self : WgslIrLowerer,
math_function : MathFunction,
arguments : Array[@ast.WgslExprNode],
) -> Expression raise WgslIrLowerError {
let arguments = wgsl_ir_flatten_expression_arguments(arguments)
guard arguments is [first, .. rest] else {
raise UnsupportedExpression("math call requires at least one argument")
}
let a = self.lower_global_expression_node(first)
let b = match rest {
[value, ..] => Some(self.lower_global_expression_node(value))
[] => None
}
let c = match rest {
[_, value, ..] => Some(self.lower_global_expression_node(value))
_ => None
}
let d = match rest {
[_, _, value, ..] => Some(self.lower_global_expression_node(value))
_ => None
}
Math(math_function, a, b, c, d)
}
///|
fn WgslIrLowerer::lower_global_relational_call(
self : WgslIrLowerer,
relational_function : RelationalFunction,
arguments : Array[@ast.WgslExprNode],
) -> Expression 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",
)
}
Relational(relational_function, self.lower_global_expression_node(expr))
}