///|
fn WgslIrValidator::function_expression_type(
self : WgslIrValidator,
function : Function,
handle : Handle,
) -> Handle? {
match wgsl_ir_function_named_expression_type(function, handle) {
Some(ty) => return Some(ty)
None => ()
}
match function.expressions.items.get(handle.index()) {
Some(expression) =>
self.function_expression_inner_type(function, expression)
None => None
}
}
///|
fn WgslIrValidator::store_target_value_type(
self : WgslIrValidator,
function : Function,
handle : Handle,
) -> Handle? {
match function.expressions.items.get(handle.index()) {
Some(expression) =>
match expression {
FunctionArgument(_) =>
match self.function_expression_inner_type(function, expression) {
Some(ty) =>
if self.type_is_pointer_like(ty) &&
self.pointer_type_is_writable(ty) {
self.deref_type(ty)
} else {
None
}
None => None
}
LocalVariable(local_handle) =>
match function.local_variables.items.get(local_handle.index()) {
Some(local_variable) =>
if self.type_is_pointer_like(local_variable.ty) &&
self.pointer_type_is_writable(local_variable.ty) {
self.deref_type(local_variable.ty)
} else {
match local_variable.kind {
Var => Some(local_variable.ty)
Let => None
}
}
None => None
}
GlobalVariable(global) =>
match self.shader_module.global_variables.items.get(global.index()) {
Some(variable) =>
if self.global_address_space_is_writable(variable.space) {
Some(variable.ty)
} else {
None
}
None => None
}
Load(inner) =>
match self.function_expression_type(function, inner) {
Some(ty) =>
if self.type_is_pointer_like(ty) &&
self.pointer_type_is_writable(ty) {
self.deref_type(ty)
} else {
None
}
None => None
}
Access(_, _) | AccessIndex(_, _) | Component(_, _) | Swizzle(_, _, _) =>
if self.expression_is_addressable(function, handle) {
self.function_expression_inner_type(function, expression)
} else {
None
}
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::function_expression_value_type(
self : WgslIrValidator,
function : Function,
handle : Handle,
) -> Handle? {
match function.expressions.items.get(handle.index()) {
Some(expression) =>
match expression {
FunctionArgument(_) =>
match self.function_expression_inner_type(function, expression) {
Some(ty) =>
if self.type_is_pointer_like(ty) {
self.deref_type(ty)
} else {
None
}
None => None
}
LocalVariable(local_handle) =>
match function.local_variables.items.get(local_handle.index()) {
Some(local_variable) =>
if local_variable.kind == Var ||
self.type_is_pointer_like(local_variable.ty) {
Some(local_variable.ty)
} else {
None
}
None => None
}
GlobalVariable(global) =>
match self.shader_module.global_variables.items.get(global.index()) {
Some(variable) => Some(variable.ty)
None => None
}
Load(inner) =>
match self.function_expression_type(function, inner) {
Some(ty) =>
if self.type_is_pointer_like(ty) {
self.deref_type(ty)
} else {
None
}
None => None
}
Access(_, _) | AccessIndex(_, _) | Component(_, _) | Swizzle(_, _, _) =>
if self.expression_is_addressable(function, handle) {
self.function_expression_inner_type(function, expression)
} else {
None
}
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::function_expression_inner_type(
self : WgslIrValidator,
function : Function,
expression : Expression,
) -> Handle? {
match expression {
FunctionArgument(index) =>
match function.arguments.get(index) {
Some(argument) => Some(argument.ty)
None => None
}
LocalVariable(handle) =>
match function.local_variables.items.get(handle.index()) {
Some(local_variable) => Some(local_variable.ty)
None => None
}
GlobalVariable(handle) =>
match self.shader_module.global_variables.items.get(handle.index()) {
Some(global) => Some(global.ty)
None => None
}
Constant(handle) =>
match self.shader_module.constants.items.get(handle.index()) {
Some(constant) => Some(constant.ty)
None => None
}
Override(handle) =>
match self.shader_module.overrides.items.get(handle.index()) {
Some(override_) => Some(override_.ty)
None => None
}
Load(inner) =>
match self.function_expression_type(function, inner) {
Some(ty) => self.load_result_type(ty)
None => None
}
AddressOf(ty, _) => Some(ty)
Compose(ty, _) | ZeroValue(ty) | Bitcast(ty, _) => Some(ty)
AccessIndex(base, index) =>
match self.function_expression_type(function, base) {
Some(base_ty) => self.indexed_type(base_ty, Some(index))
None => None
}
Component(base, _) =>
match self.function_expression_type(function, base) {
Some(base_ty) => self.indexed_type(base_ty, Some(0))
None => None
}
Access(base, _) =>
match self.function_expression_type(function, base) {
Some(base_ty) => self.indexed_type(base_ty, None)
None => None
}
Splat(size, inner) =>
match self.function_expression_type(function, inner) {
Some(ty) => self.vector_type_from_scalar_type(size, ty)
None => None
}
Swizzle(size, base, _) =>
match self.function_expression_type(function, base) {
Some(ty) => self.vector_or_scalar_swizzle_type(size, ty)
None => None
}
Unary(_, inner) => self.function_expression_type(function, inner)
Binary(op, left, right) =>
self.binary_result_type(
op,
self.function_expression_type(function, left),
self.function_expression_type(function, right),
)
FunctionCall(handle, _) | CallResult(handle) =>
self.function_result_type(handle)
Select(_, accept, reject) =>
match self.function_expression_type(function, accept) {
Some(ty) => Some(ty)
None => self.function_expression_type(function, reject)
}
Derivative(_, _, expr) => self.function_expression_type(function, expr)
Relational(relational_function, expr) =>
self.relational_result_type(
relational_function,
self.function_expression_type(function, expr),
)
Math(math_function, a, _, _, _) =>
self.math_result_type(
math_function,
self.function_expression_type(function, a),
)
AtomicCall(atomic_function, arguments) =>
self.atomic_result_type(function, atomic_function, arguments)
ImageSample(image, _, gather, _, _, _, _, depth_ref, _) =>
self.image_result_type(function, image, gather, depth_ref)
ImageLoad(image, _, _, _, _) =>
self.image_result_type(function, image, None, None)
ImageQuery(image, query) =>
self.image_query_result_type(function, image, query)
ArrayLength(_) => self.find_scalar_type(Scalar(Uint, 4))
WorkGroupUniformLoad(pointer) | WorkGroupUniformLoadResult(pointer) =>
match self.function_expression_type(function, pointer) {
Some(ty) => self.deref_type(ty)
None => None
}
AtomicResult(ty, _) => Some(ty)
RayQueryProceedResult => self.find_scalar_type(Scalar(Bool, 1))
SubgroupBallotResult => self.vector_type(Quad, Scalar(Uint, 4))
SubgroupOperationResult(handle) =>
self.function_expression_type(function, handle)
SubgroupCall(subgroup_function, arguments) =>
self.subgroup_result_type(function, subgroup_function, arguments)
CooperativeLoad(columns, rows, role, data) =>
match self.cooperative_data_scalar(function, data) {
Some(scalar) =>
self.cooperative_matrix_type(columns, rows, scalar, role)
None => None
}
CooperativeMultiplyAdd(_, _, c) =>
self.function_expression_type(function, c)
Literal(literal) => self.literal_type(literal)
As(expr, kind, width) =>
self.as_result_type(
self.function_expression_type(function, expr),
kind,
width.unwrap_or(4),
)
RayQueryGetIntersection(_, _) => self.find_type_by_name("RayIntersection")
RayQueryVertexPositions(_, _) =>
self.shader_module.special_types.ray_vertex_return
RayQueryProceed(_) => self.find_scalar_type(Scalar(Bool, 1))
RayQueryInitialize(_, _, _)
| RayQueryGenerateIntersection(_, _)
| RayQueryConfirmIntersection(_)
| RayQueryTerminate(_) => None
}
}
///|
fn WgslIrValidator::global_expression_type(
self : WgslIrValidator,
handle : Handle,
) -> Handle? {
match self.shader_module.global_expressions.items.get(handle.index()) {
Some(expression) => self.global_expression_inner_type(expression)
None => None
}
}
///|
fn WgslIrValidator::global_expression_inner_type(
self : WgslIrValidator,
expression : Expression,
) -> Handle? {
match expression {
Constant(handle) =>
match self.shader_module.constants.items.get(handle.index()) {
Some(constant) => Some(constant.ty)
None => None
}
Override(handle) =>
match self.shader_module.overrides.items.get(handle.index()) {
Some(override_) => Some(override_.ty)
None => None
}
GlobalVariable(handle) =>
match self.shader_module.global_variables.items.get(handle.index()) {
Some(global) => Some(global.ty)
None => None
}
Load(inner) =>
match self.global_expression_type(inner) {
Some(ty) => self.load_result_type(ty)
None => None
}
AddressOf(ty, _) => Some(ty)
Compose(ty, _) | ZeroValue(ty) | Bitcast(ty, _) => Some(ty)
AccessIndex(base, index) =>
match self.global_expression_type(base) {
Some(base_ty) => self.indexed_type(base_ty, Some(index))
None => None
}
Component(base, _) =>
match self.global_expression_type(base) {
Some(base_ty) => self.indexed_type(base_ty, Some(0))
None => None
}
Access(base, _) =>
match self.global_expression_type(base) {
Some(base_ty) => self.indexed_type(base_ty, None)
None => None
}
Unary(_, inner) => self.global_expression_type(inner)
Binary(op, left, right) =>
self.binary_result_type(
op,
self.global_expression_type(left),
self.global_expression_type(right),
)
FunctionCall(handle, _) => self.function_result_type(handle)
Select(_, accept, reject) =>
match self.global_expression_type(accept) {
Some(ty) => Some(ty)
None => self.global_expression_type(reject)
}
Relational(relational_function, expr) =>
self.relational_result_type(
relational_function,
self.global_expression_type(expr),
)
Literal(literal) => self.literal_type(literal)
As(expr, kind, width) =>
self.as_result_type(
self.global_expression_type(expr),
kind,
width.unwrap_or(4),
)
_ => None
}
}
///|
fn WgslIrValidator::function_result_type(
self : WgslIrValidator,
handle : Handle,
) -> Handle? {
match self.shader_module.functions.items.get(handle.index()) {
Some(function) =>
match function.result {
Some(result) => Some(result.ty)
None => None
}
None => None
}
}
///|
fn WgslIrValidator::literal_type(
self : WgslIrValidator,
literal : Literal,
) -> Handle? {
match literal {
Bool(_) => self.find_scalar_type(Scalar(Bool, 1))
I32(_) => self.find_scalar_type(Scalar(Sint, 4))
U32(_) => self.find_scalar_type(Scalar(Uint, 4))
I64(_) => self.find_scalar_type(Scalar(Sint, 8))
U64(_) => self.find_scalar_type(Scalar(Uint, 8))
I16(_) => self.find_scalar_type(Scalar(Sint, 2))
U16(_) => self.find_scalar_type(Scalar(Uint, 2))
F16(_) => self.find_scalar_type(Scalar(Float, 2))
F32(_) | F32Exact(_) => self.find_scalar_type(Scalar(Float, 4))
F64(_) => self.find_scalar_type(Scalar(Float, 8))
AbstractInt(_) => self.find_scalar_type(Scalar(AbstractInt, 8))
AbstractFloat(_) => self.find_scalar_type(Scalar(AbstractFloat, 8))
}
}
///|
fn WgslIrValidator::indexed_type(
self : WgslIrValidator,
ty : Handle,
index : Int32?,
) -> Handle? {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Struct(members, _) | PredeclaredStruct(members, _) =>
match index {
Some(i) =>
match members.get(i) {
Some(struct_member) => Some(struct_member.ty)
None => None
}
None => None
}
Vector(size, scalar) =>
if self.constant_index_is_in_bounds(index, size.width()) {
self.find_scalar_type(scalar)
} else {
None
}
Matrix(columns, rows, scalar) =>
if self.constant_index_is_in_bounds(index, columns.width()) {
self.vector_type(rows, scalar)
} else {
None
}
Array(element, size, _) | BindingArray(element, size) =>
if self.array_index_is_in_bounds(index, size) {
Some(element)
} else {
None
}
Pointer(base, _) => self.indexed_type(base, index)
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::dynamic_indexed_type(
self : WgslIrValidator,
ty : Handle,
) -> Handle? {
self.indexed_type(ty, None)
}
///|
fn WgslIrValidator::constant_index_is_in_bounds(
self : WgslIrValidator,
index : Int32?,
count : Int32,
) -> Bool {
ignore(self)
match index {
Some(value) => value >= 0 && value < count
None => true
}
}
///|
fn WgslIrValidator::array_index_is_in_bounds(
self : WgslIrValidator,
index : Int32?,
size : ArraySize,
) -> Bool {
ignore(self)
match (index, size) {
(Some(value), Constant(count)) => value >= 0 && value < count
(Some(value), _) => value >= 0
(None, _) => true
}
}
///|
fn WgslIrValidator::pointer_pointee_type(
self : WgslIrValidator,
ty : Handle,
) -> Handle? {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Pointer(base, _) => Some(base)
ValuePointer(size, scalar, _) =>
match size {
Some(vector_size) => self.vector_type(vector_size, scalar)
None => self.find_scalar_type(scalar)
}
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::pointer_address_space(
self : WgslIrValidator,
ty : Handle,
) -> AddressSpace? {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Pointer(_, space) | ValuePointer(_, _, space) => Some(space)
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::pointer_type_is_writable(
self : WgslIrValidator,
ty : Handle,
) -> Bool {
match self.pointer_address_space(ty) {
Some(space) => self.global_address_space_is_writable(space)
None => false
}
}
///|
fn WgslIrValidator::global_address_space_is_writable(
self : WgslIrValidator,
space : AddressSpace,
) -> Bool {
ignore(self)
match space {
Function | Private | WorkGroup | TaskPayload | RayPayload => true
Storage(access) =>
access.contains(StorageAccess::store()) ||
access.contains(StorageAccess::atomic_access())
_ => false
}
}
///|
fn WgslIrValidator::expression_is_addressable(
self : WgslIrValidator,
function : Function,
handle : Handle,
) -> Bool {
match function.expressions.items.get(handle.index()) {
Some(expression) =>
match expression {
FunctionArgument(_) =>
match self.function_expression_inner_type(function, expression) {
Some(ty) => self.type_is_pointer_like(ty)
None => false
}
LocalVariable(local_handle) =>
match function.local_variables.items.get(local_handle.index()) {
Some(local_variable) =>
local_variable.kind == Var ||
self.type_is_pointer_like(local_variable.ty)
None => false
}
GlobalVariable(global) =>
self.shader_module.global_variables.items.get(global.index()) != None
Load(inner) =>
match self.function_expression_type(function, inner) {
Some(ty) => self.type_is_pointer_like(ty)
None => false
}
Access(base, _)
| AccessIndex(base, _)
| Component(base, _)
| Swizzle(_, base, _) => self.expression_is_addressable(function, base)
_ => false
}
None => false
}
}
///|
fn WgslIrValidator::global_expression_is_addressable(
self : WgslIrValidator,
handle : Handle,
) -> Bool {
match self.shader_module.global_expressions.items.get(handle.index()) {
Some(expression) =>
match expression {
GlobalVariable(global) =>
self.shader_module.global_variables.items.get(global.index()) != None
Load(inner) =>
match self.global_expression_type(inner) {
Some(ty) => self.type_is_pointer_like(ty)
None => false
}
Access(base, _) | AccessIndex(base, _) | Component(base, _) =>
self.global_expression_is_addressable(base)
_ => false
}
None => false
}
}
///|
fn WgslIrValidator::global_expression_value_type(
self : WgslIrValidator,
handle : Handle,
) -> Handle? {
match self.shader_module.global_expressions.items.get(handle.index()) {
Some(expression) =>
match expression {
GlobalVariable(global) =>
match self.shader_module.global_variables.items.get(global.index()) {
Some(variable) => Some(variable.ty)
None => None
}
Load(inner) =>
match self.global_expression_type(inner) {
Some(ty) => self.deref_type(ty)
None => None
}
Access(_, _) | AccessIndex(_, _) | Component(_, _) =>
self.global_expression_inner_type(expression)
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::deref_type(self : WgslIrValidator, ty : Handle) -> Handle? {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Pointer(base, _) => self.deref_type(base)
ValuePointer(size, scalar, _) =>
match size {
Some(vector_size) => self.vector_type(vector_size, scalar)
None => self.find_scalar_type(scalar)
}
_ => Some(ty)
}
None => None
}
}
///|
fn WgslIrValidator::load_result_type(
self : WgslIrValidator,
ty : Handle,
) -> Handle? {
match self.deref_type(ty) {
Some(deref) =>
match self.shader_module.types.get(deref) {
Some(type_) =>
match type_.inner {
Atomic(scalar) => self.find_scalar_type(scalar)
_ => Some(deref)
}
None => Some(deref)
}
None => None
}
}
///|
fn WgslIrValidator::vector_type_from_scalar_type(
self : WgslIrValidator,
size : VectorSize,
ty : Handle,
) -> Handle? {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Scalar(scalar) => self.vector_type(size, scalar)
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::vector_or_scalar_swizzle_type(
self : WgslIrValidator,
size : VectorSize,
ty : Handle,
) -> Handle? {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Vector(_, scalar) => self.vector_type(size, scalar)
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::binary_result_type(
self : WgslIrValidator,
op : BinaryOperator,
left : Handle?,
right : Handle?,
) -> Handle? {
if wgsl_ir_validation_binary_operator_is_comparison(op) {
return self.boolean_result_type(left, right)
}
match (left, right) {
(Some(left_ty), Some(right_ty)) =>
if op == Multiply {
match self.matrix_vector_multiply_result_type(left_ty, right_ty) {
Some(ty) => Some(ty)
None => self.numeric_binary_fallback_type(left_ty, right_ty)
}
} else {
self.numeric_binary_fallback_type(left_ty, right_ty)
}
(Some(ty), None) | (None, Some(ty)) => Some(ty)
(None, None) => None
}
}
///|
fn WgslIrValidator::numeric_binary_fallback_type(
self : WgslIrValidator,
left : Handle,
right : Handle,
) -> Handle? {
if self.type_is_scalar(left) && !self.type_is_scalar(right) {
return Some(right)
}
if !self.type_is_scalar(left) && self.type_is_scalar(right) {
return Some(left)
}
Some(left)
}
///|
fn WgslIrValidator::matrix_vector_multiply_result_type(
self : WgslIrValidator,
left : Handle,
right : Handle,
) -> Handle? {
match self.shader_module.types.get(left) {
Some(left_type) =>
match left_type.inner {
Matrix(left_columns, rows, scalar) =>
match self.shader_module.types.get(right) {
Some(right_type) =>
match right_type.inner {
Vector(_, _) => self.vector_type(rows, scalar)
Matrix(columns, right_rows, _) =>
if right_rows == left_columns {
self.matrix_type(columns, rows, scalar)
} else {
None
}
_ => None
}
None => None
}
Vector(_, scalar) =>
match self.shader_module.types.get(right) {
Some(right_type) =>
match right_type.inner {
Matrix(columns, _, _) => self.vector_type(columns, scalar)
_ => None
}
None => None
}
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::boolean_result_type(
self : WgslIrValidator,
left : Handle?,
right : Handle?,
) -> Handle? {
match left {
Some(ty) =>
match self.vector_size(ty) {
Some(size) => return self.vector_type(size, Scalar(Bool, 1))
None => ()
}
None => ()
}
match right {
Some(ty) =>
match self.vector_size(ty) {
Some(size) => self.vector_type(size, Scalar(Bool, 1))
None => self.find_scalar_type(Scalar(Bool, 1))
}
None => self.find_scalar_type(Scalar(Bool, 1))
}
}
///|
fn WgslIrValidator::relational_result_type(
self : WgslIrValidator,
relational_function : RelationalFunction,
input : Handle?,
) -> Handle? {
match relational_function {
All | Any => self.find_scalar_type(Scalar(Bool, 1))
IsNan | IsInf => self.boolean_result_type(input, input)
}
}
///|
fn WgslIrValidator::math_result_type(
self : WgslIrValidator,
math_function : MathFunction,
input : Handle?,
) -> Handle? {
guard input is Some(input_ty) else { return None }
match math_function {
Modf => self.predeclared_numeric_result_type(input_ty, false)
Frexp => self.predeclared_numeric_result_type(input_ty, true)
Pack4x8snorm
| Pack4x8unorm
| Pack2x16snorm
| Pack2x16unorm
| Pack2x16float
| Pack4xI8
| Pack4xU8
| Pack4xI8Clamp
| Pack4xU8Clamp
| Dot4U8Packed => self.find_scalar_type(Scalar(Uint, 4))
Dot4I8Packed => self.find_scalar_type(Scalar(Sint, 4))
Unpack4x8snorm | Unpack4x8unorm => self.vector_type(Quad, Scalar(Float, 4))
Unpack2x16snorm | Unpack2x16unorm | Unpack2x16float =>
self.vector_type(Bi, Scalar(Float, 4))
Unpack4xI8 => self.vector_type(Quad, Scalar(Sint, 4))
Unpack4xU8 => self.vector_type(Quad, Scalar(Uint, 4))
Dot | Distance | Length | Determinant =>
self.scalar_type_from_type(input_ty)
Transpose => self.transpose_type(input_ty)
_ => Some(input_ty)
}
}
///|
fn WgslIrValidator::predeclared_numeric_result_type(
self : WgslIrValidator,
input_ty : Handle,
frexp : Bool,
) -> Handle? {
match self.shader_module.types.get(input_ty) {
Some(type_) =>
match type_.inner {
Scalar(scalar) =>
if frexp {
self.predeclared_type_handle(FrexpResult(None, scalar))
} else {
self.predeclared_type_handle(ModfResult(None, scalar))
}
Vector(size, scalar) =>
if frexp {
self.predeclared_type_handle(FrexpResult(Some(size), scalar))
} else {
self.predeclared_type_handle(ModfResult(Some(size), scalar))
}
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::predeclared_type_handle(
self : WgslIrValidator,
predeclared : PredeclaredType,
) -> Handle? {
for item in self.shader_module.special_types.predeclared_types {
let (existing, handle) = item
if existing == predeclared {
return Some(handle)
}
}
None
}
///|
fn WgslIrValidator::as_result_type(
self : WgslIrValidator,
input : Handle?,
kind : ScalarKind,
width : Int32,
) -> Handle? {
guard input is Some(input_ty) else { return None }
let scalar = Scalar::Scalar(kind, width)
match self.shader_module.types.get(input_ty) {
Some(type_) =>
match type_.inner {
Scalar(_) => self.find_scalar_type(scalar)
Vector(size, _) => self.vector_type(size, scalar)
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::atomic_result_type(
self : WgslIrValidator,
function : Function,
atomic_function : AtomicFunction,
arguments : Array[Handle],
) -> Handle? {
guard arguments is [pointer, ..] else { return None }
let scalar = match self.function_expression_type(function, pointer) {
Some(ty) => self.atomic_scalar_type(ty)
None => None
}
match atomic_function {
Store => None
CompareExchangeWeak =>
match scalar {
Some(value) => self.predeclared_atomic_compare_exchange_type(value)
None => None
}
_ =>
match scalar {
Some(value) => self.find_scalar_type(value)
None => None
}
}
}
///|
fn WgslIrValidator::image_result_type(
self : WgslIrValidator,
function : Function,
image : Handle,
gather : SwizzleComponent?,
depth_ref : Handle?,
) -> Handle? {
guard self.function_expression_type(function, image) is Some(image_ty) else {
return None
}
match self.shader_module.types.get(image_ty) {
Some(type_) =>
match type_.inner {
Image(_, _, Sampled(kind, _)) => self.vector_type(Quad, Scalar(kind, 4))
Image(_, _, Depth(_)) =>
if gather != None {
self.vector_type(Quad, Scalar(Float, 4))
} else {
ignore(depth_ref)
self.find_scalar_type(Scalar(Float, 4))
}
Image(_, _, Storage(format, _)) =>
self.vector_type(
Quad,
wgsl_ir_validation_storage_format_scalar(format),
)
Image(_, _, External) => self.vector_type(Quad, Scalar(Float, 4))
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::image_query_result_type(
self : WgslIrValidator,
function : Function,
image : Handle,
query : ImageQuery,
) -> Handle? {
match query {
Size(_) =>
match self.image_dimension(function, image) {
Some(D1) => self.find_scalar_type(Scalar(Uint, 4))
Some(D2) | Some(Cube) => self.vector_type(Bi, Scalar(Uint, 4))
Some(D3) => self.vector_type(Tri, Scalar(Uint, 4))
None => None
}
NumLevels | NumLayers | NumSamples => self.find_scalar_type(Scalar(Uint, 4))
}
}
///|
fn WgslIrValidator::subgroup_result_type(
self : WgslIrValidator,
function : Function,
subgroup_function : SubgroupFunction,
arguments : Array[Handle],
) -> Handle? {
match subgroup_function {
Ballot => self.vector_type(Quad, Scalar(Uint, 4))
All | Any => self.find_scalar_type(Scalar(Bool, 1))
_ =>
match arguments.get(0) {
Some(argument) => self.function_expression_type(function, argument)
None => None
}
}
}
///|
fn WgslIrValidator::image_dimension(
self : WgslIrValidator,
function : Function,
image : Handle,
) -> ImageDimension? {
guard self.function_expression_type(function, image) is Some(image_ty) else {
return None
}
match self.shader_module.types.get(image_ty) {
Some(type_) =>
match type_.inner {
Image(dimension, _, _) => Some(dimension)
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::cooperative_data_scalar(
self : WgslIrValidator,
function : Function,
data : CooperativeData,
) -> Scalar? {
guard self.function_expression_type(function, data.pointer)
is Some(pointer_ty) else {
return None
}
match self.pointer_pointee_type(pointer_ty) {
Some(value_ty) => self.scalar_from_type(value_ty)
None => self.scalar_from_type(pointer_ty)
}
}
///|
fn WgslIrValidator::atomic_scalar_type(
self : WgslIrValidator,
ty : Handle,
) -> Scalar? {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Atomic(scalar) => Some(scalar)
Pointer(base, _) => self.atomic_scalar_type(base)
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::predeclared_atomic_compare_exchange_type(
self : WgslIrValidator,
scalar : Scalar,
) -> Handle? {
self.predeclared_type_handle(AtomicCompareExchangeWeakResult(scalar))
}
///|
fn WgslIrValidator::scalar_type_from_type(
self : WgslIrValidator,
ty : Handle,
) -> Handle? {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Scalar(_) => Some(ty)
Vector(_, scalar) | Matrix(_, _, scalar) =>
self.find_scalar_type(scalar)
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::scalar_from_type(
self : WgslIrValidator,
ty : Handle,
) -> Scalar? {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Scalar(scalar) | Vector(_, scalar) | Matrix(_, _, scalar) =>
Some(scalar)
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::transpose_type(
self : WgslIrValidator,
ty : Handle,
) -> Handle? {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Matrix(columns, rows, scalar) => self.matrix_type(rows, columns, scalar)
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::type_assignable(
self : WgslIrValidator,
expected : Handle,
actual : Handle,
) -> Bool {
if expected == actual {
return true
}
match
(
self.shader_module.types.get(expected),
self.shader_module.types.get(actual),
) {
(Some(expected_ty), Some(actual_ty)) =>
self.type_inner_assignable(expected_ty.inner, actual_ty.inner)
_ => false
}
}
///|
fn WgslIrValidator::type_inner_assignable(
self : WgslIrValidator,
expected : TypeInner,
actual : TypeInner,
) -> Bool {
if expected == actual {
return true
}
match (expected, actual) {
(Scalar(expected_scalar), Scalar(actual_scalar)) =>
wgsl_ir_validation_scalar_assignable(expected_scalar, actual_scalar)
(Vector(expected_size, expected_scalar), Vector(actual_size, actual_scalar)) =>
expected_size == actual_size &&
wgsl_ir_validation_scalar_assignable(expected_scalar, actual_scalar)
(
Matrix(expected_columns, expected_rows, expected_scalar),
Matrix(actual_columns, actual_rows, actual_scalar),
) =>
expected_columns == actual_columns &&
expected_rows == actual_rows &&
wgsl_ir_validation_scalar_assignable(expected_scalar, actual_scalar)
(
Array(expected_element, expected_size, expected_stride),
Array(actual_element, actual_size, actual_stride),
) =>
expected_size == actual_size &&
expected_stride == actual_stride &&
self.type_assignable(expected_element, actual_element)
(
BindingArray(expected_element, expected_size),
BindingArray(actual_element, actual_size),
) =>
expected_size == actual_size &&
self.type_assignable(expected_element, actual_element)
(
Pointer(expected_pointee, expected_space),
Pointer(actual_pointee, actual_space),
) =>
expected_space == actual_space &&
self.type_assignable(expected_pointee, actual_pointee)
(Atomic(expected_scalar), Atomic(actual_scalar)) =>
wgsl_ir_validation_scalar_assignable(expected_scalar, actual_scalar)
_ => false
}
}
///|
fn WgslIrValidator::types_are_select_compatible(
self : WgslIrValidator,
accept : Handle,
reject : Handle,
) -> Bool {
self.type_assignable(accept, reject) || self.type_assignable(reject, accept)
}
///|
fn WgslIrValidator::select_condition_type_matches_result(
self : WgslIrValidator,
condition : Handle,
result : Handle,
) -> Bool {
if self.type_is_bool_scalar(condition) {
return true
}
match self.type_bool_vector_size(condition) {
Some(condition_size) =>
match self.vector_size(result) {
Some(result_size) => condition_size == result_size
None => false
}
None => false
}
}
///|
fn WgslIrValidator::type_is_bool_scalar(
self : WgslIrValidator,
ty : Handle,
) -> Bool {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Scalar(scalar) => scalar.kind == Bool
_ => false
}
None => false
}
}
///|
fn WgslIrValidator::type_bool_vector_size(
self : WgslIrValidator,
ty : Handle,
) -> VectorSize? {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Vector(size, scalar) if scalar.kind == Bool => Some(size)
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::type_is_integer_scalar(
self : WgslIrValidator,
ty : Handle,
) -> Bool {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Scalar(scalar) =>
scalar.kind == Sint ||
scalar.kind == Uint ||
scalar.kind == AbstractInt
_ => false
}
None => false
}
}
///|
fn WgslIrValidator::type_is_scalar(self : WgslIrValidator, ty : Handle) -> Bool {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Scalar(_) => true
_ => false
}
None => false
}
}
///|
fn WgslIrValidator::type_is_pointer_like(
self : WgslIrValidator,
ty : Handle,
) -> Bool {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Pointer(_, _) | ValuePointer(_, _, _) => true
_ => false
}
None => false
}
}
///|
fn WgslIrValidator::vector_size(
self : WgslIrValidator,
ty : Handle,
) -> VectorSize? {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Vector(size, _) => Some(size)
_ => None
}
None => None
}
}
///|
fn WgslIrValidator::type_lane_count(
self : WgslIrValidator,
ty : Handle,
) -> Int32 {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Vector(size, _) => size.width()
Matrix(columns, rows, _) => columns.width() * rows.width()
_ => 1
}
None => 1
}
}
///|
fn WgslIrValidator::type_is_handle_resource(
self : WgslIrValidator,
ty : Handle,
) -> Bool {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Image(_, _, _) | Sampler(_) | AccelerationStructure(_) | RayQuery(_) =>
true
BindingArray(element, _) => self.type_is_handle_resource(element)
_ => false
}
None => false
}
}
///|
fn WgslIrValidator::type_is_runtime_array(
self : WgslIrValidator,
ty : Handle,
) -> Bool {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Array(_, Dynamic, _) | BindingArray(_, Dynamic) => true
_ => false
}
None => false
}
}
///|
fn WgslIrValidator::pointer_targets_runtime_array(
self : WgslIrValidator,
ty : Handle,
) -> Bool {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Pointer(base, _) => self.type_or_struct_tail_is_runtime_array(base)
_ => false
}
None => false
}
}
///|
fn WgslIrValidator::type_or_struct_tail_is_runtime_array(
self : WgslIrValidator,
ty : Handle,
) -> Bool {
match self.shader_module.types.get(ty) {
Some(type_) =>
match type_.inner {
Array(_, Dynamic, _) => true
Struct(members, _) | PredeclaredStruct(members, _) =>
match members.last() {
Some(struct_member) => self.type_is_runtime_array(struct_member.ty)
None => false
}
_ => false
}
None => false
}
}