Implement Pointers and References
This change implements pointers and references as described by the WGSL
specification change in https://github.com/gpuweb/gpuweb/pull/1569.
reader/spirv:
* Now emits address-of `&expr` and indirection `*expr` operators as
needed.
* As an identifier may now resolve to a pointer or reference type
depending on whether the declaration is a `var`, `let` or
parameter, `Function::identifier_values_` has been changed from
an ID set to an ID -> Type* map.
resolver:
* Now correctly resolves all expressions to either a value type,
reference type or pointer type.
* Validates pointer / reference rules on assignment, `var` and `let`
construction, and usage.
* Handles the address-of and indirection operators.
* No longer does any implicit loads of pointer types.
* Storage class validation is still TODO (crbug.com/tint/809)
writer/spirv:
* Correctly handles variables and expressions of pointer and
reference types, emitting OpLoads where necessary.
test:
* Lots of new test cases
Fixed: tint:727
Change-Id: I77d3281590e35e5a3122f5b74cdeb71a6fe51f74
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/50740
Commit-Queue: Ben Clayton <bclayton@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 77d3eeb..9927bdd 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -550,6 +550,8 @@
resolver/intrinsic_test.cc
resolver/is_host_shareable_test.cc
resolver/is_storeable_test.cc
+ resolver/ptr_ref_test.cc
+ resolver/ptr_ref_validation_test.cc
resolver/pipeline_overridable_constant_test.cc
resolver/resolver_test_helper.cc
resolver/resolver_test_helper.h
@@ -561,6 +563,8 @@
resolver/type_constructor_validation_test.cc
resolver/type_validation_test.cc
resolver/validation_test.cc
+ resolver/var_let_test.cc
+ resolver/var_let_validation_test.cc
scope_stack_test.cc
sem/intrinsic_test.cc
symbol_table_test.cc
diff --git a/src/inspector/inspector.cc b/src/inspector/inspector.cc
index eb79153..b8ac9b4 100644
--- a/src/inspector/inspector.cc
+++ b/src/inspector/inspector.cc
@@ -227,7 +227,7 @@
stage_variable.name = name;
stage_variable.component_type = ComponentType::kUnknown;
- auto* type = var->Type()->UnwrapAll();
+ auto* type = var->Type()->UnwrapRef();
if (type->is_float_scalar_or_vector() || type->is_float_matrix()) {
stage_variable.component_type = ComponentType::kFloat;
} else if (type->is_unsigned_scalar_or_vector()) {
@@ -400,7 +400,7 @@
auto* var = ruv.first;
auto binding_info = ruv.second;
- auto* unwrapped_type = var->Type()->UnwrapAccess();
+ auto* unwrapped_type = var->Type()->UnwrapRef();
auto* str = unwrapped_type->As<sem::Struct>();
if (str == nullptr) {
continue;
@@ -522,7 +522,7 @@
entry.bind_group = binding_info.group->value();
entry.binding = binding_info.binding->value();
- auto* texture_type = var->Type()->UnwrapAccess()->As<sem::Texture>();
+ auto* texture_type = var->Type()->UnwrapRef()->As<sem::Texture>();
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(
texture_type->dim());
@@ -550,7 +550,7 @@
entry.bind_group = binding_info.group->value();
entry.binding = binding_info.binding->value();
- auto* texture_type = var->Type()->UnwrapAccess()->As<sem::Texture>();
+ auto* texture_type = var->Type()->UnwrapRef()->As<sem::Texture>();
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(
texture_type->dim());
@@ -584,7 +584,7 @@
return;
}
- auto* unwrapped_type = type->UnwrapAll();
+ auto* unwrapped_type = type->UnwrapRef();
if (auto* struct_ty = unwrapped_type->As<sem::Struct>()) {
// Recurse into members.
@@ -641,7 +641,7 @@
continue;
}
- auto* str = var->Type()->UnwrapAccess()->As<sem::Struct>();
+ auto* str = var->Type()->UnwrapRef()->As<sem::Struct>();
if (!str) {
continue;
}
@@ -685,7 +685,7 @@
entry.bind_group = binding_info.group->value();
entry.binding = binding_info.binding->value();
- auto* texture_type = var->Type()->UnwrapAccess()->As<sem::Texture>();
+ auto* texture_type = var->Type()->UnwrapRef()->As<sem::Texture>();
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(
texture_type->dim());
@@ -717,7 +717,7 @@
auto* var = ref.first;
auto binding_info = ref.second;
- auto* texture_type = var->Type()->As<sem::StorageTexture>();
+ auto* texture_type = var->Type()->UnwrapRef()->As<sem::StorageTexture>();
if (read_only !=
(texture_type->access_control() == ast::AccessControl::kReadOnly)) {
diff --git a/src/intrinsic_table.cc b/src/intrinsic_table.cc
index 802034f..e313d0a 100644
--- a/src/intrinsic_table.cc
+++ b/src/intrinsic_table.cc
@@ -1305,7 +1305,7 @@
ss << ", ";
}
first = false;
- ss << arg->FriendlyName(builder.Symbols());
+ ss << arg->UnwrapRef()->FriendlyName(builder.Symbols());
}
}
ss << ")";
@@ -1391,14 +1391,7 @@
return nullptr;
}
- auto* arg_ty = args[i];
- if (auto* ptr = arg_ty->As<sem::Pointer>()) {
- if (!parameters[i].matcher->ExpectsPointer()) {
- // Argument is a pointer, but the matcher isn't expecting one.
- // Perform an implicit dereference.
- arg_ty = ptr->StoreType();
- }
- }
+ auto* arg_ty = args[i]->UnwrapRef();
if (parameters[i].matcher->Match(matcher_state, arg_ty)) {
// A correct parameter match is scored higher than number of parameters to
// arguments.
diff --git a/src/intrinsic_table_test.cc b/src/intrinsic_table_test.cc
index 5bd2f5d..8065f03 100644
--- a/src/intrinsic_table_test.cc
+++ b/src/intrinsic_table_test.cc
@@ -19,6 +19,7 @@
#include "src/sem/depth_texture_type.h"
#include "src/sem/external_texture_type.h"
#include "src/sem/multisampled_texture_type.h"
+#include "src/sem/reference_type.h"
#include "src/sem/sampled_texture_type.h"
#include "src/sem/storage_texture_type.h"
@@ -345,10 +346,11 @@
ASSERT_THAT(result.diagnostics.str(), HasSubstr("no matching call"));
}
-TEST_F(IntrinsicTableTest, MatchAutoPointerDereference) {
- auto result =
- table->Lookup(*this, IntrinsicType::kCos,
- {ty.pointer<f32>(ast::StorageClass::kNone)}, Source{});
+TEST_F(IntrinsicTableTest, ImplicitLoadOnReference) {
+ auto result = table->Lookup(
+ *this, IntrinsicType::kCos,
+ {create<sem::Reference>(create<sem::F32>(), ast::StorageClass::kNone)},
+ Source{});
ASSERT_NE(result.intrinsic, nullptr);
ASSERT_EQ(result.diagnostics.str(), "");
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kCos);
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 805fc56..c3d6b06 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -1088,15 +1088,15 @@
ast::VariableList ast_params;
function_.ForEachParam(
[this, &ast_params](const spvtools::opt::Instruction* param) {
- auto* ast_type = parser_impl_.ConvertType(param->type_id());
- if (ast_type != nullptr) {
+ auto* type = parser_impl_.ConvertType(param->type_id());
+ if (type != nullptr) {
auto* ast_param = parser_impl_.MakeVariable(
- param->result_id(), ast::StorageClass::kNone, ast_type, true,
- nullptr, ast::DecorationList{});
+ param->result_id(), ast::StorageClass::kNone, type, true, nullptr,
+ ast::DecorationList{});
// Parameters are treated as const declarations.
ast_params.emplace_back(ast_param);
// The value is accessible by name.
- identifier_values_.insert(param->result_id());
+ identifier_types_.emplace(param->result_id(), type);
} else {
// We've already logged an error and emitted a diagnostic. Do nothing
// here.
@@ -2194,8 +2194,8 @@
constructor, ast::DecorationList{});
auto* var_decl_stmt = create<ast::VariableDeclStatement>(Source{}, var);
AddStatement(var_decl_stmt);
- // Save this as an already-named value.
- identifier_values_.insert(inst.result_id());
+ auto* var_type = ty_.Reference(var_store_type, ast::StorageClass::kNone);
+ identifier_types_.emplace(inst.result_id(), var_type);
}
return success();
}
@@ -2246,7 +2246,15 @@
create<ast::IdentifierExpression>(
Source{}, builder_.Symbols().Register(name))};
}
- if (identifier_values_.count(id) || parser_impl_.IsScalarSpecConstant(id)) {
+ auto type_it = identifier_types_.find(id);
+ if (type_it != identifier_types_.end()) {
+ auto name = namer_.Name(id);
+ auto* type = type_it->second;
+ return TypedExpression{type,
+ create<ast::IdentifierExpression>(
+ Source{}, builder_.Symbols().Register(name))};
+ }
+ if (parser_impl_.IsScalarSpecConstant(id)) {
auto name = namer_.Name(id);
return TypedExpression{
parser_impl_.ConvertType(def_use_mgr_->GetDef(id)->type_id()),
@@ -2271,9 +2279,10 @@
case SpvOpVariable: {
// This occurs for module-scope variables.
auto name = namer_.Name(inst->result_id());
- return TypedExpression{parser_impl_.ConvertType(inst->type_id()),
- create<ast::IdentifierExpression>(
- Source{}, builder_.Symbols().Register(name))};
+ return TypedExpression{
+ parser_impl_.ConvertType(inst->type_id(), PtrAs::Ref),
+ create<ast::IdentifierExpression>(Source{},
+ builder_.Symbols().Register(name))};
}
case SpvOpUndef:
// Substitute a null value for undef.
@@ -2624,7 +2633,7 @@
// just like in the original SPIR-V.
PushTrueGuard(construct->end_id);
} else {
- // Add a flow guard around the blocks in the premege area.
+ // Add a flow guard around the blocks in the premerge area.
PushGuard(guard_name, construct->end_id);
}
}
@@ -2836,7 +2845,7 @@
const auto true_dest = terminator.GetSingleWordInOperand(1);
const auto false_dest = terminator.GetSingleWordInOperand(2);
if (true_dest == false_dest) {
- // This is like an uncondtional branch.
+ // This is like an unconditional branch.
AddStatement(MakeBranch(block_info, *GetBlockInfo(true_dest)));
return true;
}
@@ -3064,14 +3073,14 @@
for (auto id : sorted_by_index(block_info.hoisted_ids)) {
const auto* def_inst = def_use_mgr_->GetDef(id);
TINT_ASSERT(def_inst);
- auto* ast_type =
+ auto* storage_type =
RemapStorageClass(parser_impl_.ConvertType(def_inst->type_id()), id);
AddStatement(create<ast::VariableDeclStatement>(
Source{},
- parser_impl_.MakeVariable(id, ast::StorageClass::kNone, ast_type, false,
- nullptr, ast::DecorationList{})));
- // Save this as an already-named value.
- identifier_values_.insert(id);
+ parser_impl_.MakeVariable(id, ast::StorageClass::kNone, storage_type,
+ false, nullptr, ast::DecorationList{})));
+ auto* type = ty_.Reference(storage_type, ast::StorageClass::kNone);
+ identifier_types_.emplace(id, type);
}
// Emit declarations of phi state variables, in index order.
for (auto id : sorted_by_index(block_info.phis_needing_state_vars)) {
@@ -3131,25 +3140,29 @@
bool FunctionEmitter::EmitConstDefinition(
const spvtools::opt::Instruction& inst,
- TypedExpression ast_expr) {
- if (!ast_expr) {
+ TypedExpression expr) {
+ if (!expr) {
return false;
}
+ if (expr.type->Is<Reference>()) {
+ // `let` declarations cannot hold references, so we need to take the address
+ // of the RHS, and make the `let` be a pointer.
+ expr = AddressOf(expr);
+ }
auto* ast_const = parser_impl_.MakeVariable(
- inst.result_id(), ast::StorageClass::kNone, ast_expr.type, true,
- ast_expr.expr, ast::DecorationList{});
+ inst.result_id(), ast::StorageClass::kNone, expr.type, true, expr.expr,
+ ast::DecorationList{});
if (!ast_const) {
return false;
}
AddStatement(create<ast::VariableDeclStatement>(Source{}, ast_const));
- // Save this as an already-named value.
- identifier_values_.insert(inst.result_id());
+ identifier_types_.emplace(inst.result_id(), expr.type);
return success();
}
bool FunctionEmitter::EmitConstDefOrWriteToHoistedVar(
const spvtools::opt::Instruction& inst,
- TypedExpression ast_expr) {
+ TypedExpression expr) {
const auto result_id = inst.result_id();
const auto* def_info = GetDefInfo(result_id);
if (def_info && def_info->requires_hoisted_def) {
@@ -3159,10 +3172,10 @@
Source{},
create<ast::IdentifierExpression>(Source{},
builder_.Symbols().Register(name)),
- ast_expr.expr));
+ expr.expr));
return true;
}
- return EmitConstDefinition(inst, ast_expr);
+ return EmitConstDefinition(inst, expr);
}
bool FunctionEmitter::EmitStatement(const spvtools::opt::Instruction& inst) {
@@ -3283,6 +3296,12 @@
return false;
}
+ if (lhs.type->Is<Pointer>()) {
+ // LHS of an assignment must be a reference type.
+ // Convert the LHS to a reference by dereferencing it.
+ lhs = Dereference(lhs);
+ }
+
AddStatement(
create<ast::AssignmentStatement>(Source{}, lhs.expr, rhs.expr));
return success();
@@ -3343,16 +3362,21 @@
return false;
}
- // The load result type is the pointee type of its operand.
- TINT_ASSERT(expr.type->Is<Pointer>());
- expr.type = expr.type->As<Pointer>()->type;
+ // The load result type is the storage type of its operand.
+ if (expr.type->Is<Pointer>()) {
+ expr = Dereference(expr);
+ } else if (auto* ref = expr.type->As<Reference>()) {
+ expr.type = ref->type;
+ } else {
+ Fail() << "OpLoad expression is not a pointer or reference";
+ return false;
+ }
+
return EmitConstDefOrWriteToHoistedVar(inst, expr);
}
case SpvOpCopyMemory: {
// Generate an assignment.
- // TODO(dneto): When supporting ptr-ref, the LHS pointer and RHS pointer
- // map to reference types in WGSL.
auto lhs = MakeOperand(inst, 0);
auto rhs = MakeOperand(inst, 1);
// Ignore any potential memory operands. Currently they are all for
@@ -3367,6 +3391,15 @@
if (!success()) {
return false;
}
+
+ // LHS and RHS pointers must be reference types in WGSL.
+ if (lhs.type->Is<Pointer>()) {
+ lhs = Dereference(lhs);
+ }
+ if (rhs.type->Is<Pointer>()) {
+ rhs = Dereference(rhs);
+ }
+
AddStatement(
create<ast::AssignmentStatement>(Source{}, lhs.expr, rhs.expr));
return success();
@@ -3386,6 +3419,11 @@
if (!expr) {
return false;
}
+ if (expr.type->Is<Reference>()) {
+ // If the source is a reference, then we need to take the address of the
+ // expression.
+ expr = AddressOf(expr);
+ }
expr.type = RemapStorageClass(expr.type, result_id);
return EmitConstDefOrWriteToHoistedVar(inst, expr);
}
@@ -3782,7 +3820,7 @@
auto name = namer_.Name(base_id);
current_expr.expr = create<ast::IdentifierExpression>(
Source{}, builder_.Symbols().Register(name));
- current_expr.type = parser_impl_.ConvertType(ptr_ty_id);
+ current_expr.type = parser_impl_.ConvertType(ptr_ty_id, PtrAs::Ref);
}
}
@@ -3898,10 +3936,9 @@
}
const auto pointer_type_id =
type_mgr_->FindPointerToType(pointee_type_id, storage_class);
- auto* ast_pointer_type = parser_impl_.ConvertType(pointer_type_id);
- TINT_ASSERT(ast_pointer_type);
- TINT_ASSERT(ast_pointer_type->Is<Pointer>());
- current_expr = TypedExpression{ast_pointer_type, next_expr};
+ auto* type = parser_impl_.ConvertType(pointer_type_id, PtrAs::Ref);
+ TINT_ASSERT(type && type->Is<Reference>());
+ current_expr = TypedExpression{type, next_expr};
}
return current_expr;
}
@@ -3932,7 +3969,7 @@
// A SPIR-V composite extract is a single instruction with multiple
// literal indices walking down into composites.
// A SPIR-V composite insert is similar but also tells you what component
- // to inject. This function is respnosible for the the walking-into part
+ // to inject. This function is responsible for the the walking-into part
// of composite-insert.
//
// The Tint AST represents this as ever-deeper nested indexing expressions.
@@ -4476,15 +4513,24 @@
auto* function = create<ast::IdentifierExpression>(
Source{}, builder_.Symbols().Register(name));
- ast::ExpressionList params;
+ ast::ExpressionList args;
for (uint32_t iarg = 1; iarg < inst.NumInOperands(); ++iarg) {
- params.emplace_back(MakeOperand(inst, iarg).expr);
+ auto expr = MakeOperand(inst, iarg);
+ if (!expr) {
+ return false;
+ }
+ if (expr.type->Is<Reference>()) {
+ // Functions cannot use references as parameters, so we need to pass by
+ // pointer.
+ expr = AddressOf(expr);
+ }
+ args.emplace_back(expr.expr);
}
if (failed()) {
return false;
}
auto* call_expr =
- create<ast::CallExpression>(Source{}, function, std::move(params));
+ create<ast::CallExpression>(Source{}, function, std::move(args));
auto* result_type = parser_impl_.ConvertType(inst.type_id());
if (!result_type) {
return Fail() << "internal error: no mapped type result of call: "
@@ -5394,6 +5440,32 @@
{ast_type, create<ast::IdentifierExpression>(registered_temp_name)});
}
+TypedExpression FunctionEmitter::AddressOf(TypedExpression expr) {
+ auto* ref = expr.type->As<Reference>();
+ if (!ref) {
+ Fail() << "AddressOf() called on non-reference type";
+ return {};
+ }
+ return {
+ ty_.Pointer(ref->type, ref->storage_class),
+ create<ast::UnaryOpExpression>(Source{}, ast::UnaryOp::kAddressOf,
+ expr.expr),
+ };
+}
+
+TypedExpression FunctionEmitter::Dereference(TypedExpression expr) {
+ auto* ptr = expr.type->As<Pointer>();
+ if (!ptr) {
+ Fail() << "Dereference() called on non-pointer type";
+ return {};
+ }
+ return {
+ ptr->type,
+ create<ast::UnaryOpExpression>(Source{}, ast::UnaryOp::kIndirection,
+ expr.expr),
+ };
+}
+
FunctionEmitter::FunctionDeclaration::FunctionDeclaration() = default;
FunctionEmitter::FunctionDeclaration::~FunctionDeclaration() = default;
diff --git a/src/reader/spirv/function.h b/src/reader/spirv/function.h
index edff907..940e84a 100644
--- a/src/reader/spirv/function.h
+++ b/src/reader/spirv/function.h
@@ -1127,6 +1127,16 @@
/// @returns a boolean false expression.
ast::Expression* MakeFalse(const Source&) const;
+ /// @param expr the expression to take the address of
+ /// @returns a TypedExpression that is the address-of `expr` (`&expr`)
+ /// @note `expr` must be a reference type
+ TypedExpression AddressOf(TypedExpression expr);
+
+ /// @param expr the expression to dereference
+ /// @returns a TypedExpression that is the dereference-of `expr` (`*expr`)
+ /// @note `expr` must be a pointer type
+ TypedExpression Dereference(TypedExpression expr);
+
/// Creates a new `ast::Node` owned by the ProgramBuilder.
/// @param args the arguments to pass to the type constructor
/// @returns the node pointer
@@ -1136,6 +1146,7 @@
}
using StatementsStack = std::vector<StatementBlock>;
+ using PtrAs = ParserImpl::PtrAs;
ParserImpl& parser_impl_;
TypeManager& ty_;
@@ -1160,8 +1171,9 @@
// lifetime of the EmitFunctionBodyStatements method.
StatementsStack statements_stack_;
- // The set of IDs that have already had an identifier name generated for it.
- std::unordered_set<uint32_t> identifier_values_;
+ // The map of IDs that have already had an identifier name generated for it,
+ // to their Type.
+ std::unordered_map<uint32_t, const Type*> identifier_types_;
// Mapping from SPIR-V ID that is used at most once, to its AST expression.
std::unordered_map<uint32_t, TypedExpression> singly_used_values_;
diff --git a/src/reader/spirv/function_composite_test.cc b/src/reader/spirv/function_composite_test.cc
index 2724fd5..4fd0f07 100644
--- a/src/reader/spirv/function_composite_test.cc
+++ b/src/reader/spirv/function_composite_test.cc
@@ -923,7 +923,7 @@
VariableConst{
x_1
none
- __type_name_S_1
+ __type_name_S_2
{
Identifier[not set]{x_40}
}
@@ -1178,7 +1178,10 @@
none
__ptr_function__u32
{
- Identifier[not set]{x_10}
+ UnaryOp[not set]{
+ address-of
+ Identifier[not set]{x_10}
+ }
}
}
}
diff --git a/src/reader/spirv/function_memory_test.cc b/src/reader/spirv/function_memory_test.cc
index e6b1d3e..f44846a 100644
--- a/src/reader/spirv/function_memory_test.cc
+++ b/src/reader/spirv/function_memory_test.cc
@@ -1019,18 +1019,24 @@
none
__ptr_storage__u32
{
- ArrayAccessor[not set]{
- MemberAccessor[not set]{
- Identifier[not set]{myvar}
- Identifier[not set]{field1}
+ UnaryOp[not set]{
+ address-of
+ ArrayAccessor[not set]{
+ MemberAccessor[not set]{
+ Identifier[not set]{myvar}
+ Identifier[not set]{field1}
+ }
+ ScalarConstructor[not set]{1u}
}
- ScalarConstructor[not set]{1u}
}
}
}
}
Assignment{
- Identifier[not set]{x_2}
+ UnaryOp[not set]{
+ indirection
+ Identifier[not set]{x_2}
+ }
ScalarConstructor[not set]{0u}
})")) << p->error();
}
@@ -1082,12 +1088,15 @@
{
Assignment{
Identifier[not set]{x_2}
- ArrayAccessor[not set]{
- MemberAccessor[not set]{
- Identifier[not set]{myvar}
- Identifier[not set]{field1}
+ UnaryOp[not set]{
+ address-of
+ ArrayAccessor[not set]{
+ MemberAccessor[not set]{
+ Identifier[not set]{myvar}
+ Identifier[not set]{field1}
+ }
+ ScalarConstructor[not set]{1u}
}
- ScalarConstructor[not set]{1u}
}
}
}
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index 7f3ae37..986ca7a 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -24,6 +24,7 @@
#include "src/ast/override_decoration.h"
#include "src/ast/struct_block_decoration.h"
#include "src/ast/type_name.h"
+#include "src/ast/unary_op_expression.h"
#include "src/reader/spirv/function.h"
#include "src/sem/depth_texture_type.h"
#include "src/sem/multisampled_texture_type.h"
@@ -304,7 +305,7 @@
return tint::Program(std::move(builder_));
}
-const Type* ParserImpl::ConvertType(uint32_t type_id) {
+const Type* ParserImpl::ConvertType(uint32_t type_id, PtrAs ptr_as) {
if (!success_) {
return nullptr;
}
@@ -349,7 +350,7 @@
return maybe_generate_alias(ConvertType(type_id, spirv_type->AsStruct()));
case spvtools::opt::analysis::Type::kPointer:
return maybe_generate_alias(
- ConvertType(type_id, spirv_type->AsPointer()));
+ ConvertType(type_id, ptr_as, spirv_type->AsPointer()));
case spvtools::opt::analysis::Type::kFunction:
// Tint doesn't have a Function type.
// We need to convert the result type and parameter types.
@@ -1041,6 +1042,7 @@
}
const Type* ParserImpl::ConvertType(uint32_t type_id,
+ PtrAs ptr_as,
const spvtools::opt::analysis::Pointer*) {
const auto* inst = def_use_mgr_->GetDef(type_id);
const auto pointee_type_id = inst->GetSingleWordInOperand(1);
@@ -1051,7 +1053,7 @@
builtin_position_.storage_class = storage_class;
return nullptr;
}
- auto* ast_elem_ty = ConvertType(pointee_type_id);
+ auto* ast_elem_ty = ConvertType(pointee_type_id, PtrAs::Ptr);
if (ast_elem_ty == nullptr) {
Fail() << "SPIR-V pointer type with ID " << type_id
<< " has invalid pointee type " << pointee_type_id;
@@ -1079,8 +1081,14 @@
ast_storage_class = ast::StorageClass::kPrivate;
}
}
-
- return ty_.Pointer(ast_elem_ty, ast_storage_class);
+ switch (ptr_as) {
+ case PtrAs::Ref:
+ return ty_.Reference(ast_elem_ty, ast_storage_class);
+ case PtrAs::Ptr:
+ return ty_.Pointer(ast_elem_ty, ast_storage_class);
+ }
+ Fail() << "invalid value for ptr_as: " << static_cast<int>(ptr_as);
+ return nullptr;
}
bool ParserImpl::RegisterTypes() {
@@ -1094,7 +1102,7 @@
}
ConvertType(type_or_const.result_id());
}
- // Manufacture a type for the gl_Position varible if we have to.
+ // Manufacture a type for the gl_Position variable if we have to.
if ((builtin_position_.struct_type_id != 0) &&
(builtin_position_.position_member_pointer_type_id == 0)) {
builtin_position_.position_member_pointer_type_id =
@@ -1337,25 +1345,25 @@
ast::Variable* ParserImpl::MakeVariable(uint32_t id,
ast::StorageClass sc,
- const Type* type,
+ const Type* storage_type,
bool is_const,
ast::Expression* constructor,
ast::DecorationList decorations) {
- if (type == nullptr) {
+ if (storage_type == nullptr) {
Fail() << "internal error: can't make ast::Variable for null type";
return nullptr;
}
if (sc == ast::StorageClass::kStorage) {
bool read_only = false;
- if (auto* tn = type->As<Named>()) {
+ if (auto* tn = storage_type->As<Named>()) {
read_only = read_only_struct_types_.count(tn->name) > 0;
}
// Apply the access(read) or access(read_write) modifier.
auto access = read_only ? ast::AccessControl::kReadOnly
: ast::AccessControl::kReadWrite;
- type = ty_.AccessControl(type, access);
+ storage_type = ty_.AccessControl(storage_type, access);
}
// Handle variables (textures and samplers) are always in the handle
@@ -1367,15 +1375,20 @@
// In almost all cases, copy the decorations from SPIR-V to the variable.
// But avoid doing so when converting pipeline IO to private variables.
if (sc != ast::StorageClass::kPrivate) {
- if (!ConvertDecorationsForVariable(id, &type, &decorations)) {
+ if (!ConvertDecorationsForVariable(id, &storage_type, &decorations)) {
return nullptr;
}
}
std::string name = namer_.Name(id);
+
+ // Note: we're constructing the variable here with the *storage* type,
+ // regardless of whether this is a `let` or `var` declaration.
+ // `var` declarations will have a resolved type of ref<storage>, but at the
+ // AST level both `var` and `let` are declared with the same type.
return create<ast::Variable>(Source{}, builder_.Symbols().Register(name), sc,
- type->Build(builder_), is_const, constructor,
- decorations);
+ storage_type->Build(builder_), is_const,
+ constructor, decorations);
}
bool ParserImpl::ConvertDecorationsForVariable(
diff --git a/src/reader/spirv/parser_impl.h b/src/reader/spirv/parser_impl.h
index 9f3e336..14250fc 100644
--- a/src/reader/spirv/parser_impl.h
+++ b/src/reader/spirv/parser_impl.h
@@ -153,6 +153,14 @@
return glsl_std_450_imports_;
}
+ /// Desired handling of SPIR-V pointers by ConvertType()
+ enum class PtrAs {
+ // SPIR-V pointer is converted to a spirv::Pointer
+ Ptr,
+ // SPIR-V pointer is converted to a spirv::Reference
+ Ref
+ };
+
/// Converts a SPIR-V type to a Tint type, and saves it for fast lookup.
/// If the type is only used for builtins, then register that specially,
/// and return null. If the type is a sampler, image, or sampled image, then
@@ -161,8 +169,11 @@
/// On failure, logs an error and returns null. This should only be called
/// after the internal representation of the module has been built.
/// @param type_id the SPIR-V ID of a type.
+ /// @param ptr_as if the SPIR-V type is a pointer and ptr_as is equal to
+ /// PtrAs::Ref then a Reference will be returned, otherwise a Pointer will be
+ /// returned for a SPIR-V pointer
/// @returns a Tint type, or nullptr
- const Type* ConvertType(uint32_t type_id);
+ const Type* ConvertType(uint32_t type_id, PtrAs ptr_as = PtrAs::Ptr);
/// Emits an alias type declaration for the given type, if necessary, and
/// also updates the mapping of the SPIR-V type ID to the alias type.
@@ -339,7 +350,7 @@
/// decorations, unless it's an ignorable builtin variable.
/// @param id the SPIR-V result ID
/// @param sc the storage class, which cannot be ast::StorageClass::kNone
- /// @param type the type
+ /// @param storage_type the storage type of the variable
/// @param is_const if true, the variable is const
/// @param constructor the variable constructor
/// @param decorations the variable decorations
@@ -347,7 +358,7 @@
/// in the error case
ast::Variable* MakeVariable(uint32_t id,
ast::StorageClass sc,
- const Type* type,
+ const Type* storage_type,
bool is_const,
ast::Expression* constructor,
ast::DecorationList decorations);
@@ -616,12 +627,15 @@
/// @param struct_ty the Tint type
const Type* ConvertType(uint32_t type_id,
const spvtools::opt::analysis::Struct* struct_ty);
- /// Converts a specific SPIR-V type to a Tint type. Pointer case
+ /// Converts a specific SPIR-V type to a Tint type. Pointer / Reference case
/// The pointer to gl_PerVertex maps to nullptr, and instead is recorded
/// in member #builtin_position_.
/// @param type_id the SPIR-V ID for the type.
+ /// @param ptr_as if PtrAs::Ref then a Reference will be returned, otherwise
+ /// Pointer
/// @param ptr_ty the Tint type
const Type* ConvertType(uint32_t type_id,
+ PtrAs ptr_as,
const spvtools::opt::analysis::Pointer* ptr_ty);
/// If `type` is a signed integral, or vector of signed integral,
diff --git a/src/reader/spirv/parser_impl_module_var_test.cc b/src/reader/spirv/parser_impl_module_var_test.cc
index 97d2aed..7899896 100644
--- a/src/reader/spirv/parser_impl_module_var_test.cc
+++ b/src/reader/spirv/parser_impl_module_var_test.cc
@@ -2413,7 +2413,10 @@
none
__ptr_in__u32
{
- Identifier[not set]{x_1}
+ UnaryOp[not set]{
+ address-of
+ Identifier[not set]{x_1}
+ }
}
}
}
@@ -2423,7 +2426,10 @@
none
__u32
{
- Identifier[not set]{x_11}
+ UnaryOp[not set]{
+ indirection
+ Identifier[not set]{x_11}
+ }
}
}
})"))
@@ -3295,7 +3301,10 @@
none
__ptr_in__u32
{
- Identifier[not set]{x_1}
+ UnaryOp[not set]{
+ address-of
+ Identifier[not set]{x_1}
+ }
}
}
}
@@ -3305,7 +3314,10 @@
none
__u32
{
- Identifier[not set]{x_11}
+ UnaryOp[not set]{
+ indirection
+ Identifier[not set]{x_11}
+ }
}
}
})"))
@@ -3614,7 +3626,10 @@
none
__ptr_in__u32
{
- Identifier[not set]{x_1}
+ UnaryOp[not set]{
+ address-of
+ Identifier[not set]{x_1}
+ }
}
}
}
@@ -3624,7 +3639,10 @@
none
__u32
{
- Identifier[not set]{x_11}
+ UnaryOp[not set]{
+ indirection
+ Identifier[not set]{x_11}
+ }
}
}
})"))
diff --git a/src/resolver/assignment_validation_test.cc b/src/resolver/assignment_validation_test.cc
index 1c5e696..86a92c2 100644
--- a/src/resolver/assignment_validation_test.cc
+++ b/src/resolver/assignment_validation_test.cc
@@ -31,39 +31,13 @@
// }
auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
- auto* lhs = Expr("a");
- auto* rhs = Expr(2.3f);
- auto* assign = Assign(Source{{12, 34}}, lhs, rhs);
+ auto* assign = Assign(Source{{12, 34}}, "a", 2.3f);
WrapInFunction(var, assign);
ASSERT_FALSE(r()->Resolve());
- EXPECT_EQ(
- r()->error(),
- R"(12:34 error: invalid assignment: cannot assign value of type 'f32' to a variable of type 'i32')");
-}
-
-TEST_F(ResolverAssignmentValidationTest,
- AssignThroughPointerWrongeStoreType_Fail) {
- // var a : f32;
- // let b : ptr<function,f32> = a;
- // b = 2;
- const auto priv = ast::StorageClass::kFunction;
- auto* var_a = Var("a", ty.f32(), priv);
- auto* var_b = Const("b", ty.pointer<float>(priv), Expr("a"), {});
-
- auto* lhs = Expr("a");
- auto* rhs = Expr(2);
-
- auto* assign = Assign(Source{{12, 34}}, lhs, rhs);
- WrapInFunction(var_a, var_b, assign);
-
- ASSERT_FALSE(r()->Resolve());
-
- EXPECT_EQ(
- r()->error(),
- R"(12:34 error: invalid assignment: cannot assign value of type 'i32' to a variable of type 'f32')");
+ EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'f32' to 'i32'");
}
TEST_F(ResolverAssignmentValidationTest,
@@ -73,11 +47,7 @@
// a = 2
// }
auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
- auto* lhs = Expr("a");
- auto* rhs = Expr(2);
-
- auto* body = Block(Decl(var), Assign(Source{{12, 34}}, lhs, rhs));
- WrapInFunction(body);
+ WrapInFunction(var, Assign("a", 2));
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
@@ -90,17 +60,11 @@
// }
auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
- auto* lhs = Expr("a");
- auto* rhs = Expr(2.3f);
-
- auto* block = Block(Decl(var), Assign(Source{{12, 34}}, lhs, rhs));
- WrapInFunction(block);
+ WrapInFunction(var, Assign(Source{{12, 34}}, "a", 2.3f));
ASSERT_FALSE(r()->Resolve());
- EXPECT_EQ(
- r()->error(),
- R"(12:34 error: invalid assignment: cannot assign value of type 'f32' to a variable of type 'i32')");
+ EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'f32' to 'i32'");
}
TEST_F(ResolverAssignmentValidationTest,
@@ -113,20 +77,13 @@
// }
auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
- auto* lhs = Expr("a");
- auto* rhs = Expr(2.3f);
-
- auto* inner_block = Block(Decl(var), Assign(Source{{12, 34}}, lhs, rhs));
-
+ auto* inner_block = Block(Decl(var), Assign(Source{{12, 34}}, "a", 2.3f));
auto* outer_block = Block(inner_block);
-
WrapInFunction(outer_block);
ASSERT_FALSE(r()->Resolve());
- EXPECT_EQ(
- r()->error(),
- R"(12:34 error: invalid assignment: cannot assign value of type 'f32' to a variable of type 'i32')");
+ EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'f32' to 'i32'");
}
TEST_F(ResolverAssignmentValidationTest, AssignToScalar_Fail) {
@@ -134,28 +91,17 @@
// 1 = my_var;
auto* var = Var("my_var", ty.i32(), ast::StorageClass::kNone, Expr(2));
- auto* lhs = Expr(1);
- auto* rhs = Expr("my_var");
-
- auto* assign = Assign(Source{{12, 34}}, lhs, rhs);
- WrapInFunction(Decl(var), assign);
+ WrapInFunction(var, Assign(Expr(Source{{12, 34}}, 1), "my_var"));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "12:34 error v-000x: invalid assignment: left-hand-side does not "
- "reference storage: i32");
+ EXPECT_EQ(r()->error(), "12:34 error: cannot assign to value of type 'i32'");
}
TEST_F(ResolverAssignmentValidationTest, AssignCompatibleTypes_Pass) {
- // var a :i32 = 2;
+ // var a : i32 = 2;
// a = 2
auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
-
- auto* lhs = Expr("a");
- auto* rhs = Expr(2);
-
- auto* assign = Assign(Source{Source::Location{12, 34}}, lhs, rhs);
- WrapInFunction(Decl(var), assign);
+ WrapInFunction(var, Assign(Source{{12, 34}}, "a", 2));
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -163,17 +109,12 @@
TEST_F(ResolverAssignmentValidationTest,
AssignCompatibleTypesThroughAlias_Pass) {
// alias myint = i32;
- // var a :myint = 2;
+ // var a : myint = 2;
// a = 2
auto* myint = ty.alias("myint", ty.i32());
AST().AddConstructedType(myint);
auto* var = Var("a", myint, ast::StorageClass::kNone, Expr(2));
-
- auto* lhs = Expr("a");
- auto* rhs = Expr(2);
-
- auto* assign = Assign(Source{Source::Location{12, 34}}, lhs, rhs);
- WrapInFunction(Decl(var), assign);
+ WrapInFunction(var, Assign(Source{{12, 34}}, "a", 2));
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -185,29 +126,19 @@
// a = b;
auto* var_a = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
auto* var_b = Var("b", ty.i32(), ast::StorageClass::kNone, Expr(3));
-
- auto* lhs = Expr("a");
- auto* rhs = Expr("b");
-
- auto* assign = Assign(Source{Source::Location{12, 34}}, lhs, rhs);
- WrapInFunction(Decl(var_a), Decl(var_b), assign);
+ WrapInFunction(var_a, var_b, Assign(Source{{12, 34}}, "a", "b"));
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverAssignmentValidationTest, AssignThroughPointer_Pass) {
- // var a :i32;
- // let b : ptr<function,i32> = a;
- // b = 2;
+ // var a : i32;
+ // let b : ptr<function,i32> = &a;
+ // *b = 2;
const auto func = ast::StorageClass::kFunction;
auto* var_a = Var("a", ty.i32(), func, Expr(2), {});
- auto* var_b = Const("b", ty.pointer<int>(func), Expr("a"), {});
-
- auto* lhs = Expr("b");
- auto* rhs = Expr(2);
-
- auto* assign = Assign(Source{Source::Location{12, 34}}, lhs, rhs);
- WrapInFunction(Decl(var_a), Decl(var_b), assign);
+ auto* var_b = Const("b", ty.pointer<int>(func), AddressOf(Expr("a")), {});
+ WrapInFunction(var_a, var_b, Assign(Source{{12, 34}}, Deref("b"), 2));
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
@@ -218,21 +149,13 @@
// a = 2
// }
auto* var = Const("a", ty.i32(), Expr(2));
-
- auto* lhs = Expr("a");
- auto* rhs = Expr(2);
-
- auto* body =
- Block(Decl(var), Assign(Source{Source::Location{12, 34}}, lhs, rhs));
-
- WrapInFunction(body);
+ WrapInFunction(var, Assign(Expr(Source{{12, 34}}, "a"), 2));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "12:34 error v-0021: cannot re-assign a constant: 'a'");
+ EXPECT_EQ(r()->error(), "12:34 error: cannot assign to value of type 'i32'");
}
-TEST_F(ResolverAssignmentValidationTest, AssignFromPointer_Fail) {
+TEST_F(ResolverAssignmentValidationTest, AssignNonStorable_Fail) {
// var a : [[access(read)]] texture_storage_1d<rgba8unorm>;
// var b : [[access(read)]] texture_storage_1d<rgba8unorm>;
// a = b;
@@ -243,24 +166,23 @@
return ty.access(ast::AccessControl::kReadOnly, tex_type);
};
- auto* var_a = Global("a", make_type(), ast::StorageClass::kNone, nullptr,
- {
- create<ast::BindingDecoration>(0),
- create<ast::GroupDecoration>(0),
- });
- auto* var_b = Global("b", make_type(), ast::StorageClass::kNone, nullptr,
- {
- create<ast::BindingDecoration>(1),
- create<ast::GroupDecoration>(0),
- });
+ Global("a", make_type(), ast::StorageClass::kNone, nullptr,
+ {
+ create<ast::BindingDecoration>(0),
+ create<ast::GroupDecoration>(0),
+ });
+ Global("b", make_type(), ast::StorageClass::kNone, nullptr,
+ {
+ create<ast::BindingDecoration>(1),
+ create<ast::GroupDecoration>(0),
+ });
- WrapInFunction(Assign(Source{{12, 34}}, var_a, var_b));
+ WrapInFunction(Assign("a", Expr(Source{{12, 34}}, "b")));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "12:34 error v-000x: invalid assignment: right-hand-side is not "
- "storable: ptr<uniform_constant, texture_storage_1d<rgba8unorm, "
- "read_only>>");
+ EXPECT_EQ(
+ r()->error(),
+ R"(12:34 error: '[[access(read)]] texture_storage_1d<rgba8unorm>' is not storable)");
}
} // namespace
diff --git a/src/resolver/builtins_validation_test.cc b/src/resolver/builtins_validation_test.cc
index 363b35a..fe2b59d 100644
--- a/src/resolver/builtins_validation_test.cc
+++ b/src/resolver/builtins_validation_test.cc
@@ -108,7 +108,7 @@
TEST_F(ResolverBuiltinsValidationTest, Frexp_Scalar) {
auto* a = Var("a", ty.i32());
- auto* builtin = Call("frexp", 1.0f, Expr("a"));
+ auto* builtin = Call("frexp", 1.0f, AddressOf(Expr("a")));
WrapInFunction(Decl(a), builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -118,10 +118,8 @@
TEST_F(ResolverBuiltinsValidationTest, Frexp_Vec2) {
auto* a = Var("a", ty.vec2<int>());
- auto* b = Const("b", ty.pointer(ty.vec2<i32>(), ast::StorageClass::kFunction),
- Expr("a"), {});
- auto* builtin = Call("frexp", vec2<f32>(1.0f, 1.0f), Expr("b"));
- WrapInFunction(Decl(a), Decl(b), builtin);
+ auto* builtin = Call("frexp", vec2<f32>(1.0f, 1.0f), AddressOf(Expr("a")));
+ WrapInFunction(Decl(a), builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
@@ -130,10 +128,9 @@
TEST_F(ResolverBuiltinsValidationTest, Frexp_Vec3) {
auto* a = Var("a", ty.vec3<int>());
- auto* b = Const("b", ty.pointer(ty.vec3<i32>(), ast::StorageClass::kFunction),
- Expr("a"), {});
- auto* builtin = Call("frexp", vec3<f32>(1.0f, 1.0f, 1.0f), Expr("b"));
- WrapInFunction(Decl(a), Decl(b), builtin);
+ auto* builtin =
+ Call("frexp", vec3<f32>(1.0f, 1.0f, 1.0f), AddressOf(Expr("a")));
+ WrapInFunction(Decl(a), builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
@@ -142,10 +139,9 @@
TEST_F(ResolverBuiltinsValidationTest, Frexp_Vec4) {
auto* a = Var("a", ty.vec4<int>());
- auto* b = Const("b", ty.pointer(ty.vec4<i32>(), ast::StorageClass::kFunction),
- Expr("a"), {});
- auto* builtin = Call("frexp", vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f), Expr("b"));
- WrapInFunction(Decl(a), Decl(b), builtin);
+ auto* builtin =
+ Call("frexp", vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f), AddressOf(Expr("a")));
+ WrapInFunction(Decl(a), builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
@@ -154,10 +150,8 @@
TEST_F(ResolverBuiltinsValidationTest, Modf_Scalar) {
auto* a = Var("a", ty.f32());
- auto* b =
- Const("b", ty.pointer<f32>(ast::StorageClass::kFunction), Expr("a"), {});
- auto* builtin = Call("modf", 1.0f, Expr("b"));
- WrapInFunction(Decl(a), Decl(b), builtin);
+ auto* builtin = Call("modf", 1.0f, AddressOf(Expr("a")));
+ WrapInFunction(Decl(a), builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->Is<sem::F32>());
@@ -166,10 +160,8 @@
TEST_F(ResolverBuiltinsValidationTest, Modf_Vec2) {
auto* a = Var("a", ty.vec2<f32>());
- auto* b = Const("b", ty.pointer(ty.vec2<f32>(), ast::StorageClass::kFunction),
- Expr("a"), {});
- auto* builtin = Call("modf", vec2<f32>(1.0f, 1.0f), Expr("b"));
- WrapInFunction(Decl(a), Decl(b), builtin);
+ auto* builtin = Call("modf", vec2<f32>(1.0f, 1.0f), AddressOf(Expr("a")));
+ WrapInFunction(Decl(a), builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
@@ -178,10 +170,9 @@
TEST_F(ResolverBuiltinsValidationTest, Modf_Vec3) {
auto* a = Var("a", ty.vec3<f32>());
- auto* b = Const("b", ty.pointer(ty.vec3<f32>(), ast::StorageClass::kFunction),
- Expr("a"), {});
- auto* builtin = Call("modf", vec3<f32>(1.0f, 1.0f, 1.0f), Expr("b"));
- WrapInFunction(Decl(a), Decl(b), builtin);
+ auto* builtin =
+ Call("modf", vec3<f32>(1.0f, 1.0f, 1.0f), AddressOf(Expr("a")));
+ WrapInFunction(Decl(a), builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
@@ -190,10 +181,9 @@
TEST_F(ResolverBuiltinsValidationTest, Modf_Vec4) {
auto* a = Var("a", ty.vec4<f32>());
- auto* b = Const("b", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction),
- Expr("a"), {});
- auto* builtin = Call("modf", vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f), Expr("b"));
- WrapInFunction(Decl(a), Decl(b), builtin);
+ auto* builtin =
+ Call("modf", vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f), AddressOf(Expr("a")));
+ WrapInFunction(Decl(a), builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
diff --git a/src/resolver/intrinsic_test.cc b/src/resolver/intrinsic_test.cc
index af7323d..eb704bf 100644
--- a/src/resolver/intrinsic_test.cc
+++ b/src/resolver/intrinsic_test.cc
@@ -182,7 +182,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "error: no matching call to " + name +
- "(ptr<in, f32>, f32)\n\n"
+ "(f32, f32)\n\n"
"2 candidate functions:\n " +
name + "(f32) -> bool\n " + name +
"(vecN<f32>) -> vecN<bool>\n");
@@ -435,9 +435,8 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(
- r()->error(),
- R"(error: no matching call to dot(ptr<in, vec4<i32>>, ptr<in, vec4<i32>>)
+ EXPECT_EQ(r()->error(),
+ R"(error: no matching call to dot(vec4<i32>, vec4<i32>)
1 candidate function:
dot(vecN<f32>, vecN<f32>) -> f32
@@ -793,7 +792,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "error: no matching call to arrayLength(ptr<in, array<i32, 4>>)\n\n"
+ "error: no matching call to arrayLength(array<i32, 4>)\n\n"
"1 candidate function:\n"
" arrayLength(array<T>) -> u32\n");
}
@@ -823,7 +822,7 @@
TEST_F(ResolverIntrinsicDataTest, FrexpScalar) {
Global("exp", ty.i32(), ast::StorageClass::kWorkgroup);
- auto* call = Call("frexp", 1.0f, "exp");
+ auto* call = Call("frexp", 1.0f, AddressOf("exp"));
WrapInFunction(call);
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -834,7 +833,7 @@
TEST_F(ResolverIntrinsicDataTest, FrexpVector) {
Global("exp", ty.vec3<i32>(), ast::StorageClass::kWorkgroup);
- auto* call = Call("frexp", vec3<f32>(1.0f, 2.0f, 3.0f), "exp");
+ auto* call = Call("frexp", vec3<f32>(1.0f, 2.0f, 3.0f), AddressOf("exp"));
WrapInFunction(call);
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -846,7 +845,7 @@
TEST_F(ResolverIntrinsicDataTest, Frexp_Error_FirstParamInt) {
Global("exp", ty.i32(), ast::StorageClass::kWorkgroup);
- auto* call = Call("frexp", 1, "exp");
+ auto* call = Call("frexp", 1, AddressOf("exp"));
WrapInFunction(call);
EXPECT_FALSE(r()->Resolve());
@@ -861,7 +860,7 @@
TEST_F(ResolverIntrinsicDataTest, Frexp_Error_SecondParamFloatPtr) {
Global("exp", ty.f32(), ast::StorageClass::kWorkgroup);
- auto* call = Call("frexp", 1.0f, "exp");
+ auto* call = Call("frexp", 1.0f, AddressOf("exp"));
WrapInFunction(call);
EXPECT_FALSE(r()->Resolve());
@@ -890,23 +889,24 @@
TEST_F(ResolverIntrinsicDataTest, Frexp_Error_VectorSizesDontMatch) {
Global("exp", ty.vec4<i32>(), ast::StorageClass::kWorkgroup);
- auto* call = Call("frexp", vec2<f32>(1.0f, 2.0f), "exp");
+ auto* call = Call("frexp", vec2<f32>(1.0f, 2.0f), AddressOf("exp"));
WrapInFunction(call);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "error: no matching call to frexp(vec2<f32>, ptr<workgroup, "
- "vec4<i32>>)\n\n"
- "2 candidate functions:\n"
- " frexp(f32, ptr<T>) -> f32 where: T is i32 or u32\n"
- " frexp(vecN<f32>, ptr<vecN<T>>) -> vecN<f32> "
- "where: T is i32 or u32\n");
+ EXPECT_EQ(
+ r()->error(),
+ R"(error: no matching call to frexp(vec2<f32>, ptr<workgroup, vec4<i32>>)
+
+2 candidate functions:
+ frexp(f32, ptr<T>) -> f32 where: T is i32 or u32
+ frexp(vecN<f32>, ptr<vecN<T>>) -> vecN<f32> where: T is i32 or u32
+)");
}
TEST_F(ResolverIntrinsicDataTest, ModfScalar) {
Global("whole", ty.f32(), ast::StorageClass::kWorkgroup);
- auto* call = Call("modf", 1.0f, "whole");
+ auto* call = Call("modf", 1.0f, AddressOf("whole"));
WrapInFunction(call);
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -917,7 +917,7 @@
TEST_F(ResolverIntrinsicDataTest, ModfVector) {
Global("whole", ty.vec3<f32>(), ast::StorageClass::kWorkgroup);
- auto* call = Call("modf", vec3<f32>(1.0f, 2.0f, 3.0f), "whole");
+ auto* call = Call("modf", vec3<f32>(1.0f, 2.0f, 3.0f), AddressOf("whole"));
WrapInFunction(call);
EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -929,7 +929,7 @@
TEST_F(ResolverIntrinsicDataTest, Modf_Error_FirstParamInt) {
Global("whole", ty.f32(), ast::StorageClass::kWorkgroup);
- auto* call = Call("modf", 1, "whole");
+ auto* call = Call("modf", 1, AddressOf("whole"));
WrapInFunction(call);
EXPECT_FALSE(r()->Resolve());
@@ -943,7 +943,7 @@
TEST_F(ResolverIntrinsicDataTest, Modf_Error_SecondParamIntPtr) {
Global("whole", ty.i32(), ast::StorageClass::kWorkgroup);
- auto* call = Call("modf", 1.0f, "whole");
+ auto* call = Call("modf", 1.0f, AddressOf("whole"));
WrapInFunction(call);
EXPECT_FALSE(r()->Resolve());
@@ -970,17 +970,19 @@
TEST_F(ResolverIntrinsicDataTest, Modf_Error_VectorSizesDontMatch) {
Global("whole", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
- auto* call = Call("modf", vec2<f32>(1.0f, 2.0f), "whole");
+ auto* call = Call("modf", vec2<f32>(1.0f, 2.0f), AddressOf("whole"));
WrapInFunction(call);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "error: no matching call to modf(vec2<f32>, ptr<workgroup, "
- "vec4<f32>>)\n\n"
- "2 candidate functions:\n"
- " modf(vecN<f32>, ptr<vecN<f32>>) -> vecN<f32>\n"
- " modf(f32, ptr<f32>) -> f32\n");
+ EXPECT_EQ(
+ r()->error(),
+ R"(error: no matching call to modf(vec2<f32>, ptr<workgroup, vec4<f32>>)
+
+2 candidate functions:
+ modf(vecN<f32>, ptr<vecN<f32>>) -> vecN<f32>
+ modf(f32, ptr<f32>) -> f32
+)");
}
using ResolverIntrinsicTest_SingleParam_FloatOrInt =
@@ -1652,11 +1654,10 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(
- r()->error(),
- "error: no matching call to determinant(ptr<private, mat2x3<f32>>)\n\n"
- "1 candidate function:\n"
- " determinant(matNxN<f32>) -> f32\n");
+ EXPECT_EQ(r()->error(),
+ "error: no matching call to determinant(mat2x3<f32>)\n\n"
+ "1 candidate function:\n"
+ " determinant(matNxN<f32>) -> f32\n");
}
TEST_F(ResolverIntrinsicTest, Determinant_NotMatrix) {
@@ -1668,7 +1669,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "error: no matching call to determinant(ptr<private, f32>)\n\n"
+ "error: no matching call to determinant(f32)\n\n"
"1 candidate function:\n"
" determinant(matNxN<f32>) -> f32\n");
}
diff --git a/src/resolver/ptr_ref_test.cc b/src/resolver/ptr_ref_test.cc
new file mode 100644
index 0000000..e66a0ce
--- /dev/null
+++ b/src/resolver/ptr_ref_test.cc
@@ -0,0 +1,62 @@
+// Copyright 2021 The Tint Authors.
+//
+// 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.
+
+#include "src/resolver/resolver.h"
+#include "src/resolver/resolver_test_helper.h"
+#include "src/sem/reference_type.h"
+
+#include "gmock/gmock.h"
+
+namespace tint {
+namespace resolver {
+namespace {
+
+struct ResolverPtrRefTest : public resolver::TestHelper,
+ public testing::Test {};
+
+TEST_F(ResolverPtrRefTest, AddressOf) {
+ // var v : i32;
+ // &v
+
+ auto* v = Var("v", ty.i32(), ast::StorageClass::kNone);
+ auto* expr = AddressOf(v);
+
+ WrapInFunction(v, expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_TRUE(TypeOf(expr)->Is<sem::Pointer>());
+ EXPECT_TRUE(TypeOf(expr)->As<sem::Pointer>()->StoreType()->Is<sem::I32>());
+ EXPECT_EQ(TypeOf(expr)->As<sem::Pointer>()->StorageClass(),
+ ast::StorageClass::kFunction);
+}
+
+TEST_F(ResolverPtrRefTest, AddressOfThenDeref) {
+ // var v : i32;
+ // *(&v)
+
+ auto* v = Var("v", ty.i32(), ast::StorageClass::kNone);
+ auto* expr = Deref(AddressOf(v));
+
+ WrapInFunction(v, expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_TRUE(TypeOf(expr)->Is<sem::Reference>());
+ EXPECT_TRUE(TypeOf(expr)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
+}
+
+} // namespace
+} // namespace resolver
+} // namespace tint
diff --git a/src/resolver/ptr_ref_validation_test.cc b/src/resolver/ptr_ref_validation_test.cc
new file mode 100644
index 0000000..0b2d07d
--- /dev/null
+++ b/src/resolver/ptr_ref_validation_test.cc
@@ -0,0 +1,82 @@
+// Copyright 2021 The Tint Authors.
+//
+// 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.
+
+#include "src/resolver/resolver.h"
+#include "src/resolver/resolver_test_helper.h"
+#include "src/sem/reference_type.h"
+
+#include "gmock/gmock.h"
+
+namespace tint {
+namespace resolver {
+namespace {
+
+struct ResolverPtrRefValidationTest : public resolver::TestHelper,
+ public testing::Test {};
+
+TEST_F(ResolverPtrRefValidationTest, AddressOfLiteral) {
+ // &1
+
+ auto* expr = AddressOf(Expr(Source{{12, 34}}, 1));
+
+ WrapInFunction(expr);
+
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(r()->error(), "12:34 error: cannot take the address of expression");
+}
+
+TEST_F(ResolverPtrRefValidationTest, AddressOfLet) {
+ // let l : i32 = 1;
+ // &l
+ auto* l = Const("l", ty.i32(), Expr(1));
+ auto* expr = AddressOf(Expr(Source{{12, 34}}, "l"));
+
+ WrapInFunction(l, expr);
+
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(r()->error(), "12:34 error: cannot take the address of expression");
+}
+
+TEST_F(ResolverPtrRefValidationTest, DerefOfLiteral) {
+ // *1
+
+ auto* expr = Deref(Expr(Source{{12, 34}}, 1));
+
+ WrapInFunction(expr);
+
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(r()->error(),
+ "12:34 error: cannot dereference expression of type 'i32'");
+}
+
+TEST_F(ResolverPtrRefValidationTest, DerefOfVar) {
+ // var v : i32 = 1;
+ // *1
+ auto* v = Var("v", ty.i32());
+ auto* expr = Deref(Expr(Source{{12, 34}}, "v"));
+
+ WrapInFunction(v, expr);
+
+ EXPECT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(r()->error(),
+ "12:34 error: cannot dereference expression of type 'i32'");
+}
+
+} // namespace
+} // namespace resolver
+} // namespace tint
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index 67b0734..a5e3379 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -53,6 +53,7 @@
#include "src/sem/member_accessor_expression.h"
#include "src/sem/multisampled_texture_type.h"
#include "src/sem/pointer_type.h"
+#include "src/sem/reference_type.h"
#include "src/sem/sampled_texture_type.h"
#include "src/sem/sampler_type.h"
#include "src/sem/statement.h"
@@ -226,22 +227,6 @@
return false;
}
-bool Resolver::IsValidAssignment(const sem::Type* lhs, const sem::Type* rhs) {
- // TODO(crbug.com/tint/659): This is a rough approximation, and is missing
- // checks for writability of pointer storage class, access control, etc.
- // This will need to be fixed after WGSL agrees the behavior of pointers /
- // references.
- // Check:
- if (lhs->UnwrapAccess() != rhs->UnwrapAccess()) {
- // Try RHS dereference
- if (lhs->UnwrapAccess() != rhs->UnwrapAll()) {
- return false;
- }
- }
-
- return true;
-}
-
bool Resolver::ResolveInternal() {
Mark(&builder_->AST());
@@ -438,7 +423,7 @@
}
Resolver::VariableInfo* Resolver::Variable(ast::Variable* var,
- bool is_parameter) {
+ VariableKind kind) {
if (variable_to_info_.count(var)) {
TINT_ICE(diagnostics_) << "Variable "
<< builder_->Symbols().NameFor(var->symbol())
@@ -446,17 +431,21 @@
return nullptr;
}
- // If the variable has a declared type, resolve it.
std::string type_name;
- const sem::Type* type = nullptr;
+ const sem::Type* storage_type = nullptr;
+
+ // If the variable has a declared type, resolve it.
if (auto* ty = var->type()) {
type_name = ty->FriendlyName(builder_->Symbols());
- type = Type(ty);
- if (!type) {
+ storage_type = Type(ty);
+ if (!storage_type) {
return nullptr;
}
}
+ std::string rhs_type_name;
+ const sem::Type* rhs_type = nullptr;
+
// Does the variable have a constructor?
if (auto* ctor = var->constructor()) {
Mark(var->constructor());
@@ -465,32 +454,57 @@
}
// Fetch the constructor's type
- auto* rhs_type = TypeOf(ctor);
+ rhs_type_name = TypeNameOf(ctor);
+ rhs_type = TypeOf(ctor);
if (!rhs_type) {
return nullptr;
}
// If the variable has no declared type, infer it from the RHS
- if (type == nullptr) {
- type_name = TypeNameOf(ctor);
- type = rhs_type->UnwrapPtr();
+ if (!storage_type) {
+ type_name = rhs_type_name;
+ storage_type = rhs_type->UnwrapRef(); // Implicit load of RHS
}
-
- if (!IsValidAssignment(type, rhs_type)) {
- diagnostics_.add_error(
- "variable of type '" + type_name +
- "' cannot be initialized with a value of type '" +
- TypeNameOf(ctor) + "'",
- var->source());
- return nullptr;
- }
- } else if (var->is_const() && !is_parameter &&
+ } else if (var->is_const() && kind != VariableKind::kParameter &&
!ast::HasDecoration<ast::OverrideDecoration>(var->decorations())) {
diagnostics_.add_error("let declarations must have initializers",
var->source());
return nullptr;
}
+ if (!storage_type) {
+ TINT_ICE(diagnostics_)
+ << "failed to determine storage type for variable '" +
+ builder_->Symbols().NameFor(var->symbol()) + "'\n"
+ << "Source: " << var->source();
+ return nullptr;
+ }
+
+ auto storage_class = var->declared_storage_class();
+ if (storage_class == ast::StorageClass::kNone) {
+ if (storage_type->UnwrapRef()->is_handle()) {
+ // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
+ // If the store type is a texture type or a sampler type, then the
+ // variable declaration must not have a storage class decoration. The
+ // storage class will always be handle.
+ storage_class = ast::StorageClass::kUniformConstant;
+ } else if (kind == VariableKind::kLocal && !var->is_const()) {
+ storage_class = ast::StorageClass::kFunction;
+ }
+ }
+
+ auto* type = storage_type;
+ if (!var->is_const()) {
+ // Variable declaration. Unlike `let`, `var` has storage.
+ // Variables are always of a reference type to the declared storage type.
+ type = builder_->create<sem::Reference>(storage_type, storage_class);
+ }
+
+ if (rhs_type && !ValidateVariableConstructor(var, storage_type, type_name,
+ rhs_type, rhs_type_name)) {
+ return nullptr;
+ }
+
// TODO(crbug.com/tint/802): Temporary while ast::AccessControl exits.
auto find_first_access_control =
[this](ast::Type* ty) -> ast::AccessControl* {
@@ -519,12 +533,39 @@
}
auto* info = variable_infos_.Create(var, const_cast<sem::Type*>(type),
- type_name, access_control);
+ type_name, storage_class, access_control);
variable_to_info_.emplace(var, info);
return info;
}
+bool Resolver::ValidateVariableConstructor(const ast::Variable* var,
+ const sem::Type* storage_type,
+ const std::string& type_name,
+ const sem::Type* rhs_type,
+ const std::string& rhs_type_name) {
+ auto* value_type = rhs_type->UnwrapRef(); // Implicit load of RHS
+
+ // RHS needs to be of a storable type
+ if (!var->is_const() && !IsStorable(value_type)) {
+ diagnostics_.add_error(
+ "'" + rhs_type_name + "' is not storable for assignment",
+ var->constructor()->source());
+ return false;
+ }
+
+ // Value type has to match storage type
+ if (storage_type->UnwrapAccess() != value_type->UnwrapAccess()) {
+ std::string decl = var->is_const() ? "let" : "var";
+ diagnostics_.add_error("cannot initialize " + decl + " of type '" +
+ type_name + "' with value of type '" +
+ rhs_type_name + "'",
+ var->source());
+ return false;
+ }
+ return true;
+}
+
bool Resolver::GlobalVariable(ast::Variable* var) {
if (variable_stack_.has(var->symbol())) {
diagnostics_.add_error("v-0011",
@@ -534,7 +575,7 @@
return false;
}
- auto* info = Variable(var, /* is_parameter */ false);
+ auto* info = Variable(var, VariableKind::kGlobal);
if (!info) {
return false;
}
@@ -571,8 +612,9 @@
return false;
}
- if (!ApplyStorageClassUsageToType(info->storage_class, info->type,
- var->source())) {
+ if (!ApplyStorageClassUsageToType(
+ info->storage_class, const_cast<sem::Type*>(info->type->UnwrapRef()),
+ var->source())) {
diagnostics_.add_note("while instantiating variable " +
builder_->Symbols().NameFor(var->symbol()),
var->source());
@@ -636,7 +678,8 @@
// attributes.
if (!binding_point) {
diagnostics_.add_error(
- "resource variables require [[group]] and [[binding]] decorations",
+ "resource variables require [[group]] and [[binding]] "
+ "decorations",
info->declaration->source());
return false;
}
@@ -666,7 +709,7 @@
// attribute, satisfying the storage class constraints.
auto* str = info->access_control != ast::AccessControl::kInvalid
- ? info->type->As<sem::Struct>()
+ ? info->type->UnwrapRef()->As<sem::Struct>()
: nullptr;
if (!str) {
@@ -695,7 +738,7 @@
// A variable in the uniform storage class is a uniform buffer variable.
// Its store type must be a host-shareable structure type with block
// attribute, satisfying the storage class constraints.
- auto* str = info->type->As<sem::Struct>();
+ auto* str = info->type->UnwrapRef()->As<sem::Struct>();
if (!str) {
diagnostics_.add_error(
"variables declared in the <uniform> storage class must be of a "
@@ -726,8 +769,8 @@
bool Resolver::ValidateVariable(const VariableInfo* info) {
auto* var = info->declaration;
- auto* type = info->type;
- if (auto* r = type->As<sem::Array>()) {
+ auto* storage_type = info->type->UnwrapRef();
+ if (auto* r = storage_type->As<sem::Array>()) {
if (r->IsRuntimeSized()) {
diagnostics_.add_error(
"v-0015",
@@ -737,15 +780,14 @@
}
}
- if (auto* r = type->As<sem::MultisampledTexture>()) {
+ if (auto* r = storage_type->As<sem::MultisampledTexture>()) {
if (r->dim() != ast::TextureDimension::k2d) {
diagnostics_.add_error("Only 2d multisampled textures are supported",
var->source());
return false;
}
- auto* data_type = r->type()->UnwrapAll();
- if (!data_type->is_numeric_scalar()) {
+ if (!r->type()->UnwrapRef()->is_numeric_scalar()) {
diagnostics_.add_error(
"texture_multisampled_2d<type>: type must be f32, i32 or u32",
var->source());
@@ -753,7 +795,7 @@
}
}
- if (auto* storage_tex = type->As<sem::StorageTexture>()) {
+ if (auto* storage_tex = info->type->UnwrapRef()->As<sem::StorageTexture>()) {
if (storage_tex->access_control() == ast::AccessControl::kInvalid) {
diagnostics_.add_error("Storage Textures must have access control.",
var->source());
@@ -786,12 +828,12 @@
}
}
- if (type->UnwrapAll()->is_handle() &&
+ if (storage_type->is_handle() &&
var->declared_storage_class() != ast::StorageClass::kNone) {
// https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
- // If the store type is a texture type or a sampler type, then the variable
- // declaration must not have a storage class decoration. The storage class
- // will always be handle.
+ // If the store type is a texture type or a sampler type, then the
+ // variable declaration must not have a storage class decoration. The
+ // storage class will always be handle.
diagnostics_.add_error("variables of type '" + info->type_name +
"' must not have a storage class",
var->source());
@@ -893,10 +935,10 @@
bool Resolver::ValidateEntryPoint(const ast::Function* func,
const FunctionInfo* info) {
// Use a lambda to validate the entry point decorations for a type.
- // Persistent state is used to track which builtins and locations have already
- // been seen, in order to catch conflicts.
- // TODO(jrprice): This state could be stored in FunctionInfo instead, and then
- // passed to sem::Function since it would be useful there too.
+ // Persistent state is used to track which builtins and locations have
+ // already been seen, in order to catch conflicts.
+ // TODO(jrprice): This state could be stored in FunctionInfo instead, and
+ // then passed to sem::Function since it would be useful there too.
std::unordered_set<ast::Builtin> builtins;
std::unordered_set<uint32_t> locations;
enum class ParamOrRetType {
@@ -1147,7 +1189,7 @@
variable_stack_.push_scope();
for (auto* param : func->params()) {
Mark(param);
- auto* param_info = Variable(param, /* is_parameter */ true);
+ auto* param_info = Variable(param, VariableKind::kParameter);
if (!param_info) {
return false;
}
@@ -1377,7 +1419,7 @@
return false;
}
- auto* cond_type = TypeOf(stmt->condition())->UnwrapAll();
+ auto* cond_type = TypeOf(stmt->condition())->UnwrapRef();
if (cond_type != builder_->ty.bool_()) {
diagnostics_.add_error("if statement condition must be bool, got " +
cond_type->FriendlyName(builder_->Symbols()),
@@ -1409,7 +1451,7 @@
return false;
}
- auto* else_cond_type = TypeOf(cond)->UnwrapAll();
+ auto* else_cond_type = TypeOf(cond)->UnwrapRef();
if (else_cond_type != builder_->ty.bool_()) {
diagnostics_.add_error(
"else statement condition must be bool, got " +
@@ -1525,7 +1567,7 @@
}
auto* res = TypeOf(expr->array());
- auto* parent_type = res->UnwrapAll();
+ auto* parent_type = res->UnwrapRef();
const sem::Type* ret = nullptr;
if (auto* arr = parent_type->As<sem::Array>()) {
ret = arr->ElemType();
@@ -1540,15 +1582,9 @@
return false;
}
- // If we're extracting from a pointer, we return a pointer.
- if (auto* ptr = res->As<sem::Pointer>()) {
- ret = builder_->create<sem::Pointer>(ret, ptr->StorageClass());
- } else if (auto* arr = parent_type->As<sem::Array>()) {
- if (!arr->ElemType()->is_scalar()) {
- // If we extract a non-scalar from an array then we also get a pointer. We
- // will generate a Function storage class variable to store this into.
- ret = builder_->create<sem::Pointer>(ret, ast::StorageClass::kFunction);
- }
+ // If we're extracting from a reference, we return a reference.
+ if (auto* ref = res->As<sem::Reference>()) {
+ ret = builder_->create<sem::Reference>(ret, ref->StorageClass());
}
SetType(expr, ret);
@@ -1569,9 +1605,9 @@
return false;
}
- // The expression has to be an identifier as you can't store function pointers
- // but, if it isn't we'll just use the normal result determination to be on
- // the safe side.
+ // The expression has to be an identifier as you can't store function
+ // pointers but, if it isn't we'll just use the normal result determination
+ // to be on the safe side.
Mark(call->func());
auto* ident = call->func()->As<ast::IdentifierExpression>();
if (!ident) {
@@ -1605,7 +1641,8 @@
auto* callee_func = callee_func_it->second;
// Note: Requires called functions to be resolved first.
- // This is currently guaranteed as functions must be declared before use.
+ // This is currently guaranteed as functions must be declared before
+ // use.
current_function_->transitive_calls.add(callee_func);
for (auto* transitive_call : callee_func->transitive_calls) {
current_function_->transitive_calls.add(transitive_call);
@@ -1692,10 +1729,10 @@
const ast::TypeConstructorExpression* ctor,
const sem::Vector* vec_type) {
auto& values = ctor->values();
- auto* elem_type = vec_type->type()->UnwrapAll();
+ auto* elem_type = vec_type->type();
size_t value_cardinality_sum = 0;
for (auto* value : values) {
- auto* value_type = TypeOf(value)->UnwrapAll();
+ auto* value_type = TypeOf(value)->UnwrapRef();
if (value_type->is_scalar()) {
if (elem_type != value_type) {
diagnostics_.add_error(
@@ -1709,7 +1746,7 @@
value_cardinality_sum++;
} else if (auto* value_vec = value_type->As<sem::Vector>()) {
- auto* value_elem_type = value_vec->type()->UnwrapAll();
+ auto* value_elem_type = value_vec->type();
// A mismatch of vector type parameter T is only an error if multiple
// arguments are present. A single argument constructor constitutes a
// type conversion expression.
@@ -1766,7 +1803,7 @@
return true;
}
- auto* elem_type = matrix_type->type()->UnwrapAll();
+ auto* elem_type = matrix_type->type();
if (matrix_type->columns() != values.size()) {
const Source& values_start = values[0]->source();
const Source& values_end = values[values.size() - 1]->source();
@@ -1780,11 +1817,11 @@
}
for (auto* value : values) {
- auto* value_type = TypeOf(value)->UnwrapAll();
+ auto* value_type = TypeOf(value)->UnwrapRef();
auto* value_vec = value_type->As<sem::Vector>();
if (!value_vec || value_vec->size() != matrix_type->rows() ||
- elem_type != value_vec->type()->UnwrapAll()) {
+ elem_type != value_vec->type()) {
diagnostics_.add_error("expected argument type '" +
VectorPretty(matrix_type->rows(), elem_type) +
"' in '" + TypeNameOf(ctor) +
@@ -1802,26 +1839,15 @@
auto symbol = expr->symbol();
VariableInfo* var;
if (variable_stack_.get(symbol, &var)) {
- // A constant is the type, but a variable is always a pointer so synthesize
- // the pointer around the variable type.
- if (var->declaration->is_const()) {
- SetType(expr, var->type, var->type_name);
- } else if (var->type->Is<sem::Pointer>()) {
- SetType(expr, var->type, var->type_name);
- } else {
- SetType(expr,
- builder_->create<sem::Pointer>(const_cast<sem::Type*>(var->type),
- var->storage_class),
- var->type_name);
- }
+ SetType(expr, var->type, var->type_name);
var->users.push_back(expr);
set_referenced_from_function_if_needed(var, true);
if (current_block_) {
- // If identifier is part of a loop continuing block, make sure it doesn't
- // refer to a variable that is bypassed by a continue statement in the
- // loop's body block.
+ // If identifier is part of a loop continuing block, make sure it
+ // doesn't refer to a variable that is bypassed by a continue statement
+ // in the loop's body block.
if (auto* continuing_block = current_block_->FindFirstParent(
sem::BlockStatement::Type::kLoopContinuing)) {
auto* loop_block =
@@ -1878,13 +1904,13 @@
return false;
}
- auto* res = TypeOf(expr->structure());
- auto* data_type = res->UnwrapAll();
+ auto* structure = TypeOf(expr->structure());
+ auto* storage_type = structure->UnwrapRef();
sem::Type* ret = nullptr;
std::vector<uint32_t> swizzle;
- if (auto* str = data_type->As<sem::Struct>()) {
+ if (auto* str = storage_type->As<sem::Struct>()) {
Mark(expr->member());
auto symbol = expr->member()->symbol();
@@ -1904,14 +1930,14 @@
return false;
}
- // If we're extracting from a pointer, we return a pointer.
- if (auto* ptr = res->As<sem::Pointer>()) {
- ret = builder_->create<sem::Pointer>(ret, ptr->StorageClass());
+ // If we're extracting from a reference, we return a reference.
+ if (auto* ref = structure->As<sem::Reference>()) {
+ ret = builder_->create<sem::Reference>(ret, ref->StorageClass());
}
builder_->Sem().Add(expr, builder_->create<sem::StructMemberAccess>(
expr, ret, current_statement_, member));
- } else if (auto* vec = data_type->As<sem::Vector>()) {
+ } else if (auto* vec = storage_type->As<sem::Vector>()) {
Mark(expr->member());
std::string s = builder_->Symbols().NameFor(expr->member()->symbol());
auto size = s.size();
@@ -1967,9 +1993,9 @@
if (size == 1) {
// A single element swizzle is just the type of the vector.
ret = vec->type();
- // If we're extracting from a pointer, we return a pointer.
- if (auto* ptr = res->As<sem::Pointer>()) {
- ret = builder_->create<sem::Pointer>(ret, ptr->StorageClass());
+ // If we're extracting from a reference, we return a reference.
+ if (auto* ref = structure->As<sem::Reference>()) {
+ ret = builder_->create<sem::Reference>(ret, ref->StorageClass());
}
} else {
// The vector will have a number of components equal to the length of
@@ -1983,7 +2009,7 @@
} else {
diagnostics_.add_error(
"invalid use of member accessor on a non-vector/non-struct " +
- data_type->type_name(),
+ TypeNameOf(expr->structure()),
expr->source());
return false;
}
@@ -2001,8 +2027,8 @@
using Matrix = sem::Matrix;
using Vector = sem::Vector;
- auto* lhs_type = const_cast<sem::Type*>(TypeOf(expr->lhs())->UnwrapAll());
- auto* rhs_type = const_cast<sem::Type*>(TypeOf(expr->rhs())->UnwrapAll());
+ auto* lhs_type = const_cast<sem::Type*>(TypeOf(expr->lhs())->UnwrapRef());
+ auto* rhs_type = const_cast<sem::Type*>(TypeOf(expr->rhs())->UnwrapRef());
auto* lhs_vec = lhs_type->As<Vector>();
auto* lhs_vec_elem_type = lhs_vec ? lhs_vec->type() : nullptr;
@@ -2169,7 +2195,7 @@
if (expr->IsAnd() || expr->IsOr() || expr->IsXor() || expr->IsShiftLeft() ||
expr->IsShiftRight() || expr->IsAdd() || expr->IsSubtract() ||
expr->IsDivide() || expr->IsModulo()) {
- SetType(expr, TypeOf(expr->lhs())->UnwrapPtr());
+ SetType(expr, TypeOf(expr->lhs())->UnwrapRef());
return true;
}
// Result type is a scalar or vector of boolean type
@@ -2177,7 +2203,7 @@
expr->IsNotEqual() || expr->IsLessThan() || expr->IsGreaterThan() ||
expr->IsLessThanEqual() || expr->IsGreaterThanEqual()) {
auto* bool_type = builder_->create<sem::Bool>();
- auto* param_type = TypeOf(expr->lhs())->UnwrapAll();
+ auto* param_type = TypeOf(expr->lhs())->UnwrapRef();
sem::Type* result_type = bool_type;
if (auto* vec = param_type->As<sem::Vector>()) {
result_type = builder_->create<sem::Vector>(bool_type, vec->size());
@@ -2186,8 +2212,8 @@
return true;
}
if (expr->IsMultiply()) {
- auto* lhs_type = TypeOf(expr->lhs())->UnwrapAll();
- auto* rhs_type = TypeOf(expr->rhs())->UnwrapAll();
+ auto* lhs_type = TypeOf(expr->lhs())->UnwrapRef();
+ auto* rhs_type = TypeOf(expr->rhs())->UnwrapRef();
// Note, the ordering here matters. The later checks depend on the prior
// checks having been done.
@@ -2234,16 +2260,55 @@
return false;
}
-bool Resolver::UnaryOp(ast::UnaryOpExpression* expr) {
- Mark(expr->expr());
+bool Resolver::UnaryOp(ast::UnaryOpExpression* unary) {
+ Mark(unary->expr());
- // Result type matches the parameter type.
- if (!Expression(expr->expr())) {
+ // Resolve the inner expression
+ if (!Expression(unary->expr())) {
return false;
}
- auto* result_type = TypeOf(expr->expr())->UnwrapPtr();
- SetType(expr, result_type);
+ auto* expr_type = TypeOf(unary->expr());
+ if (!expr_type) {
+ return false;
+ }
+
+ std::string type_name;
+ const sem::Type* type = nullptr;
+
+ switch (unary->op()) {
+ case ast::UnaryOp::kNegation:
+ case ast::UnaryOp::kNot:
+ // Result type matches the deref'd inner type.
+ type_name = TypeNameOf(unary->expr());
+ type = expr_type->UnwrapRef();
+ break;
+
+ case ast::UnaryOp::kAddressOf:
+ if (auto* ref = expr_type->As<sem::Reference>()) {
+ type = builder_->create<sem::Pointer>(ref->StoreType(),
+ ref->StorageClass());
+ } else {
+ diagnostics_.add_error("cannot take the address of expression",
+ unary->expr()->source());
+ return false;
+ }
+ break;
+
+ case ast::UnaryOp::kIndirection:
+ if (auto* ptr = expr_type->As<sem::Pointer>()) {
+ type = builder_->create<sem::Reference>(ptr->StoreType(),
+ ptr->StorageClass());
+ } else {
+ diagnostics_.add_error("cannot dereference expression of type '" +
+ TypeNameOf(unary->expr()) + "'",
+ unary->expr()->source());
+ return false;
+ }
+ break;
+ }
+
+ SetType(unary, type);
return true;
}
@@ -2257,11 +2322,11 @@
diagnostics_.add_error(error_code,
"redeclared identifier '" +
builder_->Symbols().NameFor(var->symbol()) + "'",
- stmt->source());
+ var->source());
return false;
}
- auto* info = Variable(var, /* is_parameter */ false);
+ auto* info = Variable(var, VariableKind::kLocal);
if (!info) {
return false;
}
@@ -2357,8 +2422,8 @@
void Resolver::CreateSemanticNodes() const {
auto& sem = builder_->Sem();
- // Collate all the 'ancestor_entry_points' - this is a map of function symbol
- // to all the entry points that transitively call the function.
+ // Collate all the 'ancestor_entry_points' - this is a map of function
+ // symbol to all the entry points that transitively call the function.
std::unordered_map<Symbol, std::vector<Symbol>> ancestor_entry_points;
for (auto* func : builder_->AST().Functions()) {
auto it = function_to_info_.find(func);
@@ -2641,7 +2706,7 @@
bool Resolver::ValidateStructure(const sem::Struct* str) {
for (auto* member : str->Members()) {
- if (auto* r = member->Type()->UnwrapAll()->As<sem::Array>()) {
+ if (auto* r = member->Type()->As<sem::Array>()) {
if (r->IsRuntimeSized()) {
if (member != str->Members().back()) {
diagnostics_.add_error(
@@ -2738,8 +2803,8 @@
for (auto* deco : member->decorations()) {
Mark(deco);
if (auto* o = deco->As<ast::StructMemberOffsetDecoration>()) {
- // Offset decorations are not part of the WGSL spec, but are emitted by
- // the SPIR-V reader.
+ // Offset decorations are not part of the WGSL spec, but are emitted
+ // by the SPIR-V reader.
if (o->offset() < struct_size) {
diagnostics_.add_error("offsets must be in ascending order",
o->source());
@@ -2805,10 +2870,10 @@
bool Resolver::ValidateReturn(const ast::ReturnStatement* ret) {
auto* func_type = current_function_->return_type;
- auto* ret_type = ret->has_value() ? TypeOf(ret->value())->UnwrapAll()
+ auto* ret_type = ret->has_value() ? TypeOf(ret->value())->UnwrapRef()
: builder_->ty.void_();
- if (func_type->UnwrapAll() != ret_type) {
+ if (func_type->UnwrapRef() != ret_type) {
diagnostics_.add_error("v-000y",
"return statement type must match its function "
"return type, returned '" +
@@ -2828,8 +2893,8 @@
if (auto* value = ret->value()) {
Mark(value);
- // Validate after processing the return value expression so that its type is
- // available for validation
+ // Validate after processing the return value expression so that its type
+ // is available for validation
return Expression(value) && ValidateReturn(ret);
}
@@ -2837,7 +2902,7 @@
}
bool Resolver::ValidateSwitch(const ast::SwitchStatement* s) {
- auto* cond_type = TypeOf(s->condition())->UnwrapAll();
+ auto* cond_type = TypeOf(s->condition())->UnwrapRef();
if (!cond_type->is_integer_scalar()) {
diagnostics_.add_error("v-0025",
"switch statement selector expression must be of a "
@@ -2928,67 +2993,6 @@
return true;
}
-bool Resolver::ValidateAssignment(const ast::AssignmentStatement* a) {
- auto* lhs = a->lhs();
- auto* rhs = a->rhs();
-
- // TODO(crbug.com/tint/659): This logic needs updating once pointers are
- // pinned down in the WGSL spec.
- auto* lhs_type = TypeOf(lhs)->UnwrapAll();
- auto* rhs_type = TypeOf(rhs);
- if (!IsValidAssignment(lhs_type, rhs_type)) {
- diagnostics_.add_error("invalid assignment: cannot assign value of type '" +
- rhs_type->FriendlyName(builder_->Symbols()) +
- "' to a variable of type '" +
- lhs_type->FriendlyName(builder_->Symbols()) +
- "'",
- a->source());
- return false;
- }
-
- // Pointers are not storable in WGSL, but the right-hand side must be
- // storable. The raw right-hand side might be a pointer value which must be
- // loaded (dereferenced) to provide the value to be stored.
- auto* rhs_result_type = TypeOf(rhs)->UnwrapAll();
- if (!IsStorable(rhs_result_type)) {
- diagnostics_.add_error(
- "v-000x",
- "invalid assignment: right-hand-side is not storable: " +
- TypeOf(rhs)->FriendlyName(builder_->Symbols()),
- a->source());
- return false;
- }
-
- // lhs must be a pointer or a constant
- auto* lhs_result_type = TypeOf(lhs)->UnwrapAccess();
- if (!lhs_result_type->Is<sem::Pointer>()) {
- // In case lhs is a constant identifier, output a nicer message as it's
- // likely to be a common programmer error.
- if (auto* ident = lhs->As<ast::IdentifierExpression>()) {
- VariableInfo* var;
- if (variable_stack_.get(ident->symbol(), &var) &&
- var->declaration->is_const()) {
- diagnostics_.add_error(
- "v-0021",
- "cannot re-assign a constant: '" +
- builder_->Symbols().NameFor(ident->symbol()) + "'",
- a->source());
- return false;
- }
- }
-
- // Issue a generic error.
- diagnostics_.add_error(
- "v-000x",
- "invalid assignment: left-hand-side does not reference storage: " +
- TypeOf(lhs)->FriendlyName(builder_->Symbols()),
- a->source());
- return false;
- }
-
- return true;
-}
-
bool Resolver::Assignment(ast::AssignmentStatement* a) {
Mark(a->lhs());
Mark(a->rhs());
@@ -2999,10 +3003,52 @@
return ValidateAssignment(a);
}
+bool Resolver::ValidateAssignment(const ast::AssignmentStatement* a) {
+ // https://gpuweb.github.io/gpuweb/wgsl/#assignment-statement
+ auto const* lhs_type = TypeOf(a->lhs());
+ auto const* rhs_type = TypeOf(a->rhs());
+
+ auto* lhs_ref = lhs_type->As<sem::Reference>();
+ if (!lhs_ref) {
+ // LHS is not a reference, so it has no storage.
+ diagnostics_.add_error(
+ "cannot assign to value of type '" + TypeNameOf(a->lhs()) + "'",
+ a->lhs()->source());
+
+ return false;
+ }
+
+ auto* storage_type_with_access = lhs_ref->StoreType();
+
+ // TODO(crbug.com/tint/809): The originating variable of the left-hand side
+ // must not have an access(read) access attribute.
+ // https://gpuweb.github.io/gpuweb/wgsl/#assignment
+
+ auto* storage_type = storage_type_with_access->UnwrapAccess();
+ auto* value_type = rhs_type->UnwrapRef(); // Implicit load of RHS
+
+ // RHS needs to be of a storable type
+ if (!IsStorable(value_type)) {
+ diagnostics_.add_error("'" + TypeNameOf(a->rhs()) + "' is not storable",
+ a->rhs()->source());
+ return false;
+ }
+
+ // Value type has to match storage type
+ if (storage_type != value_type) {
+ diagnostics_.add_error("cannot assign '" + TypeNameOf(a->rhs()) + "' to '" +
+ TypeNameOf(a->lhs()) + "'",
+ a->source());
+ return false;
+ }
+
+ return true;
+}
+
bool Resolver::ApplyStorageClassUsageToType(ast::StorageClass sc,
sem::Type* ty,
const Source& usage) {
- ty = const_cast<sem::Type*>(ty->UnwrapAccess());
+ ty = const_cast<sem::Type*>(ty->UnwrapRef());
if (auto* str = ty->As<sem::Struct>()) {
if (str->StorageClassUsage().count(sc)) {
@@ -3079,23 +3125,15 @@
}
Resolver::VariableInfo::VariableInfo(const ast::Variable* decl,
- sem::Type* ctype,
+ sem::Type* ty,
const std::string& tn,
+ ast::StorageClass sc,
ast::AccessControl::Access ac)
: declaration(decl),
- type(ctype),
+ type(ty),
type_name(tn),
- storage_class(decl->declared_storage_class()),
- access_control(ac) {
- if (storage_class == ast::StorageClass::kNone &&
- type->UnwrapAll()->is_handle()) {
- // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
- // If the store type is a texture type or a sampler type, then the variable
- // declaration must not have a storage class decoration. The storage class
- // will always be handle.
- storage_class = ast::StorageClass::kUniformConstant;
- }
-}
+ storage_class(sc),
+ access_control(ac) {}
Resolver::VariableInfo::~VariableInfo() = default;
diff --git a/src/resolver/resolver.h b/src/resolver/resolver.h
index 3b8b05e..76a722f 100644
--- a/src/resolver/resolver.h
+++ b/src/resolver/resolver.h
@@ -79,13 +79,6 @@
/// @returns true if the given type is host-shareable
bool IsHostShareable(const sem::Type* type);
- /// @param lhs the assignment store type (non-pointer)
- /// @param rhs the assignment source type (non-pointer or pointer with
- /// auto-deref)
- /// @returns true an expression of type `rhs` can be assigned to a variable,
- /// structure member or array element of type `lhs`
- static bool IsValidAssignment(const sem::Type* lhs, const sem::Type* rhs);
-
private:
/// Structure holding semantic information about a variable.
/// Used to build the sem::Variable nodes at the end of resolving.
@@ -93,6 +86,7 @@
VariableInfo(const ast::Variable* decl,
sem::Type* type,
const std::string& type_name,
+ ast::StorageClass storage_class,
ast::AccessControl::Access ac);
~VariableInfo();
@@ -139,6 +133,43 @@
sem::Statement* statement;
};
+ /// Structure holding semantic information about a block (i.e. scope), such as
+ /// parent block and variables declared in the block.
+ /// Used to validate variable scoping rules.
+ struct BlockInfo {
+ enum class Type { kGeneric, kLoop, kLoopContinuing, kSwitchCase };
+
+ BlockInfo(const ast::BlockStatement* block, Type type, BlockInfo* parent);
+ ~BlockInfo();
+
+ template <typename Pred>
+ BlockInfo* FindFirstParent(Pred&& pred) {
+ BlockInfo* curr = this;
+ while (curr && !pred(curr)) {
+ curr = curr->parent;
+ }
+ return curr;
+ }
+
+ BlockInfo* FindFirstParent(BlockInfo::Type ty) {
+ return FindFirstParent(
+ [ty](auto* block_info) { return block_info->type == ty; });
+ }
+
+ ast::BlockStatement const* const block;
+ Type const type;
+ BlockInfo* const parent;
+ std::vector<const ast::Variable*> decls;
+
+ // first_continue is set to the index of the first variable in decls
+ // declared after the first continue statement in a loop block, if any.
+ constexpr static size_t kNoContinue = size_t(~0);
+ size_t first_continue = kNoContinue;
+ };
+
+ /// Describes the context in which a variable is declared
+ enum class VariableKind { kParameter, kLocal, kGlobal };
+
/// Resolves the program, without creating final the semantic nodes.
/// @returns true on success, false on error
bool ResolveInternal();
@@ -207,6 +238,11 @@
bool ValidateStructure(const sem::Struct* str);
bool ValidateSwitch(const ast::SwitchStatement* s);
bool ValidateVariable(const VariableInfo* info);
+ bool ValidateVariableConstructor(const ast::Variable* var,
+ const sem::Type* storage_type,
+ const std::string& type_name,
+ const sem::Type* rhs_type,
+ const std::string& rhs_type_name);
bool ValidateVectorConstructor(const ast::TypeConstructorExpression* ctor,
const sem::Vector* vec_type);
@@ -235,8 +271,8 @@
/// @note this method does not resolve the decorations as these are
/// context-dependent (global, local, parameter)
/// @param var the variable to create or return the `VariableInfo` for
- /// @param is_parameter true if the variable represents a parameter
- VariableInfo* Variable(ast::Variable* var, bool is_parameter);
+ /// @param kind what kind of variable we are declaring
+ VariableInfo* Variable(ast::Variable* var, VariableKind kind);
/// Records the storage class usage for the given type, and any transient
/// dependencies of the type. Validates that the type can be used for the
diff --git a/src/resolver/resolver_test.cc b/src/resolver/resolver_test.cc
index 330492e..e81be39 100644
--- a/src/resolver/resolver_test.cc
+++ b/src/resolver/resolver_test.cc
@@ -36,6 +36,7 @@
#include "src/sem/call.h"
#include "src/sem/function.h"
#include "src/sem/member_accessor_expression.h"
+#include "src/sem/reference_type.h"
#include "src/sem/sampled_texture_type.h"
#include "src/sem/statement.h"
#include "src/sem/variable.h"
@@ -66,7 +67,7 @@
ASSERT_NE(TypeOf(lhs), nullptr);
ASSERT_NE(TypeOf(rhs), nullptr);
- EXPECT_TRUE(TypeOf(lhs)->UnwrapAll()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(lhs)->UnwrapRef()->Is<sem::F32>());
EXPECT_TRUE(TypeOf(rhs)->Is<sem::F32>());
EXPECT_EQ(StmtOf(lhs), assign);
EXPECT_EQ(StmtOf(rhs), assign);
@@ -90,7 +91,7 @@
ASSERT_NE(TypeOf(lhs), nullptr);
ASSERT_NE(TypeOf(rhs), nullptr);
- EXPECT_TRUE(TypeOf(lhs)->UnwrapAll()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(lhs)->UnwrapRef()->Is<sem::F32>());
EXPECT_TRUE(TypeOf(rhs)->Is<sem::F32>());
EXPECT_EQ(StmtOf(lhs), assign);
EXPECT_EQ(StmtOf(rhs), assign);
@@ -110,7 +111,7 @@
ASSERT_NE(TypeOf(lhs), nullptr);
ASSERT_NE(TypeOf(rhs), nullptr);
- EXPECT_TRUE(TypeOf(lhs)->UnwrapAll()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(lhs)->UnwrapRef()->Is<sem::F32>());
EXPECT_TRUE(TypeOf(rhs)->Is<sem::F32>());
EXPECT_EQ(StmtOf(lhs), assign);
EXPECT_EQ(StmtOf(rhs), assign);
@@ -147,9 +148,9 @@
ASSERT_NE(TypeOf(lhs), nullptr);
ASSERT_NE(TypeOf(rhs), nullptr);
EXPECT_TRUE(TypeOf(stmt->condition())->Is<sem::Bool>());
- EXPECT_TRUE(TypeOf(else_lhs)->UnwrapAll()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(else_lhs)->UnwrapRef()->Is<sem::F32>());
EXPECT_TRUE(TypeOf(else_rhs)->Is<sem::F32>());
- EXPECT_TRUE(TypeOf(lhs)->UnwrapAll()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(lhs)->UnwrapRef()->Is<sem::F32>());
EXPECT_TRUE(TypeOf(rhs)->Is<sem::F32>());
EXPECT_EQ(StmtOf(lhs), assign);
EXPECT_EQ(StmtOf(rhs), assign);
@@ -180,9 +181,9 @@
ASSERT_NE(TypeOf(body_rhs), nullptr);
ASSERT_NE(TypeOf(continuing_lhs), nullptr);
ASSERT_NE(TypeOf(continuing_rhs), nullptr);
- EXPECT_TRUE(TypeOf(body_lhs)->UnwrapAll()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(body_lhs)->UnwrapRef()->Is<sem::F32>());
EXPECT_TRUE(TypeOf(body_rhs)->Is<sem::F32>());
- EXPECT_TRUE(TypeOf(continuing_lhs)->UnwrapAll()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(continuing_lhs)->UnwrapRef()->Is<sem::F32>());
EXPECT_TRUE(TypeOf(continuing_rhs)->Is<sem::F32>());
EXPECT_EQ(BlockOf(body_lhs), body);
EXPECT_EQ(BlockOf(body_rhs), body);
@@ -224,7 +225,7 @@
ASSERT_NE(TypeOf(rhs), nullptr);
EXPECT_TRUE(TypeOf(stmt->condition())->Is<sem::I32>());
- EXPECT_TRUE(TypeOf(lhs)->UnwrapAll()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(lhs)->UnwrapRef()->Is<sem::F32>());
EXPECT_TRUE(TypeOf(rhs)->Is<sem::F32>());
EXPECT_EQ(BlockOf(lhs), case_block);
EXPECT_EQ(BlockOf(rhs), case_block);
@@ -328,9 +329,9 @@
ASSERT_NE(TypeOf(foo_f32_init), nullptr);
EXPECT_TRUE(TypeOf(foo_f32_init)->Is<sem::F32>());
ASSERT_NE(TypeOf(bar_i32_init), nullptr);
- EXPECT_TRUE(TypeOf(bar_i32_init)->UnwrapAll()->Is<sem::I32>());
+ EXPECT_TRUE(TypeOf(bar_i32_init)->UnwrapRef()->Is<sem::I32>());
ASSERT_NE(TypeOf(bar_f32_init), nullptr);
- EXPECT_TRUE(TypeOf(bar_f32_init)->UnwrapAll()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(bar_f32_init)->UnwrapRef()->Is<sem::F32>());
EXPECT_EQ(StmtOf(foo_i32_init), foo_i32_decl);
EXPECT_EQ(StmtOf(bar_i32_init), bar_i32_decl);
EXPECT_EQ(StmtOf(foo_f32_init), foo_f32_decl);
@@ -377,7 +378,7 @@
ASSERT_NE(TypeOf(fn_i32_init), nullptr);
EXPECT_TRUE(TypeOf(fn_i32_init)->Is<sem::I32>());
ASSERT_NE(TypeOf(fn_f32_init), nullptr);
- EXPECT_TRUE(TypeOf(fn_f32_init)->UnwrapAll()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(fn_f32_init)->UnwrapRef()->Is<sem::F32>());
EXPECT_EQ(StmtOf(fn_i32_init), fn_i32_decl);
EXPECT_EQ(StmtOf(mod_init), nullptr);
EXPECT_EQ(StmtOf(fn_f32_init), fn_f32_decl);
@@ -397,10 +398,10 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(acc), nullptr);
- ASSERT_TRUE(TypeOf(acc)->Is<sem::Pointer>());
+ ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
- auto* ptr = TypeOf(acc)->As<sem::Pointer>();
- EXPECT_TRUE(ptr->StoreType()->Is<sem::F32>());
+ auto* ref = TypeOf(acc)->As<sem::Reference>();
+ EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
}
TEST_F(ResolverTest, Expr_ArrayAccessor_Alias_Array) {
@@ -415,10 +416,10 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(acc), nullptr);
- ASSERT_TRUE(TypeOf(acc)->Is<sem::Pointer>());
+ ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
- auto* ptr = TypeOf(acc)->As<sem::Pointer>();
- EXPECT_TRUE(ptr->StoreType()->Is<sem::F32>());
+ auto* ref = TypeOf(acc)->As<sem::Reference>();
+ EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
}
TEST_F(ResolverTest, Expr_ArrayAccessor_Array_Constant) {
@@ -442,11 +443,11 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(acc), nullptr);
- ASSERT_TRUE(TypeOf(acc)->Is<sem::Pointer>());
+ ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
- auto* ptr = TypeOf(acc)->As<sem::Pointer>();
- ASSERT_TRUE(ptr->StoreType()->Is<sem::Vector>());
- EXPECT_EQ(ptr->StoreType()->As<sem::Vector>()->size(), 3u);
+ auto* ref = TypeOf(acc)->As<sem::Reference>();
+ ASSERT_TRUE(ref->StoreType()->Is<sem::Vector>());
+ EXPECT_EQ(ref->StoreType()->As<sem::Vector>()->size(), 3u);
}
TEST_F(ResolverTest, Expr_ArrayAccessor_Matrix_BothDimensions) {
@@ -458,10 +459,10 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(acc), nullptr);
- ASSERT_TRUE(TypeOf(acc)->Is<sem::Pointer>());
+ ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
- auto* ptr = TypeOf(acc)->As<sem::Pointer>();
- EXPECT_TRUE(ptr->StoreType()->Is<sem::F32>());
+ auto* ref = TypeOf(acc)->As<sem::Reference>();
+ EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
}
TEST_F(ResolverTest, Expr_ArrayAccessor_Vector) {
@@ -473,10 +474,10 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(acc), nullptr);
- ASSERT_TRUE(TypeOf(acc)->Is<sem::Pointer>());
+ ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
- auto* ptr = TypeOf(acc)->As<sem::Pointer>();
- EXPECT_TRUE(ptr->StoreType()->Is<sem::F32>());
+ auto* ref = TypeOf(acc)->As<sem::Reference>();
+ EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
}
TEST_F(ResolverTest, Expr_Bitcast) {
@@ -519,7 +520,10 @@
TEST_F(ResolverTest, Expr_Call_WithParams) {
ast::VariableList params;
- Func("my_func", params, ty.void_(), {}, ast::DecorationList{});
+ Func("my_func", params, ty.f32(),
+ {
+ Return(1.2f),
+ });
auto* param = Expr(2.4f);
@@ -609,8 +613,8 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(ident), nullptr);
- EXPECT_TRUE(TypeOf(ident)->Is<sem::Pointer>());
- EXPECT_TRUE(TypeOf(ident)->As<sem::Pointer>()->StoreType()->Is<sem::F32>());
+ ASSERT_TRUE(TypeOf(ident)->Is<sem::Reference>());
+ EXPECT_TRUE(TypeOf(ident)->UnwrapRef()->Is<sem::F32>());
EXPECT_TRUE(CheckVarUsers(my_var, {ident}));
ASSERT_NE(VarOf(ident), nullptr);
EXPECT_EQ(VarOf(ident)->Declaration(), my_var);
@@ -674,14 +678,12 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(my_var_a), nullptr);
- EXPECT_TRUE(TypeOf(my_var_a)->Is<sem::Pointer>());
- EXPECT_TRUE(
- TypeOf(my_var_a)->As<sem::Pointer>()->StoreType()->Is<sem::F32>());
+ ASSERT_TRUE(TypeOf(my_var_a)->Is<sem::Reference>());
+ EXPECT_TRUE(TypeOf(my_var_a)->UnwrapRef()->Is<sem::F32>());
EXPECT_EQ(StmtOf(my_var_a), assign);
ASSERT_NE(TypeOf(my_var_b), nullptr);
- EXPECT_TRUE(TypeOf(my_var_b)->Is<sem::Pointer>());
- EXPECT_TRUE(
- TypeOf(my_var_b)->As<sem::Pointer>()->StoreType()->Is<sem::F32>());
+ ASSERT_TRUE(TypeOf(my_var_b)->Is<sem::Reference>());
+ EXPECT_TRUE(TypeOf(my_var_b)->UnwrapRef()->Is<sem::F32>());
EXPECT_EQ(StmtOf(my_var_b), assign);
EXPECT_TRUE(CheckVarUsers(var, {my_var_a, my_var_b}));
ASSERT_NE(VarOf(my_var_a), nullptr);
@@ -691,29 +693,30 @@
}
TEST_F(ResolverTest, Expr_Identifier_Function_Ptr) {
- auto* my_var_a = Expr("my_var");
- auto* my_var_b = Expr("my_var");
- auto* assign = Assign(my_var_a, my_var_b);
-
+ auto* v = Expr("v");
+ auto* p = Expr("p");
+ auto* v_decl = Decl(Var("v", ty.f32()));
+ auto* p_decl = Decl(
+ Const("p", ty.pointer<f32>(ast::StorageClass::kFunction), AddressOf(v)));
+ auto* assign = Assign(Deref(p), 1.23f);
Func("my_func", ast::VariableList{}, ty.void_(),
{
- Decl(Var("my_var", ty.pointer<f32>(ast::StorageClass::kFunction))),
+ v_decl,
+ p_decl,
assign,
},
ast::DecorationList{});
EXPECT_TRUE(r()->Resolve()) << r()->error();
- ASSERT_NE(TypeOf(my_var_a), nullptr);
- EXPECT_TRUE(TypeOf(my_var_a)->Is<sem::Pointer>());
- EXPECT_TRUE(
- TypeOf(my_var_a)->As<sem::Pointer>()->StoreType()->Is<sem::F32>());
- EXPECT_EQ(StmtOf(my_var_a), assign);
- ASSERT_NE(TypeOf(my_var_b), nullptr);
- EXPECT_TRUE(TypeOf(my_var_b)->Is<sem::Pointer>());
- EXPECT_TRUE(
- TypeOf(my_var_b)->As<sem::Pointer>()->StoreType()->Is<sem::F32>());
- EXPECT_EQ(StmtOf(my_var_b), assign);
+ ASSERT_NE(TypeOf(v), nullptr);
+ ASSERT_TRUE(TypeOf(v)->Is<sem::Reference>());
+ EXPECT_TRUE(TypeOf(v)->UnwrapRef()->Is<sem::F32>());
+ EXPECT_EQ(StmtOf(v), p_decl);
+ ASSERT_NE(TypeOf(p), nullptr);
+ ASSERT_TRUE(TypeOf(p)->Is<sem::Pointer>());
+ EXPECT_TRUE(TypeOf(p)->UnwrapPtr()->Is<sem::F32>());
+ EXPECT_EQ(StmtOf(p), assign);
}
TEST_F(ResolverTest, Expr_Call_Function) {
@@ -895,10 +898,10 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(mem), nullptr);
- ASSERT_TRUE(TypeOf(mem)->Is<sem::Pointer>());
+ ASSERT_TRUE(TypeOf(mem)->Is<sem::Reference>());
- auto* ptr = TypeOf(mem)->As<sem::Pointer>();
- EXPECT_TRUE(ptr->StoreType()->Is<sem::F32>());
+ auto* ref = TypeOf(mem)->As<sem::Reference>();
+ EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
auto* sma = Sem().Get(mem)->As<sem::StructMemberAccess>();
ASSERT_NE(sma, nullptr);
EXPECT_EQ(sma->Member()->Type(), ty.f32());
@@ -920,10 +923,10 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(mem), nullptr);
- ASSERT_TRUE(TypeOf(mem)->Is<sem::Pointer>());
+ ASSERT_TRUE(TypeOf(mem)->Is<sem::Reference>());
- auto* ptr = TypeOf(mem)->As<sem::Pointer>();
- EXPECT_TRUE(ptr->StoreType()->Is<sem::F32>());
+ auto* ref = TypeOf(mem)->As<sem::Reference>();
+ EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
auto* sma = Sem().Get(mem)->As<sem::StructMemberAccess>();
ASSERT_NE(sma, nullptr);
EXPECT_EQ(sma->Member()->Type(), ty.f32());
@@ -956,10 +959,10 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(mem), nullptr);
- ASSERT_TRUE(TypeOf(mem)->Is<sem::Pointer>());
+ ASSERT_TRUE(TypeOf(mem)->Is<sem::Reference>());
- auto* ptr = TypeOf(mem)->As<sem::Pointer>();
- ASSERT_TRUE(ptr->StoreType()->Is<sem::F32>());
+ auto* ref = TypeOf(mem)->As<sem::Reference>();
+ ASSERT_TRUE(ref->StoreType()->Is<sem::F32>());
ASSERT_TRUE(Sem().Get(mem)->Is<sem::Swizzle>());
EXPECT_THAT(Sem().Get(mem)->As<sem::Swizzle>()->Indices(), ElementsAre(2));
}
diff --git a/src/resolver/type_constructor_validation_test.cc b/src/resolver/type_constructor_validation_test.cc
index e5d06d0..94fc5ee 100644
--- a/src/resolver/type_constructor_validation_test.cc
+++ b/src/resolver/type_constructor_validation_test.cc
@@ -13,6 +13,7 @@
// limitations under the License.
#include "src/resolver/resolver_test_helper.h"
+#include "src/sem/reference_type.h"
namespace tint {
namespace resolver {
@@ -51,13 +52,19 @@
auto* a_ident = Expr("a");
auto* b_ident = Expr("b");
- WrapInFunction(Decl(a), Decl(b), Assign(a_ident, "a"), Assign(b_ident, "b"));
+ WrapInFunction(a, b, Assign(a_ident, "a"), Assign(b_ident, "b"));
ASSERT_TRUE(r()->Resolve()) << r()->error();
- ASSERT_EQ(TypeOf(a_ident),
- ty.pointer(ty.i32(), ast::StorageClass::kFunction));
- ASSERT_EQ(TypeOf(b_ident),
- ty.pointer(ty.i32(), ast::StorageClass::kFunction));
+ ASSERT_TRUE(TypeOf(a_ident)->Is<sem::Reference>());
+ EXPECT_TRUE(
+ TypeOf(a_ident)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
+ EXPECT_EQ(TypeOf(a_ident)->As<sem::Reference>()->StorageClass(),
+ ast::StorageClass::kFunction);
+ ASSERT_TRUE(TypeOf(b_ident)->Is<sem::Reference>());
+ EXPECT_TRUE(
+ TypeOf(b_ident)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
+ EXPECT_EQ(TypeOf(b_ident)->As<sem::Reference>()->StorageClass(),
+ ast::StorageClass::kFunction);
}
using InferTypeTest_FromConstructorExpression = ResolverTestWithParam<Params>;
@@ -79,9 +86,8 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* got = TypeOf(a_ident);
- auto* expected =
- ty.pointer(params.create_rhs_sem_type(ty), ast::StorageClass::kFunction)
- .sem;
+ auto* expected = create<sem::Reference>(params.create_rhs_sem_type(ty),
+ ast::StorageClass::kFunction);
ASSERT_EQ(got, expected) << "got: " << FriendlyName(got) << "\n"
<< "expected: " << FriendlyName(expected) << "\n";
}
@@ -134,9 +140,8 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* got = TypeOf(a_ident);
- auto* expected =
- ty.pointer(params.create_rhs_sem_type(ty), ast::StorageClass::kFunction)
- .sem;
+ auto* expected = create<sem::Reference>(params.create_rhs_sem_type(ty),
+ ast::StorageClass::kFunction);
ASSERT_EQ(got, expected) << "got: " << FriendlyName(got) << "\n"
<< "expected: " << FriendlyName(expected) << "\n";
}
@@ -184,9 +189,8 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* got = TypeOf(a_ident);
- auto* expected =
- ty.pointer(params.create_rhs_sem_type(ty), ast::StorageClass::kFunction)
- .sem;
+ auto* expected = create<sem::Reference>(params.create_rhs_sem_type(ty),
+ ast::StorageClass::kFunction);
ASSERT_EQ(got, expected) << "got: " << FriendlyName(got) << "\n"
<< "expected: " << FriendlyName(expected) << "\n";
}
diff --git a/src/resolver/type_validation_test.cc b/src/resolver/type_validation_test.cc
index beec7d5..de11bb9 100644
--- a/src/resolver/type_validation_test.cc
+++ b/src/resolver/type_validation_test.cc
@@ -49,27 +49,6 @@
ASSERT_NE(TypeOf(rhs), nullptr);
}
-TEST_F(ResolverTypeValidationTest, FunctionConstantNoConstructor_Fail) {
- // {
- // let a :i32;
- // }
- auto* var = Const(Source{{12, 34}}, "a", ty.i32(), nullptr);
- WrapInFunction(var);
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "12:34 error: let declarations must have initializers");
-}
-
-TEST_F(ResolverTypeValidationTest, GlobalConstantNoConstructor_Fail) {
- // let a :i32;
- GlobalConst(Source{{12, 34}}, "a", ty.i32(), nullptr);
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "12:34 error: let declarations must have initializers");
-}
-
TEST_F(ResolverTypeValidationTest, GlobalConstantNoConstructor_Pass) {
// [[override(0)]] let a :i32;
GlobalConst(Source{{12, 34}}, "a", ty.i32(), nullptr,
@@ -117,19 +96,6 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_F(ResolverTypeValidationTest, GlobalVariableNotUnique_Fail) {
- // var global_var : f32 = 0.1;
- // var global_var : i32 = 0;
- Global("global_var", ty.f32(), ast::StorageClass::kPrivate, Expr(0.1f));
-
- Global(Source{{12, 34}}, "global_var", ty.i32(), ast::StorageClass::kPrivate,
- Expr(0));
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "12:34 error v-0011: redeclared global identifier 'global_var'");
-}
-
TEST_F(ResolverTypeValidationTest,
GlobalVariableFunctionVariableNotUnique_Pass) {
// fn my_func() {
@@ -146,48 +112,6 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_F(ResolverTypeValidationTest,
- GlobalVariableFunctionVariableNotUnique_Fail) {
- // var a: f32 = 2.1;
- // fn my_func() {
- // var a: f32 = 2.0;
- // return 0;
- // }
-
- Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1f));
-
- auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
-
- Func("my_func", ast::VariableList{}, ty.void_(),
- ast::StatementList{
- Decl(Source{{12, 34}}, var),
- },
- ast::DecorationList{});
-
- EXPECT_FALSE(r()->Resolve()) << r()->error();
- EXPECT_EQ(r()->error(), "12:34 error v-0013: redeclared identifier 'a'");
-}
-
-TEST_F(ResolverTypeValidationTest, RedeclaredIdentifier_Fail) {
- // fn my_func()() {
- // var a :i32 = 2;
- // var a :f21 = 2.0;
- // }
- auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
-
- auto* var_a_float = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(0.1f));
-
- Func("my_func", ast::VariableList{}, ty.void_(),
- ast::StatementList{
- Decl(var),
- Decl(Source{{12, 34}}, var_a_float),
- },
- ast::DecorationList{});
-
- EXPECT_FALSE(r()->Resolve()) << r()->error();
- EXPECT_EQ(r()->error(), "12:34 error v-0014: redeclared identifier 'a'");
-}
-
TEST_F(ResolverTypeValidationTest, RedeclaredIdentifierInnerScope_Pass) {
// {
// if (true) { var a : f32 = 2.0; }
@@ -209,31 +133,6 @@
EXPECT_TRUE(r()->Resolve());
}
-TEST_F(ResolverTypeValidationTest,
- DISABLED_RedeclaredIdentifierInnerScope_False) {
- // TODO(sarahM0): remove DISABLED after implementing ValidateIfStatement
- // and it should just work
- // {
- // var a : f32 = 3.14;
- // if (true) { var a : f32 = 2.0; }
- // }
- auto* var_a_float = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(3.1f));
-
- auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
-
- auto* cond = Expr(true);
- auto* body = Block(Decl(Source{{12, 34}}, var));
-
- auto* outer_body =
- Block(Decl(var_a_float),
- create<ast::IfStatement>(cond, body, ast::ElseStatementList{}));
-
- WrapInFunction(outer_body);
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error v-0014: redeclared identifier 'a'");
-}
-
TEST_F(ResolverTypeValidationTest, RedeclaredIdentifierInnerScopeBlock_Pass) {
// {
// { var a : f32; }
@@ -250,23 +149,6 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
-TEST_F(ResolverTypeValidationTest, RedeclaredIdentifierInnerScopeBlock_Fail) {
- // {
- // var a : f32;
- // { var a : f32; }
- // }
- auto* var_inner = Var("a", ty.f32(), ast::StorageClass::kNone);
- auto* inner = Block(Decl(Source{{12, 34}}, var_inner));
-
- auto* var_outer = Var("a", ty.f32(), ast::StorageClass::kNone);
- auto* outer_body = Block(Decl(var_outer), inner);
-
- WrapInFunction(outer_body);
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error v-0014: redeclared identifier 'a'");
-}
-
TEST_F(ResolverTypeValidationTest,
RedeclaredIdentifierDifferentFunctions_Pass) {
// func0 { var a : f32 = 2.0; return; }
@@ -519,7 +401,7 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
- auto* got = TypeOf(expr)->UnwrapPtr();
+ auto* got = TypeOf(expr)->UnwrapRef();
auto* expected = params.create_sem_type(ty);
EXPECT_EQ(got, expected) << "got: " << FriendlyName(got) << "\n"
diff --git a/src/resolver/validation_test.cc b/src/resolver/validation_test.cc
index 9440f1f..ed4d089 100644
--- a/src/resolver/validation_test.cc
+++ b/src/resolver/validation_test.cc
@@ -160,34 +160,6 @@
"12:34 error: else statement condition must be bool, got f32");
}
-TEST_F(ResolverValidationTest,
- Stmt_VariableDecl_MismatchedTypeScalarConstructor) {
- u32 unsigned_value = 2u; // Type does not match variable type
- auto* decl = Decl(Var(Source{{3, 3}}, "my_var", ty.i32(),
- ast::StorageClass::kNone, Expr(unsigned_value)));
- WrapInFunction(decl);
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(
- r()->error(),
- R"(3:3 error: variable of type 'i32' cannot be initialized with a value of type 'u32')");
-}
-
-TEST_F(ResolverValidationTest,
- Stmt_VariableDecl_MismatchedTypeScalarConstructor_Alias) {
- auto* my_int = ty.alias("MyInt", ty.i32());
- AST().AddConstructedType(my_int);
- u32 unsigned_value = 2u; // Type does not match variable type
- auto* decl = Decl(Var(Source{{3, 3}}, "my_var", my_int,
- ast::StorageClass::kNone, Expr(unsigned_value)));
- WrapInFunction(decl);
-
- EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(
- r()->error(),
- R"(3:3 error: variable of type 'MyInt' cannot be initialized with a value of type 'u32')");
-}
-
TEST_F(ResolverValidationTest, Expr_Error_Unknown) {
auto* e = create<FakeExpr>(Source{Source::Location{2, 30}});
WrapInFunction(e);
diff --git a/src/resolver/var_let_test.cc b/src/resolver/var_let_test.cc
new file mode 100644
index 0000000..bf37ace
--- /dev/null
+++ b/src/resolver/var_let_test.cc
@@ -0,0 +1,133 @@
+// Copyright 2021 The Tint Authors.
+//
+// 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.
+
+#include "src/resolver/resolver.h"
+#include "src/resolver/resolver_test_helper.h"
+#include "src/sem/reference_type.h"
+
+#include "gmock/gmock.h"
+
+namespace tint {
+namespace resolver {
+namespace {
+
+struct ResolverVarLetTest : public resolver::TestHelper,
+ public testing::Test {};
+
+TEST_F(ResolverVarLetTest, TypeOfVar) {
+ // struct S { i : i32; }
+ // alias A = S;
+ // fn F(){
+ // var i : i32;
+ // var u : u32;
+ // var f : f32;
+ // var b : bool;
+ // var s : S;
+ // var a : A;
+ // }
+
+ auto* S = Structure("S", {Member("i", ty.i32())});
+ auto* A = ty.alias("A", S);
+ AST().AddConstructedType(A);
+
+ auto* i = Var("i", ty.i32(), ast::StorageClass::kNone);
+ auto* u = Var("u", ty.u32(), ast::StorageClass::kNone);
+ auto* f = Var("f", ty.f32(), ast::StorageClass::kNone);
+ auto* b = Var("b", ty.bool_(), ast::StorageClass::kNone);
+ auto* s = Var("s", S, ast::StorageClass::kNone);
+ auto* a = Var("a", A, ast::StorageClass::kNone);
+
+ Func("F", {}, ty.void_(),
+ {
+ Decl(i),
+ Decl(u),
+ Decl(f),
+ Decl(b),
+ Decl(s),
+ Decl(a),
+ });
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ // `var` declarations are always of reference type
+ ASSERT_TRUE(TypeOf(i)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(u)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(f)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(b)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(s)->Is<sem::Reference>());
+ ASSERT_TRUE(TypeOf(a)->Is<sem::Reference>());
+
+ EXPECT_TRUE(TypeOf(i)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
+ EXPECT_TRUE(TypeOf(u)->As<sem::Reference>()->StoreType()->Is<sem::U32>());
+ EXPECT_TRUE(TypeOf(f)->As<sem::Reference>()->StoreType()->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(b)->As<sem::Reference>()->StoreType()->Is<sem::Bool>());
+ EXPECT_TRUE(TypeOf(s)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
+ EXPECT_TRUE(TypeOf(a)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
+}
+
+TEST_F(ResolverVarLetTest, TypeOfLet) {
+ // struct S { i : i32; }
+ // fn F(){
+ // var v : i32;
+ // let i : i32 = 1;
+ // let u : u32 = 1u;
+ // let f : f32 = 1.;
+ // let b : bool = true;
+ // let s : S = S(1);
+ // let a : A = A(1);
+ // let p : pointer<function, i32> = &V;
+ // }
+
+ auto* S = Structure("S", {Member("i", ty.i32())});
+ auto* A = ty.alias("A", S);
+ AST().AddConstructedType(A);
+
+ auto* v = Var("v", ty.i32(), ast::StorageClass::kNone);
+ auto* i = Const("i", ty.i32(), Expr(1));
+ auto* u = Const("u", ty.u32(), Expr(1u));
+ auto* f = Const("f", ty.f32(), Expr(1.f));
+ auto* b = Const("b", ty.bool_(), Expr(true));
+ auto* s = Const("s", S, Construct(S, Expr(1)));
+ auto* a = Const("a", A, Construct(A, Expr(1)));
+ auto* p =
+ Const("p", ty.pointer<i32>(ast::StorageClass::kFunction), AddressOf(v));
+
+ Func("F", {}, ty.void_(),
+ {
+ Decl(v),
+ Decl(i),
+ Decl(u),
+ Decl(f),
+ Decl(b),
+ Decl(s),
+ Decl(a),
+ Decl(p),
+ });
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ // `let` declarations are always of the storage type
+ EXPECT_TRUE(TypeOf(i)->Is<sem::I32>());
+ EXPECT_TRUE(TypeOf(u)->Is<sem::U32>());
+ EXPECT_TRUE(TypeOf(f)->Is<sem::F32>());
+ EXPECT_TRUE(TypeOf(b)->Is<sem::Bool>());
+ EXPECT_TRUE(TypeOf(s)->Is<sem::Struct>());
+ EXPECT_TRUE(TypeOf(a)->Is<sem::Struct>());
+ ASSERT_TRUE(TypeOf(p)->Is<sem::Pointer>());
+ EXPECT_TRUE(TypeOf(p)->As<sem::Pointer>()->StoreType()->Is<sem::I32>());
+}
+
+} // namespace
+} // namespace resolver
+} // namespace tint
diff --git a/src/resolver/var_let_validation_test.cc b/src/resolver/var_let_validation_test.cc
new file mode 100644
index 0000000..23c42e9
--- /dev/null
+++ b/src/resolver/var_let_validation_test.cc
@@ -0,0 +1,220 @@
+// Copyright 2021 The Tint Authors.
+//
+// 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.
+
+#include "src/resolver/resolver.h"
+#include "src/resolver/resolver_test_helper.h"
+
+#include "gmock/gmock.h"
+
+namespace tint {
+namespace resolver {
+namespace {
+
+struct ResolverVarLetValidationTest : public resolver::TestHelper,
+ public testing::Test {};
+
+TEST_F(ResolverVarLetValidationTest, LetNoInitializer) {
+ // let a : i32;
+ WrapInFunction(Const(Source{{12, 34}}, "a", ty.i32(), nullptr));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ "12:34 error: let declarations must have initializers");
+}
+
+TEST_F(ResolverVarLetValidationTest, GlobalLetNoInitializer) {
+ // let a : i32;
+ GlobalConst(Source{{12, 34}}, "a", ty.i32(), nullptr);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ "12:34 error: let declarations must have initializers");
+}
+
+TEST_F(ResolverVarLetValidationTest, VarConstructorNotStorable) {
+ // var i : i32;
+ // var p : pointer<function, i32> = &v;
+ auto* i = Var("i", ty.i32(), ast::StorageClass::kNone);
+ auto* p = Var("a", ty.i32(), ast::StorageClass::kNone,
+ AddressOf(Source{{12, 34}}, "i"));
+ WrapInFunction(i, p);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ "12:34 error: 'ptr<function, i32>' is not storable for assignment");
+}
+
+TEST_F(ResolverVarLetValidationTest, LetConstructorWrongType) {
+ // var v : i32 = 2u
+ WrapInFunction(Const(Source{{3, 3}}, "v", ty.i32(), Expr(2u)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(3:3 error: cannot initialize let of type 'i32' with value of type 'u32')");
+}
+
+TEST_F(ResolverVarLetValidationTest, VarConstructorWrongType) {
+ // var v : i32 = 2u
+ WrapInFunction(
+ Var(Source{{3, 3}}, "v", ty.i32(), ast::StorageClass::kNone, Expr(2u)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(3:3 error: cannot initialize var of type 'i32' with value of type 'u32')");
+}
+
+TEST_F(ResolverVarLetValidationTest, LetConstructorWrongTypeViaAlias) {
+ auto* a = ty.alias("I32", ty.i32());
+ AST().AddConstructedType(a);
+ WrapInFunction(Const(Source{{3, 3}}, "v", a, Expr(2u)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(3:3 error: cannot initialize let of type 'I32' with value of type 'u32')");
+}
+
+TEST_F(ResolverVarLetValidationTest, VarConstructorWrongTypeViaAlias) {
+ auto* a = ty.alias("I32", ty.i32());
+ AST().AddConstructedType(a);
+ WrapInFunction(
+ Var(Source{{3, 3}}, "v", a, ast::StorageClass::kNone, Expr(2u)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(3:3 error: cannot initialize var of type 'I32' with value of type 'u32')");
+}
+
+TEST_F(ResolverVarLetValidationTest, LetOfPtrConstructedWithRef) {
+ // var a : f32;
+ // let b : ptr<function,f32> = a;
+ const auto priv = ast::StorageClass::kFunction;
+ auto* var_a = Var("a", ty.f32(), priv);
+ auto* var_b =
+ Const(Source{{12, 34}}, "b", ty.pointer<float>(priv), Expr("a"), {});
+ WrapInFunction(var_a, var_b);
+
+ ASSERT_FALSE(r()->Resolve());
+
+ EXPECT_EQ(
+ r()->error(),
+ R"(12:34 error: cannot initialize let of type 'ptr<function, f32>' with value of type 'f32')");
+}
+
+TEST_F(ResolverVarLetValidationTest, LocalVarRedeclared) {
+ // var v : f32;
+ // var v : i32;
+ auto* v1 = Var("v", ty.f32(), ast::StorageClass::kNone);
+ auto* v2 = Var(Source{{12, 34}}, "v", ty.i32(), ast::StorageClass::kNone);
+ WrapInFunction(v1, v2);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error v-0014: redeclared identifier 'v'");
+}
+
+TEST_F(ResolverVarLetValidationTest, LocalLetRedeclared) {
+ // let l : f32 = 1.;
+ // let l : i32 = 0;
+ auto* l1 = Const("l", ty.f32(), Expr(1.f));
+ auto* l2 = Const(Source{{12, 34}}, "l", ty.i32(), Expr(0));
+ WrapInFunction(l1, l2);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error v-0014: redeclared identifier 'l'");
+}
+
+TEST_F(ResolverVarLetValidationTest, GlobalVarRedeclared) {
+ // var v : f32;
+ // var v : i32;
+ Global("v", ty.f32(), ast::StorageClass::kPrivate);
+ Global(Source{{12, 34}}, "v", ty.i32(), ast::StorageClass::kPrivate);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ "12:34 error v-0011: redeclared global identifier 'v'");
+}
+
+TEST_F(ResolverVarLetValidationTest, GlobalLetRedeclared) {
+ // let l : f32 = 0.1;
+ // let l : i32 = 0;
+ GlobalConst("l", ty.f32(), Expr(0.1f));
+ GlobalConst(Source{{12, 34}}, "l", ty.i32(), Expr(0));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ "12:34 error v-0011: redeclared global identifier 'l'");
+}
+
+TEST_F(ResolverVarLetValidationTest, GlobalVarRedeclaredAsLocal) {
+ // var v : f32 = 2.1;
+ // fn my_func() {
+ // var v : f32 = 2.0;
+ // return 0;
+ // }
+
+ Global("v", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1f));
+
+ WrapInFunction(Var(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kNone,
+ Expr(2.0f)));
+
+ EXPECT_FALSE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(), "12:34 error v-0013: redeclared identifier 'v'");
+}
+
+TEST_F(ResolverVarLetValidationTest, VarRedeclaredInInnerBlock) {
+ // {
+ // var v : f32;
+ // { var v : f32; }
+ // }
+ auto* var_outer = Var("v", ty.f32(), ast::StorageClass::kNone);
+ auto* var_inner =
+ Var(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kNone);
+ auto* inner = Block(Decl(var_inner));
+ auto* outer_body = Block(Decl(var_outer), inner);
+
+ WrapInFunction(outer_body);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error v-0014: redeclared identifier 'v'");
+}
+
+TEST_F(ResolverVarLetValidationTest, VarRedeclaredInIfBlock) {
+ // {
+ // var v : f32 = 3.14;
+ // if (true) { var v : f32 = 2.0; }
+ // }
+ auto* var_a_float = Var("v", ty.f32(), ast::StorageClass::kNone, Expr(3.1f));
+
+ auto* var = Var(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kNone,
+ Expr(2.0f));
+
+ auto* cond = Expr(true);
+ auto* body = Block(Decl(var));
+
+ auto* outer_body =
+ Block(Decl(var_a_float),
+ create<ast::IfStatement>(cond, body, ast::ElseStatementList{}));
+
+ WrapInFunction(outer_body);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error v-0014: redeclared identifier 'v'");
+}
+
+} // namespace
+} // namespace resolver
+} // namespace tint
diff --git a/src/sem/function.cc b/src/sem/function.cc
index 35c2e71..0c5e844 100644
--- a/src/sem/function.cc
+++ b/src/sem/function.cc
@@ -139,7 +139,7 @@
VariableBindings ret;
for (auto* var : ReferencedModuleVariables()) {
- auto* unwrapped_type = var->Type()->UnwrapAccess();
+ auto* unwrapped_type = var->Type()->UnwrapRef();
auto* storage_texture = unwrapped_type->As<sem::StorageTexture>();
if (storage_texture == nullptr) {
continue;
@@ -156,7 +156,7 @@
VariableBindings ret;
for (auto* var : ReferencedModuleVariables()) {
- auto* unwrapped_type = var->Type()->UnwrapAccess();
+ auto* unwrapped_type = var->Type()->UnwrapRef();
auto* storage_texture = unwrapped_type->As<sem::DepthTexture>();
if (storage_texture == nullptr) {
continue;
@@ -174,7 +174,7 @@
VariableBindings ret;
for (auto* var : ReferencedModuleVariables()) {
- auto* unwrapped_type = var->Type()->UnwrapAccess();
+ auto* unwrapped_type = var->Type()->UnwrapRef();
auto* external_texture = unwrapped_type->As<sem::ExternalTexture>();
if (external_texture == nullptr) {
continue;
@@ -201,7 +201,7 @@
VariableBindings ret;
for (auto* var : ReferencedModuleVariables()) {
- auto* unwrapped_type = var->Type()->UnwrapAccess();
+ auto* unwrapped_type = var->Type()->UnwrapRef();
auto* sampler = unwrapped_type->As<sem::Sampler>();
if (sampler == nullptr || sampler->kind() != kind) {
continue;
@@ -219,7 +219,7 @@
VariableBindings ret;
for (auto* var : ReferencedModuleVariables()) {
- auto* unwrapped_type = var->Type()->UnwrapAccess();
+ auto* unwrapped_type = var->Type()->UnwrapRef();
auto* texture = unwrapped_type->As<sem::Texture>();
if (texture == nullptr) {
continue;
diff --git a/src/sem/type.cc b/src/sem/type.cc
index 1f7ffca..00f9e10 100644
--- a/src/sem/type.cc
+++ b/src/sem/type.cc
@@ -19,6 +19,7 @@
#include "src/sem/i32_type.h"
#include "src/sem/matrix_type.h"
#include "src/sem/pointer_type.h"
+#include "src/sem/reference_type.h"
#include "src/sem/sampler_type.h"
#include "src/sem/texture_type.h"
#include "src/sem/u32_type.h"
@@ -43,21 +44,17 @@
return type;
}
-const Type* Type::UnwrapAccess() const {
- // TODO(amaiorano): Delete this function
+const Type* Type::UnwrapRef() const {
auto* type = this;
+ if (auto* ref = type->As<sem::Reference>()) {
+ type = ref->StoreType();
+ }
return type;
}
-const Type* Type::UnwrapAll() const {
+const Type* Type::UnwrapAccess() const {
+ // TODO(amaiorano): Delete this function
auto* type = this;
- while (true) {
- if (auto* ptr = type->As<sem::Pointer>()) {
- type = ptr->StoreType();
- } else {
- break;
- }
- }
return type;
}
diff --git a/src/sem/type.h b/src/sem/type.h
index 76a64e1..11dd080 100644
--- a/src/sem/type.h
+++ b/src/sem/type.h
@@ -49,15 +49,13 @@
/// otherwise
const Type* UnwrapPtr() const;
+ /// @returns the inner type if this is a reference, `this` otherwise
+ const Type* UnwrapRef() const;
+
/// @returns the inner most type if this is an access control, `this`
/// otherwise
const Type* UnwrapAccess() const;
- /// Returns the type found after removing all layers of access control and
- /// pointer
- /// @returns the unwrapped type
- const Type* UnwrapAll() const;
-
/// @returns true if this type is a scalar
bool is_scalar() const;
/// @returns true if this type is a numeric scalar
diff --git a/src/transform/binding_remapper.cc b/src/transform/binding_remapper.cc
index 8a1c42c..f89bfd9 100644
--- a/src/transform/binding_remapper.cc
+++ b/src/transform/binding_remapper.cc
@@ -113,7 +113,7 @@
auto ac_it = remappings->access_controls.find(from);
if (ac_it != remappings->access_controls.end()) {
ast::AccessControl::Access ac = ac_it->second;
- auto* ty = in->Sem().Get(var)->Type();
+ auto* ty = in->Sem().Get(var)->Type()->UnwrapRef();
ast::Type* inner_ty = CreateASTTypeFor(&ctx, ty);
auto* new_ty = ctx.dst->create<ast::AccessControl>(ac, inner_ty);
auto* new_var = ctx.dst->create<ast::Variable>(
diff --git a/src/transform/bound_array_accessors.cc b/src/transform/bound_array_accessors.cc
index 82c221b..19a9643 100644
--- a/src/transform/bound_array_accessors.cc
+++ b/src/transform/bound_array_accessors.cc
@@ -41,7 +41,7 @@
CloneContext* ctx) {
auto& diags = ctx->dst->Diagnostics();
- auto* ret_type = ctx->src->Sem().Get(expr->array())->Type()->UnwrapAll();
+ auto* ret_type = ctx->src->Sem().Get(expr->array())->Type()->UnwrapRef();
if (!ret_type->Is<sem::Array>() && !ret_type->Is<sem::Matrix>() &&
!ret_type->Is<sem::Vector>()) {
return nullptr;
diff --git a/src/transform/bound_array_accessors_test.cc b/src/transform/bound_array_accessors_test.cc
index 00414f1..b9120d4 100644
--- a/src/transform/bound_array_accessors_test.cc
+++ b/src/transform/bound_array_accessors_test.cc
@@ -29,7 +29,7 @@
let c : u32 = 1u;
fn f() {
- let b : ptr<private, f32> = a[c];
+ let b : f32 = a[c];
}
)";
@@ -39,7 +39,7 @@
let c : u32 = 1u;
fn f() {
- let b : ptr<private, f32> = a[min(u32(c), 2u)];
+ let b : f32 = a[min(u32(c), 2u)];
}
)";
diff --git a/src/transform/calculate_array_length.cc b/src/transform/calculate_array_length.cc
index 96efb9d..e6becb4 100644
--- a/src/transform/calculate_array_length.cc
+++ b/src/transform/calculate_array_length.cc
@@ -142,7 +142,7 @@
auto* storage_buffer_expr = accessor->structure();
auto* storage_buffer_sem = sem.Get(storage_buffer_expr);
auto* storage_buffer_type =
- storage_buffer_sem->Type()->UnwrapAll()->As<sem::Struct>();
+ storage_buffer_sem->Type()->UnwrapRef()->As<sem::Struct>();
// Generate BufferSizeIntrinsic for this storage type if we haven't
// already
diff --git a/src/transform/canonicalize_entry_point_io.cc b/src/transform/canonicalize_entry_point_io.cc
index 8da983f..bb1cb71 100644
--- a/src/transform/canonicalize_entry_point_io.cc
+++ b/src/transform/canonicalize_entry_point_io.cc
@@ -115,7 +115,7 @@
// Pull out all struct members and build initializer list.
std::vector<Symbol> member_names;
for (auto* member : str->Members()) {
- if (member->Type()->UnwrapAll()->Is<sem::Struct>()) {
+ if (member->Type()->Is<sem::Struct>()) {
TINT_ICE(ctx.dst->Diagnostics()) << "nested pipeline IO struct";
}
@@ -205,7 +205,7 @@
if (auto* str = ret_type->As<sem::Struct>()) {
// Rebuild struct with only the entry point IO attributes.
for (auto* member : str->Members()) {
- if (member->Type()->UnwrapAll()->Is<sem::Struct>()) {
+ if (member->Type()->Is<sem::Struct>()) {
TINT_ICE(ctx.dst->Diagnostics()) << "nested pipeline IO struct";
}
diff --git a/src/transform/decompose_storage_access.cc b/src/transform/decompose_storage_access.cc
index ab256a2..46495a1 100644
--- a/src/transform/decompose_storage_access.cc
+++ b/src/transform/decompose_storage_access.cc
@@ -29,6 +29,7 @@
#include "src/sem/array.h"
#include "src/sem/call.h"
#include "src/sem/member_accessor_expression.h"
+#include "src/sem/reference_type.h"
#include "src/sem/struct.h"
#include "src/sem/variable.h"
#include "src/utils/get_or_create.h"
@@ -56,7 +57,7 @@
explicit OffsetExpr(ast::Expression* e) : expr(e) {}
ast::Expression* Build(CloneContext& ctx) override {
- auto* type = ctx.src->Sem().Get(expr)->Type()->UnwrapAll();
+ auto* type = ctx.src->Sem().Get(expr)->Type()->UnwrapRef();
auto* res = ctx.Clone(expr);
if (!type->Is<sem::U32>()) {
res = ctx.dst->Construct<ProgramBuilder::u32>(res);
@@ -333,8 +334,8 @@
/// @returns the unwrapped, user-declared constructed type of ty.
const ast::NamedType* ConstructedTypeOf(const sem::Type* ty) {
while (true) {
- if (auto* ptr = ty->As<sem::Pointer>()) {
- ty = ptr->StoreType();
+ if (auto* ref = ty->As<sem::Reference>()) {
+ ty = ref->StoreType();
continue;
}
if (auto* str = ty->As<sem::Struct>()) {
@@ -466,14 +467,14 @@
for (auto* member : str->Members()) {
auto* offset = ctx.dst->Add("offset", member->Offset());
Symbol load = LoadFunc(ctx, insert_after, buf_ty,
- member->Type()->UnwrapAll(), var_user);
+ member->Type()->UnwrapRef(), var_user);
values.emplace_back(ctx.dst->Call(load, "buffer", offset));
}
} else if (auto* arr = el_ty->As<sem::Array>()) {
for (uint32_t i = 0; i < arr->Count(); i++) {
auto* offset = ctx.dst->Add("offset", arr->Stride() * i);
Symbol load = LoadFunc(ctx, insert_after, buf_ty,
- arr->ElemType()->UnwrapAll(), var_user);
+ arr->ElemType()->UnwrapRef(), var_user);
values.emplace_back(ctx.dst->Call(load, "buffer", offset));
}
}
@@ -546,7 +547,7 @@
auto* access = ctx.dst->MemberAccessor(
"value", ctx.Clone(member->Declaration()->symbol()));
Symbol store = StoreFunc(ctx, insert_after, buf_ty,
- member->Type()->UnwrapAll(), var_user);
+ member->Type()->UnwrapRef(), var_user);
auto* call = ctx.dst->Call(store, "buffer", offset, access);
body.emplace_back(ctx.dst->create<ast::CallStatement>(call));
}
@@ -555,7 +556,7 @@
auto* offset = ctx.dst->Add("offset", arr->Stride() * i);
auto* access = ctx.dst->IndexAccessor("value", ctx.dst->Expr(i));
Symbol store = StoreFunc(ctx, insert_after, buf_ty,
- arr->ElemType()->UnwrapAll(), var_user);
+ arr->ElemType()->UnwrapRef(), var_user);
auto* call = ctx.dst->Call(store, "buffer", offset, access);
body.emplace_back(ctx.dst->create<ast::CallStatement>(call));
}
@@ -661,7 +662,7 @@
state.AddAccess(ident, {
var,
ToOffset(0u),
- var->Type()->UnwrapAll(),
+ var->Type()->UnwrapRef(),
});
}
}
@@ -681,7 +682,7 @@
accessor, {
access.var,
Add(std::move(access.offset), std::move(offset)),
- vec_ty->type()->UnwrapAll(),
+ vec_ty->type()->UnwrapRef(),
});
}
}
@@ -694,7 +695,7 @@
{
access.var,
Add(std::move(access.offset), std::move(offset)),
- member->Type()->UnwrapAll(),
+ member->Type()->UnwrapRef(),
});
}
}
@@ -710,7 +711,7 @@
{
access.var,
Add(std::move(access.offset), std::move(offset)),
- arr->ElemType()->UnwrapAll(),
+ arr->ElemType()->UnwrapRef(),
});
continue;
}
@@ -720,7 +721,7 @@
{
access.var,
Add(std::move(access.offset), std::move(offset)),
- vec_ty->type()->UnwrapAll(),
+ vec_ty->type()->UnwrapRef(),
});
continue;
}
@@ -770,8 +771,8 @@
auto* buf = access.var->Declaration();
auto* offset = access.offset->Build(ctx);
- auto* buf_ty = access.var->Type()->UnwrapPtr();
- auto* el_ty = access.type->UnwrapAll();
+ auto* buf_ty = access.var->Type()->UnwrapRef();
+ auto* el_ty = access.type->UnwrapRef();
auto* insert_after = ConstructedTypeOf(access.var->Type());
Symbol func = state.LoadFunc(ctx, insert_after, buf_ty, el_ty,
access.var->As<sem::VariableUser>());
@@ -785,8 +786,8 @@
for (auto& store : state.stores) {
auto* buf = store.target.var->Declaration();
auto* offset = store.target.offset->Build(ctx);
- auto* buf_ty = store.target.var->Type()->UnwrapPtr();
- auto* el_ty = store.target.type->UnwrapAll();
+ auto* buf_ty = store.target.var->Type()->UnwrapRef();
+ auto* el_ty = store.target.type->UnwrapRef();
auto* value = store.assignment->rhs();
auto* insert_after = ConstructedTypeOf(store.target.var->Type());
Symbol func = state.StoreFunc(ctx, insert_after, buf_ty, el_ty,
diff --git a/src/transform/external_texture_transform.cc b/src/transform/external_texture_transform.cc
index d4095f5..c8fb07f 100644
--- a/src/transform/external_texture_transform.cc
+++ b/src/transform/external_texture_transform.cc
@@ -52,7 +52,10 @@
// if the first parameter is an external texture.
if (auto* var =
sem.Get(call_expr->params()[0])->As<sem::VariableUser>()) {
- if (var->Variable()->Type()->Is<sem::ExternalTexture>()) {
+ if (var->Variable()
+ ->Type()
+ ->UnwrapRef()
+ ->Is<sem::ExternalTexture>()) {
if (intrinsic->Type() == sem::IntrinsicType::kTextureLoad &&
call_expr->params().size() != 2) {
TINT_ICE(ctx.dst->Diagnostics())
diff --git a/src/transform/transform.cc b/src/transform/transform.cc
index d7ead87..f288451 100644
--- a/src/transform/transform.cc
+++ b/src/transform/transform.cc
@@ -17,6 +17,7 @@
#include <algorithm>
#include "src/program_builder.h"
+#include "src/sem/reference_type.h"
TINT_INSTANTIATE_TYPEINFO(tint::transform::Data);
@@ -107,6 +108,9 @@
return ctx->dst->create<ast::TypeName>(
ctx->Clone(s->Declaration()->name()));
}
+ if (auto* s = ty->As<sem::Reference>()) {
+ return CreateASTTypeFor(ctx, s->StoreType());
+ }
TINT_UNREACHABLE(ctx->dst->Diagnostics())
<< "Unhandled type: " << ty->TypeInfo().name;
return nullptr;
diff --git a/src/writer/append_vector.cc b/src/writer/append_vector.cc
index 9e64ac4..dcf179f 100644
--- a/src/writer/append_vector.cc
+++ b/src/writer/append_vector.cc
@@ -41,7 +41,7 @@
uint32_t packed_size;
const sem::Type* packed_el_sem_ty;
auto* vector_sem = b->Sem().Get(vector);
- auto* vector_ty = vector_sem->Type()->UnwrapPtr();
+ auto* vector_ty = vector_sem->Type()->UnwrapRef();
if (auto* vec = vector_ty->As<sem::Vector>()) {
packed_size = vec->size() + 1;
packed_el_sem_ty = vec->type();
@@ -72,7 +72,7 @@
} else {
packed.emplace_back(vector);
}
- if (packed_el_sem_ty != b->TypeOf(scalar)->UnwrapPtr()) {
+ if (packed_el_sem_ty != b->TypeOf(scalar)->UnwrapRef()) {
// Cast scalar to the vector element type
auto* scalar_cast = b->Construct(packed_el_ty, scalar);
b->Sem().Add(scalar_cast, b->create<sem::Expression>(
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index 95a77f2..e894106 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -317,8 +317,8 @@
return true;
}
- auto* lhs_type = TypeOf(expr->lhs())->UnwrapAll();
- auto* rhs_type = TypeOf(expr->rhs())->UnwrapAll();
+ auto* lhs_type = TypeOf(expr->lhs())->UnwrapRef();
+ auto* rhs_type = TypeOf(expr->rhs())->UnwrapRef();
// Multiplying by a matrix requires the use of `mul` in order to get the
// type of multiply we desire.
if (expr->op() == ast::BinaryOp::kMultiply &&
@@ -854,7 +854,7 @@
return false;
}
- auto* texture_type = TypeOf(texture)->UnwrapAll()->As<sem::Texture>();
+ auto* texture_type = TypeOf(texture)->UnwrapRef()->As<sem::Texture>();
switch (intrinsic->Type()) {
case sem::IntrinsicType::kTextureDimensions:
@@ -1300,7 +1300,7 @@
bool GeneratorImpl::EmitTypeConstructor(std::ostream& pre,
std::ostream& out,
ast::TypeConstructorExpression* expr) {
- auto* type = TypeOf(expr);
+ auto* type = TypeOf(expr)->UnwrapRef();
// If the type constructor is empty then we need to construct with the zero
// value for all components.
@@ -1699,7 +1699,7 @@
continue; // Global already emitted
}
- auto* type = var->Type()->UnwrapAccess();
+ auto* type = var->Type()->UnwrapRef();
if (auto* strct = type->As<sem::Struct>()) {
out << "ConstantBuffer<"
<< builder_.Symbols().NameFor(strct->Declaration()->name()) << "> "
@@ -1748,8 +1748,9 @@
return false;
}
- if (!EmitType(out, var->Type(), ast::StorageClass::kStorage,
- var->AccessControl(), "")) {
+ auto* type = var->Type()->UnwrapRef();
+ if (!EmitType(out, type, ast::StorageClass::kStorage, var->AccessControl(),
+ "")) {
return false;
}
@@ -1781,7 +1782,7 @@
auto* var = data.first;
auto* deco = data.second;
auto* sem = builder_.Sem().Get(var);
- auto* type = sem->Type();
+ auto* type = sem->Type()->UnwrapRef();
make_indent(out);
if (!EmitType(out, type, sem->StorageClass(), sem->AccessControl(),
@@ -1832,7 +1833,7 @@
auto* var = data.first;
auto* deco = data.second;
auto* sem = builder_.Sem().Get(var);
- auto* type = sem->Type();
+ auto* type = sem->Type()->UnwrapRef();
make_indent(out);
if (!EmitType(out, type, sem->StorageClass(), sem->AccessControl(),
@@ -1877,7 +1878,7 @@
for (auto* var : func_sem->ReferencedModuleVariables()) {
auto* decl = var->Declaration();
- auto* unwrapped_type = var->Type()->UnwrapAll();
+ auto* unwrapped_type = var->Type()->UnwrapRef();
if (!emitted_globals.emplace(decl->symbol()).second) {
continue; // Global already emitted
}
@@ -1903,11 +1904,12 @@
}
auto name = builder_.Symbols().NameFor(decl->symbol());
- if (!EmitType(out, var->Type(), var->StorageClass(), var->AccessControl(),
+ auto* type = var->Type()->UnwrapRef();
+ if (!EmitType(out, type, var->StorageClass(), var->AccessControl(),
name)) {
return false;
}
- if (!var->Type()->Is<sem::Array>()) {
+ if (!type->Is<sem::Array>()) {
out << " " << name;
}
@@ -2230,7 +2232,8 @@
if (var->constructor() != nullptr) {
out << constructor_out.str();
} else {
- if (!EmitZeroValue(out, builder_.Sem().Get(var)->Type())) {
+ auto* type = builder_.Sem().Get(var)->Type()->UnwrapRef();
+ if (!EmitZeroValue(out, type)) {
return false;
}
}
@@ -2639,7 +2642,7 @@
make_indent(out);
auto* sem = builder_.Sem().Get(var);
- auto* type = sem->Type();
+ auto* type = sem->Type()->UnwrapRef();
// TODO(dsinclair): Handle variable decorations
if (!var->decorations().empty()) {
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index 08255ae..c4d25cf 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -41,6 +41,7 @@
#include "src/sem/member_accessor_expression.h"
#include "src/sem/multisampled_texture_type.h"
#include "src/sem/pointer_type.h"
+#include "src/sem/reference_type.h"
#include "src/sem/sampled_texture_type.h"
#include "src/sem/storage_texture_type.h"
#include "src/sem/struct.h"
@@ -177,7 +178,7 @@
bool GeneratorImpl::EmitBitcast(ast::BitcastExpression* expr) {
out_ << "as_type<";
- if (!EmitType(TypeOf(expr), "")) {
+ if (!EmitType(TypeOf(expr)->UnwrapRef(), "")) {
return false;
}
@@ -484,7 +485,7 @@
return false;
}
- auto* texture_type = TypeOf(texture)->UnwrapAll()->As<sem::Texture>();
+ auto* texture_type = TypeOf(texture)->UnwrapRef()->As<sem::Texture>();
switch (intrinsic->Type()) {
case sem::IntrinsicType::kTextureDimensions: {
@@ -530,7 +531,7 @@
get_dim(dims[0]);
out_ << ")";
} else {
- EmitType(TypeOf(expr), "");
+ EmitType(TypeOf(expr)->UnwrapRef(), "");
out_ << "(";
for (size_t i = 0; i < dims.size(); i++) {
if (i > 0) {
@@ -880,7 +881,7 @@
}
bool GeneratorImpl::EmitTypeConstructor(ast::TypeConstructorExpression* expr) {
- auto* type = TypeOf(expr);
+ auto* type = TypeOf(expr)->UnwrapRef();
if (type->IsAnyOf<sem::Array, sem::Struct>()) {
out_ << "{";
@@ -1016,7 +1017,7 @@
uint32_t loc = data.second;
make_indent();
- if (!EmitType(program_->Sem().Get(var)->Type(),
+ if (!EmitType(program_->Sem().Get(var)->Type()->UnwrapRef(),
program_->Symbols().NameFor(var->symbol()))) {
return false;
}
@@ -1053,7 +1054,7 @@
auto* deco = data.second;
make_indent();
- if (!EmitType(program_->Sem().Get(var)->Type(),
+ if (!EmitType(program_->Sem().Get(var)->Type()->UnwrapRef(),
program_->Symbols().NameFor(var->symbol()))) {
return false;
}
@@ -1267,7 +1268,7 @@
first = false;
out_ << "thread ";
- if (!EmitType(var->Type(), "")) {
+ if (!EmitType(var->Type()->UnwrapRef(), "")) {
return false;
}
out_ << "& " << program_->Symbols().NameFor(var->Declaration()->symbol());
@@ -1282,7 +1283,7 @@
out_ << "constant ";
// TODO(dsinclair): Can arrays be uniform? If so, fix this ...
- if (!EmitType(var->Type(), "")) {
+ if (!EmitType(var->Type()->UnwrapRef(), "")) {
return false;
}
out_ << "& " << program_->Symbols().NameFor(var->Declaration()->symbol());
@@ -1300,7 +1301,7 @@
}
out_ << "device ";
- if (!EmitType(var->Type(), "")) {
+ if (!EmitType(var->Type()->UnwrapRef(), "")) {
return false;
}
out_ << "& " << program_->Symbols().NameFor(var->Declaration()->symbol());
@@ -1414,7 +1415,7 @@
}
first = false;
- auto* type = program_->Sem().Get(var)->Type();
+ auto* type = program_->Sem().Get(var)->Type()->UnwrapRef();
if (!EmitType(type, "")) {
return false;
@@ -1462,7 +1463,7 @@
auto* builtin = data.second;
- if (!EmitType(var->Type(), "")) {
+ if (!EmitType(var->Type()->UnwrapRef(), "")) {
return false;
}
@@ -1497,7 +1498,7 @@
out_ << "constant ";
// TODO(dsinclair): Can you have a uniform array? If so, this needs to be
// updated to handle arrays property.
- if (!EmitType(var->Type(), "")) {
+ if (!EmitType(var->Type()->UnwrapRef(), "")) {
return false;
}
out_ << "& " << program_->Symbols().NameFor(var->Declaration()->symbol())
@@ -1522,7 +1523,7 @@
}
out_ << "device ";
- if (!EmitType(var->Type(), "")) {
+ if (!EmitType(var->Type()->UnwrapRef(), "")) {
return false;
}
out_ << "& " << program_->Symbols().NameFor(var->Declaration()->symbol())
@@ -1659,7 +1660,8 @@
return false;
}
} else {
- if (!EmitZeroValue(program_->Sem().Get(var)->Type())) {
+ auto* type = program_->Sem().Get(var)->Type()->UnwrapRef();
+ if (!EmitZeroValue(type)) {
return false;
}
}
@@ -2186,13 +2188,14 @@
diagnostics_.add_error("Variable decorations are not handled yet");
return false;
}
- if (decl->is_const()) {
- out_ << "const ";
- }
- if (!EmitType(var->Type(), program_->Symbols().NameFor(decl->symbol()))) {
+ auto* type = var->Type()->UnwrapRef();
+ if (!EmitType(type, program_->Symbols().NameFor(decl->symbol()))) {
return false;
}
- if (!var->Type()->Is<sem::Array>()) {
+ if (decl->is_const()) {
+ out_ << " const";
+ }
+ if (!type->Is<sem::Array>()) {
out_ << " " << program_->Symbols().NameFor(decl->symbol());
}
@@ -2206,7 +2209,7 @@
var->StorageClass() == ast::StorageClass::kFunction ||
var->StorageClass() == ast::StorageClass::kNone ||
var->StorageClass() == ast::StorageClass::kOutput) {
- if (!EmitZeroValue(var->Type())) {
+ if (!EmitZeroValue(type)) {
return false;
}
}
@@ -2231,7 +2234,7 @@
}
out_ << "constant ";
- auto* type = program_->Sem().Get(var)->Type();
+ auto* type = program_->Sem().Get(var)->Type()->UnwrapRef();
if (!EmitType(type, program_->Symbols().NameFor(var->symbol()))) {
return false;
}
@@ -2265,7 +2268,7 @@
// https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf
// 2.2.3 Packed Vector Types
auto num_els = vec->size();
- auto* el_ty = vec->type()->UnwrapAll();
+ auto* el_ty = vec->type();
if (el_ty->IsAnyOf<sem::U32, sem::I32, sem::F32>()) {
return SizeAndAlign{num_els * 4, 4};
}
@@ -2276,7 +2279,7 @@
// 2.3 Matrix Data Types
auto cols = mat->columns();
auto rows = mat->rows();
- auto* el_ty = mat->type()->UnwrapAll();
+ auto* el_ty = mat->type();
if (el_ty->IsAnyOf<sem::U32, sem::I32, sem::F32>()) {
static constexpr SizeAndAlign table[] = {
/* float2x2 */ {16, 8},
diff --git a/src/writer/msl/generator_impl_function_test.cc b/src/writer/msl/generator_impl_function_test.cc
index dafc9ca..83ffab0 100644
--- a/src/writer/msl/generator_impl_function_test.cc
+++ b/src/writer/msl/generator_impl_function_test.cc
@@ -112,7 +112,7 @@
};
fragment tint_symbol_2 frag_main(tint_symbol_1 tint_symbol [[stage_in]]) {
- const float foo = tint_symbol.foo;
+ float const foo = tint_symbol.foo;
return {foo};
}
@@ -146,7 +146,7 @@
};
fragment tint_symbol_2 frag_main(tint_symbol_1 tint_symbol [[stage_in]]) {
- const float4 coord = tint_symbol.coord;
+ float4 const coord = tint_symbol.coord;
return {coord.x};
}
@@ -214,14 +214,14 @@
};
vertex tint_symbol vert_main() {
- const Interface tint_symbol_1 = {0.5f, 0.25f, float4(0.0f)};
+ Interface const tint_symbol_1 = {0.5f, 0.25f, float4(0.0f)};
return {tint_symbol_1.col1, tint_symbol_1.col2, tint_symbol_1.pos};
}
fragment void frag_main(tint_symbol_3 tint_symbol_2 [[stage_in]]) {
- const Interface colors = {tint_symbol_2.col1, tint_symbol_2.col2, tint_symbol_2.pos};
- const float r = colors.col1;
- const float g = colors.col2;
+ Interface const colors = {tint_symbol_2.col1, tint_symbol_2.col2, tint_symbol_2.pos};
+ float const r = colors.col1;
+ float const g = colors.col2;
return;
}
@@ -283,12 +283,12 @@
}
vertex tint_symbol vert_main1() {
- const VertexOutput tint_symbol_1 = {foo(0.5f)};
+ VertexOutput const tint_symbol_1 = {foo(0.5f)};
return {tint_symbol_1.pos};
}
vertex tint_symbol_2 vert_main2() {
- const VertexOutput tint_symbol_3 = {foo(0.25f)};
+ VertexOutput const tint_symbol_3 = {foo(0.25f)};
return {tint_symbol_3.pos};
}
diff --git a/src/writer/msl/generator_impl_intrinsic_texture_test.cc b/src/writer/msl/generator_impl_intrinsic_texture_test.cc
index 02d058d..901f100 100644
--- a/src/writer/msl/generator_impl_intrinsic_texture_test.cc
+++ b/src/writer/msl/generator_impl_intrinsic_texture_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/ast/call_statement.h"
#include "src/ast/intrinsic_texture_helper_test.h"
#include "src/writer/msl/test_helper.h"
@@ -259,7 +260,14 @@
auto* call =
create<ast::CallExpression>(Expr(param.function), param.args(this));
- WrapInFunction(call);
+
+ Func("main", ast::VariableList{}, ty.void_(),
+ ast::StatementList{
+ create<ast::CallStatement>(call),
+ },
+ ast::DecorationList{
+ Stage(ast::PipelineStage::kFragment),
+ });
GeneratorImpl& gen = Build();
diff --git a/src/writer/msl/generator_impl_variable_decl_statement_test.cc b/src/writer/msl/generator_impl_variable_decl_statement_test.cc
index 04e7e34..548a705 100644
--- a/src/writer/msl/generator_impl_variable_decl_statement_test.cc
+++ b/src/writer/msl/generator_impl_variable_decl_statement_test.cc
@@ -48,7 +48,7 @@
gen.increment_indent();
ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
- EXPECT_EQ(gen.result(), " const float a = float(0.0f);\n");
+ EXPECT_EQ(gen.result(), " float const a = float(0.0f);\n");
}
TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Array) {
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index 9c2cf36..22f4a6a 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -28,9 +28,11 @@
#include "src/sem/intrinsic.h"
#include "src/sem/member_accessor_expression.h"
#include "src/sem/multisampled_texture_type.h"
+#include "src/sem/reference_type.h"
#include "src/sem/sampled_texture_type.h"
#include "src/sem/struct.h"
#include "src/sem/variable.h"
+#include "src/utils/get_or_create.h"
#include "src/writer/append_vector.h"
namespace tint {
@@ -357,7 +359,7 @@
return false;
}
- // If the thing we're assigning is a pointer then we must load it first.
+ // If the thing we're assigning is a reference then we must load it first.
auto* type = TypeOf(assign->rhs());
rhs_id = GenerateLoadIfNeeded(type, rhs_id);
@@ -598,7 +600,9 @@
return false;
}
auto* type = TypeOf(var->constructor());
- init_id = GenerateLoadIfNeeded(type, init_id);
+ if (type->Is<sem::Reference>()) {
+ init_id = GenerateLoadIfNeeded(type, init_id);
+ }
}
if (var->is_const()) {
@@ -615,8 +619,7 @@
auto var_id = result.to_i();
auto sc = ast::StorageClass::kFunction;
auto* type = builder_.Sem().Get(var)->Type();
- sem::Pointer pt(type, sc);
- auto type_id = GenerateTypeIfNeeded(&pt);
+ auto type_id = GenerateTypeIfNeeded(type);
if (type_id == 0) {
return false;
}
@@ -627,7 +630,7 @@
// TODO(dsinclair) We could detect if the constructor is fully const and emit
// an initializer value for the variable instead of doing the OpLoad.
- auto null_id = GenerateConstantNullIfNeeded(type->UnwrapPtr());
+ auto null_id = GenerateConstantNullIfNeeded(type->UnwrapRef());
if (null_id == 0) {
return 0;
}
@@ -654,6 +657,7 @@
bool Builder::GenerateGlobalVariable(ast::Variable* var) {
auto* sem = builder_.Sem().Get(var);
+ auto* type = sem->Type()->UnwrapRef();
uint32_t init_id = 0;
if (var->has_constructor()) {
@@ -679,16 +683,16 @@
}
// SPIR-V requires specialization constants to have initializers.
- if (sem->Type()->Is<sem::F32>()) {
+ if (type->Is<sem::F32>()) {
ast::FloatLiteral l(ProgramID(), Source{}, 0.0f);
init_id = GenerateLiteralIfNeeded(var, &l);
- } else if (sem->Type()->Is<sem::U32>()) {
+ } else if (type->Is<sem::U32>()) {
ast::UintLiteral l(ProgramID(), Source{}, 0);
init_id = GenerateLiteralIfNeeded(var, &l);
- } else if (sem->Type()->Is<sem::I32>()) {
+ } else if (type->Is<sem::I32>()) {
ast::SintLiteral l(ProgramID(), Source{}, 0);
init_id = GenerateLiteralIfNeeded(var, &l);
- } else if (sem->Type()->Is<sem::Bool>()) {
+ } else if (type->Is<sem::Bool>()) {
ast::BoolLiteral l(ProgramID(), Source{}, false);
init_id = GenerateLiteralIfNeeded(var, &l);
} else {
@@ -715,8 +719,7 @@
? ast::StorageClass::kPrivate
: sem->StorageClass();
- sem::Pointer pt(sem->Type(), sc);
- auto type_id = GenerateTypeIfNeeded(&pt);
+ auto type_id = GenerateTypeIfNeeded(sem->Type());
if (type_id == 0) {
return false;
}
@@ -728,8 +731,6 @@
OperandList ops = {Operand::Int(type_id), result,
Operand::Int(ConvertStorageClass(sc))};
- auto* type = sem->Type();
-
if (var->has_constructor()) {
ops.push_back(Operand::Int(init_id));
} else if (sem->AccessControl() != ast::AccessControl::kInvalid) {
@@ -806,8 +807,10 @@
auto* type = TypeOf(expr->idx_expr());
idx_id = GenerateLoadIfNeeded(type, idx_id);
- // If the source is a pointer, we access chain into it.
- if (info->source_type->Is<sem::Pointer>()) {
+ // If the source is a reference, we access chain into it.
+ // In the future, pointers may support access-chaining.
+ // See https://github.com/gpuweb/gpuweb/pull/1580
+ if (info->source_type->Is<sem::Reference>()) {
info->access_chain_indices.push_back(idx_id);
info->source_type = TypeOf(expr);
return true;
@@ -870,7 +873,7 @@
if (auto* access = expr_sem->As<sem::StructMemberAccess>()) {
uint32_t idx = access->Member()->Index();
- if (info->source_type->Is<sem::Pointer>()) {
+ if (info->source_type->Is<sem::Reference>()) {
auto idx_id = GenerateConstantIfNeeded(ScalarConstant::U32(idx));
if (idx_id == 0) {
return 0;
@@ -903,7 +906,7 @@
// Single element swizzle is either an access chain or a composite extract
auto& indices = swizzle->Indices();
if (indices.size() == 1) {
- if (info->source_type->Is<sem::Pointer>()) {
+ if (info->source_type->Is<sem::Reference>()) {
auto idx_id = GenerateConstantIfNeeded(ScalarConstant::U32(indices[0]));
if (idx_id == 0) {
return 0;
@@ -954,7 +957,7 @@
}
info->source_id = GenerateLoadIfNeeded(expr_type, extract_id);
- info->source_type = expr_type->UnwrapPtr();
+ info->source_type = expr_type->UnwrapRef();
info->access_chain_indices.clear();
}
@@ -1022,25 +1025,31 @@
// If our initial access is into a non-pointer array, and either has a
// non-scalar element type or the accessor uses a non-literal index, then we
// need to load that array into a variable in order to access chain into it.
- // TODO(jrprice): The non-scalar part shouldn't be necessary, but is tied to
- // how the Resolver currently determines the type of these expression. This
- // should be fixed when proper support for ptr/ref types is implemented.
- if (auto* array = accessors[0]->As<ast::ArrayAccessorExpression>()) {
- auto* ary_res_type = TypeOf(array->array())->As<sem::Array>();
- if (ary_res_type &&
- (!ary_res_type->ElemType()->is_scalar() ||
- !array->idx_expr()->Is<ast::ScalarConstructorExpression>())) {
- // Wrap the source type in a pointer to function storage.
- auto ptr =
- builder_.ty.pointer(ary_res_type, ast::StorageClass::kFunction);
- auto result_type_id = GenerateTypeIfNeeded(ptr);
+
+ // TODO(bclayton): The requirement for scalar element types is because of
+ // arrays-of-arrays - this logic only considers whether the root index is
+ // compile-time-constant, and not whether there are any dynamic, inner-array
+ // indexing being performed. Instead of trying to do complex hoisting in this
+ // writer, move this hoisting into the transform::Spirv sanitizer.
+
+ bool needs_load = false; // Was the expression hoist to a temporary variable?
+ if (auto* access = accessors[0]->As<ast::ArrayAccessorExpression>()) {
+ auto* array = TypeOf(access->array())->As<sem::Array>();
+ bool trivial_indexing =
+ array && array->ElemType()->is_scalar() &&
+ access->idx_expr()->Is<ast::ScalarConstructorExpression>();
+ if (array && !trivial_indexing) {
+ // Wrap the source type in a reference to function storage.
+ auto* ref =
+ builder_.create<sem::Reference>(array, ast::StorageClass::kFunction);
+ auto result_type_id = GenerateTypeIfNeeded(ref);
if (result_type_id == 0) {
return 0;
}
auto ary_result = result_op();
- auto init = GenerateConstantNullIfNeeded(ary_res_type);
+ auto init = GenerateConstantNullIfNeeded(array);
// If we're access chaining into an array then we must be in a function
push_function_var(
@@ -1054,7 +1063,8 @@
}
info.source_id = ary_result.to_i();
- info.source_type = ptr;
+ info.source_type = ref;
+ needs_load = true;
}
}
@@ -1076,17 +1086,12 @@
}
if (!info.access_chain_indices.empty()) {
- bool needs_load = false;
- auto* ptr = TypeOf(expr);
- if (!ptr->Is<sem::Pointer>()) {
- // We are performing an access chain but the final result is not a
- // pointer, so we need to perform a load to get it. This happens when we
- // have to copy the source expression into a function variable.
- ptr = builder_.ty.pointer(ptr, ast::StorageClass::kFunction);
- needs_load = true;
+ auto* type = TypeOf(expr);
+ if (needs_load) {
+ type =
+ builder_.create<sem::Reference>(type, ast::StorageClass::kFunction);
}
-
- auto result_type_id = GenerateTypeIfNeeded(ptr);
+ auto result_type_id = GenerateTypeIfNeeded(type);
if (result_type_id == 0) {
return 0;
}
@@ -1107,7 +1112,7 @@
// Load from the access chain result if required.
if (needs_load) {
- info.source_id = GenerateLoadIfNeeded(ptr, result_id);
+ info.source_id = GenerateLoadIfNeeded(type, result_id);
}
}
@@ -1127,16 +1132,18 @@
}
uint32_t Builder::GenerateLoadIfNeeded(const sem::Type* type, uint32_t id) {
- if (!type->Is<sem::Pointer>()) {
+ if (auto* ref = type->As<sem::Reference>()) {
+ type = ref->StoreType();
+ } else {
return id;
}
- auto type_id = GenerateTypeIfNeeded(type->UnwrapPtr());
+ auto type_id = GenerateTypeIfNeeded(type);
auto result = result_op();
auto result_id = result.to_i();
if (!push_function_inst(spv::Op::OpLoad,
{Operand::Int(type_id), result, Operand::Int(id)})) {
- return false;
+ return 0;
}
return result_id;
}
@@ -1149,6 +1156,27 @@
if (val_id == 0) {
return 0;
}
+
+ spv::Op op = spv::Op::OpNop;
+ switch (expr->op()) {
+ case ast::UnaryOp::kNegation:
+ if (TypeOf(expr)->is_float_scalar_or_vector()) {
+ op = spv::Op::OpFNegate;
+ } else {
+ op = spv::Op::OpSNegate;
+ }
+ break;
+ case ast::UnaryOp::kNot:
+ op = spv::Op::OpLogicalNot;
+ break;
+ case ast::UnaryOp::kAddressOf:
+ case ast::UnaryOp::kIndirection:
+ // Address-of converts a reference to a pointer, and dereference converts
+ // a pointer to a reference. These are the same thing in SPIR-V, so this
+ // is a no-op.
+ return val_id;
+ }
+
val_id = GenerateLoadIfNeeded(TypeOf(expr->expr()), val_id);
auto type_id = GenerateTypeIfNeeded(TypeOf(expr));
@@ -1156,21 +1184,6 @@
return 0;
}
- spv::Op op = spv::Op::OpNop;
- if (expr->op() == ast::UnaryOp::kNegation) {
- if (TypeOf(expr)->is_float_scalar_or_vector()) {
- op = spv::Op::OpFNegate;
- } else {
- op = spv::Op::OpSNegate;
- }
- } else if (expr->op() == ast::UnaryOp::kNot) {
- op = spv::Op::OpLogicalNot;
- }
- if (op == spv::Op::OpNop) {
- error_ = "invalid unary op type";
- return 0;
- }
-
if (!push_function_inst(
op, {Operand::Int(type_id), result, Operand::Int(val_id)})) {
return false;
@@ -1218,7 +1231,7 @@
}
auto* tc = constructor->As<ast::TypeConstructorExpression>();
- auto* result_type = TypeOf(tc)->UnwrapAll();
+ auto* result_type = TypeOf(tc)->UnwrapRef();
for (size_t i = 0; i < tc->values().size(); ++i) {
auto* e = tc->values()[i];
@@ -1246,17 +1259,17 @@
continue;
}
- const sem::Type* subtype = result_type->UnwrapAll();
+ const sem::Type* subtype = result_type->UnwrapRef();
if (auto* vec = subtype->As<sem::Vector>()) {
- subtype = vec->type()->UnwrapAll();
+ subtype = vec->type();
} else if (auto* mat = subtype->As<sem::Matrix>()) {
- subtype = mat->type()->UnwrapAll();
+ subtype = mat->type();
} else if (auto* arr = subtype->As<sem::Array>()) {
- subtype = arr->ElemType()->UnwrapAll();
+ subtype = arr->ElemType();
} else if (auto* str = subtype->As<sem::Struct>()) {
- subtype = str->Members()[i]->Type()->UnwrapAll();
+ subtype = str->Members()[i]->Type();
}
- if (subtype != TypeOf(sc)->UnwrapAll()) {
+ if (subtype != TypeOf(sc)->UnwrapRef()) {
return false;
}
}
@@ -1272,13 +1285,13 @@
// Generate the zero initializer if there are no values provided.
if (values.empty()) {
- return GenerateConstantNullIfNeeded(result_type->UnwrapPtr());
+ return GenerateConstantNullIfNeeded(result_type->UnwrapRef());
}
std::ostringstream out;
out << "__const_" << init->type()->FriendlyName(builder_.Symbols()) << "_";
- result_type = result_type->UnwrapAll();
+ result_type = result_type->UnwrapRef();
bool constructor_is_const = is_constructor_const(init, is_global_init);
if (has_error()) {
return 0;
@@ -1288,7 +1301,7 @@
if (auto* res_vec = result_type->As<sem::Vector>()) {
if (res_vec->type()->is_scalar()) {
- auto* value_type = TypeOf(values[0])->UnwrapAll();
+ auto* value_type = TypeOf(values[0])->UnwrapRef();
if (auto* val_vec = value_type->As<sem::Vector>()) {
if (val_vec->type()->is_scalar()) {
can_cast_or_copy = res_vec->size() == val_vec->size();
@@ -1327,7 +1340,7 @@
return 0;
}
- auto* value_type = TypeOf(e)->UnwrapPtr();
+ auto* value_type = TypeOf(e)->UnwrapRef();
// If the result and value types are the same we can just use the object.
// If the result is not a vector then we should have validated that the
// value type is a correctly sized vector so we can just use it directly.
@@ -1444,7 +1457,7 @@
}
val_id = GenerateLoadIfNeeded(TypeOf(from_expr), val_id);
- auto* from_type = TypeOf(from_expr)->UnwrapPtr();
+ auto* from_type = TypeOf(from_expr)->UnwrapRef();
spv::Op op = spv::Op::OpNop;
if ((from_type->Is<sem::I32>() && to_type->Is<sem::F32>()) ||
@@ -1728,8 +1741,8 @@
// Handle int and float and the vectors of those types. Other types
// should have been rejected by validation.
- auto* lhs_type = TypeOf(expr->lhs())->UnwrapAll();
- auto* rhs_type = TypeOf(expr->rhs())->UnwrapAll();
+ auto* lhs_type = TypeOf(expr->lhs())->UnwrapRef();
+ auto* rhs_type = TypeOf(expr->rhs())->UnwrapRef();
bool lhs_is_float_or_vec = lhs_type->is_float_scalar_or_vector();
bool lhs_is_unsigned = lhs_type->is_unsigned_scalar_or_vector();
@@ -1904,13 +1917,18 @@
}
ops.push_back(Operand::Int(func_id));
- for (auto* param : expr->params()) {
- auto id = GenerateExpression(param);
+ size_t arg_idx = 0;
+ for (auto* arg : expr->params()) {
+ auto id = GenerateExpression(arg);
if (id == 0) {
return 0;
}
- id = GenerateLoadIfNeeded(TypeOf(param), id);
+ id = GenerateLoadIfNeeded(TypeOf(arg), id);
+ if (id == 0) {
+ return 0;
+ }
ops.push_back(Operand::Int(id));
+ arg_idx++;
}
if (!push_function_inst(spv::Op::OpFunctionCall, std::move(ops))) {
@@ -1982,7 +2000,7 @@
}
params.push_back(Operand::Int(struct_id));
- auto* type = TypeOf(accessor->structure())->UnwrapAll();
+ auto* type = TypeOf(accessor->structure())->UnwrapRef();
if (!type->Is<sem::Struct>()) {
error_ =
"invalid type (" + type->type_name() + ") for runtime array length";
@@ -2134,7 +2152,7 @@
TINT_ICE(builder_.Diagnostics()) << "missing texture argument";
}
- auto* texture_type = TypeOf(texture)->UnwrapAll()->As<sem::Texture>();
+ auto* texture_type = TypeOf(texture)->UnwrapRef()->As<sem::Texture>();
auto op = spv::Op::OpNop;
@@ -2580,8 +2598,8 @@
val_id = GenerateLoadIfNeeded(TypeOf(expr->expr()), val_id);
// Bitcast does not allow same types, just emit a CopyObject
- auto* to_type = TypeOf(expr)->UnwrapPtr();
- auto* from_type = TypeOf(expr->expr())->UnwrapPtr();
+ auto* to_type = TypeOf(expr)->UnwrapRef();
+ auto* from_type = TypeOf(expr->expr())->UnwrapRef();
if (to_type->type_name() == from_type->type_name()) {
if (!push_function_inst(
spv::Op::OpCopyObject,
@@ -2932,84 +2950,97 @@
return 0;
}
- auto val = type_name_to_id_.find(type->type_name());
- if (val != type_name_to_id_.end()) {
- return val->second;
- }
-
- auto result = result_op();
- auto id = result.to_i();
- if (auto* arr = type->As<sem::Array>()) {
- if (!GenerateArrayType(arr, result)) {
- return 0;
- }
- } else if (type->Is<sem::Bool>()) {
- push_type(spv::Op::OpTypeBool, {result});
- } else if (type->Is<sem::F32>()) {
- push_type(spv::Op::OpTypeFloat, {result, Operand::Int(32)});
- } else if (type->Is<sem::I32>()) {
- push_type(spv::Op::OpTypeInt, {result, Operand::Int(32), Operand::Int(1)});
- } else if (auto* mat = type->As<sem::Matrix>()) {
- if (!GenerateMatrixType(mat, result)) {
- return 0;
- }
- } else if (auto* ptr = type->As<sem::Pointer>()) {
- if (!GeneratePointerType(ptr, result)) {
- return 0;
- }
- } else if (auto* str = type->As<sem::Struct>()) {
- if (!GenerateStructType(str, result)) {
- return 0;
- }
- } else if (type->Is<sem::U32>()) {
- push_type(spv::Op::OpTypeInt, {result, Operand::Int(32), Operand::Int(0)});
- } else if (auto* vec = type->As<sem::Vector>()) {
- if (!GenerateVectorType(vec, result)) {
- return 0;
- }
- } else if (type->Is<sem::Void>()) {
- push_type(spv::Op::OpTypeVoid, {result});
- } else if (auto* tex = type->As<sem::Texture>()) {
- if (!GenerateTextureType(tex, result)) {
- return 0;
- }
-
- if (auto* st = tex->As<sem::StorageTexture>()) {
- // Register all three access types of StorageTexture names. In SPIR-V, we
- // must output a single type, while the variable is annotated with the
- // access type. Doing this ensures we de-dupe.
- type_name_to_id_[builder_
- .create<sem::StorageTexture>(
- st->dim(), st->image_format(),
- ast::AccessControl::kReadOnly, st->type())
- ->type_name()] = id;
- type_name_to_id_[builder_
- .create<sem::StorageTexture>(
- st->dim(), st->image_format(),
- ast::AccessControl::kWriteOnly, st->type())
- ->type_name()] = id;
- type_name_to_id_[builder_
- .create<sem::StorageTexture>(
- st->dim(), st->image_format(),
- ast::AccessControl::kReadWrite, st->type())
- ->type_name()] = id;
- }
-
- } else if (type->Is<sem::Sampler>()) {
- push_type(spv::Op::OpTypeSampler, {result});
-
- // Register both of the sampler type names. In SPIR-V they're the same
- // sampler type, so we need to match that when we do the dedup check.
- type_name_to_id_["__sampler_sampler"] = id;
- type_name_to_id_["__sampler_comparison"] = id;
-
+ // Pointers and References both map to a SPIR-V pointer type.
+ // Transform a Reference to a Pointer to prevent these having duplicated
+ // definitions in the generated SPIR-V. Note that nested references are not
+ // legal, so only considering the top-level type is fine.
+ std::string type_name;
+ if (auto* ref = type->As<sem::Reference>()) {
+ type_name = sem::Pointer(ref->StoreType(), ref->StorageClass()).type_name();
} else {
- error_ = "unable to convert type: " + type->type_name();
- return 0;
+ type_name = type->type_name();
}
- type_name_to_id_[type->type_name()] = id;
- return id;
+ return utils::GetOrCreate(type_name_to_id_, type_name, [&]() -> uint32_t {
+ auto result = result_op();
+ auto id = result.to_i();
+ if (auto* arr = type->As<sem::Array>()) {
+ if (!GenerateArrayType(arr, result)) {
+ return 0;
+ }
+ } else if (type->Is<sem::Bool>()) {
+ push_type(spv::Op::OpTypeBool, {result});
+ } else if (type->Is<sem::F32>()) {
+ push_type(spv::Op::OpTypeFloat, {result, Operand::Int(32)});
+ } else if (type->Is<sem::I32>()) {
+ push_type(spv::Op::OpTypeInt,
+ {result, Operand::Int(32), Operand::Int(1)});
+ } else if (auto* mat = type->As<sem::Matrix>()) {
+ if (!GenerateMatrixType(mat, result)) {
+ return 0;
+ }
+ } else if (auto* ptr = type->As<sem::Pointer>()) {
+ if (!GeneratePointerType(ptr, result)) {
+ return 0;
+ }
+ } else if (auto* ref = type->As<sem::Reference>()) {
+ if (!GenerateReferenceType(ref, result)) {
+ return 0;
+ }
+ } else if (auto* str = type->As<sem::Struct>()) {
+ if (!GenerateStructType(str, result)) {
+ return 0;
+ }
+ } else if (type->Is<sem::U32>()) {
+ push_type(spv::Op::OpTypeInt,
+ {result, Operand::Int(32), Operand::Int(0)});
+ } else if (auto* vec = type->As<sem::Vector>()) {
+ if (!GenerateVectorType(vec, result)) {
+ return 0;
+ }
+ } else if (type->Is<sem::Void>()) {
+ push_type(spv::Op::OpTypeVoid, {result});
+ } else if (auto* tex = type->As<sem::Texture>()) {
+ if (!GenerateTextureType(tex, result)) {
+ return 0;
+ }
+
+ if (auto* st = tex->As<sem::StorageTexture>()) {
+ // Register all three access types of StorageTexture names. In SPIR-V,
+ // we must output a single type, while the variable is annotated with
+ // the access type. Doing this ensures we de-dupe.
+ type_name_to_id_[builder_
+ .create<sem::StorageTexture>(
+ st->dim(), st->image_format(),
+ ast::AccessControl::kReadOnly, st->type())
+ ->type_name()] = id;
+ type_name_to_id_[builder_
+ .create<sem::StorageTexture>(
+ st->dim(), st->image_format(),
+ ast::AccessControl::kWriteOnly, st->type())
+ ->type_name()] = id;
+ type_name_to_id_[builder_
+ .create<sem::StorageTexture>(
+ st->dim(), st->image_format(),
+ ast::AccessControl::kReadWrite, st->type())
+ ->type_name()] = id;
+ }
+
+ } else if (type->Is<sem::Sampler>()) {
+ push_type(spv::Op::OpTypeSampler, {result});
+
+ // Register both of the sampler type names. In SPIR-V they're the same
+ // sampler type, so we need to match that when we do the dedup check.
+ type_name_to_id_["__sampler_sampler"] = id;
+ type_name_to_id_["__sampler_comparison"] = id;
+
+ } else {
+ error_ = "unable to convert type: " + type->type_name();
+ return 0;
+ }
+
+ return id;
+ });
}
// TODO(tommek): Cover multisampled textures here when they're included in AST
@@ -3131,8 +3162,8 @@
bool Builder::GeneratePointerType(const sem::Pointer* ptr,
const Operand& result) {
- auto pointee_id = GenerateTypeIfNeeded(ptr->StoreType());
- if (pointee_id == 0) {
+ auto subtype_id = GenerateTypeIfNeeded(ptr->StoreType());
+ if (subtype_id == 0) {
return false;
}
@@ -3143,7 +3174,26 @@
}
push_type(spv::Op::OpTypePointer,
- {result, Operand::Int(stg_class), Operand::Int(pointee_id)});
+ {result, Operand::Int(stg_class), Operand::Int(subtype_id)});
+
+ return true;
+}
+
+bool Builder::GenerateReferenceType(const sem::Reference* ref,
+ const Operand& result) {
+ auto subtype_id = GenerateTypeIfNeeded(ref->StoreType());
+ if (subtype_id == 0) {
+ return false;
+ }
+
+ auto stg_class = ConvertStorageClass(ref->StorageClass());
+ if (stg_class == SpvStorageClassMax) {
+ error_ = "invalid storage class for reference";
+ return false;
+ }
+
+ push_type(spv::Op::OpTypePointer,
+ {result, Operand::Int(stg_class), Operand::Int(subtype_id)});
return true;
}
diff --git a/src/writer/spirv/builder.h b/src/writer/spirv/builder.h
index 53c917b..98675ff 100644
--- a/src/writer/spirv/builder.h
+++ b/src/writer/spirv/builder.h
@@ -43,6 +43,7 @@
// Forward declarations
namespace sem {
class Call;
+class Reference;
} // namespace sem
namespace writer {
@@ -66,7 +67,7 @@
/// result_type of the current source defined above.
const sem::Type* source_type;
/// A list of access chain indices to emit. Note, we _only_ have access
- /// chain indices if the source is pointer.
+ /// chain indices if the source is reference.
std::vector<uint32_t> access_chain_indices;
};
@@ -411,7 +412,7 @@
/// Geneates an OpLoad
/// @param type the type to load
/// @param id the variable id to load
- /// @returns the ID of the loaded value or `id` if type is not a pointer
+ /// @returns the ID of the loaded value or `id` if type is not a reference
uint32_t GenerateLoadIfNeeded(const sem::Type* type, uint32_t id);
/// Generates an OpStore. Emits an error and returns false if we're
/// currently outside a function.
@@ -443,6 +444,11 @@
/// @param result the result operand
/// @returns true if the pointer was successfully generated
bool GeneratePointerType(const sem::Pointer* ptr, const Operand& result);
+ /// Generates a reference type declaration
+ /// @param ref the reference type to generate
+ /// @param result the result operand
+ /// @returns true if the reference was successfully generated
+ bool GenerateReferenceType(const sem::Reference* ref, const Operand& result);
/// Generates a vector type declaration
/// @param struct_type the vector to generate
/// @param result the result operand
diff --git a/src/writer/spirv/builder_accessor_expression_test.cc b/src/writer/spirv/builder_accessor_expression_test.cc
index 6962231..6e36a06 100644
--- a/src/writer/spirv/builder_accessor_expression_test.cc
+++ b/src/writer/spirv/builder_accessor_expression_test.cc
@@ -766,7 +766,7 @@
b.push_function(Function{});
ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
- EXPECT_EQ(b.GenerateAccessorExpression(expr), 18u) << b.error();
+ EXPECT_EQ(b.GenerateAccessorExpression(expr), 19u) << b.error();
EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
%2 = OpTypeVector %3 2
@@ -791,6 +791,57 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
R"(OpStore %14 %12
%18 = OpAccessChain %17 %14 %16
+%19 = OpLoad %2 %18
+)");
+}
+
+TEST_F(BuilderTest, Accessor_Array_Of_Array_Of_f32) {
+ // let pos : array<array<f32, 2>, 3> = array<vec2<f32, 2>, 3>(
+ // array<f32, 2>(0.0, 0.5),
+ // array<f32, 2>(-0.5, -0.5),
+ // array<f32, 2>(0.5, -0.5));
+ // pos[2][1]
+
+ auto* var =
+ Const("pos", ty.array(ty.vec2<f32>(), 3),
+ Construct(ty.array(ty.vec2<f32>(), 3), vec2<f32>(0.0f, 0.5f),
+ vec2<f32>(-0.5f, -0.5f), vec2<f32>(0.5f, -0.5f)));
+
+ auto* expr = IndexAccessor(IndexAccessor("pos", 2u), 1u);
+ WrapInFunction(var, expr);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+ EXPECT_EQ(b.GenerateAccessorExpression(expr), 21u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+%2 = OpTypeVector %3 2
+%4 = OpTypeInt 32 0
+%5 = OpConstant %4 3
+%1 = OpTypeArray %2 %5
+%6 = OpConstant %3 0
+%7 = OpConstant %3 0.5
+%8 = OpConstantComposite %2 %6 %7
+%9 = OpConstant %3 -0.5
+%10 = OpConstantComposite %2 %9 %9
+%11 = OpConstantComposite %2 %7 %9
+%12 = OpConstantComposite %1 %8 %10 %11
+%13 = OpTypePointer Function %1
+%15 = OpConstantNull %1
+%16 = OpConstant %4 2
+%17 = OpConstant %4 1
+%19 = OpTypePointer Function %3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+ R"(%14 = OpVariable %13 Function %15
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %14 %12
+%18 = OpCompositeExtract %3 %14 1
+%20 = OpAccessChain %19 %18 %16
+%21 = OpLoad %3 %20
)");
}
diff --git a/src/writer/spirv/builder_ident_expression_test.cc b/src/writer/spirv/builder_ident_expression_test.cc
index 821f9e5..c57b44a 100644
--- a/src/writer/spirv/builder_ident_expression_test.cc
+++ b/src/writer/spirv/builder_ident_expression_test.cc
@@ -90,7 +90,7 @@
}
TEST_F(BuilderTest, IdentifierExpression_FunctionVar) {
- auto* v = Var("var", ty.f32(), ast::StorageClass::kNone);
+ auto* v = Var("var", ty.f32(), ast::StorageClass::kFunction);
auto* expr = Expr("var");
WrapInFunction(v, expr);
diff --git a/src/writer/spirv/builder_intrinsic_test.cc b/src/writer/spirv/builder_intrinsic_test.cc
index bca5f4a..d6d8156 100644
--- a/src/writer/spirv/builder_intrinsic_test.cc
+++ b/src/writer/spirv/builder_intrinsic_test.cc
@@ -1262,7 +1262,7 @@
TEST_F(IntrinsicBuilderTest, Call_Modf) {
auto* out = Var("out", ty.vec2<f32>());
- auto* expr = Call("modf", vec2<f32>(1.0f, 2.0f), "out");
+ auto* expr = Call("modf", vec2<f32>(1.0f, 2.0f), AddressOf("out"));
Func("a_func", ast::VariableList{}, ty.void_(),
ast::StatementList{
Decl(out),
@@ -1306,7 +1306,7 @@
TEST_F(IntrinsicBuilderTest, Call_Frexp) {
auto* out = Var("out", ty.vec2<i32>());
- auto* expr = Call("frexp", vec2<f32>(1.0f, 2.0f), "out");
+ auto* expr = Call("frexp", vec2<f32>(1.0f, 2.0f), AddressOf("out"));
Func("a_func", ast::VariableList{}, ty.void_(),
ast::StatementList{
Decl(out),
diff --git a/test/BUILD.gn b/test/BUILD.gn
index 88b158a..867e8d7 100644
--- a/test/BUILD.gn
+++ b/test/BUILD.gn
@@ -257,6 +257,8 @@
"../src/resolver/intrinsic_test.cc",
"../src/resolver/is_host_shareable_test.cc",
"../src/resolver/is_storeable_test.cc",
+ "../src/resolver/ptr_ref_test.cc",
+ "../src/resolver/ptr_ref_validation_test.cc",
"../src/resolver/pipeline_overridable_constant_test.cc",
"../src/resolver/resolver_test.cc",
"../src/resolver/resolver_test_helper.cc",
@@ -268,6 +270,8 @@
"../src/resolver/type_constructor_validation_test.cc",
"../src/resolver/type_validation_test.cc",
"../src/resolver/validation_test.cc",
+ "../src/resolver/var_let_test.cc",
+ "../src/resolver/var_let_validation_test.cc",
"../src/scope_stack_test.cc",
"../src/sem/bool_type_test.cc",
"../src/sem/depth_texture_type_test.cc",
diff --git a/test/access/let/matrix.spvasm.expected.msl b/test/access/let/matrix.spvasm.expected.msl
index 0915f03..2f5de98 100644
--- a/test/access/let/matrix.spvasm.expected.msl
+++ b/test/access/let/matrix.spvasm.expected.msl
@@ -2,7 +2,7 @@
using namespace metal;
kernel void tint_symbol() {
- const float x_24 = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f))[1u].y;
+ float const x_24 = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f))[1u].y;
return;
}
diff --git a/test/access/let/matrix.wgsl.expected.msl b/test/access/let/matrix.wgsl.expected.msl
index 43c391a..f8f945d 100644
--- a/test/access/let/matrix.wgsl.expected.msl
+++ b/test/access/let/matrix.wgsl.expected.msl
@@ -2,9 +2,9 @@
using namespace metal;
kernel void tint_symbol() {
- const float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
- const float3 v = m[1];
- const float f = v[1];
+ float3x3 const m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
+ float3 const v = m[1];
+ float const f = v[1];
return;
}
diff --git a/test/access/let/vector.spvasm b/test/access/let/vector.spvasm
index 9de59d2..6e52ba9 100644
--- a/test/access/let/vector.spvasm
+++ b/test/access/let/vector.spvasm
@@ -3,24 +3,24 @@
; Generator: Google Tint Compiler; 0
; Bound: 15
; Schema: 0
- OpCapability Shader
- OpMemoryModel Logical GLSL450
- OpEntryPoint GLCompute %main "main"
- OpExecutionMode %main LocalSize 1 1 1
- OpName %main "main"
- %void = OpTypeVoid
- %1 = OpTypeFunction %void
- %float = OpTypeFloat 32
- %v3float = OpTypeVector %float 3
- %float_1 = OpConstant %float 1
- %float_2 = OpConstant %float 2
- %float_3 = OpConstant %float 3
- %10 = OpConstantComposite %v3float %float_1 %float_2 %float_3
- %v2float = OpTypeVector %float 2
- %main = OpFunction %void None %1
- %4 = OpLabel
- %11 = OpCompositeExtract %float %10 1
- %13 = OpVectorShuffle %v2float %10 %10 0 2
- %14 = OpVectorShuffle %v3float %10 %10 0 2 1
- OpReturn
- OpFunctionEnd
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+%v3float = OpTypeVector %float 3
+%float_1 = OpConstant %float 1
+%float_2 = OpConstant %float 2
+%float_3 = OpConstant %float 3
+ %10 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+%v2float = OpTypeVector %float 2
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %11 = OpCompositeExtract %float %10 1
+ %13 = OpVectorShuffle %v2float %10 %10 0 2
+ %14 = OpVectorShuffle %v3float %10 %10 0 2 1
+ OpReturn
+ OpFunctionEnd
diff --git a/test/access/let/vector.spvasm.expected.msl b/test/access/let/vector.spvasm.expected.msl
index aa214b4..60e701c 100644
--- a/test/access/let/vector.spvasm.expected.msl
+++ b/test/access/let/vector.spvasm.expected.msl
@@ -2,9 +2,9 @@
using namespace metal;
kernel void tint_symbol() {
- const float x_11 = float3(1.0f, 2.0f, 3.0f).y;
- const float2 x_13 = float2(float3(1.0f, 2.0f, 3.0f).x, float3(1.0f, 2.0f, 3.0f).z);
- const float3 x_14 = float3(float3(1.0f, 2.0f, 3.0f).x, float3(1.0f, 2.0f, 3.0f).z, float3(1.0f, 2.0f, 3.0f).y);
+ float const x_11 = float3(1.0f, 2.0f, 3.0f).y;
+ float2 const x_13 = float2(float3(1.0f, 2.0f, 3.0f).x, float3(1.0f, 2.0f, 3.0f).z);
+ float3 const x_14 = float3(float3(1.0f, 2.0f, 3.0f).x, float3(1.0f, 2.0f, 3.0f).z, float3(1.0f, 2.0f, 3.0f).y);
return;
}
diff --git a/test/access/let/vector.wgsl.expected.msl b/test/access/let/vector.wgsl.expected.msl
index d2f878e..e690077 100644
--- a/test/access/let/vector.wgsl.expected.msl
+++ b/test/access/let/vector.wgsl.expected.msl
@@ -2,10 +2,10 @@
using namespace metal;
kernel void tint_symbol() {
- const float3 v = float3(1.0f, 2.0f, 3.0f);
- const float scalar = v.y;
- const float2 swizzle2 = v.xz;
- const float3 swizzle3 = v.xzy;
+ float3 const v = float3(1.0f, 2.0f, 3.0f);
+ float const scalar = v.y;
+ float2 const swizzle2 = v.xz;
+ float3 const swizzle3 = v.xzy;
return;
}
diff --git a/test/access/var/matrix.spvasm.expected.msl b/test/access/var/matrix.spvasm.expected.msl
index 01c32f9..12a0b73 100644
--- a/test/access/var/matrix.spvasm.expected.msl
+++ b/test/access/var/matrix.spvasm.expected.msl
@@ -3,8 +3,8 @@
using namespace metal;
kernel void tint_symbol() {
float3x3 m = float3x3(float3(0.0f, 0.0f, 0.0f), float3(0.0f, 0.0f, 0.0f), float3(0.0f, 0.0f, 0.0f));
- const float3 x_15 = m[1];
- const float x_16 = x_15.y;
+ float3 const x_15 = m[1];
+ float const x_16 = x_15.y;
return;
}
diff --git a/test/access/var/matrix.wgsl.expected.msl b/test/access/var/matrix.wgsl.expected.msl
index ef02f47..c577ac1 100644
--- a/test/access/var/matrix.wgsl.expected.msl
+++ b/test/access/var/matrix.wgsl.expected.msl
@@ -3,8 +3,8 @@
using namespace metal;
kernel void tint_symbol() {
float3x3 m = 0.0f;
- const float3 v = m[1];
- const float f = v[1];
+ float3 const v = m[1];
+ float const f = v[1];
return;
}
diff --git a/test/access/var/vector.spvasm b/test/access/var/vector.spvasm
index 11a010c..ef66598 100644
--- a/test/access/var/vector.spvasm
+++ b/test/access/var/vector.spvasm
@@ -3,30 +3,30 @@
; Generator: Google Tint Compiler; 0
; Bound: 20
; Schema: 0
- OpCapability Shader
- OpMemoryModel Logical GLSL450
- OpEntryPoint GLCompute %main "main"
- OpExecutionMode %main LocalSize 1 1 1
- OpName %main "main"
- OpName %v "v"
- %void = OpTypeVoid
- %1 = OpTypeFunction %void
- %float = OpTypeFloat 32
- %v3float = OpTypeVector %float 3
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %v "v"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
%_ptr_Function_v3float = OpTypePointer Function %v3float
- %9 = OpConstantNull %v3float
- %uint = OpTypeInt 32 0
- %uint_1 = OpConstant %uint 1
-%_ptr_Function_float = OpTypePointer Function %float
- %v2float = OpTypeVector %float 2
- %main = OpFunction %void None %1
- %4 = OpLabel
- %v = OpVariable %_ptr_Function_v3float Function %9
- %13 = OpAccessChain %_ptr_Function_float %v %uint_1
- %14 = OpLoad %float %13
- %16 = OpLoad %v3float %v
- %17 = OpVectorShuffle %v2float %16 %16 0 2
- %18 = OpLoad %v3float %v
- %19 = OpVectorShuffle %v3float %18 %18 0 2 1
- OpReturn
- OpFunctionEnd
+ %9 = OpConstantNull %v3float
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 1
+ %_ptr_Function_float = OpTypePointer Function %float
+ %v2float = OpTypeVector %float 2
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %v = OpVariable %_ptr_Function_v3float Function %9
+ %13 = OpAccessChain %_ptr_Function_float %v %uint_1
+ %14 = OpLoad %float %13
+ %16 = OpLoad %v3float %v
+ %17 = OpVectorShuffle %v2float %16 %16 0 2
+ %18 = OpLoad %v3float %v
+ %19 = OpVectorShuffle %v3float %18 %18 0 2 1
+ OpReturn
+ OpFunctionEnd
diff --git a/test/access/var/vector.spvasm.expected.msl b/test/access/var/vector.spvasm.expected.msl
index 3011d7e..fb9d008 100644
--- a/test/access/var/vector.spvasm.expected.msl
+++ b/test/access/var/vector.spvasm.expected.msl
@@ -3,11 +3,11 @@
using namespace metal;
kernel void tint_symbol() {
float3 v = float3(0.0f, 0.0f, 0.0f);
- const float x_14 = v.y;
- const float3 x_16 = v;
- const float2 x_17 = float2(x_16.x, x_16.z);
- const float3 x_18 = v;
- const float3 x_19 = float3(x_18.x, x_18.z, x_18.y);
+ float const x_14 = v.y;
+ float3 const x_16 = v;
+ float2 const x_17 = float2(x_16.x, x_16.z);
+ float3 const x_18 = v;
+ float3 const x_19 = float3(x_18.x, x_18.z, x_18.y);
return;
}
diff --git a/test/access/var/vector.wgsl.expected.msl b/test/access/var/vector.wgsl.expected.msl
index 62c927e..542eae7 100644
--- a/test/access/var/vector.wgsl.expected.msl
+++ b/test/access/var/vector.wgsl.expected.msl
@@ -3,9 +3,9 @@
using namespace metal;
kernel void tint_symbol() {
float3 v = 0.0f;
- const float scalar = v.y;
- const float2 swizzle2 = v.xz;
- const float3 swizzle3 = v.xzy;
+ float const scalar = v.y;
+ float2 const swizzle2 = v.xz;
+ float3 const swizzle3 = v.xzy;
return;
}
diff --git a/test/bug/tint/749.spvasm.expected.spvasm b/test/bug/tint/749.spvasm.expected.spvasm
index d7f3593..ae34237 100644
--- a/test/bug/tint/749.spvasm.expected.spvasm
+++ b/test/bug/tint/749.spvasm.expected.spvasm
@@ -1,5 +1,2129 @@
-SKIP:
-
-Validation Failure:
- 1:1: OpLoad Pointer <id> '51[%51]' is not a logical pointer.
- %52 = OpLoad %int %51
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 1887
+; Schema: 0
+ OpCapability Shader
+ %1759 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %gl_FragCoord %x_GLF_color
+ OpExecutionMode %main OriginUpperLeft
+ OpName %QuicksortObject "QuicksortObject"
+ OpMemberName %QuicksortObject 0 "numbers"
+ OpName %obj "obj"
+ OpName %gl_FragCoord "gl_FragCoord"
+ OpName %buf0 "buf0"
+ OpMemberName %buf0 0 "resolution"
+ OpName %x_188 "x_188"
+ OpName %x_GLF_color "x_GLF_color"
+ OpName %swap_i1_i1_ "swap_i1_i1_"
+ OpName %i "i"
+ OpName %j "j"
+ OpName %temp "temp"
+ OpName %performPartition_i1_i1_ "performPartition_i1_i1_"
+ OpName %l "l"
+ OpName %h "h"
+ OpName %param_3 "param_3"
+ OpName %i_1 "i_1"
+ OpName %j_1 "j_1"
+ OpName %param_2 "param_2"
+ OpName %param_1 "param_1"
+ OpName %param "param"
+ OpName %pivot "pivot"
+ OpName %x_537 "x_537"
+ OpName %x_538 "x_538"
+ OpName %quicksort_ "quicksort_"
+ OpName %param_4 "param_4"
+ OpName %h_1 "h_1"
+ OpName %p "p"
+ OpName %l_1 "l_1"
+ OpName %top "top"
+ OpName %stack "stack"
+ OpName %param_5 "param_5"
+ OpName %main "main"
+ OpName %color "color"
+ OpName %i_2 "i_2"
+ OpName %uv "uv"
+ OpMemberDecorate %QuicksortObject 0 Offset 0
+ OpDecorate %_arr_int_uint_10 ArrayStride 4
+ OpDecorate %gl_FragCoord BuiltIn FragCoord
+ OpDecorate %buf0 Block
+ OpMemberDecorate %buf0 0 Offset 0
+ OpDecorate %x_188 DescriptorSet 0
+ OpDecorate %x_188 Binding 0
+ OpDecorate %x_GLF_color Location 0
+ %int = OpTypeInt 32 1
+ %uint = OpTypeInt 32 0
+ %uint_10 = OpConstant %uint 10
+%_arr_int_uint_10 = OpTypeArray %int %uint_10
+%QuicksortObject = OpTypeStruct %_arr_int_uint_10
+%_ptr_Private_QuicksortObject = OpTypePointer Private %QuicksortObject
+ %8 = OpConstantNull %QuicksortObject
+ %obj = OpVariable %_ptr_Private_QuicksortObject Private %8
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+ %v2float = OpTypeVector %float 2
+ %buf0 = OpTypeStruct %v2float
+%_ptr_Uniform_buf0 = OpTypePointer Uniform %buf0
+ %x_188 = OpVariable %_ptr_Uniform_buf0 Uniform
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+ %19 = OpConstantNull %v4float
+%x_GLF_color = OpVariable %_ptr_Output_v4float Output %19
+ %void = OpTypeVoid
+%_ptr_Function_int = OpTypePointer Function %int
+ %20 = OpTypeFunction %void %_ptr_Function_int %_ptr_Function_int
+ %28 = OpConstantNull %int
+ %int_0 = OpConstant %int 0
+ %v3float = OpTypeVector %float 3
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %35 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+ %uint_0 = OpConstant %uint 0
+%_ptr_Private_int = OpTypePointer Private %int
+ %103 = OpConstantComposite %_arr_int_uint_10 %int_0 %int_0 %int_0 %int_0 %int_0 %int_0 %int_0 %int_0 %int_0 %int_0
+ %104 = OpConstantComposite %QuicksortObject %103
+ %157 = OpTypeFunction %int %_ptr_Function_int %_ptr_Function_int
+%_ptr_Function_v2float = OpTypePointer Function %v2float
+ %171 = OpConstantNull %v2float
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+ %174 = OpConstantNull %v3float
+ %uint_1 = OpConstant %uint 1
+ %int_10 = OpConstant %int 10
+%_ptr_Function_float = OpTypePointer Function %float
+ %bool = OpTypeBool
+ %int_1 = OpConstant %int 1
+ %426 = OpTypeFunction %void
+%_ptr_Function__arr_int_uint_10 = OpTypePointer Function %_arr_int_uint_10
+ %436 = OpConstantNull %_arr_int_uint_10
+ %int_9 = OpConstant %int 9
+ %int_n1 = OpConstant %int -1
+ %float_0 = OpConstant %float 0
+ %897 = OpConstantComposite %v2float %float_0 %float_0
+ %true = OpConstantTrue %bool
+ %909 = OpConstantComposite %v3float %float_0 %float_0 %float_0
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+ %float_0_25 = OpConstant %float 0.25
+ %float_0_5 = OpConstant %float 0.5
+ %uint_2 = OpConstant %uint 2
+ %float_0_75 = OpConstant %float 0.75
+ %int_3 = OpConstant %int 3
+ %int_4 = OpConstant %int 4
+ %uint_5 = OpConstant %uint 5
+ %uint_6 = OpConstant %uint 6
+ %int_7 = OpConstant %int 7
+ %int_8 = OpConstant %int 8
+ %uint_9 = OpConstant %uint 9
+%swap_i1_i1_ = OpFunction %void None %20
+ %i = OpFunctionParameter %_ptr_Function_int
+ %j = OpFunctionParameter %_ptr_Function_int
+ %26 = OpLabel
+ %temp = OpVariable %_ptr_Function_int Function %28
+ %29 = OpLoad %int %temp
+ OpStore %temp %int_0
+ OpStore %temp %29
+ %36 = OpCompositeExtract %float %35 2
+ %37 = OpCompositeExtract %float %35 1
+ %38 = OpCompositeExtract %float %35 2
+ %39 = OpCompositeConstruct %v3float %36 %37 %38
+ %41 = OpLoad %int %i
+ OpStore %i %int_0
+ OpStore %i %41
+ %45 = OpLoad %int %i
+ %47 = OpLoad %int %j
+ OpStore %j %int_0
+ OpStore %j %47
+ %50 = OpCompositeExtract %float %39 1
+ %51 = OpCompositeExtract %float %39 0
+ %52 = OpCompositeExtract %float %39 1
+ %53 = OpCompositeConstruct %v3float %50 %51 %52
+ %54 = OpLoad %int %temp
+ OpStore %temp %int_0
+ OpStore %temp %54
+ %58 = OpAccessChain %_ptr_Private_int %obj %uint_0 %45
+ %60 = OpLoad %int %58
+ OpStore %58 %int_0
+ OpStore %58 %60
+ %64 = OpLoad %int %58
+ %65 = OpLoad %int %temp
+ OpStore %temp %int_0
+ OpStore %temp %65
+ OpStore %temp %64
+ %67 = OpLoad %int %j
+ OpStore %j %int_0
+ OpStore %j %67
+ %70 = OpCompositeExtract %float %39 2
+ %71 = OpCompositeExtract %float %35 0
+ %72 = OpCompositeExtract %float %39 1
+ %73 = OpCompositeConstruct %v3float %70 %71 %72
+ %75 = OpLoad %int %i
+ OpStore %i %int_0
+ OpStore %i %75
+ %79 = OpLoad %int %i
+ %81 = OpLoad %int %58
+ OpStore %58 %int_0
+ OpStore %58 %81
+ %85 = OpLoad %int %j
+ %87 = OpLoad %int %i
+ OpStore %i %int_0
+ OpStore %i %87
+ %90 = OpCompositeExtract %float %73 0
+ %91 = OpCompositeExtract %float %73 2
+ %92 = OpCompositeExtract %float %73 2
+ %93 = OpCompositeConstruct %v3float %90 %91 %92
+ %95 = OpLoad %int %58
+ OpStore %58 %int_0
+ OpStore %58 %95
+ %99 = OpAccessChain %_ptr_Private_int %obj %uint_0 %85
+ %101 = OpLoad %int %99
+ %102 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %102
+ %105 = OpCompositeExtract %float %93 0
+ %106 = OpCompositeExtract %float %93 0
+ %107 = OpCompositeConstruct %v2float %105 %106
+ %109 = OpAccessChain %_ptr_Private_int %obj %uint_0 %79
+ %110 = OpCompositeExtract %float %53 0
+ %111 = OpCompositeExtract %float %53 2
+ %112 = OpCompositeExtract %float %53 0
+ %113 = OpCompositeConstruct %v3float %110 %111 %112
+ OpStore %109 %101
+ %115 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %115
+ %116 = OpCompositeExtract %float %93 1
+ %117 = OpCompositeExtract %float %93 2
+ %118 = OpCompositeExtract %float %93 0
+ %119 = OpCompositeConstruct %v3float %116 %117 %118
+ %121 = OpLoad %int %i
+ OpStore %i %int_0
+ OpStore %i %121
+ %125 = OpLoad %int %j
+ %126 = OpLoad %int %temp
+ OpStore %temp %int_0
+ OpStore %temp %126
+ %127 = OpCompositeExtract %float %119 2
+ %128 = OpCompositeExtract %float %119 1
+ %129 = OpCompositeConstruct %v2float %127 %128
+ %131 = OpLoad %int %99
+ OpStore %99 %int_0
+ OpStore %99 %131
+ %134 = OpLoad %int %temp
+ %136 = OpLoad %int %j
+ OpStore %j %int_0
+ OpStore %j %136
+ %139 = OpCompositeExtract %float %107 0
+ %140 = OpCompositeExtract %float %93 1
+ %141 = OpCompositeExtract %float %93 0
+ %142 = OpCompositeConstruct %v3float %139 %140 %141
+ %144 = OpLoad %int %109
+ OpStore %109 %int_0
+ OpStore %109 %144
+ %147 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %147
+ %148 = OpCompositeExtract %float %113 0
+ %149 = OpCompositeExtract %float %113 1
+ %150 = OpCompositeExtract %float %113 0
+ %151 = OpCompositeConstruct %v3float %148 %149 %150
+ %153 = OpLoad %int %99
+ OpStore %99 %int_0
+ OpStore %99 %153
+ %156 = OpAccessChain %_ptr_Private_int %obj %uint_0 %125
+ OpStore %156 %134
+ OpReturn
+ OpFunctionEnd
+%performPartition_i1_i1_ = OpFunction %int None %157
+ %l = OpFunctionParameter %_ptr_Function_int
+ %h = OpFunctionParameter %_ptr_Function_int
+ %161 = OpLabel
+ %param_3 = OpVariable %_ptr_Function_int Function %28
+ %i_1 = OpVariable %_ptr_Function_int Function %28
+ %j_1 = OpVariable %_ptr_Function_int Function %28
+ %param_2 = OpVariable %_ptr_Function_int Function %28
+ %param_1 = OpVariable %_ptr_Function_int Function %28
+ %param = OpVariable %_ptr_Function_int Function %28
+ %pivot = OpVariable %_ptr_Function_int Function %28
+ %x_537 = OpVariable %_ptr_Function_v2float Function %171
+ %x_538 = OpVariable %_ptr_Function_v3float Function %174
+ %176 = OpLoad %int %h
+ OpStore %h %int_0
+ OpStore %h %176
+ %180 = OpLoad %int %h
+ %182 = OpLoad %int %l
+ OpStore %l %int_0
+ OpStore %l %182
+ %186 = OpAccessChain %_ptr_Private_int %obj %uint_0 %180
+ %188 = OpLoad %int %186
+ OpStore %186 %int_0
+ OpStore %186 %188
+ %192 = OpLoad %int %186
+ %193 = OpLoad %int %param_3
+ OpStore %param_3 %int_0
+ OpStore %param_3 %193
+ %194 = OpCompositeExtract %float %35 2
+ %195 = OpCompositeExtract %float %35 0
+ %196 = OpCompositeExtract %float %35 2
+ %197 = OpCompositeConstruct %v3float %194 %195 %196
+ %198 = OpLoad %int %param_1
+ OpStore %param_1 %int_0
+ OpStore %param_1 %198
+ OpStore %pivot %192
+ %200 = OpLoad %int %l
+ %202 = OpLoad %int %h
+ OpStore %h %int_0
+ OpStore %h %202
+ %205 = OpLoad %int %j_1
+ OpStore %j_1 %int_0
+ OpStore %j_1 %205
+ %206 = OpCompositeExtract %float %197 1
+ %207 = OpCompositeExtract %float %197 2
+ %208 = OpCompositeExtract %float %197 1
+ %209 = OpCompositeConstruct %v3float %206 %207 %208
+ %211 = OpLoad %int %l
+ OpStore %l %int_0
+ OpStore %l %211
+ %214 = OpBitcast %int %uint_1
+ %216 = OpISub %int %200 %214
+ OpStore %i_1 %216
+ %218 = OpLoad %int %l
+ %219 = OpCompositeExtract %float %197 0
+ %220 = OpCompositeExtract %float %197 2
+ %221 = OpCompositeExtract %float %209 0
+ %222 = OpCompositeConstruct %v3float %219 %220 %221
+ OpStore %j_1 %int_10
+ %224 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %224
+ OpBranch %225
+ %225 = OpLabel
+ OpLoopMerge %226 %227 None
+ OpBranch %228
+ %228 = OpLabel
+ %229 = OpLoad %int %pivot
+ OpStore %pivot %int_0
+ OpStore %pivot %229
+ %230 = OpLoad %int %param_1
+ OpStore %param_1 %int_0
+ OpStore %param_1 %230
+ %231 = OpLoad %int %j_1
+ %232 = OpLoad %int %pivot
+ OpStore %pivot %int_0
+ OpStore %pivot %232
+ %233 = OpCompositeExtract %float %35 1
+ %234 = OpCompositeExtract %float %35 2
+ %235 = OpCompositeConstruct %v2float %233 %234
+ OpStore %x_537 %235
+ %236 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %236
+ %238 = OpLoad %int %h
+ %240 = OpLoad %int %h
+ OpStore %h %int_0
+ OpStore %h %240
+ %243 = OpLoad %int %param
+ OpStore %param %int_0
+ OpStore %param %243
+ %244 = OpLoad %int %j_1
+ OpStore %j_1 %int_0
+ OpStore %j_1 %244
+ %245 = OpCompositeExtract %float %197 0
+ %247 = OpAccessChain %_ptr_Function_float %x_537 %uint_1
+ %248 = OpLoad %float %247
+ %249 = OpCompositeExtract %float %197 2
+ %250 = OpCompositeConstruct %v3float %245 %248 %249
+ OpStore %x_538 %250
+ %251 = OpLoad %int %param
+ OpStore %param %int_0
+ OpStore %param %251
+ %252 = OpBitcast %int %uint_1
+ %253 = OpISub %int %238 %252
+ %254 = OpSLessThanEqual %bool %231 %253
+ OpSelectionMerge %256 None
+ OpBranchConditional %254 %257 %258
+ %257 = OpLabel
+ OpBranch %256
+ %258 = OpLabel
+ OpBranch %226
+ %256 = OpLabel
+ %259 = OpLoad %int %j_1
+ %261 = OpLoad %int %186
+ OpStore %186 %int_0
+ OpStore %186 %261
+ %265 = OpAccessChain %_ptr_Private_int %obj %uint_0 %259
+ %267 = OpLoad %int %h
+ OpStore %h %int_0
+ OpStore %h %267
+ %270 = OpAccessChain %_ptr_Function_float %x_537 %uint_0
+ %271 = OpLoad %float %270
+ %272 = OpCompositeExtract %float %209 2
+ %273 = OpAccessChain %_ptr_Function_float %x_537 %uint_0
+ %274 = OpLoad %float %273
+ %275 = OpCompositeConstruct %v3float %271 %272 %274
+ %276 = OpLoad %int %param_1
+ OpStore %param_1 %int_0
+ OpStore %param_1 %276
+ %278 = OpLoad %int %265
+ %279 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %279
+ %280 = OpLoad %int %pivot
+ %281 = OpCompositeExtract %float %35 1
+ %282 = OpCompositeExtract %float %197 2
+ %283 = OpCompositeConstruct %v2float %281 %282
+ %284 = OpLoad %int %i_1
+ OpStore %i_1 %int_0
+ OpStore %i_1 %284
+ %286 = OpLoad %int %l
+ OpStore %l %int_0
+ OpStore %l %286
+ %289 = OpCompositeExtract %float %197 1
+ %290 = OpCompositeExtract %float %197 0
+ %291 = OpCompositeExtract %float %197 1
+ %292 = OpCompositeConstruct %v3float %289 %290 %291
+ %293 = OpLoad %int %pivot
+ OpStore %pivot %int_0
+ OpStore %pivot %293
+ %294 = OpSLessThanEqual %bool %278 %280
+ OpSelectionMerge %295 None
+ OpBranchConditional %294 %296 %295
+ %296 = OpLabel
+ %297 = OpCompositeExtract %float %292 2
+ %298 = OpCompositeExtract %float %292 0
+ %299 = OpCompositeExtract %float %292 0
+ %300 = OpCompositeConstruct %v3float %297 %298 %299
+ %301 = OpLoad %int %param_3
+ OpStore %param_3 %int_0
+ OpStore %param_3 %301
+ %302 = OpLoad %int %i_1
+ %303 = OpLoad %int %pivot
+ OpStore %pivot %int_0
+ OpStore %pivot %303
+ %304 = OpCompositeExtract %float %275 0
+ %305 = OpCompositeExtract %float %292 1
+ %306 = OpCompositeConstruct %v2float %304 %305
+ %307 = OpLoad %int %i_1
+ OpStore %i_1 %int_0
+ OpStore %i_1 %307
+ %308 = OpLoad %int %param
+ OpStore %param %int_0
+ OpStore %param %308
+ %309 = OpBitcast %int %uint_1
+ %310 = OpIAdd %int %302 %309
+ OpStore %i_1 %310
+ %312 = OpLoad %int %l
+ OpStore %l %int_0
+ OpStore %l %312
+ %315 = OpCompositeExtract %float %35 2
+ %316 = OpCompositeExtract %float %35 1
+ %317 = OpCompositeExtract %float %283 0
+ %318 = OpCompositeConstruct %v3float %315 %316 %317
+ %319 = OpLoad %int %i_1
+ %320 = OpAccessChain %_ptr_Function_float %x_537 %uint_1
+ %321 = OpLoad %float %320
+ %322 = OpAccessChain %_ptr_Function_float %x_538 %uint_0
+ %323 = OpLoad %float %322
+ %324 = OpCompositeConstruct %v2float %321 %323
+ %325 = OpLoad %int %param
+ OpStore %param %int_0
+ OpStore %param %325
+ OpStore %param %319
+ %326 = OpLoad %int %param
+ OpStore %param %int_0
+ OpStore %param %326
+ %327 = OpCompositeExtract %float %324 0
+ %328 = OpCompositeExtract %float %324 0
+ %329 = OpCompositeConstruct %v2float %327 %328
+ %330 = OpLoad %int %i_1
+ OpStore %i_1 %int_0
+ OpStore %i_1 %330
+ %331 = OpLoad %int %j_1
+ OpStore %param_1 %331
+ %332 = OpLoad %int %param_3
+ OpStore %param_3 %int_0
+ OpStore %param_3 %332
+ %333 = OpFunctionCall %void %swap_i1_i1_ %param %param_1
+ %336 = OpLoad %int %param_1
+ OpStore %param_1 %int_0
+ OpStore %param_1 %336
+ OpBranch %295
+ %295 = OpLabel
+ %337 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %337
+ OpBranch %227
+ %227 = OpLabel
+ %339 = OpLoad %int %h
+ OpStore %h %int_0
+ OpStore %h %339
+ %342 = OpLoad %int %j_1
+ %344 = OpLoad %int %h
+ OpStore %h %int_0
+ OpStore %h %344
+ %347 = OpCompositeExtract %float %275 0
+ %348 = OpCompositeExtract %float %292 2
+ %349 = OpCompositeExtract %float %292 2
+ %350 = OpCompositeConstruct %v3float %347 %348 %349
+ %352 = OpLoad %int %265
+ OpStore %265 %int_0
+ OpStore %265 %352
+ %355 = OpLoad %int %param
+ OpStore %param %int_0
+ OpStore %param %355
+ %357 = OpIAdd %int %int_1 %342
+ OpStore %j_1 %357
+ %358 = OpLoad %int %param_1
+ OpStore %param_1 %int_0
+ OpStore %param_1 %358
+ %359 = OpCompositeExtract %float %292 1
+ %360 = OpCompositeExtract %float %292 2
+ %361 = OpCompositeExtract %float %292 0
+ %362 = OpCompositeConstruct %v3float %359 %360 %361
+ %364 = OpLoad %int %265
+ OpStore %265 %int_0
+ OpStore %265 %364
+ OpBranch %225
+ %226 = OpLabel
+ %367 = OpLoad %int %i_1
+ %369 = OpLoad %int %186
+ OpStore %186 %int_0
+ OpStore %186 %369
+ %372 = OpCompositeExtract %float %197 0
+ %373 = OpCompositeExtract %float %197 1
+ %374 = OpCompositeConstruct %v2float %372 %373
+ %375 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %375
+ %377 = OpLoad %int %h
+ OpStore %h %int_0
+ OpStore %h %377
+ %380 = OpIAdd %int %int_1 %367
+ OpStore %i_1 %380
+ %381 = OpLoad %int %param_1
+ OpStore %param_1 %int_0
+ OpStore %param_1 %381
+ %382 = OpLoad %int %i_1
+ %383 = OpLoad %int %j_1
+ OpStore %j_1 %int_0
+ OpStore %j_1 %383
+ %384 = OpCompositeExtract %float %197 0
+ %385 = OpCompositeExtract %float %197 0
+ %386 = OpCompositeConstruct %v2float %384 %385
+ %387 = OpLoad %int %param_1
+ OpStore %param_1 %int_0
+ OpStore %param_1 %387
+ OpStore %param_2 %382
+ %388 = OpCompositeExtract %float %197 1
+ %389 = OpCompositeExtract %float %222 0
+ %390 = OpCompositeConstruct %v2float %388 %389
+ %391 = OpLoad %int %pivot
+ OpStore %pivot %int_0
+ OpStore %pivot %391
+ %393 = OpLoad %int %h
+ %394 = OpCompositeExtract %float %386 0
+ %395 = OpCompositeExtract %float %374 1
+ %396 = OpCompositeConstruct %v2float %394 %395
+ %398 = OpLoad %int %h
+ OpStore %h %int_0
+ OpStore %h %398
+ OpStore %param_3 %393
+ %401 = OpLoad %int %i_1
+ OpStore %i_1 %int_0
+ OpStore %i_1 %401
+ %402 = OpCompositeExtract %float %374 1
+ %403 = OpCompositeExtract %float %396 0
+ %404 = OpCompositeConstruct %v2float %402 %403
+ %406 = OpLoad %int %h
+ OpStore %h %int_0
+ OpStore %h %406
+ %409 = OpFunctionCall %void %swap_i1_i1_ %param_2 %param_3
+ %413 = OpLoad %int %l
+ OpStore %l %int_0
+ OpStore %l %413
+ %416 = OpCompositeExtract %float %222 2
+ %417 = OpCompositeExtract %float %35 1
+ %418 = OpCompositeConstruct %v2float %416 %417
+ %419 = OpLoad %int %param_1
+ OpStore %param_1 %int_0
+ OpStore %param_1 %419
+ %420 = OpLoad %int %i_1
+ %421 = OpLoad %int %param
+ OpStore %param %int_0
+ OpStore %param %421
+ %422 = OpCompositeExtract %float %197 1
+ %423 = OpCompositeExtract %float %197 0
+ %424 = OpCompositeConstruct %v2float %422 %423
+ %425 = OpLoad %int %j_1
+ OpStore %j_1 %int_0
+ OpStore %j_1 %425
+ OpReturnValue %420
+ OpFunctionEnd
+ %quicksort_ = OpFunction %void None %426
+ %428 = OpLabel
+ %param_4 = OpVariable %_ptr_Function_int Function %28
+ %h_1 = OpVariable %_ptr_Function_int Function %28
+ %p = OpVariable %_ptr_Function_int Function %28
+ %l_1 = OpVariable %_ptr_Function_int Function %28
+ %top = OpVariable %_ptr_Function_int Function %28
+ %stack = OpVariable %_ptr_Function__arr_int_uint_10 Function %436
+ %param_5 = OpVariable %_ptr_Function_int Function %28
+ OpStore %l_1 %int_0
+ %438 = OpLoad %int %param_5
+ OpStore %param_5 %int_0
+ OpStore %param_5 %438
+ OpStore %h_1 %int_9
+ %440 = OpLoad %_arr_int_uint_10 %stack
+ OpStore %stack %103
+ OpStore %stack %440
+ %441 = OpCompositeExtract %float %35 1
+ %442 = OpCompositeExtract %float %35 1
+ %443 = OpCompositeConstruct %v2float %441 %442
+ %444 = OpLoad %int %param_5
+ OpStore %param_5 %int_0
+ OpStore %param_5 %444
+ OpStore %top %int_n1
+ %446 = OpLoad %int %p
+ OpStore %p %int_0
+ OpStore %p %446
+ %447 = OpLoad %int %top
+ %448 = OpCompositeExtract %float %35 0
+ %449 = OpCompositeExtract %float %35 0
+ %450 = OpCompositeConstruct %v2float %448 %449
+ %451 = OpLoad %int %p
+ OpStore %p %int_0
+ OpStore %p %451
+ %452 = OpBitcast %int %uint_1
+ %453 = OpIAdd %int %447 %452
+ %454 = OpLoad %int %top
+ OpStore %top %int_0
+ OpStore %top %454
+ %455 = OpCompositeExtract %float %443 1
+ %456 = OpCompositeExtract %float %450 1
+ %457 = OpCompositeConstruct %v2float %455 %456
+ %458 = OpLoad %int %param_4
+ OpStore %param_4 %int_0
+ OpStore %param_4 %458
+ OpStore %top %453
+ %459 = OpLoad %int %h_1
+ OpStore %h_1 %int_0
+ OpStore %h_1 %459
+ %460 = OpCompositeExtract %float %450 1
+ %461 = OpCompositeExtract %float %450 0
+ %462 = OpCompositeExtract %float %450 0
+ %463 = OpCompositeConstruct %v3float %460 %461 %462
+ %464 = OpLoad %int %param_4
+ OpStore %param_4 %int_0
+ OpStore %param_4 %464
+ %465 = OpLoad %int %l_1
+ %466 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %466
+ %467 = OpCompositeExtract %float %463 1
+ %468 = OpCompositeExtract %float %463 0
+ %469 = OpCompositeExtract %float %450 0
+ %470 = OpCompositeConstruct %v3float %467 %468 %469
+ %472 = OpAccessChain %_ptr_Function_int %stack %453
+ %473 = OpLoad %_arr_int_uint_10 %stack
+ OpStore %stack %103
+ OpStore %stack %473
+ %474 = OpCompositeExtract %float %443 1
+ %475 = OpCompositeExtract %float %443 1
+ %476 = OpCompositeExtract %float %443 1
+ %477 = OpCompositeConstruct %v3float %474 %475 %476
+ %478 = OpLoad %int %l_1
+ OpStore %l_1 %int_0
+ OpStore %l_1 %int_0
+ OpStore %472 %465
+ %480 = OpLoad %int %param_5
+ OpStore %param_5 %int_0
+ OpStore %param_5 %480
+ %481 = OpLoad %int %top
+ %482 = OpLoad %int %param_4
+ OpStore %param_4 %int_0
+ OpStore %param_4 %482
+ %483 = OpCompositeExtract %float %35 2
+ %484 = OpCompositeExtract %float %457 1
+ %485 = OpCompositeExtract %float %35 1
+ %486 = OpCompositeConstruct %v3float %483 %484 %485
+ %488 = OpLoad %int %472
+ OpStore %472 %int_0
+ OpStore %472 %488
+ %491 = OpIAdd %int %481 %int_1
+ %493 = OpLoad %int %472
+ OpStore %472 %int_0
+ OpStore %472 %493
+ %496 = OpCompositeExtract %float %463 0
+ %497 = OpCompositeExtract %float %463 2
+ %498 = OpCompositeExtract %float %443 1
+ %499 = OpCompositeConstruct %v3float %496 %497 %498
+ OpStore %top %491
+ %500 = OpLoad %int %param_4
+ OpStore %param_4 %int_0
+ OpStore %param_4 %500
+ %501 = OpLoad %int %h_1
+ %502 = OpLoad %int %param_4
+ OpStore %param_4 %int_0
+ OpStore %param_4 %502
+ %503 = OpCompositeExtract %float %457 0
+ %504 = OpCompositeExtract %float %477 0
+ %505 = OpCompositeExtract %float %457 1
+ %506 = OpCompositeConstruct %v3float %503 %504 %505
+ %507 = OpLoad %int %l_1
+ OpStore %l_1 %int_0
+ OpStore %l_1 %507
+ %509 = OpAccessChain %_ptr_Function_int %stack %491
+ %510 = OpLoad %int %param_5
+ OpStore %param_5 %int_0
+ OpStore %param_5 %510
+ %511 = OpCompositeExtract %float %506 2
+ %512 = OpCompositeExtract %float %506 2
+ %513 = OpCompositeConstruct %v2float %511 %512
+ %514 = OpLoad %int %p
+ OpStore %p %int_0
+ OpStore %p %514
+ OpStore %509 %501
+ OpBranch %516
+ %516 = OpLabel
+ OpLoopMerge %517 %518 None
+ OpBranch %519
+ %519 = OpLabel
+ %520 = OpCompositeExtract %float %499 0
+ %521 = OpCompositeExtract %float %499 0
+ %522 = OpCompositeExtract %float %499 0
+ %523 = OpCompositeConstruct %v3float %520 %521 %522
+ %524 = OpLoad %int %h_1
+ OpStore %h_1 %int_0
+ OpStore %h_1 %524
+ %525 = OpLoad %_arr_int_uint_10 %stack
+ OpStore %stack %103
+ OpStore %stack %525
+ %526 = OpLoad %int %top
+ %527 = OpLoad %_arr_int_uint_10 %stack
+ OpStore %stack %103
+ OpStore %stack %527
+ %528 = OpCompositeExtract %float %457 0
+ %529 = OpCompositeExtract %float %506 2
+ %530 = OpCompositeConstruct %v2float %528 %529
+ %531 = OpLoad %int %param_4
+ OpStore %param_4 %int_0
+ OpStore %param_4 %531
+ %532 = OpBitcast %int %uint_0
+ %533 = OpSGreaterThanEqual %bool %526 %532
+ OpSelectionMerge %534 None
+ OpBranchConditional %533 %535 %536
+ %535 = OpLabel
+ OpBranch %534
+ %536 = OpLabel
+ OpBranch %517
+ %534 = OpLabel
+ %537 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %537
+ %538 = OpCompositeExtract %float %463 1
+ %539 = OpCompositeExtract %float %463 0
+ %540 = OpCompositeExtract %float %499 1
+ %541 = OpCompositeConstruct %v3float %538 %539 %540
+ %542 = OpLoad %int %param_4
+ OpStore %param_4 %int_0
+ OpStore %param_4 %542
+ %543 = OpLoad %int %top
+ %544 = OpCompositeExtract %float %513 0
+ %545 = OpCompositeExtract %float %530 1
+ %546 = OpCompositeExtract %float %513 0
+ %547 = OpCompositeConstruct %v3float %544 %545 %546
+ %548 = OpLoad %int %h_1
+ OpStore %h_1 %int_0
+ OpStore %h_1 %548
+ %549 = OpCompositeExtract %float %443 0
+ %550 = OpCompositeExtract %float %443 0
+ %551 = OpCompositeConstruct %v2float %549 %550
+ %552 = OpLoad %int %p
+ OpStore %p %int_0
+ OpStore %p %552
+ %553 = OpBitcast %int %uint_1
+ %554 = OpISub %int %543 %553
+ OpStore %top %554
+ %555 = OpLoad %int %p
+ OpStore %p %int_0
+ OpStore %p %555
+ %557 = OpAccessChain %_ptr_Function_int %stack %543
+ %559 = OpLoad %int %472
+ OpStore %472 %int_0
+ OpStore %472 %559
+ %563 = OpLoad %int %557
+ %564 = OpLoad %_arr_int_uint_10 %stack
+ OpStore %stack %103
+ OpStore %stack %564
+ %565 = OpCompositeExtract %float %463 1
+ %566 = OpCompositeExtract %float %463 0
+ %567 = OpCompositeExtract %float %506 1
+ %568 = OpCompositeConstruct %v3float %565 %566 %567
+ %569 = OpLoad %int %l_1
+ OpStore %l_1 %int_0
+ OpStore %l_1 %569
+ OpStore %h_1 %563
+ %570 = OpLoad %_arr_int_uint_10 %stack
+ OpStore %stack %103
+ OpStore %stack %570
+ %571 = OpCompositeExtract %float %486 1
+ %572 = OpCompositeExtract %float %477 1
+ %573 = OpCompositeConstruct %v2float %571 %572
+ %574 = OpLoad %int %p
+ OpStore %p %int_0
+ OpStore %p %574
+ %575 = OpLoad %int %top
+ %576 = OpLoad %int %param_4
+ OpStore %param_4 %int_0
+ OpStore %param_4 %576
+ %578 = OpLoad %int %509
+ OpStore %509 %int_0
+ OpStore %509 %578
+ %581 = OpCompositeExtract %float %35 1
+ %582 = OpCompositeExtract %float %35 2
+ %583 = OpCompositeConstruct %v2float %581 %582
+ %584 = OpISub %int %575 %int_1
+ OpStore %top %584
+ %585 = OpLoad %int %param_5
+ OpStore %param_5 %int_0
+ OpStore %param_5 %585
+ %586 = OpCompositeExtract %float %551 1
+ %587 = OpCompositeExtract %float %513 0
+ %588 = OpCompositeExtract %float %551 1
+ %589 = OpCompositeConstruct %v3float %586 %587 %588
+ %590 = OpLoad %int %h_1
+ OpStore %h_1 %int_0
+ OpStore %h_1 %590
+ %592 = OpAccessChain %_ptr_Function_int %stack %575
+ %593 = OpCompositeExtract %float %506 1
+ %594 = OpCompositeExtract %float %506 2
+ %595 = OpCompositeConstruct %v2float %593 %594
+ %597 = OpLoad %int %509
+ OpStore %509 %int_0
+ OpStore %509 %597
+ %601 = OpLoad %int %592
+ %602 = OpLoad %int %p
+ OpStore %p %int_0
+ OpStore %p %602
+ %603 = OpCompositeExtract %float %583 1
+ %604 = OpCompositeExtract %float %583 1
+ %605 = OpCompositeExtract %float %513 0
+ %606 = OpCompositeConstruct %v3float %603 %604 %605
+ %607 = OpLoad %int %param_5
+ OpStore %param_5 %int_0
+ OpStore %param_5 %607
+ OpStore %l_1 %601
+ %608 = OpLoad %int %top
+ OpStore %top %int_0
+ OpStore %top %608
+ %609 = OpLoad %int %l_1
+ OpStore %param_4 %609
+ %611 = OpLoad %int %557
+ OpStore %557 %int_0
+ OpStore %557 %611
+ %614 = OpCompositeExtract %float %547 1
+ %615 = OpCompositeExtract %float %547 2
+ %616 = OpCompositeConstruct %v2float %614 %615
+ %617 = OpLoad %int %h_1
+ %618 = OpCompositeExtract %float %457 0
+ %619 = OpCompositeExtract %float %35 1
+ %620 = OpCompositeConstruct %v2float %618 %619
+ OpStore %param_5 %617
+ %622 = OpLoad %int %509
+ OpStore %509 %int_0
+ OpStore %509 %622
+ %625 = OpFunctionCall %int %performPartition_i1_i1_ %param_4 %param_5
+ %628 = OpCompositeExtract %float %530 0
+ %629 = OpCompositeExtract %float %541 0
+ %630 = OpCompositeConstruct %v2float %628 %629
+ %631 = OpLoad %int %param_5
+ OpStore %param_5 %int_0
+ OpStore %param_5 %631
+ OpStore %p %625
+ %632 = OpLoad %int %param_4
+ OpStore %param_4 %int_0
+ OpStore %param_4 %632
+ %633 = OpLoad %int %p
+ %634 = OpLoad %int %h_1
+ OpStore %h_1 %int_0
+ OpStore %h_1 %634
+ %635 = OpCompositeExtract %float %541 1
+ %636 = OpCompositeExtract %float %541 1
+ %637 = OpCompositeConstruct %v2float %635 %636
+ %638 = OpLoad %int %l_1
+ OpStore %l_1 %int_0
+ OpStore %l_1 %638
+ %639 = OpLoad %int %h_1
+ OpStore %h_1 %int_0
+ OpStore %h_1 %639
+ %640 = OpLoad %int %l_1
+ %642 = OpLoad %int %557
+ OpStore %557 %int_0
+ OpStore %557 %642
+ %645 = OpLoad %int %h_1
+ OpStore %h_1 %int_0
+ OpStore %h_1 %645
+ %646 = OpCompositeExtract %float %530 1
+ %647 = OpCompositeExtract %float %583 0
+ %648 = OpCompositeConstruct %v2float %646 %647
+ %650 = OpLoad %int %509
+ OpStore %509 %int_0
+ OpStore %509 %650
+ %653 = OpBitcast %int %uint_1
+ %654 = OpISub %int %633 %653
+ %655 = OpSGreaterThan %bool %654 %640
+ OpSelectionMerge %656 None
+ OpBranchConditional %655 %657 %656
+ %657 = OpLabel
+ %658 = OpLoad %int %param_4
+ OpStore %param_4 %int_0
+ OpStore %param_4 %658
+ %659 = OpLoad %int %top
+ %660 = OpCompositeExtract %float %568 1
+ %661 = OpCompositeExtract %float %443 1
+ %662 = OpCompositeConstruct %v2float %660 %661
+ %664 = OpLoad %int %509
+ OpStore %509 %int_0
+ OpStore %509 %664
+ %667 = OpLoad %_arr_int_uint_10 %stack
+ OpStore %stack %103
+ OpStore %stack %667
+ %668 = OpCompositeExtract %float %547 2
+ %669 = OpCompositeExtract %float %547 1
+ %670 = OpCompositeConstruct %v2float %668 %669
+ %671 = OpCompositeExtract %float %637 1
+ %672 = OpCompositeExtract %float %616 0
+ %673 = OpCompositeExtract %float %616 0
+ %674 = OpCompositeConstruct %v3float %671 %672 %673
+ %675 = OpLoad %int %l_1
+ %677 = OpLoad %int %592
+ OpStore %592 %int_0
+ OpStore %592 %677
+ %680 = OpCompositeExtract %float %506 0
+ %681 = OpCompositeExtract %float %674 0
+ %682 = OpCompositeConstruct %v2float %680 %681
+ %683 = OpLoad %int %param_5
+ OpStore %param_5 %int_0
+ OpStore %param_5 %683
+ %685 = OpIAdd %int %int_1 %659
+ %686 = OpAccessChain %_ptr_Function_int %stack %685
+ %688 = OpLoad %int %557
+ OpStore %557 %int_0
+ OpStore %557 %688
+ %691 = OpCompositeExtract %float %523 1
+ %692 = OpCompositeExtract %float %523 1
+ %693 = OpCompositeExtract %float %499 0
+ %694 = OpCompositeConstruct %v3float %691 %692 %693
+ %695 = OpLoad %int %param_5
+ OpStore %param_5 %int_0
+ OpStore %param_5 %695
+ OpStore %686 %675
+ %697 = OpLoad %int %top
+ %699 = OpLoad %int %509
+ OpStore %509 %int_0
+ OpStore %509 %699
+ %702 = OpCompositeExtract %float %595 1
+ %703 = OpCompositeExtract %float %595 0
+ %704 = OpCompositeConstruct %v2float %702 %703
+ %706 = OpLoad %int %686
+ OpStore %686 %int_0
+ OpStore %686 %706
+ %710 = OpBitcast %uint %697
+ %711 = OpIAdd %uint %uint_1 %710
+ %709 = OpBitcast %int %711
+ %713 = OpLoad %int %509
+ OpStore %509 %int_0
+ OpStore %509 %713
+ %716 = OpCompositeExtract %float %606 2
+ %717 = OpCompositeExtract %float %704 1
+ %718 = OpCompositeExtract %float %606 2
+ %719 = OpCompositeConstruct %v3float %716 %717 %718
+ %720 = OpLoad %int %h_1
+ OpStore %h_1 %int_0
+ OpStore %h_1 %720
+ OpStore %top %709
+ %721 = OpLoad %_arr_int_uint_10 %stack
+ OpStore %stack %103
+ OpStore %stack %721
+ %722 = OpLoad %int %p
+ %723 = OpCompositeExtract %float %606 0
+ %724 = OpCompositeExtract %float %583 1
+ %725 = OpCompositeConstruct %v2float %723 %724
+ %727 = OpLoad %int %592
+ OpStore %592 %int_0
+ OpStore %592 %727
+ %731 = OpAccessChain %_ptr_Function_int %stack %709
+ %733 = OpLoad %int %592
+ OpStore %592 %int_0
+ OpStore %592 %733
+ %737 = OpBitcast %int %uint_1
+ %738 = OpISub %int %722 %737
+ OpStore %731 %738
+ %740 = OpLoad %int %472
+ OpStore %472 %int_0
+ OpStore %472 %740
+ %743 = OpCompositeExtract %float %547 2
+ %744 = OpCompositeExtract %float %547 1
+ %745 = OpCompositeConstruct %v2float %743 %744
+ %747 = OpLoad %int %731
+ OpStore %731 %int_0
+ OpStore %731 %747
+ OpBranch %656
+ %656 = OpLabel
+ %751 = OpLoad %int %472
+ OpStore %472 %int_0
+ OpStore %472 %751
+ %754 = OpCompositeExtract %float %35 0
+ %755 = OpCompositeExtract %float %35 1
+ %756 = OpCompositeConstruct %v2float %754 %755
+ %757 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %757
+ %758 = OpLoad %int %p
+ %760 = OpLoad %int %592
+ OpStore %592 %int_0
+ OpStore %592 %760
+ %763 = OpCompositeExtract %float %568 2
+ %764 = OpCompositeExtract %float %443 0
+ %765 = OpCompositeExtract %float %443 1
+ %766 = OpCompositeConstruct %v3float %763 %764 %765
+ %767 = OpLoad %int %p
+ OpStore %p %int_0
+ OpStore %p %767
+ %768 = OpCompositeExtract %float %499 2
+ %769 = OpCompositeExtract %float %499 0
+ %770 = OpCompositeExtract %float %595 0
+ %771 = OpCompositeConstruct %v3float %768 %769 %770
+ %773 = OpLoad %int %592
+ OpStore %592 %int_0
+ OpStore %592 %773
+ %776 = OpLoad %int %h_1
+ %777 = OpLoad %int %top
+ OpStore %top %int_0
+ OpStore %top %777
+ %778 = OpCompositeExtract %float %470 2
+ %779 = OpCompositeExtract %float %541 0
+ %780 = OpCompositeExtract %float %470 0
+ %781 = OpCompositeConstruct %v3float %778 %779 %780
+ %783 = OpLoad %int %509
+ OpStore %509 %int_0
+ OpStore %509 %783
+ %786 = OpLoad %int %p
+ OpStore %p %int_0
+ OpStore %p %786
+ %788 = OpBitcast %uint %758
+ %789 = OpIAdd %uint %uint_1 %788
+ %787 = OpBitcast %int %789
+ %790 = OpSLessThan %bool %787 %776
+ OpSelectionMerge %791 None
+ OpBranchConditional %790 %792 %791
+ %792 = OpLabel
+ %794 = OpLoad %int %592
+ OpStore %592 %int_0
+ OpStore %592 %794
+ %797 = OpCompositeExtract %float %756 1
+ %798 = OpCompositeExtract %float %648 0
+ %799 = OpCompositeConstruct %v2float %797 %798
+ %800 = OpLoad %int %l_1
+ OpStore %l_1 %int_0
+ OpStore %l_1 %800
+ %801 = OpLoad %int %top
+ %803 = OpLoad %int %592
+ OpStore %592 %int_0
+ OpStore %592 %803
+ %806 = OpCompositeExtract %float %486 1
+ %807 = OpCompositeExtract %float %470 1
+ %808 = OpCompositeExtract %float %470 1
+ %809 = OpCompositeConstruct %v3float %806 %807 %808
+ %810 = OpIAdd %int %801 %int_1
+ %811 = OpLoad %int %param_5
+ OpStore %param_5 %int_0
+ OpStore %param_5 %811
+ OpStore %top %810
+ %813 = OpLoad %int %592
+ OpStore %592 %int_0
+ OpStore %592 %813
+ %816 = OpLoad %int %p
+ %817 = OpLoad %int %param_5
+ OpStore %param_5 %int_0
+ OpStore %param_5 %817
+ %818 = OpCompositeExtract %float %470 2
+ %819 = OpCompositeExtract %float %470 0
+ %820 = OpCompositeExtract %float %541 0
+ %821 = OpCompositeConstruct %v3float %818 %819 %820
+ %822 = OpLoad %int %p
+ OpStore %p %int_0
+ OpStore %p %822
+ %823 = OpCompositeExtract %float %443 0
+ %824 = OpCompositeExtract %float %637 0
+ %825 = OpCompositeExtract %float %637 0
+ %826 = OpCompositeConstruct %v3float %823 %824 %825
+ %828 = OpLoad %int %509
+ OpStore %509 %int_0
+ OpStore %509 %828
+ %832 = OpAccessChain %_ptr_Function_int %stack %810
+ %834 = OpLoad %int %557
+ OpStore %557 %int_0
+ OpStore %557 %834
+ %837 = OpCompositeExtract %float %499 0
+ %838 = OpCompositeExtract %float %499 1
+ %839 = OpCompositeConstruct %v2float %837 %838
+ %842 = OpBitcast %uint %816
+ %843 = OpIAdd %uint %uint_1 %842
+ %841 = OpBitcast %int %843
+ OpStore %832 %841
+ %844 = OpLoad %_arr_int_uint_10 %stack
+ OpStore %stack %103
+ OpStore %stack %844
+ %845 = OpLoad %int %top
+ %847 = OpLoad %int %592
+ OpStore %592 %int_0
+ OpStore %592 %847
+ %850 = OpCompositeExtract %float %513 1
+ %851 = OpCompositeExtract %float %821 1
+ %852 = OpCompositeConstruct %v2float %850 %851
+ %853 = OpLoad %_arr_int_uint_10 %stack
+ OpStore %stack %103
+ OpStore %stack %853
+ %854 = OpBitcast %int %uint_1
+ %855 = OpIAdd %int %845 %854
+ %857 = OpLoad %int %832
+ OpStore %832 %int_0
+ OpStore %832 %857
+ OpStore %top %855
+ %860 = OpLoad %int %param_4
+ OpStore %param_4 %int_0
+ OpStore %param_4 %860
+ %861 = OpLoad %int %h_1
+ %863 = OpLoad %int %509
+ OpStore %509 %int_0
+ OpStore %509 %863
+ %867 = OpLoad %int %472
+ OpStore %472 %int_0
+ OpStore %472 %867
+ %870 = OpAccessChain %_ptr_Function_int %stack %855
+ OpStore %870 %861
+ %872 = OpLoad %int %592
+ OpStore %592 %int_0
+ OpStore %592 %872
+ %875 = OpCompositeExtract %float %541 1
+ %876 = OpCompositeExtract %float %506 0
+ %877 = OpCompositeExtract %float %506 0
+ %878 = OpCompositeConstruct %v3float %875 %876 %877
+ %879 = OpLoad %int %l_1
+ OpStore %l_1 %int_0
+ OpStore %l_1 %879
+ OpBranch %791
+ %791 = OpLabel
+ %881 = OpLoad %int %509
+ OpStore %509 %int_0
+ OpStore %509 %881
+ OpBranch %518
+ %518 = OpLabel
+ %884 = OpLoad %int %l_1
+ OpStore %l_1 %int_0
+ OpStore %l_1 %884
+ %885 = OpCompositeExtract %float %499 2
+ %886 = OpCompositeExtract %float %506 0
+ %887 = OpCompositeConstruct %v2float %885 %886
+ %888 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %888
+ OpBranch %516
+ %517 = OpLabel
+ %889 = OpLoad %int %h_1
+ OpStore %h_1 %int_0
+ OpStore %h_1 %889
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %426
+ %891 = OpLabel
+ %color = OpVariable %_ptr_Function_v3float Function %174
+ %i_2 = OpVariable %_ptr_Function_int Function %28
+ %uv = OpVariable %_ptr_Function_v2float Function %171
+ %895 = OpLoad %v2float %uv
+ OpStore %uv %897
+ OpStore %uv %895
+ OpStore %i_2 %int_0
+ %898 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %898
+ OpSelectionMerge %900 None
+ OpBranchConditional %true %901 %900
+ %901 = OpLabel
+ %902 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %902
+ %903 = OpCompositeExtract %float %35 0
+ %904 = OpCompositeExtract %float %35 0
+ %905 = OpCompositeConstruct %v2float %903 %904
+ %906 = OpLoad %int %i_2
+ %907 = OpLoad %v2float %uv
+ OpStore %uv %897
+ OpStore %uv %907
+ %908 = OpLoad %v3float %color
+ OpStore %color %909
+ OpStore %color %908
+ %910 = OpCompositeExtract %float %905 1
+ %911 = OpCompositeExtract %float %905 1
+ %912 = OpCompositeConstruct %v2float %910 %911
+ %913 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %913
+ OpBranch %900
+ %900 = OpLabel
+ %914 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %914
+ %915 = OpCompositeExtract %float %897 0
+ %916 = OpCompositeExtract %float %897 0
+ %917 = OpCompositeConstruct %v2float %915 %916
+ %918 = OpLoad %int %i_2
+ OpStore %i_2 %int_0
+ OpStore %i_2 %918
+ %919 = OpFunctionCall %void %quicksort_
+ %920 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %920
+ %921 = OpLoad %v4float %gl_FragCoord
+ %922 = OpLoad %v2float %uv
+ OpStore %uv %897
+ OpStore %uv %922
+ %923 = OpCompositeExtract %float %897 1
+ %924 = OpCompositeExtract %float %897 1
+ %925 = OpCompositeConstruct %v2float %923 %924
+ %926 = OpLoad %v2float %uv
+ OpStore %uv %897
+ OpStore %uv %926
+ %927 = OpCompositeExtract %float %921 0
+ %928 = OpCompositeExtract %float %921 1
+ %929 = OpCompositeConstruct %v2float %927 %928
+ %930 = OpCompositeExtract %float %929 1
+ %931 = OpCompositeExtract %float %917 1
+ %932 = OpCompositeExtract %float %917 1
+ %933 = OpCompositeConstruct %v3float %930 %931 %932
+ %934 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %934
+ %935 = OpLoad %v2float %uv
+ OpStore %uv %897
+ OpStore %uv %935
+ %937 = OpAccessChain %_ptr_Uniform_v2float %x_188 %uint_0
+ %938 = OpLoad %v2float %937
+ %939 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %939
+ %940 = OpCompositeExtract %float %921 1
+ %941 = OpCompositeExtract %float %35 2
+ %942 = OpCompositeExtract %float %921 3
+ %943 = OpCompositeConstruct %v3float %940 %941 %942
+ %944 = OpLoad %v3float %color
+ OpStore %color %909
+ OpStore %color %944
+ %945 = OpFDiv %v2float %929 %938
+ %946 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %946
+ %947 = OpCompositeExtract %float %925 0
+ %948 = OpCompositeExtract %float %929 1
+ %949 = OpCompositeConstruct %v2float %947 %948
+ %950 = OpLoad %v3float %color
+ OpStore %color %909
+ %951 = OpLoad %v3float %color
+ OpStore %color %909
+ OpStore %color %951
+ OpStore %color %950
+ OpStore %uv %945
+ OpStore %color %35
+ %952 = OpLoad %v3float %color
+ OpStore %color %909
+ OpStore %color %952
+ %953 = OpCompositeExtract %float %929 0
+ %954 = OpCompositeExtract %float %929 1
+ %955 = OpCompositeExtract %float %917 1
+ %956 = OpCompositeConstruct %v3float %953 %954 %955
+ %957 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %957
+ %959 = OpAccessChain %_ptr_Private_int %obj %uint_0 %uint_0
+ %961 = OpLoad %int %959
+ OpStore %959 %int_0
+ OpStore %959 %961
+ %965 = OpLoad %int %959
+ %966 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %966
+ %968 = OpAccessChain %_ptr_Function_float %color %uint_0
+ %970 = OpLoad %int %959
+ OpStore %959 %int_0
+ OpStore %959 %970
+ %974 = OpLoad %float %968
+ %976 = OpLoad %float %968
+ OpStore %968 %float_0
+ OpStore %968 %976
+ %979 = OpCompositeExtract %float %35 2
+ %980 = OpCompositeExtract %float %35 1
+ %981 = OpCompositeConstruct %v2float %979 %980
+ %982 = OpLoad %int %i_2
+ OpStore %i_2 %int_0
+ OpStore %i_2 %982
+ %983 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %983
+ %985 = OpAccessChain %_ptr_Function_float %color %uint_0
+ %986 = OpCompositeExtract %float %956 0
+ %987 = OpCompositeExtract %float %949 0
+ %988 = OpCompositeExtract %float %949 1
+ %989 = OpCompositeConstruct %v3float %986 %987 %988
+ %991 = OpConvertSToF %float %965
+ %992 = OpFAdd %float %974 %991
+ OpStore %985 %992
+ %993 = OpLoad %v2float %uv
+ OpStore %uv %897
+ OpStore %uv %993
+ %995 = OpAccessChain %_ptr_Function_float %uv %uint_0
+ %996 = OpLoad %v2float %uv
+ OpStore %uv %897
+ OpStore %uv %996
+ %997 = OpCompositeExtract %float %921 1
+ %998 = OpCompositeExtract %float %921 1
+ %999 = OpCompositeConstruct %v2float %997 %998
+ %1001 = OpLoad %float %995
+ %1002 = OpCompositeExtract %float %945 1
+ %1003 = OpCompositeExtract %float %945 0
+ %1004 = OpCompositeConstruct %v2float %1002 %1003
+ %1006 = OpLoad %float %995
+ OpStore %995 %float_0
+ OpStore %995 %1006
+ %1009 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %1009
+ %1011 = OpFOrdGreaterThan %bool %1001 %float_0_25
+ OpSelectionMerge %1012 None
+ OpBranchConditional %1011 %1013 %1012
+ %1013 = OpLabel
+ %1014 = OpLoad %int %i_2
+ OpStore %i_2 %int_0
+ OpStore %i_2 %1014
+ %1016 = OpLoad %int %959
+ OpStore %959 %int_0
+ OpStore %959 %1016
+ %1019 = OpCompositeExtract %float %897 1
+ %1020 = OpCompositeExtract %float %933 1
+ %1021 = OpCompositeExtract %float %933 1
+ %1022 = OpCompositeConstruct %v3float %1019 %1020 %1021
+ %1024 = OpLoad %float %995
+ OpStore %995 %float_0
+ OpStore %995 %1024
+ %1027 = OpAccessChain %_ptr_Private_int %obj %uint_0 %int_1
+ %1028 = OpLoad %int %1027
+ %1029 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %1029
+ %1030 = OpCompositeExtract %float %999 0
+ %1031 = OpCompositeExtract %float %999 0
+ %1032 = OpCompositeConstruct %v2float %1030 %1031
+ %1033 = OpLoad %v2float %uv
+ OpStore %uv %897
+ OpStore %uv %1033
+ %1035 = OpAccessChain %_ptr_Function_float %color %int_0
+ %1036 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %1036
+ %1037 = OpCompositeExtract %float %35 2
+ %1038 = OpCompositeExtract %float %897 1
+ %1039 = OpCompositeConstruct %v2float %1037 %1038
+ %1040 = OpLoad %int %i_2
+ OpStore %i_2 %int_0
+ OpStore %i_2 %1040
+ %1042 = OpLoad %float %1035
+ %1044 = OpLoad %float %1035
+ OpStore %1035 %float_0
+ OpStore %1035 %1044
+ %1047 = OpLoad %v3float %color
+ OpStore %color %909
+ OpStore %color %1047
+ %1048 = OpLoad %v3float %color
+ OpStore %color %909
+ OpStore %color %1048
+ %1049 = OpCompositeExtract %float %999 1
+ %1050 = OpCompositeExtract %float %999 1
+ %1051 = OpCompositeExtract %float %925 1
+ %1052 = OpCompositeConstruct %v3float %1049 %1050 %1051
+ %1054 = OpLoad %float %1035
+ OpStore %1035 %float_0
+ OpStore %1035 %1054
+ %1057 = OpAccessChain %_ptr_Function_float %color %uint_0
+ %1058 = OpConvertSToF %float %1028
+ %1059 = OpFAdd %float %1058 %1042
+ OpStore %1057 %1059
+ %1061 = OpLoad %int %959
+ OpStore %959 %int_0
+ OpStore %959 %1061
+ OpBranch %1012
+ %1012 = OpLabel
+ %1065 = OpLoad %float %995
+ OpStore %995 %float_0
+ OpStore %995 %1065
+ %1069 = OpAccessChain %_ptr_Function_float %uv %uint_0
+ %1071 = OpLoad %float %995
+ OpStore %995 %float_0
+ OpStore %995 %1071
+ %1075 = OpLoad %float %1069
+ %1077 = OpLoad %float %1069
+ OpStore %1069 %float_0
+ OpStore %1069 %1077
+ %1080 = OpCompositeExtract %float %989 2
+ %1081 = OpCompositeExtract %float %989 1
+ %1082 = OpCompositeExtract %float %989 1
+ %1083 = OpCompositeConstruct %v3float %1080 %1081 %1082
+ %1084 = OpLoad %v2float %uv
+ OpStore %uv %897
+ OpStore %uv %1084
+ %1086 = OpLoad %float %1069
+ OpStore %1069 %float_0
+ OpStore %1069 %1086
+ %1089 = OpCompositeExtract %float %897 1
+ %1090 = OpCompositeExtract %float %897 1
+ %1091 = OpCompositeConstruct %v2float %1089 %1090
+ %1093 = OpLoad %float %1069
+ OpStore %1069 %float_0
+ OpStore %1069 %1093
+ %1097 = OpFOrdGreaterThan %bool %1075 %float_0_5
+ OpSelectionMerge %1098 None
+ OpBranchConditional %1097 %1099 %1098
+ %1099 = OpLabel
+ %1101 = OpLoad %float %1069
+ OpStore %1069 %float_0
+ OpStore %1069 %1101
+ %1104 = OpCompositeExtract %float %917 0
+ %1105 = OpCompositeExtract %float %917 0
+ %1106 = OpCompositeConstruct %v2float %1104 %1105
+ %1108 = OpLoad %float %968
+ OpStore %968 %float_0
+ OpStore %968 %1108
+ %1113 = OpAccessChain %_ptr_Private_int %obj %uint_0 %uint_2
+ %1115 = OpLoad %float %968
+ OpStore %968 %float_0
+ OpStore %968 %1115
+ %1118 = OpCompositeExtract %float %989 0
+ %1119 = OpCompositeExtract %float %989 2
+ %1120 = OpCompositeExtract %float %1091 1
+ %1121 = OpCompositeConstruct %v3float %1118 %1119 %1120
+ %1123 = OpLoad %float %985
+ OpStore %985 %float_0
+ OpStore %985 %1123
+ %1127 = OpLoad %int %1113
+ %1129 = OpLoad %float %995
+ OpStore %995 %float_0
+ OpStore %995 %1129
+ %1133 = OpLoad %float %968
+ OpStore %968 %float_0
+ OpStore %968 %1133
+ %1137 = OpAccessChain %_ptr_Function_float %color %uint_1
+ %1139 = OpLoad %int %1113
+ OpStore %1113 %int_0
+ OpStore %1113 %1139
+ %1142 = OpCompositeExtract %float %949 1
+ %1143 = OpCompositeExtract %float %938 0
+ %1144 = OpCompositeConstruct %v2float %1142 %1143
+ %1146 = OpLoad %float %1137
+ OpStore %1137 %float_0
+ OpStore %1137 %1146
+ %1150 = OpLoad %float %1137
+ %1152 = OpLoad %int %1113
+ OpStore %1113 %int_0
+ OpStore %1113 %1152
+ %1155 = OpCompositeExtract %float %1121 0
+ %1156 = OpCompositeExtract %float %929 0
+ %1157 = OpCompositeConstruct %v2float %1155 %1156
+ %1159 = OpLoad %float %985
+ OpStore %985 %float_0
+ OpStore %985 %1159
+ %1162 = OpLoad %int %i_2
+ OpStore %i_2 %int_0
+ OpStore %i_2 %1162
+ %1163 = OpCompositeExtract %float %1004 1
+ %1164 = OpCompositeExtract %float %897 1
+ %1165 = OpCompositeConstruct %v2float %1163 %1164
+ %1166 = OpLoad %int %i_2
+ OpStore %i_2 %int_0
+ OpStore %i_2 %1166
+ %1167 = OpAccessChain %_ptr_Function_float %color %uint_1
+ %1168 = OpConvertSToF %float %1127
+ %1169 = OpFAdd %float %1168 %1150
+ OpStore %1167 %1169
+ %1171 = OpLoad %float %995
+ OpStore %995 %float_0
+ OpStore %995 %1171
+ OpBranch %1098
+ %1098 = OpLabel
+ %1175 = OpAccessChain %_ptr_Function_float %uv %int_0
+ %1176 = OpLoad %int %i_2
+ OpStore %i_2 %int_0
+ OpStore %i_2 %1176
+ %1177 = OpCompositeExtract %float %938 0
+ %1178 = OpCompositeExtract %float %938 0
+ %1179 = OpCompositeConstruct %v2float %1177 %1178
+ %1181 = OpLoad %float %1069
+ OpStore %1069 %float_0
+ OpStore %1069 %1181
+ %1185 = OpLoad %float %1175
+ %1186 = OpLoad %v3float %color
+ OpStore %color %909
+ OpStore %color %1186
+ %1188 = OpLoad %float %985
+ OpStore %985 %float_0
+ OpStore %985 %1188
+ %1192 = OpFOrdGreaterThan %bool %1185 %float_0_75
+ OpSelectionMerge %1193 None
+ OpBranchConditional %1192 %1194 %1193
+ %1194 = OpLabel
+ %1196 = OpLoad %float %968
+ OpStore %968 %float_0
+ OpStore %968 %1196
+ %1200 = OpAccessChain %_ptr_Private_int %obj %uint_0 %int_3
+ %1201 = OpLoad %int %1200
+ %1203 = OpLoad %float %985
+ OpStore %985 %float_0
+ OpStore %985 %1203
+ %1206 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %1206
+ %1207 = OpCompositeExtract %float %1179 0
+ %1208 = OpCompositeExtract %float %1179 0
+ %1209 = OpCompositeExtract %float %1179 0
+ %1210 = OpCompositeConstruct %v3float %1207 %1208 %1209
+ %1212 = OpLoad %float %1175
+ OpStore %1175 %float_0
+ OpStore %1175 %1212
+ %1216 = OpAccessChain %_ptr_Function_float %color %uint_2
+ %1218 = OpLoad %float %1069
+ OpStore %1069 %float_0
+ OpStore %1069 %1218
+ %1222 = OpLoad %float %1216
+ %1223 = OpLoad %v3float %color
+ OpStore %color %909
+ OpStore %color %1223
+ %1224 = OpCompositeExtract %float %1179 0
+ %1225 = OpCompositeExtract %float %938 1
+ %1226 = OpCompositeExtract %float %1179 1
+ %1227 = OpCompositeConstruct %v3float %1224 %1225 %1226
+ %1229 = OpLoad %float %1216
+ OpStore %1216 %float_0
+ OpStore %1216 %1229
+ %1233 = OpLoad %int %959
+ OpStore %959 %int_0
+ OpStore %959 %1233
+ %1236 = OpCompositeExtract %float %897 0
+ %1237 = OpCompositeExtract %float %897 1
+ %1238 = OpCompositeConstruct %v2float %1236 %1237
+ %1240 = OpLoad %float %1216
+ OpStore %1216 %float_0
+ OpStore %1216 %1240
+ %1243 = OpAccessChain %_ptr_Function_float %color %uint_2
+ %1244 = OpConvertSToF %float %1201
+ %1245 = OpFAdd %float %1222 %1244
+ OpStore %1243 %1245
+ %1246 = OpLoad %v2float %uv
+ OpStore %uv %897
+ OpStore %uv %1246
+ %1247 = OpCompositeExtract %float %1238 1
+ %1248 = OpCompositeExtract %float %1238 1
+ %1249 = OpCompositeConstruct %v2float %1247 %1248
+ OpBranch %1193
+ %1193 = OpLabel
+ %1251 = OpLoad %float %1175
+ OpStore %1175 %float_0
+ OpStore %1175 %1251
+ %1254 = OpCompositeExtract %float %999 0
+ %1255 = OpCompositeExtract %float %999 1
+ %1256 = OpCompositeExtract %float %999 1
+ %1257 = OpCompositeConstruct %v3float %1254 %1255 %1256
+ %1260 = OpAccessChain %_ptr_Private_int %obj %uint_0 %int_4
+ %1262 = OpLoad %int %1260
+ %1264 = OpLoad %float %1175
+ OpStore %1175 %float_0
+ OpStore %1175 %1264
+ %1267 = OpLoad %v3float %color
+ OpStore %color %909
+ OpStore %color %1267
+ %1268 = OpCompositeExtract %float %917 1
+ %1269 = OpCompositeExtract %float %989 0
+ %1270 = OpCompositeExtract %float %989 0
+ %1271 = OpCompositeConstruct %v3float %1268 %1269 %1270
+ %1273 = OpLoad %int %1260
+ OpStore %1260 %int_0
+ OpStore %1260 %1273
+ %1277 = OpAccessChain %_ptr_Function_float %color %uint_1
+ %1278 = OpCompositeExtract %float %938 0
+ %1279 = OpCompositeExtract %float %921 2
+ %1280 = OpCompositeConstruct %v2float %1278 %1279
+ %1282 = OpLoad %float %995
+ OpStore %995 %float_0
+ OpStore %995 %1282
+ %1286 = OpLoad %float %1277
+ %1288 = OpLoad %float %1277
+ OpStore %1277 %float_0
+ OpStore %1277 %1288
+ %1291 = OpCompositeExtract %float %1179 0
+ %1292 = OpCompositeExtract %float %949 0
+ %1293 = OpCompositeConstruct %v2float %1291 %1292
+ %1295 = OpLoad %float %1069
+ OpStore %1069 %float_0
+ OpStore %1069 %1295
+ %1299 = OpAccessChain %_ptr_Function_float %color %uint_1
+ %1301 = OpLoad %float %968
+ OpStore %968 %float_0
+ OpStore %968 %1301
+ %1304 = OpCompositeExtract %float %956 2
+ %1305 = OpCompositeExtract %float %1083 1
+ %1306 = OpCompositeConstruct %v2float %1304 %1305
+ %1308 = OpConvertSToF %float %1262
+ %1309 = OpFAdd %float %1286 %1308
+ OpStore %1299 %1309
+ %1310 = OpCompositeExtract %float %897 0
+ %1311 = OpCompositeExtract %float %1257 0
+ %1312 = OpCompositeExtract %float %897 1
+ %1313 = OpCompositeConstruct %v3float %1310 %1311 %1312
+ %1315 = OpLoad %float %995
+ OpStore %995 %float_0
+ OpStore %995 %1315
+ %1319 = OpAccessChain %_ptr_Function_float %uv %uint_1
+ %1321 = OpLoad %float %968
+ OpStore %968 %float_0
+ OpStore %968 %1321
+ %1324 = OpCompositeExtract %float %1257 0
+ %1325 = OpCompositeExtract %float %1257 1
+ %1326 = OpCompositeConstruct %v2float %1324 %1325
+ %1328 = OpLoad %float %1319
+ OpStore %1319 %float_0
+ OpStore %1319 %1328
+ %1332 = OpLoad %float %1319
+ %1333 = OpLoad %int %i_2
+ OpStore %i_2 %int_0
+ OpStore %i_2 %1333
+ %1334 = OpCompositeExtract %float %897 1
+ %1335 = OpCompositeExtract %float %999 1
+ %1336 = OpCompositeExtract %float %897 0
+ %1337 = OpCompositeConstruct %v3float %1334 %1335 %1336
+ %1339 = OpLoad %int %959
+ OpStore %959 %int_0
+ OpStore %959 %1339
+ %1343 = OpLoad %float %1299
+ OpStore %1299 %float_0
+ OpStore %1299 %1343
+ %1346 = OpCompositeExtract %float %917 0
+ %1347 = OpCompositeExtract %float %917 0
+ %1348 = OpCompositeExtract %float %897 1
+ %1349 = OpCompositeConstruct %v3float %1346 %1347 %1348
+ %1351 = OpLoad %float %995
+ OpStore %995 %float_0
+ OpStore %995 %1351
+ %1354 = OpFOrdGreaterThan %bool %1332 %float_0_25
+ OpSelectionMerge %1355 None
+ OpBranchConditional %1354 %1356 %1355
+ %1356 = OpLabel
+ %1357 = OpCompositeExtract %float %925 0
+ %1358 = OpCompositeExtract %float %1349 2
+ %1359 = OpCompositeConstruct %v2float %1357 %1358
+ %1360 = OpLoad %v3float %color
+ OpStore %color %909
+ OpStore %color %1360
+ %1362 = OpAccessChain %_ptr_Private_int %obj %uint_0 %uint_5
+ %1363 = OpLoad %int %1362
+ %1365 = OpLoad %float %968
+ OpStore %968 %float_0
+ OpStore %968 %1365
+ %1368 = OpLoad %int %i_2
+ OpStore %i_2 %int_0
+ OpStore %i_2 %1368
+ %1369 = OpLoad %int %i_2
+ OpStore %i_2 %int_0
+ OpStore %i_2 %1369
+ %1370 = OpAccessChain %_ptr_Function_float %color %uint_0
+ %1371 = OpLoad %float %1370
+ %1373 = OpLoad %float %1175
+ OpStore %1175 %float_0
+ OpStore %1175 %1373
+ %1376 = OpCompositeExtract %float %1004 0
+ %1377 = OpCompositeExtract %float %1293 1
+ %1378 = OpCompositeExtract %float %1004 1
+ %1379 = OpCompositeConstruct %v3float %1376 %1377 %1378
+ %1380 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %1380
+ %1382 = OpLoad %float %1319
+ OpStore %1319 %float_0
+ OpStore %1319 %1382
+ %1385 = OpLoad %int %i_2
+ OpStore %i_2 %int_0
+ OpStore %i_2 %1385
+ %1386 = OpCompositeExtract %float %921 3
+ %1387 = OpCompositeExtract %float %921 3
+ %1388 = OpCompositeExtract %float %945 0
+ %1389 = OpCompositeConstruct %v3float %1386 %1387 %1388
+ %1391 = OpLoad %float %995
+ OpStore %995 %float_0
+ OpStore %995 %1391
+ %1394 = OpAccessChain %_ptr_Function_float %color %uint_0
+ %1395 = OpConvertSToF %float %1363
+ %1396 = OpFAdd %float %1395 %1371
+ OpStore %1394 %1396
+ %1397 = OpCompositeExtract %float %999 1
+ %1398 = OpCompositeExtract %float %949 0
+ %1399 = OpCompositeExtract %float %999 1
+ %1400 = OpCompositeConstruct %v3float %1397 %1398 %1399
+ %1402 = OpLoad %float %995
+ OpStore %995 %float_0
+ OpStore %995 %1402
+ OpBranch %1355
+ %1355 = OpLabel
+ %1406 = OpLoad %float %968
+ OpStore %968 %float_0
+ OpStore %968 %1406
+ %1409 = OpCompositeExtract %float %1179 0
+ %1410 = OpCompositeExtract %float %949 1
+ %1411 = OpCompositeExtract %float %949 0
+ %1412 = OpCompositeConstruct %v3float %1409 %1410 %1411
+ %1414 = OpLoad %float %1319
+ OpStore %1319 %float_0
+ OpStore %1319 %1414
+ %1418 = OpAccessChain %_ptr_Function_float %uv %uint_1
+ %1420 = OpLoad %int %1260
+ OpStore %1260 %int_0
+ OpStore %1260 %1420
+ %1424 = OpLoad %float %1418
+ %1426 = OpLoad %int %959
+ OpStore %959 %int_0
+ OpStore %959 %1426
+ %1429 = OpFOrdGreaterThan %bool %1424 %float_0_5
+ OpSelectionMerge %1430 None
+ OpBranchConditional %1429 %1431 %1430
+ %1431 = OpLabel
+ %1433 = OpLoad %float %1069
+ OpStore %1069 %float_0
+ OpStore %1069 %1433
+ %1436 = OpCompositeExtract %float %1349 1
+ %1437 = OpCompositeExtract %float %1004 1
+ %1438 = OpCompositeConstruct %v2float %1436 %1437
+ %1441 = OpAccessChain %_ptr_Private_int %obj %uint_0 %uint_6
+ %1443 = OpLoad %float %1277
+ OpStore %1277 %float_0
+ OpStore %1277 %1443
+ %1446 = OpCompositeExtract %float %943 2
+ %1447 = OpCompositeExtract %float %943 1
+ %1448 = OpCompositeConstruct %v2float %1446 %1447
+ %1450 = OpLoad %float %1418
+ OpStore %1418 %float_0
+ OpStore %1418 %1450
+ %1454 = OpLoad %int %1441
+ %1456 = OpLoad %float %1319
+ OpStore %1319 %float_0
+ OpStore %1319 %1456
+ %1459 = OpLoad %int %i_2
+ OpStore %i_2 %int_0
+ OpStore %i_2 %1459
+ %1461 = OpLoad %int %1260
+ OpStore %1260 %int_0
+ OpStore %1260 %1461
+ %1464 = OpCompositeExtract %float %1271 2
+ %1465 = OpCompositeExtract %float %1271 1
+ %1466 = OpCompositeConstruct %v2float %1464 %1465
+ %1467 = OpAccessChain %_ptr_Function_float %color %uint_1
+ %1468 = OpLoad %float %1467
+ %1469 = OpLoad %v2float %uv
+ OpStore %uv %897
+ OpStore %uv %1469
+ %1471 = OpLoad %float %985
+ OpStore %985 %float_0
+ OpStore %985 %1471
+ %1474 = OpCompositeExtract %float %1293 1
+ %1475 = OpCompositeExtract %float %1293 0
+ %1476 = OpCompositeConstruct %v2float %1474 %1475
+ %1478 = OpLoad %int %1441
+ OpStore %1441 %int_0
+ OpStore %1441 %1478
+ %1482 = OpLoad %int %1441
+ OpStore %1441 %int_0
+ OpStore %1441 %1482
+ %1485 = OpCompositeExtract %float %1349 2
+ %1486 = OpCompositeExtract %float %1349 2
+ %1487 = OpCompositeConstruct %v2float %1485 %1486
+ %1488 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %1488
+ %1489 = OpAccessChain %_ptr_Function_float %color %uint_1
+ %1490 = OpConvertSToF %float %1454
+ %1491 = OpFAdd %float %1490 %1468
+ OpStore %1489 %1491
+ %1493 = OpLoad %float %985
+ OpStore %985 %float_0
+ OpStore %985 %1493
+ %1496 = OpCompositeExtract %float %35 1
+ %1497 = OpCompositeExtract %float %999 0
+ %1498 = OpCompositeConstruct %v2float %1496 %1497
+ %1500 = OpLoad %float %1299
+ OpStore %1299 %float_0
+ OpStore %1299 %1500
+ OpBranch %1430
+ %1430 = OpLabel
+ %1503 = OpCompositeExtract %float %1004 1
+ %1504 = OpCompositeExtract %float %1004 1
+ %1505 = OpCompositeConstruct %v2float %1503 %1504
+ %1507 = OpLoad %float %968
+ OpStore %968 %float_0
+ OpStore %968 %1507
+ %1511 = OpAccessChain %_ptr_Function_float %uv %uint_1
+ %1513 = OpLoad %float %1511
+ %1514 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %1514
+ %1515 = OpCompositeExtract %float %1293 0
+ %1516 = OpCompositeExtract %float %1293 1
+ %1517 = OpCompositeConstruct %v2float %1515 %1516
+ %1519 = OpLoad %float %1175
+ OpStore %1175 %float_0
+ OpStore %1175 %1519
+ %1523 = OpLoad %float %1299
+ OpStore %1299 %float_0
+ OpStore %1299 %1523
+ %1526 = OpCompositeExtract %float %938 0
+ %1527 = OpCompositeExtract %float %938 1
+ %1528 = OpCompositeExtract %float %938 1
+ %1529 = OpCompositeConstruct %v3float %1526 %1527 %1528
+ %1531 = OpLoad %int %1260
+ OpStore %1260 %int_0
+ OpStore %1260 %1531
+ %1534 = OpFOrdGreaterThan %bool %1513 %float_0_75
+ OpSelectionMerge %1535 None
+ OpBranchConditional %1534 %1536 %1535
+ %1536 = OpLabel
+ %1537 = OpLoad %v3float %color
+ OpStore %color %909
+ OpStore %color %1537
+ %1539 = OpLoad %float %985
+ OpStore %985 %float_0
+ OpStore %985 %1539
+ %1542 = OpCompositeExtract %float %945 1
+ %1543 = OpCompositeExtract %float %945 0
+ %1544 = OpCompositeExtract %float %945 1
+ %1545 = OpCompositeConstruct %v3float %1542 %1543 %1544
+ %1546 = OpLoad %v3float %color
+ OpStore %color %909
+ OpStore %color %1546
+ %1548 = OpAccessChain %_ptr_Private_int %obj %uint_0 %int_7
+ %1549 = OpLoad %int %1548
+ %1551 = OpLoad %float %1069
+ OpStore %1069 %float_0
+ OpStore %1069 %1551
+ %1554 = OpCompositeExtract %float %1293 0
+ %1555 = OpCompositeExtract %float %1179 1
+ %1556 = OpCompositeExtract %float %1179 0
+ %1557 = OpCompositeConstruct %v3float %1554 %1555 %1556
+ %1559 = OpLoad %float %1299
+ OpStore %1299 %float_0
+ OpStore %1299 %1559
+ %1562 = OpCompositeExtract %float %1313 0
+ %1563 = OpCompositeExtract %float %1091 1
+ %1564 = OpCompositeConstruct %v2float %1562 %1563
+ %1566 = OpLoad %int %959
+ OpStore %959 %int_0
+ OpStore %959 %1566
+ %1570 = OpLoad %float %1299
+ OpStore %1299 %float_0
+ OpStore %1299 %1570
+ %1573 = OpCompositeExtract %float %1326 0
+ %1574 = OpCompositeExtract %float %1326 1
+ %1575 = OpCompositeExtract %float %1326 0
+ %1576 = OpCompositeConstruct %v3float %1573 %1574 %1575
+ %1578 = OpLoad %float %968
+ OpStore %968 %float_0
+ OpStore %968 %1578
+ %1581 = OpAccessChain %_ptr_Function_float %color %uint_2
+ %1582 = OpLoad %float %1581
+ %1584 = OpLoad %float %1418
+ OpStore %1418 %float_0
+ OpStore %1418 %1584
+ %1587 = OpCompositeExtract %float %921 0
+ %1588 = OpCompositeExtract %float %921 1
+ %1589 = OpCompositeConstruct %v2float %1587 %1588
+ %1591 = OpLoad %float %995
+ OpStore %995 %float_0
+ OpStore %995 %1591
+ %1595 = OpLoad %float %1511
+ OpStore %1511 %float_0
+ OpStore %1511 %1595
+ %1599 = OpAccessChain %_ptr_Function_float %color %uint_2
+ %1601 = OpLoad %float %1418
+ OpStore %1418 %float_0
+ OpStore %1418 %1601
+ %1604 = OpCompositeExtract %float %1589 1
+ %1605 = OpCompositeExtract %float %1589 1
+ %1606 = OpCompositeExtract %float %1529 2
+ %1607 = OpCompositeConstruct %v3float %1604 %1605 %1606
+ %1609 = OpLoad %float %1599
+ OpStore %1599 %float_0
+ OpStore %1599 %1609
+ %1613 = OpConvertSToF %float %1549
+ %1614 = OpFAdd %float %1613 %1582
+ OpStore %1599 %1614
+ %1616 = OpLoad %float %1277
+ OpStore %1277 %float_0
+ OpStore %1277 %1616
+ %1619 = OpCompositeExtract %float %989 0
+ %1620 = OpCompositeExtract %float %989 2
+ %1621 = OpCompositeConstruct %v2float %1619 %1620
+ %1623 = OpLoad %float %968
+ OpStore %968 %float_0
+ OpStore %968 %1623
+ OpBranch %1535
+ %1535 = OpLabel
+ %1626 = OpLoad %int %i_2
+ OpStore %i_2 %int_0
+ OpStore %i_2 %1626
+ %1627 = OpCompositeExtract %float %956 1
+ %1628 = OpCompositeExtract %float %945 1
+ %1629 = OpCompositeConstruct %v2float %1627 %1628
+ %1630 = OpLoad %v2float %uv
+ OpStore %uv %897
+ OpStore %uv %1630
+ %1633 = OpAccessChain %_ptr_Private_int %obj %uint_0 %int_8
+ %1635 = OpLoad %int %1633
+ %1636 = OpLoad %int %i_2
+ OpStore %i_2 %int_0
+ OpStore %i_2 %1636
+ %1637 = OpCompositeExtract %float %929 0
+ %1638 = OpCompositeExtract %float %956 2
+ %1639 = OpCompositeConstruct %v2float %1637 %1638
+ %1641 = OpLoad %int %1633
+ OpStore %1633 %int_0
+ OpStore %1633 %1641
+ %1645 = OpLoad %float %1277
+ OpStore %1277 %float_0
+ OpStore %1277 %1645
+ %1648 = OpCompositeExtract %float %989 1
+ %1649 = OpCompositeExtract %float %897 0
+ %1650 = OpCompositeConstruct %v2float %1648 %1649
+ %1652 = OpLoad %float %968
+ OpStore %968 %float_0
+ OpStore %968 %1652
+ %1656 = OpAccessChain %_ptr_Function_float %color %uint_2
+ %1657 = OpCompositeExtract %float %1650 0
+ %1658 = OpCompositeExtract %float %1650 1
+ %1659 = OpCompositeExtract %float %1650 0
+ %1660 = OpCompositeConstruct %v3float %1657 %1658 %1659
+ %1662 = OpLoad %float %1656
+ OpStore %1656 %float_0
+ OpStore %1656 %1662
+ %1666 = OpLoad %float %1656
+ %1668 = OpLoad %float %985
+ OpStore %985 %float_0
+ OpStore %985 %1668
+ %1671 = OpCompositeExtract %float %1517 0
+ %1672 = OpCompositeExtract %float %1505 0
+ %1673 = OpCompositeConstruct %v2float %1671 %1672
+ %1675 = OpLoad %int %1260
+ OpStore %1260 %int_0
+ OpStore %1260 %1675
+ %1679 = OpLoad %float %1511
+ OpStore %1511 %float_0
+ OpStore %1511 %1679
+ %1682 = OpCompositeExtract %float %1091 0
+ %1683 = OpCompositeExtract %float %925 0
+ %1684 = OpCompositeConstruct %v2float %1682 %1683
+ %1686 = OpLoad %float %1299
+ OpStore %1299 %float_0
+ OpStore %1299 %1686
+ %1690 = OpAccessChain %_ptr_Function_float %color %uint_2
+ %1692 = OpConvertSToF %float %1635
+ %1693 = OpFAdd %float %1666 %1692
+ OpStore %1690 %1693
+ %1694 = OpLoad %v2float %uv
+ OpStore %uv %897
+ OpStore %uv %1694
+ %1696 = OpLoad %float %1069
+ OpStore %1069 %float_0
+ OpStore %1069 %1696
+ %1699 = OpCompositeExtract %float %1091 1
+ %1700 = OpCompositeExtract %float %1091 0
+ %1701 = OpCompositeExtract %float %1673 1
+ %1702 = OpCompositeConstruct %v3float %1699 %1700 %1701
+ %1704 = OpLoad %float %1069
+ OpStore %1069 %float_0
+ OpStore %1069 %1704
+ %1707 = OpAccessChain %_ptr_Function_float %uv %uint_0
+ %1708 = OpLoad %float %1707
+ %1710 = OpLoad %float %1299
+ OpStore %1299 %float_0
+ OpStore %1299 %1710
+ %1714 = OpAccessChain %_ptr_Function_float %uv %uint_1
+ %1715 = OpCompositeExtract %float %1639 1
+ %1716 = OpCompositeExtract %float %1639 0
+ %1717 = OpCompositeExtract %float %933 2
+ %1718 = OpCompositeConstruct %v3float %1715 %1716 %1717
+ %1720 = OpLoad %float %1319
+ OpStore %1319 %float_0
+ OpStore %1319 %1720
+ %1724 = OpLoad %float %1714
+ %1726 = OpLoad %float %1319
+ OpStore %1319 %float_0
+ OpStore %1319 %1726
+ %1730 = OpLoad %float %1690
+ OpStore %1690 %float_0
+ OpStore %1690 %1730
+ %1733 = OpCompositeExtract %float %35 1
+ %1734 = OpCompositeExtract %float %1412 1
+ %1735 = OpCompositeExtract %float %1412 2
+ %1736 = OpCompositeConstruct %v3float %1733 %1734 %1735
+ %1738 = OpLoad %float %1690
+ OpStore %1690 %float_0
+ OpStore %1690 %1738
+ %1741 = OpLoad %int %i_2
+ OpStore %i_2 %int_0
+ OpStore %i_2 %1741
+ %1742 = OpCompositeExtract %float %1412 2
+ %1743 = OpCompositeExtract %float %1412 1
+ %1744 = OpCompositeConstruct %v2float %1742 %1743
+ %1745 = OpLoad %v3float %color
+ OpStore %color %909
+ OpStore %color %1745
+ %1747 = OpLoad %float %1319
+ OpStore %1319 %float_0
+ OpStore %1319 %1747
+ %1750 = OpCompositeExtract %float %1004 1
+ %1751 = OpCompositeExtract %float %1004 1
+ %1752 = OpCompositeExtract %float %1004 1
+ %1753 = OpCompositeConstruct %v3float %1750 %1751 %1752
+ %1755 = OpLoad %int %1260
+ OpStore %1260 %int_0
+ OpStore %1260 %1755
+ %1760 = OpFSub %float %1708 %1724
+ %1758 = OpExtInst %float %1759 FAbs %1760
+ %1761 = OpFOrdLessThan %bool %1758 %float_0_25
+ OpSelectionMerge %1762 None
+ OpBranchConditional %1761 %1763 %1762
+ %1763 = OpLabel
+ %1765 = OpLoad %float %995
+ OpStore %995 %float_0
+ OpStore %995 %1765
+ %1768 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %1768
+ %1769 = OpCompositeExtract %float %1660 2
+ %1770 = OpCompositeExtract %float %1660 0
+ %1771 = OpCompositeExtract %float %933 0
+ %1772 = OpCompositeConstruct %v3float %1769 %1770 %1771
+ %1774 = OpLoad %int %1633
+ OpStore %1633 %int_0
+ OpStore %1633 %1774
+ %1778 = OpAccessChain %_ptr_Private_int %obj %uint_0 %uint_9
+ %1779 = OpLoad %int %1778
+ %1780 = OpCompositeExtract %float %1280 1
+ %1781 = OpCompositeExtract %float %1280 1
+ %1782 = OpCompositeExtract %float %1280 1
+ %1783 = OpCompositeConstruct %v3float %1780 %1781 %1782
+ %1785 = OpLoad %float %1319
+ OpStore %1319 %float_0
+ OpStore %1319 %1785
+ %1788 = OpAccessChain %_ptr_Function_float %color %uint_0
+ %1789 = OpLoad %float %1788
+ %1791 = OpLoad %float %1511
+ OpStore %1511 %float_0
+ OpStore %1511 %1791
+ %1794 = OpCompositeExtract %float %1629 0
+ %1795 = OpCompositeExtract %float %1629 1
+ %1796 = OpCompositeConstruct %v2float %1794 %1795
+ %1798 = OpLoad %float %968
+ OpStore %968 %float_0
+ OpStore %968 %1798
+ %1801 = OpLoad %v3float %color
+ OpStore %color %909
+ OpStore %color %1801
+ %1802 = OpCompositeExtract %float %981 0
+ %1803 = OpCompositeExtract %float %981 0
+ %1804 = OpCompositeConstruct %v2float %1802 %1803
+ %1805 = OpLoad %v2float %uv
+ OpStore %uv %897
+ OpStore %uv %1805
+ %1807 = OpAccessChain %_ptr_Function_float %color %uint_0
+ %1809 = OpLoad %float %995
+ OpStore %995 %float_0
+ OpStore %995 %1809
+ %1812 = OpCompositeExtract %float %897 0
+ %1813 = OpCompositeExtract %float %897 0
+ %1814 = OpCompositeExtract %float %897 1
+ %1815 = OpCompositeConstruct %v3float %1812 %1813 %1814
+ %1817 = OpConvertSToF %float %1779
+ %1818 = OpFAdd %float %1817 %1789
+ OpStore %1807 %1818
+ %1820 = OpLoad %float %1807
+ OpStore %1807 %float_0
+ OpStore %1807 %1820
+ %1823 = OpCompositeExtract %float %1349 1
+ %1824 = OpCompositeExtract %float %1702 0
+ %1825 = OpCompositeExtract %float %1349 0
+ %1826 = OpCompositeConstruct %v3float %1823 %1824 %1825
+ %1828 = OpLoad %float %968
+ OpStore %968 %float_0
+ OpStore %968 %1828
+ OpBranch %1762
+ %1762 = OpLabel
+ %1832 = OpLoad %float %1714
+ OpStore %1714 %float_0
+ OpStore %1714 %1832
+ %1835 = OpLoad %v3float %color
+ %1837 = OpLoad %float %1175
+ OpStore %1175 %float_0
+ OpStore %1175 %1837
+ %1840 = OpCompositeExtract %float %925 0
+ %1841 = OpCompositeExtract %float %917 0
+ %1842 = OpCompositeExtract %float %917 1
+ %1843 = OpCompositeConstruct %v3float %1840 %1841 %1842
+ %1844 = OpExtInst %v3float %1759 Normalize %1835
+ %1846 = OpLoad %float %995
+ OpStore %995 %float_0
+ OpStore %995 %1846
+ %1849 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %1849
+ %1850 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %1850
+ %1852 = OpLoad %float %1299
+ OpStore %1299 %float_0
+ OpStore %1299 %1852
+ %1855 = OpCompositeExtract %float %1673 1
+ %1856 = OpCompositeExtract %float %1843 1
+ %1857 = OpCompositeConstruct %v2float %1855 %1856
+ %1859 = OpLoad %float %1299
+ OpStore %1299 %float_0
+ OpStore %1299 %1859
+ %1862 = OpCompositeExtract %float %1844 0
+ %1863 = OpCompositeExtract %float %1844 1
+ %1864 = OpCompositeExtract %float %1844 2
+ %1865 = OpCompositeConstruct %v4float %1862 %1863 %1864 %float_1
+ %1867 = OpLoad %float %1714
+ OpStore %1714 %float_0
+ OpStore %1714 %1867
+ %1870 = OpCompositeExtract %float %35 1
+ %1871 = OpCompositeExtract %float %35 1
+ %1872 = OpCompositeExtract %float %1857 1
+ %1873 = OpCompositeConstruct %v3float %1870 %1871 %1872
+ %1875 = OpLoad %float %1069
+ OpStore %1069 %float_0
+ OpStore %1069 %1875
+ OpStore %x_GLF_color %1865
+ %1878 = OpLoad %QuicksortObject %obj
+ OpStore %obj %104
+ OpStore %obj %1878
+ %1879 = OpCompositeExtract %float %1865 3
+ %1880 = OpCompositeExtract %float %1865 1
+ %1881 = OpCompositeExtract %float %1517 0
+ %1882 = OpCompositeConstruct %v3float %1879 %1880 %1881
+ %1884 = OpLoad %float %985
+ OpStore %985 %float_0
+ OpStore %985 %1884
+ OpReturn
+ OpFunctionEnd
diff --git a/test/bug/tint/749.spvasm.expected.wgsl b/test/bug/tint/749.spvasm.expected.wgsl
index 17ceb49..48bb5b7 100644
--- a/test/bug/tint/749.spvasm.expected.wgsl
+++ b/test/bug/tint/749.spvasm.expected.wgsl
@@ -21,84 +21,84 @@
temp = 0;
temp = x_932;
let x_523 : vec3<f32> = vec3<f32>(vec3<f32>(1.0, 2.0, 3.0).z, vec3<f32>(1.0, 2.0, 3.0).y, vec3<f32>(1.0, 2.0, 3.0).z);
- let x_933 : i32 = i;
- i = 0;
- i = x_933;
- let x_28 : i32 = i;
- let x_934 : i32 = j;
- j = 0;
- j = x_934;
+ let x_933 : i32 = *(i);
+ *(i) = 0;
+ *(i) = x_933;
+ let x_28 : i32 = *(i);
+ let x_934 : i32 = *(j);
+ *(j) = 0;
+ *(j) = x_934;
let x_524 : vec3<f32> = vec3<f32>(x_523.y, x_523.x, x_523.y);
let x_935 : i32 = temp;
temp = 0;
temp = x_935;
- let x_30 : ptr<private, i32> = obj.numbers[x_28];
- let x_936 : i32 = x_30;
- x_30 = 0;
- x_30 = x_936;
- let x_31 : i32 = x_30;
+ let x_30 : ptr<private, i32> = &(obj.numbers[x_28]);
+ let x_936 : i32 = *(x_30);
+ *(x_30) = 0;
+ *(x_30) = x_936;
+ let x_31 : i32 = *(x_30);
let x_937 : i32 = temp;
temp = 0;
temp = x_937;
temp = x_31;
- let x_938 : i32 = j;
- j = 0;
- j = x_938;
+ let x_938 : i32 = *(j);
+ *(j) = 0;
+ *(j) = x_938;
let x_525 : vec3<f32> = vec3<f32>(x_523.z, vec3<f32>(1.0, 2.0, 3.0).x, x_523.y);
- let x_939 : i32 = i;
- i = 0;
- i = x_939;
- let x_32 : i32 = i;
- let x_940 : i32 = x_30;
- x_30 = 0;
- x_30 = x_940;
- let x_33 : i32 = j;
- let x_941 : i32 = i;
- i = 0;
- i = x_941;
+ let x_939 : i32 = *(i);
+ *(i) = 0;
+ *(i) = x_939;
+ let x_32 : i32 = *(i);
+ let x_940 : i32 = *(x_30);
+ *(x_30) = 0;
+ *(x_30) = x_940;
+ let x_33 : i32 = *(j);
+ let x_941 : i32 = *(i);
+ *(i) = 0;
+ *(i) = x_941;
let x_526 : vec3<f32> = vec3<f32>(x_525.x, x_525.z, x_525.z);
- let x_942 : i32 = x_30;
- x_30 = 0;
- x_30 = x_942;
- let x_34 : ptr<private, i32> = obj.numbers[x_33];
- let x_35 : i32 = x_34;
+ let x_942 : i32 = *(x_30);
+ *(x_30) = 0;
+ *(x_30) = x_942;
+ let x_34 : ptr<private, i32> = &(obj.numbers[x_33]);
+ let x_35 : i32 = *(x_34);
let x_943 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_943;
let x_527 : vec2<f32> = vec2<f32>(x_526.x, x_526.x);
- let x_36 : ptr<private, i32> = obj.numbers[x_32];
+ let x_36 : ptr<private, i32> = &(obj.numbers[x_32]);
let x_528 : vec3<f32> = vec3<f32>(x_524.x, x_524.z, x_524.x);
- x_36 = x_35;
+ *(x_36) = x_35;
let x_944 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_944;
let x_529 : vec3<f32> = vec3<f32>(x_526.y, x_526.z, x_526.x);
- let x_945 : i32 = i;
- i = 0;
- i = x_945;
- let x_37 : i32 = j;
+ let x_945 : i32 = *(i);
+ *(i) = 0;
+ *(i) = x_945;
+ let x_37 : i32 = *(j);
let x_946 : i32 = temp;
temp = 0;
temp = x_946;
let x_530 : vec2<f32> = vec2<f32>(x_529.z, x_529.y);
- let x_947 : i32 = x_34;
- x_34 = 0;
- x_34 = x_947;
+ let x_947 : i32 = *(x_34);
+ *(x_34) = 0;
+ *(x_34) = x_947;
let x_38 : i32 = temp;
- let x_948 : i32 = j;
- j = 0;
- j = x_948;
+ let x_948 : i32 = *(j);
+ *(j) = 0;
+ *(j) = x_948;
let x_531 : vec3<f32> = vec3<f32>(x_527.x, x_526.y, x_526.x);
- let x_949 : i32 = x_36;
- x_36 = 0;
- x_36 = x_949;
+ let x_949 : i32 = *(x_36);
+ *(x_36) = 0;
+ *(x_36) = x_949;
let x_950 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_950;
let x_532 : vec3<f32> = vec3<f32>(x_528.x, x_528.y, x_528.x);
- let x_951 : i32 = x_34;
- x_34 = 0;
- x_34 = x_951;
+ let x_951 : i32 = *(x_34);
+ *(x_34) = 0;
+ *(x_34) = x_951;
obj.numbers[x_37] = x_38;
return;
}
@@ -113,18 +113,18 @@
var pivot : i32;
var x_537 : vec2<f32>;
var x_538 : vec3<f32>;
- let x_952 : i32 = h;
- h = 0;
- h = x_952;
- let x_41 : i32 = h;
- let x_953 : i32 = l;
- l = 0;
- l = x_953;
- let x_42 : ptr<private, i32> = obj.numbers[x_41];
- let x_954 : i32 = x_42;
- x_42 = 0;
- x_42 = x_954;
- let x_43 : i32 = x_42;
+ let x_952 : i32 = *(h);
+ *(h) = 0;
+ *(h) = x_952;
+ let x_41 : i32 = *(h);
+ let x_953 : i32 = *(l);
+ *(l) = 0;
+ *(l) = x_953;
+ let x_42 : ptr<private, i32> = &(obj.numbers[x_41]);
+ let x_954 : i32 = *(x_42);
+ *(x_42) = 0;
+ *(x_42) = x_954;
+ let x_43 : i32 = *(x_42);
let x_955 : i32 = param_3;
param_3 = 0;
param_3 = x_955;
@@ -133,19 +133,19 @@
param_1 = 0;
param_1 = x_956;
pivot = x_43;
- let x_45 : i32 = l;
- let x_957 : i32 = h;
- h = 0;
- h = x_957;
+ let x_45 : i32 = *(l);
+ let x_957 : i32 = *(h);
+ *(h) = 0;
+ *(h) = x_957;
let x_958 : i32 = j_1;
j_1 = 0;
j_1 = x_958;
let x_535 : vec3<f32> = vec3<f32>(x_534.y, x_534.z, x_534.y);
- let x_959 : i32 = l;
- l = 0;
- l = x_959;
+ let x_959 : i32 = *(l);
+ *(l) = 0;
+ *(l) = x_959;
i_1 = (x_45 - bitcast<i32>(1u));
- let x_49 : i32 = l;
+ let x_49 : i32 = *(l);
let x_536 : vec3<f32> = vec3<f32>(x_534.x, x_534.z, x_535.x);
j_1 = 10;
let x_960 : QuicksortObject = obj;
@@ -166,10 +166,10 @@
let x_964 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_964;
- let x_56 : i32 = h;
- let x_965 : i32 = h;
- h = 0;
- h = x_965;
+ let x_56 : i32 = *(h);
+ let x_965 : i32 = *(h);
+ *(h) = 0;
+ *(h) = x_965;
let x_966 : i32 = param;
param = 0;
param = x_966;
@@ -185,18 +185,18 @@
break;
}
let x_60 : i32 = j_1;
- let x_969 : i32 = x_42;
- x_42 = 0;
- x_42 = x_969;
- let x_61 : ptr<private, i32> = obj.numbers[x_60];
- let x_970 : i32 = h;
- h = 0;
- h = x_970;
+ let x_969 : i32 = *(x_42);
+ *(x_42) = 0;
+ *(x_42) = x_969;
+ let x_61 : ptr<private, i32> = &(obj.numbers[x_60]);
+ let x_970 : i32 = *(h);
+ *(h) = 0;
+ *(h) = x_970;
let x_539 : vec3<f32> = vec3<f32>(x_537.x, x_535.z, x_537.x);
let x_971 : i32 = param_1;
param_1 = 0;
param_1 = x_971;
- let x_62 : i32 = x_61;
+ let x_62 : i32 = *(x_61);
let x_972 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_972;
@@ -205,9 +205,9 @@
let x_973 : i32 = i_1;
i_1 = 0;
i_1 = x_973;
- let x_974 : i32 = l;
- l = 0;
- l = x_974;
+ let x_974 : i32 = *(l);
+ *(l) = 0;
+ *(l) = x_974;
let x_541 : vec3<f32> = vec3<f32>(x_534.y, x_534.x, x_534.y);
let x_975 : i32 = pivot;
pivot = 0;
@@ -229,9 +229,9 @@
param = 0;
param = x_979;
i_1 = (x_67 + bitcast<i32>(1u));
- let x_980 : i32 = l;
- l = 0;
- l = x_980;
+ let x_980 : i32 = *(l);
+ *(l) = 0;
+ *(l) = x_980;
let x_544 : vec3<f32> = vec3<f32>(vec3<f32>(1.0, 2.0, 3.0).z, vec3<f32>(1.0, 2.0, 3.0).y, x_540.x);
let x_70 : i32 = i_1;
let x_545 : vec2<f32> = vec2<f32>(x_537.y, x_538.x);
@@ -251,7 +251,7 @@
let x_984 : i32 = param_3;
param_3 = 0;
param_3 = x_984;
- swap_i1_i1_(param, param_1);
+ swap_i1_i1_(&(param), &(param_1));
let x_985 : i32 = param_1;
param_1 = 0;
param_1 = x_985;
@@ -261,17 +261,17 @@
obj = x_986;
continuing {
- let x_987 : i32 = h;
- h = 0;
- h = x_987;
+ let x_987 : i32 = *(h);
+ *(h) = 0;
+ *(h) = x_987;
let x_74 : i32 = j_1;
- let x_988 : i32 = h;
- h = 0;
- h = x_988;
+ let x_988 : i32 = *(h);
+ *(h) = 0;
+ *(h) = x_988;
let x_547 : vec3<f32> = vec3<f32>(x_539.x, x_541.z, x_541.z);
- let x_989 : i32 = x_61;
- x_61 = 0;
- x_61 = x_989;
+ let x_989 : i32 = *(x_61);
+ *(x_61) = 0;
+ *(x_61) = x_989;
let x_990 : i32 = param;
param = 0;
param = x_990;
@@ -280,22 +280,22 @@
param_1 = 0;
param_1 = x_991;
let x_548 : vec3<f32> = vec3<f32>(x_541.y, x_541.z, x_541.x);
- let x_992 : i32 = x_61;
- x_61 = 0;
- x_61 = x_992;
+ let x_992 : i32 = *(x_61);
+ *(x_61) = 0;
+ *(x_61) = x_992;
}
}
let x_76 : i32 = i_1;
- let x_993 : i32 = x_42;
- x_42 = 0;
- x_42 = x_993;
+ let x_993 : i32 = *(x_42);
+ *(x_42) = 0;
+ *(x_42) = x_993;
let x_549 : vec2<f32> = vec2<f32>(x_534.x, x_534.y);
let x_994 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_994;
- let x_995 : i32 = h;
- h = 0;
- h = x_995;
+ let x_995 : i32 = *(h);
+ *(h) = 0;
+ *(h) = x_995;
i_1 = (1 + x_76);
let x_996 : i32 = param_1;
param_1 = 0;
@@ -313,23 +313,23 @@
let x_999 : i32 = pivot;
pivot = 0;
pivot = x_999;
- let x_81 : i32 = h;
+ let x_81 : i32 = *(h);
let x_552 : vec2<f32> = vec2<f32>(x_550.x, x_549.y);
- let x_1000 : i32 = h;
- h = 0;
- h = x_1000;
+ let x_1000 : i32 = *(h);
+ *(h) = 0;
+ *(h) = x_1000;
param_3 = x_81;
let x_1001 : i32 = i_1;
i_1 = 0;
i_1 = x_1001;
let x_553 : vec2<f32> = vec2<f32>(x_549.y, x_552.x);
- let x_1002 : i32 = h;
- h = 0;
- h = x_1002;
- swap_i1_i1_(param_2, param_3);
- let x_1003 : i32 = l;
- l = 0;
- l = x_1003;
+ let x_1002 : i32 = *(h);
+ *(h) = 0;
+ *(h) = x_1002;
+ swap_i1_i1_(&(param_2), &(param_3));
+ let x_1003 : i32 = *(l);
+ *(l) = 0;
+ *(l) = x_1003;
let x_554 : vec2<f32> = vec2<f32>(x_536.z, vec3<f32>(1.0, 2.0, 3.0).y);
let x_1004 : i32 = param_1;
param_1 = 0;
@@ -395,7 +395,7 @@
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_1016;
let x_560 : vec3<f32> = vec3<f32>(x_559.y, x_559.x, x_557.x);
- let x_96 : ptr<function, i32> = stack[x_94];
+ let x_96 : ptr<function, i32> = &(stack[x_94]);
let x_1017 : array<i32, 10> = stack;
stack = array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
stack = x_1017;
@@ -403,7 +403,7 @@
let x_1018 : i32 = l_1;
l_1 = 0;
l_1 = 0;
- x_96 = x_95;
+ *(x_96) = x_95;
let x_1019 : i32 = param_5;
param_5 = 0;
param_5 = x_1019;
@@ -412,13 +412,13 @@
param_4 = 0;
param_4 = x_1020;
let x_562 : vec3<f32> = vec3<f32>(vec3<f32>(1.0, 2.0, 3.0).z, x_558.y, vec3<f32>(1.0, 2.0, 3.0).y);
- let x_1021 : i32 = x_96;
- x_96 = 0;
- x_96 = x_1021;
+ let x_1021 : i32 = *(x_96);
+ *(x_96) = 0;
+ *(x_96) = x_1021;
let x_98 : i32 = (x_97 + 1);
- let x_1022 : i32 = x_96;
- x_96 = 0;
- x_96 = x_1022;
+ let x_1022 : i32 = *(x_96);
+ *(x_96) = 0;
+ *(x_96) = x_1022;
let x_563 : vec3<f32> = vec3<f32>(x_559.x, x_559.z, x_556.y);
top = x_98;
let x_1023 : i32 = param_4;
@@ -432,7 +432,7 @@
let x_1025 : i32 = l_1;
l_1 = 0;
l_1 = x_1025;
- let x_100 : ptr<function, i32> = stack[x_98];
+ let x_100 : ptr<function, i32> = &(stack[x_98]);
let x_1026 : i32 = param_5;
param_5 = 0;
param_5 = x_1026;
@@ -440,7 +440,7 @@
let x_1027 : i32 = p;
p = 0;
p = x_1027;
- x_100 = x_99;
+ *(x_100) = x_99;
loop {
let x_566 : vec3<f32> = vec3<f32>(x_563.x, x_563.x, x_563.x);
let x_1028 : i32 = h_1;
@@ -481,11 +481,11 @@
let x_1036 : i32 = p;
p = 0;
p = x_1036;
- let x_110 : ptr<function, i32> = stack[x_108];
- let x_1037 : i32 = x_96;
- x_96 = 0;
- x_96 = x_1037;
- let x_111 : i32 = x_110;
+ let x_110 : ptr<function, i32> = &(stack[x_108]);
+ let x_1037 : i32 = *(x_96);
+ *(x_96) = 0;
+ *(x_96) = x_1037;
+ let x_111 : i32 = *(x_110);
let x_1038 : array<i32, 10> = stack;
stack = array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
stack = x_1038;
@@ -505,9 +505,9 @@
let x_1042 : i32 = param_4;
param_4 = 0;
param_4 = x_1042;
- let x_1043 : i32 = x_100;
- x_100 = 0;
- x_100 = x_1043;
+ let x_1043 : i32 = *(x_100);
+ *(x_100) = 0;
+ *(x_100) = x_1043;
let x_573 : vec2<f32> = vec2<f32>(vec3<f32>(1.0, 2.0, 3.0).y, vec3<f32>(1.0, 2.0, 3.0).z);
top = (x_112 - 1);
let x_1044 : i32 = param_5;
@@ -517,12 +517,12 @@
let x_1045 : i32 = h_1;
h_1 = 0;
h_1 = x_1045;
- let x_114 : ptr<function, i32> = stack[x_112];
+ let x_114 : ptr<function, i32> = &(stack[x_112]);
let x_575 : vec2<f32> = vec2<f32>(x_564.y, x_564.z);
- let x_1046 : i32 = x_100;
- x_100 = 0;
- x_100 = x_1046;
- let x_115 : i32 = x_114;
+ let x_1046 : i32 = *(x_100);
+ *(x_100) = 0;
+ *(x_100) = x_1046;
+ let x_115 : i32 = *(x_114);
let x_1047 : i32 = p;
p = 0;
p = x_1047;
@@ -536,17 +536,17 @@
top = x_1049;
let x_118 : i32 = l_1;
param_4 = x_118;
- let x_1050 : i32 = x_110;
- x_110 = 0;
- x_110 = x_1050;
+ let x_1050 : i32 = *(x_110);
+ *(x_110) = 0;
+ *(x_110) = x_1050;
let x_577 : vec2<f32> = vec2<f32>(x_569.y, x_569.z);
let x_120 : i32 = h_1;
let x_578 : vec2<f32> = vec2<f32>(x_558.x, vec3<f32>(1.0, 2.0, 3.0).y);
param_5 = x_120;
- let x_1051 : i32 = x_100;
- x_100 = 0;
- x_100 = x_1051;
- let x_121 : i32 = performPartition_i1_i1_(param_4, param_5);
+ let x_1051 : i32 = *(x_100);
+ *(x_100) = 0;
+ *(x_100) = x_1051;
+ let x_121 : i32 = performPartition_i1_i1_(&(param_4), &(param_5));
let x_579 : vec2<f32> = vec2<f32>(x_567.x, x_568.x);
let x_1052 : i32 = param_5;
param_5 = 0;
@@ -567,59 +567,59 @@
h_1 = 0;
h_1 = x_1056;
let x_124 : i32 = l_1;
- let x_1057 : i32 = x_110;
- x_110 = 0;
- x_110 = x_1057;
+ let x_1057 : i32 = *(x_110);
+ *(x_110) = 0;
+ *(x_110) = x_1057;
let x_1058 : i32 = h_1;
h_1 = 0;
h_1 = x_1058;
let x_582 : vec2<f32> = vec2<f32>(x_567.y, x_573.x);
- let x_1059 : i32 = x_100;
- x_100 = 0;
- x_100 = x_1059;
+ let x_1059 : i32 = *(x_100);
+ *(x_100) = 0;
+ *(x_100) = x_1059;
if (((x_122 - bitcast<i32>(1u)) > x_124)) {
let x_1060 : i32 = param_4;
param_4 = 0;
param_4 = x_1060;
let x_128 : i32 = top;
let x_583 : vec2<f32> = vec2<f32>(x_571.y, x_556.y);
- let x_1061 : i32 = x_100;
- x_100 = 0;
- x_100 = x_1061;
+ let x_1061 : i32 = *(x_100);
+ *(x_100) = 0;
+ *(x_100) = x_1061;
let x_1062 : array<i32, 10> = stack;
stack = array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
stack = x_1062;
let x_584 : vec2<f32> = vec2<f32>(x_569.z, x_569.y);
let x_585 : vec3<f32> = vec3<f32>(x_580.y, x_577.x, x_577.x);
let x_130 : i32 = l_1;
- let x_1063 : i32 = x_114;
- x_114 = 0;
- x_114 = x_1063;
+ let x_1063 : i32 = *(x_114);
+ *(x_114) = 0;
+ *(x_114) = x_1063;
let x_586 : vec2<f32> = vec2<f32>(x_564.x, x_585.x);
let x_1064 : i32 = param_5;
param_5 = 0;
param_5 = x_1064;
- let x_131 : ptr<function, i32> = stack[(1 + x_128)];
- let x_1065 : i32 = x_110;
- x_110 = 0;
- x_110 = x_1065;
+ let x_131 : ptr<function, i32> = &(stack[(1 + x_128)]);
+ let x_1065 : i32 = *(x_110);
+ *(x_110) = 0;
+ *(x_110) = x_1065;
let x_587 : vec3<f32> = vec3<f32>(x_566.y, x_566.y, x_563.x);
let x_1066 : i32 = param_5;
param_5 = 0;
param_5 = x_1066;
- x_131 = x_130;
+ *(x_131) = x_130;
let x_132 : i32 = top;
- let x_1067 : i32 = x_100;
- x_100 = 0;
- x_100 = x_1067;
+ let x_1067 : i32 = *(x_100);
+ *(x_100) = 0;
+ *(x_100) = x_1067;
let x_588 : vec2<f32> = vec2<f32>(x_575.y, x_575.x);
- let x_1068 : i32 = x_131;
- x_131 = 0;
- x_131 = x_1068;
+ let x_1068 : i32 = *(x_131);
+ *(x_131) = 0;
+ *(x_131) = x_1068;
let x_133 : i32 = bitcast<i32>((1u + bitcast<u32>(x_132)));
- let x_1069 : i32 = x_100;
- x_100 = 0;
- x_100 = x_1069;
+ let x_1069 : i32 = *(x_100);
+ *(x_100) = 0;
+ *(x_100) = x_1069;
let x_589 : vec3<f32> = vec3<f32>(x_576.z, x_588.y, x_576.z);
let x_1070 : i32 = h_1;
h_1 = 0;
@@ -630,73 +630,73 @@
stack = x_1071;
let x_134 : i32 = p;
let x_590 : vec2<f32> = vec2<f32>(x_576.x, x_573.y);
- let x_1072 : i32 = x_114;
- x_114 = 0;
- x_114 = x_1072;
- let x_136 : ptr<function, i32> = stack[x_133];
- let x_1073 : i32 = x_114;
- x_114 = 0;
- x_114 = x_1073;
- x_136 = (x_134 - bitcast<i32>(1u));
- let x_1074 : i32 = x_96;
- x_96 = 0;
- x_96 = x_1074;
+ let x_1072 : i32 = *(x_114);
+ *(x_114) = 0;
+ *(x_114) = x_1072;
+ let x_136 : ptr<function, i32> = &(stack[x_133]);
+ let x_1073 : i32 = *(x_114);
+ *(x_114) = 0;
+ *(x_114) = x_1073;
+ *(x_136) = (x_134 - bitcast<i32>(1u));
+ let x_1074 : i32 = *(x_96);
+ *(x_96) = 0;
+ *(x_96) = x_1074;
let x_591 : vec2<f32> = vec2<f32>(x_569.z, x_569.y);
- let x_1075 : i32 = x_136;
- x_136 = 0;
- x_136 = x_1075;
+ let x_1075 : i32 = *(x_136);
+ *(x_136) = 0;
+ *(x_136) = x_1075;
}
- let x_1076 : i32 = x_96;
- x_96 = 0;
- x_96 = x_1076;
+ let x_1076 : i32 = *(x_96);
+ *(x_96) = 0;
+ *(x_96) = x_1076;
let x_592 : vec2<f32> = vec2<f32>(vec3<f32>(1.0, 2.0, 3.0).x, vec3<f32>(1.0, 2.0, 3.0).y);
let x_1077 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_1077;
let x_137 : i32 = p;
- let x_1078 : i32 = x_114;
- x_114 = 0;
- x_114 = x_1078;
+ let x_1078 : i32 = *(x_114);
+ *(x_114) = 0;
+ *(x_114) = x_1078;
let x_593 : vec3<f32> = vec3<f32>(x_571.z, x_556.x, x_556.y);
let x_1079 : i32 = p;
p = 0;
p = x_1079;
let x_594 : vec3<f32> = vec3<f32>(x_563.z, x_563.x, x_575.x);
- let x_1080 : i32 = x_114;
- x_114 = 0;
- x_114 = x_1080;
+ let x_1080 : i32 = *(x_114);
+ *(x_114) = 0;
+ *(x_114) = x_1080;
let x_139 : i32 = h_1;
let x_1081 : i32 = top;
top = 0;
top = x_1081;
let x_595 : vec3<f32> = vec3<f32>(x_560.z, x_568.x, x_560.x);
- let x_1082 : i32 = x_100;
- x_100 = 0;
- x_100 = x_1082;
+ let x_1082 : i32 = *(x_100);
+ *(x_100) = 0;
+ *(x_100) = x_1082;
let x_1083 : i32 = p;
p = 0;
p = x_1083;
if ((bitcast<i32>((1u + bitcast<u32>(x_137))) < x_139)) {
- let x_1084 : i32 = x_114;
- x_114 = 0;
- x_114 = x_1084;
+ let x_1084 : i32 = *(x_114);
+ *(x_114) = 0;
+ *(x_114) = x_1084;
let x_596 : vec2<f32> = vec2<f32>(x_592.y, x_582.x);
let x_1085 : i32 = l_1;
l_1 = 0;
l_1 = x_1085;
let x_143 : i32 = top;
- let x_1086 : i32 = x_114;
- x_114 = 0;
- x_114 = x_1086;
+ let x_1086 : i32 = *(x_114);
+ *(x_114) = 0;
+ *(x_114) = x_1086;
let x_597 : vec3<f32> = vec3<f32>(x_562.y, x_560.y, x_560.y);
let x_144 : i32 = (x_143 + 1);
let x_1087 : i32 = param_5;
param_5 = 0;
param_5 = x_1087;
top = x_144;
- let x_1088 : i32 = x_114;
- x_114 = 0;
- x_114 = x_1088;
+ let x_1088 : i32 = *(x_114);
+ *(x_114) = 0;
+ *(x_114) = x_1088;
let x_145 : i32 = p;
let x_1089 : i32 = param_5;
param_5 = 0;
@@ -706,53 +706,53 @@
p = 0;
p = x_1090;
let x_600 : vec3<f32> = vec3<f32>(x_556.x, x_580.x, x_580.x);
- let x_1091 : i32 = x_100;
- x_100 = 0;
- x_100 = x_1091;
- let x_147 : ptr<function, i32> = stack[x_144];
- let x_1092 : i32 = x_110;
- x_110 = 0;
- x_110 = x_1092;
+ let x_1091 : i32 = *(x_100);
+ *(x_100) = 0;
+ *(x_100) = x_1091;
+ let x_147 : ptr<function, i32> = &(stack[x_144]);
+ let x_1092 : i32 = *(x_110);
+ *(x_110) = 0;
+ *(x_110) = x_1092;
let x_601 : vec2<f32> = vec2<f32>(x_563.x, x_563.y);
- x_147 = bitcast<i32>((1u + bitcast<u32>(x_145)));
+ *(x_147) = bitcast<i32>((1u + bitcast<u32>(x_145)));
let x_1093 : array<i32, 10> = stack;
stack = array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
stack = x_1093;
let x_148 : i32 = top;
- let x_1094 : i32 = x_114;
- x_114 = 0;
- x_114 = x_1094;
+ let x_1094 : i32 = *(x_114);
+ *(x_114) = 0;
+ *(x_114) = x_1094;
let x_602 : vec2<f32> = vec2<f32>(x_565.y, x_599.y);
let x_1095 : array<i32, 10> = stack;
stack = array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
stack = x_1095;
let x_149 : i32 = (x_148 + bitcast<i32>(1u));
- let x_1096 : i32 = x_147;
- x_147 = 0;
- x_147 = x_1096;
+ let x_1096 : i32 = *(x_147);
+ *(x_147) = 0;
+ *(x_147) = x_1096;
top = x_149;
let x_1097 : i32 = param_4;
param_4 = 0;
param_4 = x_1097;
let x_150 : i32 = h_1;
- let x_1098 : i32 = x_100;
- x_100 = 0;
- x_100 = x_1098;
- let x_1099 : i32 = x_96;
- x_96 = 0;
- x_96 = x_1099;
+ let x_1098 : i32 = *(x_100);
+ *(x_100) = 0;
+ *(x_100) = x_1098;
+ let x_1099 : i32 = *(x_96);
+ *(x_96) = 0;
+ *(x_96) = x_1099;
stack[x_149] = x_150;
- let x_1100 : i32 = x_114;
- x_114 = 0;
- x_114 = x_1100;
+ let x_1100 : i32 = *(x_114);
+ *(x_114) = 0;
+ *(x_114) = x_1100;
let x_603 : vec3<f32> = vec3<f32>(x_568.y, x_564.x, x_564.x);
let x_1101 : i32 = l_1;
l_1 = 0;
l_1 = x_1101;
}
- let x_1102 : i32 = x_100;
- x_100 = 0;
- x_100 = x_1102;
+ let x_1102 : i32 = *(x_100);
+ *(x_100) = 0;
+ *(x_100) = x_1102;
continuing {
let x_1103 : i32 = l_1;
@@ -854,22 +854,22 @@
let x_769 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_769;
- let x_200 : ptr<private, i32> = obj.numbers[0u];
- let x_770 : i32 = x_200;
- x_200 = 0;
- x_200 = x_770;
- let x_201 : i32 = x_200;
+ let x_200 : ptr<private, i32> = &(obj.numbers[0u]);
+ let x_770 : i32 = *(x_200);
+ *(x_200) = 0;
+ *(x_200) = x_770;
+ let x_201 : i32 = *(x_200);
let x_771 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_771;
- let x_205 : ptr<function, f32> = color.x;
- let x_772 : i32 = x_200;
- x_200 = 0;
- x_200 = x_772;
- let x_206 : f32 = x_205;
- let x_773 : f32 = x_205;
- x_205 = 0.0;
- x_205 = x_773;
+ let x_205 : ptr<function, f32> = &(color.x);
+ let x_772 : i32 = *(x_200);
+ *(x_200) = 0;
+ *(x_200) = x_772;
+ let x_206 : f32 = *(x_205);
+ let x_773 : f32 = *(x_205);
+ *(x_205) = 0.0;
+ *(x_205) = x_773;
let x_452 : vec2<f32> = vec2<f32>(vec3<f32>(1.0, 2.0, 3.0).z, vec3<f32>(1.0, 2.0, 3.0).y);
let x_774 : i32 = i_2;
i_2 = 0;
@@ -877,22 +877,22 @@
let x_775 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_775;
- let x_208 : ptr<function, f32> = color.x;
+ let x_208 : ptr<function, f32> = &(color.x);
let x_453 : vec3<f32> = vec3<f32>(x_451.x, x_450.x, x_450.y);
- x_208 = (x_206 + f32(x_201));
+ *(x_208) = (x_206 + f32(x_201));
let x_776 : vec2<f32> = uv;
uv = vec2<f32>(0.0, 0.0);
uv = x_776;
- let x_209 : ptr<function, f32> = uv.x;
+ let x_209 : ptr<function, f32> = &(uv.x);
let x_777 : vec2<f32> = uv;
uv = vec2<f32>(0.0, 0.0);
uv = x_777;
let x_454 : vec2<f32> = vec2<f32>(x_184.y, x_184.y);
- let x_210 : f32 = x_209;
+ let x_210 : f32 = *(x_209);
let x_455 : vec2<f32> = vec2<f32>(x_192.y, x_192.x);
- let x_778 : f32 = x_209;
- x_209 = 0.0;
- x_209 = x_778;
+ let x_778 : f32 = *(x_209);
+ *(x_209) = 0.0;
+ *(x_209) = x_778;
let x_779 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_779;
@@ -900,13 +900,13 @@
let x_780 : i32 = i_2;
i_2 = 0;
i_2 = x_780;
- let x_781 : i32 = x_200;
- x_200 = 0;
- x_200 = x_781;
+ let x_781 : i32 = *(x_200);
+ *(x_200) = 0;
+ *(x_200) = x_781;
let x_456 : vec3<f32> = vec3<f32>(vec2<f32>(0.0, 0.0).y, x_448.y, x_448.y);
- let x_782 : f32 = x_209;
- x_209 = 0.0;
- x_209 = x_782;
+ let x_782 : f32 = *(x_209);
+ *(x_209) = 0.0;
+ *(x_209) = x_782;
let x_216 : i32 = obj.numbers[1];
let x_783 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
@@ -915,7 +915,7 @@
let x_784 : vec2<f32> = uv;
uv = vec2<f32>(0.0, 0.0);
uv = x_784;
- let x_218 : ptr<function, f32> = color[0];
+ let x_218 : ptr<function, f32> = &(color[0]);
let x_785 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_785;
@@ -923,10 +923,10 @@
let x_786 : i32 = i_2;
i_2 = 0;
i_2 = x_786;
- let x_219 : f32 = x_218;
- let x_787 : f32 = x_218;
- x_218 = 0.0;
- x_218 = x_787;
+ let x_219 : f32 = *(x_218);
+ let x_787 : f32 = *(x_218);
+ *(x_218) = 0.0;
+ *(x_218) = x_787;
let x_788 : vec3<f32> = color;
color = vec3<f32>(0.0, 0.0, 0.0);
color = x_788;
@@ -934,75 +934,75 @@
color = vec3<f32>(0.0, 0.0, 0.0);
color = x_789;
let x_459 : vec3<f32> = vec3<f32>(x_454.y, x_454.y, x_447.y);
- let x_790 : f32 = x_218;
- x_218 = 0.0;
- x_218 = x_790;
+ let x_790 : f32 = *(x_218);
+ *(x_218) = 0.0;
+ *(x_218) = x_790;
color.x = (f32(x_216) + x_219);
- let x_791 : i32 = x_200;
- x_200 = 0;
- x_200 = x_791;
+ let x_791 : i32 = *(x_200);
+ *(x_200) = 0;
+ *(x_200) = x_791;
}
- let x_792 : f32 = x_209;
- x_209 = 0.0;
- x_209 = x_792;
- let x_222 : ptr<function, f32> = uv.x;
- let x_793 : f32 = x_209;
- x_209 = 0.0;
- x_209 = x_793;
- let x_223 : f32 = x_222;
- let x_794 : f32 = x_222;
- x_222 = 0.0;
- x_222 = x_794;
+ let x_792 : f32 = *(x_209);
+ *(x_209) = 0.0;
+ *(x_209) = x_792;
+ let x_222 : ptr<function, f32> = &(uv.x);
+ let x_793 : f32 = *(x_209);
+ *(x_209) = 0.0;
+ *(x_209) = x_793;
+ let x_223 : f32 = *(x_222);
+ let x_794 : f32 = *(x_222);
+ *(x_222) = 0.0;
+ *(x_222) = x_794;
let x_460 : vec3<f32> = vec3<f32>(x_453.z, x_453.y, x_453.y);
let x_795 : vec2<f32> = uv;
uv = vec2<f32>(0.0, 0.0);
uv = x_795;
- let x_796 : f32 = x_222;
- x_222 = 0.0;
- x_222 = x_796;
+ let x_796 : f32 = *(x_222);
+ *(x_222) = 0.0;
+ *(x_222) = x_796;
let x_461 : vec2<f32> = vec2<f32>(vec2<f32>(0.0, 0.0).y, vec2<f32>(0.0, 0.0).y);
- let x_797 : f32 = x_222;
- x_222 = 0.0;
- x_222 = x_797;
+ let x_797 : f32 = *(x_222);
+ *(x_222) = 0.0;
+ *(x_222) = x_797;
if ((x_223 > 0.5)) {
- let x_798 : f32 = x_222;
- x_222 = 0.0;
- x_222 = x_798;
+ let x_798 : f32 = *(x_222);
+ *(x_222) = 0.0;
+ *(x_222) = x_798;
let x_462 : vec2<f32> = vec2<f32>(x_446.x, x_446.x);
- let x_799 : f32 = x_205;
- x_205 = 0.0;
- x_205 = x_799;
- let x_229 : ptr<private, i32> = obj.numbers[2u];
- let x_800 : f32 = x_205;
- x_205 = 0.0;
- x_205 = x_800;
+ let x_799 : f32 = *(x_205);
+ *(x_205) = 0.0;
+ *(x_205) = x_799;
+ let x_229 : ptr<private, i32> = &(obj.numbers[2u]);
+ let x_800 : f32 = *(x_205);
+ *(x_205) = 0.0;
+ *(x_205) = x_800;
let x_463 : vec3<f32> = vec3<f32>(x_453.x, x_453.z, x_461.y);
- let x_801 : f32 = x_208;
- x_208 = 0.0;
- x_208 = x_801;
- let x_230 : i32 = x_229;
- let x_802 : f32 = x_209;
- x_209 = 0.0;
- x_209 = x_802;
- let x_803 : f32 = x_205;
- x_205 = 0.0;
- x_205 = x_803;
- let x_233 : ptr<function, f32> = color.y;
- let x_804 : i32 = x_229;
- x_229 = 0;
- x_229 = x_804;
+ let x_801 : f32 = *(x_208);
+ *(x_208) = 0.0;
+ *(x_208) = x_801;
+ let x_230 : i32 = *(x_229);
+ let x_802 : f32 = *(x_209);
+ *(x_209) = 0.0;
+ *(x_209) = x_802;
+ let x_803 : f32 = *(x_205);
+ *(x_205) = 0.0;
+ *(x_205) = x_803;
+ let x_233 : ptr<function, f32> = &(color.y);
+ let x_804 : i32 = *(x_229);
+ *(x_229) = 0;
+ *(x_229) = x_804;
let x_464 : vec2<f32> = vec2<f32>(x_450.y, x_191.x);
- let x_805 : f32 = x_233;
- x_233 = 0.0;
- x_233 = x_805;
- let x_234 : f32 = x_233;
- let x_806 : i32 = x_229;
- x_229 = 0;
- x_229 = x_806;
+ let x_805 : f32 = *(x_233);
+ *(x_233) = 0.0;
+ *(x_233) = x_805;
+ let x_234 : f32 = *(x_233);
+ let x_806 : i32 = *(x_229);
+ *(x_229) = 0;
+ *(x_229) = x_806;
let x_465 : vec2<f32> = vec2<f32>(x_463.x, x_185.x);
- let x_807 : f32 = x_208;
- x_208 = 0.0;
- x_208 = x_807;
+ let x_807 : f32 = *(x_208);
+ *(x_208) = 0.0;
+ *(x_208) = x_807;
let x_808 : i32 = i_2;
i_2 = 0;
i_2 = x_808;
@@ -1011,136 +1011,136 @@
i_2 = 0;
i_2 = x_809;
color.y = (f32(x_230) + x_234);
- let x_810 : f32 = x_209;
- x_209 = 0.0;
- x_209 = x_810;
+ let x_810 : f32 = *(x_209);
+ *(x_209) = 0.0;
+ *(x_209) = x_810;
}
- let x_237 : ptr<function, f32> = uv[0];
+ let x_237 : ptr<function, f32> = &(uv[0]);
let x_811 : i32 = i_2;
i_2 = 0;
i_2 = x_811;
let x_467 : vec2<f32> = vec2<f32>(x_191.x, x_191.x);
- let x_812 : f32 = x_222;
- x_222 = 0.0;
- x_222 = x_812;
- let x_238 : f32 = x_237;
+ let x_812 : f32 = *(x_222);
+ *(x_222) = 0.0;
+ *(x_222) = x_812;
+ let x_238 : f32 = *(x_237);
let x_813 : vec3<f32> = color;
color = vec3<f32>(0.0, 0.0, 0.0);
color = x_813;
- let x_814 : f32 = x_208;
- x_208 = 0.0;
- x_208 = x_814;
+ let x_814 : f32 = *(x_208);
+ *(x_208) = 0.0;
+ *(x_208) = x_814;
if ((x_238 > 0.75)) {
- let x_815 : f32 = x_205;
- x_205 = 0.0;
- x_205 = x_815;
+ let x_815 : f32 = *(x_205);
+ *(x_205) = 0.0;
+ *(x_205) = x_815;
let x_245 : i32 = obj.numbers[3];
- let x_816 : f32 = x_208;
- x_208 = 0.0;
- x_208 = x_816;
+ let x_816 : f32 = *(x_208);
+ *(x_208) = 0.0;
+ *(x_208) = x_816;
let x_817 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_817;
let x_468 : vec3<f32> = vec3<f32>(x_467.x, x_467.x, x_467.x);
- let x_818 : f32 = x_237;
- x_237 = 0.0;
- x_237 = x_818;
- let x_248 : ptr<function, f32> = color.z;
- let x_819 : f32 = x_222;
- x_222 = 0.0;
- x_222 = x_819;
- let x_249 : f32 = x_248;
+ let x_818 : f32 = *(x_237);
+ *(x_237) = 0.0;
+ *(x_237) = x_818;
+ let x_248 : ptr<function, f32> = &(color.z);
+ let x_819 : f32 = *(x_222);
+ *(x_222) = 0.0;
+ *(x_222) = x_819;
+ let x_249 : f32 = *(x_248);
let x_820 : vec3<f32> = color;
color = vec3<f32>(0.0, 0.0, 0.0);
color = x_820;
let x_469 : vec3<f32> = vec3<f32>(x_467.x, x_191.y, x_467.y);
- let x_821 : f32 = x_248;
- x_248 = 0.0;
- x_248 = x_821;
- let x_822 : i32 = x_200;
- x_200 = 0;
- x_200 = x_822;
+ let x_821 : f32 = *(x_248);
+ *(x_248) = 0.0;
+ *(x_248) = x_821;
+ let x_822 : i32 = *(x_200);
+ *(x_200) = 0;
+ *(x_200) = x_822;
let x_470 : vec2<f32> = vec2<f32>(vec2<f32>(0.0, 0.0).x, vec2<f32>(0.0, 0.0).y);
- let x_823 : f32 = x_248;
- x_248 = 0.0;
- x_248 = x_823;
+ let x_823 : f32 = *(x_248);
+ *(x_248) = 0.0;
+ *(x_248) = x_823;
color.z = (x_249 + f32(x_245));
let x_824 : vec2<f32> = uv;
uv = vec2<f32>(0.0, 0.0);
uv = x_824;
let x_471 : vec2<f32> = vec2<f32>(x_470.y, x_470.y);
}
- let x_825 : f32 = x_237;
- x_237 = 0.0;
- x_237 = x_825;
+ let x_825 : f32 = *(x_237);
+ *(x_237) = 0.0;
+ *(x_237) = x_825;
let x_472 : vec3<f32> = vec3<f32>(x_454.x, x_454.y, x_454.y);
- let x_253 : ptr<private, i32> = obj.numbers[4];
- let x_254 : i32 = x_253;
- let x_826 : f32 = x_237;
- x_237 = 0.0;
- x_237 = x_826;
+ let x_253 : ptr<private, i32> = &(obj.numbers[4]);
+ let x_254 : i32 = *(x_253);
+ let x_826 : f32 = *(x_237);
+ *(x_237) = 0.0;
+ *(x_237) = x_826;
let x_827 : vec3<f32> = color;
color = vec3<f32>(0.0, 0.0, 0.0);
color = x_827;
let x_473 : vec3<f32> = vec3<f32>(x_446.y, x_453.x, x_453.x);
- let x_828 : i32 = x_253;
- x_253 = 0;
- x_253 = x_828;
- let x_256 : ptr<function, f32> = color.y;
+ let x_828 : i32 = *(x_253);
+ *(x_253) = 0;
+ *(x_253) = x_828;
+ let x_256 : ptr<function, f32> = &(color.y);
let x_474 : vec2<f32> = vec2<f32>(x_191.x, x_184.z);
- let x_829 : f32 = x_209;
- x_209 = 0.0;
- x_209 = x_829;
- let x_257 : f32 = x_256;
- let x_830 : f32 = x_256;
- x_256 = 0.0;
- x_256 = x_830;
+ let x_829 : f32 = *(x_209);
+ *(x_209) = 0.0;
+ *(x_209) = x_829;
+ let x_257 : f32 = *(x_256);
+ let x_830 : f32 = *(x_256);
+ *(x_256) = 0.0;
+ *(x_256) = x_830;
let x_475 : vec2<f32> = vec2<f32>(x_467.x, x_450.x);
- let x_831 : f32 = x_222;
- x_222 = 0.0;
- x_222 = x_831;
- let x_259 : ptr<function, f32> = color.y;
- let x_832 : f32 = x_205;
- x_205 = 0.0;
- x_205 = x_832;
+ let x_831 : f32 = *(x_222);
+ *(x_222) = 0.0;
+ *(x_222) = x_831;
+ let x_259 : ptr<function, f32> = &(color.y);
+ let x_832 : f32 = *(x_205);
+ *(x_205) = 0.0;
+ *(x_205) = x_832;
let x_476 : vec2<f32> = vec2<f32>(x_451.z, x_460.y);
- x_259 = (x_257 + f32(x_254));
+ *(x_259) = (x_257 + f32(x_254));
let x_477 : vec3<f32> = vec3<f32>(vec2<f32>(0.0, 0.0).x, x_472.x, vec2<f32>(0.0, 0.0).y);
- let x_833 : f32 = x_209;
- x_209 = 0.0;
- x_209 = x_833;
- let x_260 : ptr<function, f32> = uv.y;
- let x_834 : f32 = x_205;
- x_205 = 0.0;
- x_205 = x_834;
+ let x_833 : f32 = *(x_209);
+ *(x_209) = 0.0;
+ *(x_209) = x_833;
+ let x_260 : ptr<function, f32> = &(uv.y);
+ let x_834 : f32 = *(x_205);
+ *(x_205) = 0.0;
+ *(x_205) = x_834;
let x_478 : vec2<f32> = vec2<f32>(x_472.x, x_472.y);
- let x_835 : f32 = x_260;
- x_260 = 0.0;
- x_260 = x_835;
- let x_261 : f32 = x_260;
+ let x_835 : f32 = *(x_260);
+ *(x_260) = 0.0;
+ *(x_260) = x_835;
+ let x_261 : f32 = *(x_260);
let x_836 : i32 = i_2;
i_2 = 0;
i_2 = x_836;
let x_479 : vec3<f32> = vec3<f32>(vec2<f32>(0.0, 0.0).y, x_454.y, vec2<f32>(0.0, 0.0).x);
- let x_837 : i32 = x_200;
- x_200 = 0;
- x_200 = x_837;
- let x_838 : f32 = x_259;
- x_259 = 0.0;
- x_259 = x_838;
+ let x_837 : i32 = *(x_200);
+ *(x_200) = 0;
+ *(x_200) = x_837;
+ let x_838 : f32 = *(x_259);
+ *(x_259) = 0.0;
+ *(x_259) = x_838;
let x_480 : vec3<f32> = vec3<f32>(x_446.x, x_446.x, vec2<f32>(0.0, 0.0).y);
- let x_839 : f32 = x_209;
- x_209 = 0.0;
- x_209 = x_839;
+ let x_839 : f32 = *(x_209);
+ *(x_209) = 0.0;
+ *(x_209) = x_839;
if ((x_261 > 0.25)) {
let x_481 : vec2<f32> = vec2<f32>(x_447.x, x_480.z);
let x_840 : vec3<f32> = color;
color = vec3<f32>(0.0, 0.0, 0.0);
color = x_840;
let x_267 : i32 = obj.numbers[5u];
- let x_841 : f32 = x_205;
- x_205 = 0.0;
- x_205 = x_841;
+ let x_841 : f32 = *(x_205);
+ *(x_205) = 0.0;
+ *(x_205) = x_841;
let x_842 : i32 = i_2;
i_2 = 0;
i_2 = x_842;
@@ -1148,172 +1148,172 @@
i_2 = 0;
i_2 = x_843;
let x_270 : f32 = color.x;
- let x_844 : f32 = x_237;
- x_237 = 0.0;
- x_237 = x_844;
+ let x_844 : f32 = *(x_237);
+ *(x_237) = 0.0;
+ *(x_237) = x_844;
let x_482 : vec3<f32> = vec3<f32>(x_455.x, x_475.y, x_455.y);
let x_845 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_845;
- let x_846 : f32 = x_260;
- x_260 = 0.0;
- x_260 = x_846;
+ let x_846 : f32 = *(x_260);
+ *(x_260) = 0.0;
+ *(x_260) = x_846;
let x_847 : i32 = i_2;
i_2 = 0;
i_2 = x_847;
let x_483 : vec3<f32> = vec3<f32>(x_184.w, x_184.w, x_192.x);
- let x_848 : f32 = x_209;
- x_209 = 0.0;
- x_209 = x_848;
+ let x_848 : f32 = *(x_209);
+ *(x_209) = 0.0;
+ *(x_209) = x_848;
color.x = (f32(x_267) + x_270);
let x_484 : vec3<f32> = vec3<f32>(x_454.y, x_450.x, x_454.y);
- let x_849 : f32 = x_209;
- x_209 = 0.0;
- x_209 = x_849;
+ let x_849 : f32 = *(x_209);
+ *(x_209) = 0.0;
+ *(x_209) = x_849;
}
- let x_850 : f32 = x_205;
- x_205 = 0.0;
- x_205 = x_850;
+ let x_850 : f32 = *(x_205);
+ *(x_205) = 0.0;
+ *(x_205) = x_850;
let x_485 : vec3<f32> = vec3<f32>(x_467.x, x_450.y, x_450.x);
- let x_851 : f32 = x_260;
- x_260 = 0.0;
- x_260 = x_851;
- let x_273 : ptr<function, f32> = uv.y;
- let x_852 : i32 = x_253;
- x_253 = 0;
- x_253 = x_852;
- let x_274 : f32 = x_273;
- let x_853 : i32 = x_200;
- x_200 = 0;
- x_200 = x_853;
+ let x_851 : f32 = *(x_260);
+ *(x_260) = 0.0;
+ *(x_260) = x_851;
+ let x_273 : ptr<function, f32> = &(uv.y);
+ let x_852 : i32 = *(x_253);
+ *(x_253) = 0;
+ *(x_253) = x_852;
+ let x_274 : f32 = *(x_273);
+ let x_853 : i32 = *(x_200);
+ *(x_200) = 0;
+ *(x_200) = x_853;
if ((x_274 > 0.5)) {
- let x_854 : f32 = x_222;
- x_222 = 0.0;
- x_222 = x_854;
+ let x_854 : f32 = *(x_222);
+ *(x_222) = 0.0;
+ *(x_222) = x_854;
let x_486 : vec2<f32> = vec2<f32>(x_480.y, x_455.y);
- let x_279 : ptr<private, i32> = obj.numbers[6u];
- let x_855 : f32 = x_256;
- x_256 = 0.0;
- x_256 = x_855;
+ let x_279 : ptr<private, i32> = &(obj.numbers[6u]);
+ let x_855 : f32 = *(x_256);
+ *(x_256) = 0.0;
+ *(x_256) = x_855;
let x_487 : vec2<f32> = vec2<f32>(x_449.z, x_449.y);
- let x_856 : f32 = x_273;
- x_273 = 0.0;
- x_273 = x_856;
- let x_280 : i32 = x_279;
- let x_857 : f32 = x_260;
- x_260 = 0.0;
- x_260 = x_857;
+ let x_856 : f32 = *(x_273);
+ *(x_273) = 0.0;
+ *(x_273) = x_856;
+ let x_280 : i32 = *(x_279);
+ let x_857 : f32 = *(x_260);
+ *(x_260) = 0.0;
+ *(x_260) = x_857;
let x_858 : i32 = i_2;
i_2 = 0;
i_2 = x_858;
- let x_859 : i32 = x_253;
- x_253 = 0;
- x_253 = x_859;
+ let x_859 : i32 = *(x_253);
+ *(x_253) = 0;
+ *(x_253) = x_859;
let x_488 : vec2<f32> = vec2<f32>(x_473.z, x_473.y);
let x_283 : f32 = color.y;
let x_860 : vec2<f32> = uv;
uv = vec2<f32>(0.0, 0.0);
uv = x_860;
- let x_861 : f32 = x_208;
- x_208 = 0.0;
- x_208 = x_861;
+ let x_861 : f32 = *(x_208);
+ *(x_208) = 0.0;
+ *(x_208) = x_861;
let x_489 : vec2<f32> = vec2<f32>(x_475.y, x_475.x);
- let x_862 : i32 = x_279;
- x_279 = 0;
- x_279 = x_862;
- let x_863 : i32 = x_279;
- x_279 = 0;
- x_279 = x_863;
+ let x_862 : i32 = *(x_279);
+ *(x_279) = 0;
+ *(x_279) = x_862;
+ let x_863 : i32 = *(x_279);
+ *(x_279) = 0;
+ *(x_279) = x_863;
let x_490 : vec2<f32> = vec2<f32>(x_480.z, x_480.z);
let x_864 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_864;
color.y = (f32(x_280) + x_283);
- let x_865 : f32 = x_208;
- x_208 = 0.0;
- x_208 = x_865;
+ let x_865 : f32 = *(x_208);
+ *(x_208) = 0.0;
+ *(x_208) = x_865;
let x_491 : vec2<f32> = vec2<f32>(vec3<f32>(1.0, 2.0, 3.0).y, x_454.x);
- let x_866 : f32 = x_259;
- x_259 = 0.0;
- x_259 = x_866;
+ let x_866 : f32 = *(x_259);
+ *(x_259) = 0.0;
+ *(x_259) = x_866;
}
let x_492 : vec2<f32> = vec2<f32>(x_455.y, x_455.y);
- let x_867 : f32 = x_205;
- x_205 = 0.0;
- x_205 = x_867;
- let x_286 : ptr<function, f32> = uv.y;
- let x_287 : f32 = x_286;
+ let x_867 : f32 = *(x_205);
+ *(x_205) = 0.0;
+ *(x_205) = x_867;
+ let x_286 : ptr<function, f32> = &(uv.y);
+ let x_287 : f32 = *(x_286);
let x_868 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_868;
let x_493 : vec2<f32> = vec2<f32>(x_475.x, x_475.y);
- let x_869 : f32 = x_237;
- x_237 = 0.0;
- x_237 = x_869;
- let x_870 : f32 = x_259;
- x_259 = 0.0;
- x_259 = x_870;
+ let x_869 : f32 = *(x_237);
+ *(x_237) = 0.0;
+ *(x_237) = x_869;
+ let x_870 : f32 = *(x_259);
+ *(x_259) = 0.0;
+ *(x_259) = x_870;
let x_494 : vec3<f32> = vec3<f32>(x_191.x, x_191.y, x_191.y);
- let x_871 : i32 = x_253;
- x_253 = 0;
- x_253 = x_871;
+ let x_871 : i32 = *(x_253);
+ *(x_253) = 0;
+ *(x_253) = x_871;
if ((x_287 > 0.75)) {
let x_872 : vec3<f32> = color;
color = vec3<f32>(0.0, 0.0, 0.0);
color = x_872;
- let x_873 : f32 = x_208;
- x_208 = 0.0;
- x_208 = x_873;
+ let x_873 : f32 = *(x_208);
+ *(x_208) = 0.0;
+ *(x_208) = x_873;
let x_495 : vec3<f32> = vec3<f32>(x_192.y, x_192.x, x_192.y);
let x_874 : vec3<f32> = color;
color = vec3<f32>(0.0, 0.0, 0.0);
color = x_874;
let x_293 : i32 = obj.numbers[7];
- let x_875 : f32 = x_222;
- x_222 = 0.0;
- x_222 = x_875;
+ let x_875 : f32 = *(x_222);
+ *(x_222) = 0.0;
+ *(x_222) = x_875;
let x_496 : vec3<f32> = vec3<f32>(x_475.x, x_467.y, x_467.x);
- let x_876 : f32 = x_259;
- x_259 = 0.0;
- x_259 = x_876;
+ let x_876 : f32 = *(x_259);
+ *(x_259) = 0.0;
+ *(x_259) = x_876;
let x_497 : vec2<f32> = vec2<f32>(x_477.x, x_461.y);
- let x_877 : i32 = x_200;
- x_200 = 0;
- x_200 = x_877;
- let x_878 : f32 = x_259;
- x_259 = 0.0;
- x_259 = x_878;
+ let x_877 : i32 = *(x_200);
+ *(x_200) = 0;
+ *(x_200) = x_877;
+ let x_878 : f32 = *(x_259);
+ *(x_259) = 0.0;
+ *(x_259) = x_878;
let x_498 : vec3<f32> = vec3<f32>(x_478.x, x_478.y, x_478.x);
- let x_879 : f32 = x_205;
- x_205 = 0.0;
- x_205 = x_879;
+ let x_879 : f32 = *(x_205);
+ *(x_205) = 0.0;
+ *(x_205) = x_879;
let x_296 : f32 = color.z;
- let x_880 : f32 = x_273;
- x_273 = 0.0;
- x_273 = x_880;
+ let x_880 : f32 = *(x_273);
+ *(x_273) = 0.0;
+ *(x_273) = x_880;
let x_499 : vec2<f32> = vec2<f32>(x_184.x, x_184.y);
- let x_881 : f32 = x_209;
- x_209 = 0.0;
- x_209 = x_881;
- let x_882 : f32 = x_286;
- x_286 = 0.0;
- x_286 = x_882;
- let x_298 : ptr<function, f32> = color.z;
- let x_883 : f32 = x_273;
- x_273 = 0.0;
- x_273 = x_883;
+ let x_881 : f32 = *(x_209);
+ *(x_209) = 0.0;
+ *(x_209) = x_881;
+ let x_882 : f32 = *(x_286);
+ *(x_286) = 0.0;
+ *(x_286) = x_882;
+ let x_298 : ptr<function, f32> = &(color.z);
+ let x_883 : f32 = *(x_273);
+ *(x_273) = 0.0;
+ *(x_273) = x_883;
let x_500 : vec3<f32> = vec3<f32>(x_499.y, x_499.y, x_494.z);
- let x_884 : f32 = x_298;
- x_298 = 0.0;
- x_298 = x_884;
- x_298 = (f32(x_293) + x_296);
- let x_885 : f32 = x_256;
- x_256 = 0.0;
- x_256 = x_885;
+ let x_884 : f32 = *(x_298);
+ *(x_298) = 0.0;
+ *(x_298) = x_884;
+ *(x_298) = (f32(x_293) + x_296);
+ let x_885 : f32 = *(x_256);
+ *(x_256) = 0.0;
+ *(x_256) = x_885;
let x_501 : vec2<f32> = vec2<f32>(x_453.x, x_453.z);
- let x_886 : f32 = x_205;
- x_205 = 0.0;
- x_205 = x_886;
+ let x_886 : f32 = *(x_205);
+ *(x_205) = 0.0;
+ *(x_205) = x_886;
}
let x_887 : i32 = i_2;
i_2 = 0;
@@ -1322,74 +1322,74 @@
let x_888 : vec2<f32> = uv;
uv = vec2<f32>(0.0, 0.0);
uv = x_888;
- let x_300 : ptr<private, i32> = obj.numbers[8];
- let x_301 : i32 = x_300;
+ let x_300 : ptr<private, i32> = &(obj.numbers[8]);
+ let x_301 : i32 = *(x_300);
let x_889 : i32 = i_2;
i_2 = 0;
i_2 = x_889;
let x_503 : vec2<f32> = vec2<f32>(x_185.x, x_451.z);
- let x_890 : i32 = x_300;
- x_300 = 0;
- x_300 = x_890;
- let x_891 : f32 = x_256;
- x_256 = 0.0;
- x_256 = x_891;
+ let x_890 : i32 = *(x_300);
+ *(x_300) = 0;
+ *(x_300) = x_890;
+ let x_891 : f32 = *(x_256);
+ *(x_256) = 0.0;
+ *(x_256) = x_891;
let x_504 : vec2<f32> = vec2<f32>(x_453.y, vec2<f32>(0.0, 0.0).x);
- let x_892 : f32 = x_205;
- x_205 = 0.0;
- x_205 = x_892;
- let x_303 : ptr<function, f32> = color.z;
+ let x_892 : f32 = *(x_205);
+ *(x_205) = 0.0;
+ *(x_205) = x_892;
+ let x_303 : ptr<function, f32> = &(color.z);
let x_505 : vec3<f32> = vec3<f32>(x_504.x, x_504.y, x_504.x);
- let x_893 : f32 = x_303;
- x_303 = 0.0;
- x_303 = x_893;
- let x_304 : f32 = x_303;
- let x_894 : f32 = x_208;
- x_208 = 0.0;
- x_208 = x_894;
+ let x_893 : f32 = *(x_303);
+ *(x_303) = 0.0;
+ *(x_303) = x_893;
+ let x_304 : f32 = *(x_303);
+ let x_894 : f32 = *(x_208);
+ *(x_208) = 0.0;
+ *(x_208) = x_894;
let x_506 : vec2<f32> = vec2<f32>(x_493.x, x_492.x);
- let x_895 : i32 = x_253;
- x_253 = 0;
- x_253 = x_895;
- let x_896 : f32 = x_286;
- x_286 = 0.0;
- x_286 = x_896;
+ let x_895 : i32 = *(x_253);
+ *(x_253) = 0;
+ *(x_253) = x_895;
+ let x_896 : f32 = *(x_286);
+ *(x_286) = 0.0;
+ *(x_286) = x_896;
let x_507 : vec2<f32> = vec2<f32>(x_461.x, x_447.x);
- let x_897 : f32 = x_259;
- x_259 = 0.0;
- x_259 = x_897;
- let x_306 : ptr<function, f32> = color.z;
- x_306 = (x_304 + f32(x_301));
+ let x_897 : f32 = *(x_259);
+ *(x_259) = 0.0;
+ *(x_259) = x_897;
+ let x_306 : ptr<function, f32> = &(color.z);
+ *(x_306) = (x_304 + f32(x_301));
let x_898 : vec2<f32> = uv;
uv = vec2<f32>(0.0, 0.0);
uv = x_898;
- let x_899 : f32 = x_222;
- x_222 = 0.0;
- x_222 = x_899;
+ let x_899 : f32 = *(x_222);
+ *(x_222) = 0.0;
+ *(x_222) = x_899;
let x_508 : vec3<f32> = vec3<f32>(x_461.y, x_461.x, x_506.y);
- let x_900 : f32 = x_222;
- x_222 = 0.0;
- x_222 = x_900;
+ let x_900 : f32 = *(x_222);
+ *(x_222) = 0.0;
+ *(x_222) = x_900;
let x_308 : f32 = uv.x;
- let x_901 : f32 = x_259;
- x_259 = 0.0;
- x_259 = x_901;
- let x_309 : ptr<function, f32> = uv.y;
+ let x_901 : f32 = *(x_259);
+ *(x_259) = 0.0;
+ *(x_259) = x_901;
+ let x_309 : ptr<function, f32> = &(uv.y);
let x_509 : vec3<f32> = vec3<f32>(x_503.y, x_503.x, x_448.z);
- let x_902 : f32 = x_260;
- x_260 = 0.0;
- x_260 = x_902;
- let x_310 : f32 = x_309;
- let x_903 : f32 = x_260;
- x_260 = 0.0;
- x_260 = x_903;
- let x_904 : f32 = x_306;
- x_306 = 0.0;
- x_306 = x_904;
+ let x_902 : f32 = *(x_260);
+ *(x_260) = 0.0;
+ *(x_260) = x_902;
+ let x_310 : f32 = *(x_309);
+ let x_903 : f32 = *(x_260);
+ *(x_260) = 0.0;
+ *(x_260) = x_903;
+ let x_904 : f32 = *(x_306);
+ *(x_306) = 0.0;
+ *(x_306) = x_904;
let x_510 : vec3<f32> = vec3<f32>(vec3<f32>(1.0, 2.0, 3.0).y, x_485.y, x_485.z);
- let x_905 : f32 = x_306;
- x_306 = 0.0;
- x_306 = x_905;
+ let x_905 : f32 = *(x_306);
+ *(x_306) = 0.0;
+ *(x_306) = x_905;
let x_906 : i32 = i_2;
i_2 = 0;
i_2 = x_906;
@@ -1397,37 +1397,37 @@
let x_907 : vec3<f32> = color;
color = vec3<f32>(0.0, 0.0, 0.0);
color = x_907;
- let x_908 : f32 = x_260;
- x_260 = 0.0;
- x_260 = x_908;
+ let x_908 : f32 = *(x_260);
+ *(x_260) = 0.0;
+ *(x_260) = x_908;
let x_512 : vec3<f32> = vec3<f32>(x_455.y, x_455.y, x_455.y);
- let x_909 : i32 = x_253;
- x_253 = 0;
- x_253 = x_909;
+ let x_909 : i32 = *(x_253);
+ *(x_253) = 0;
+ *(x_253) = x_909;
if ((abs((x_308 - x_310)) < 0.25)) {
- let x_910 : f32 = x_209;
- x_209 = 0.0;
- x_209 = x_910;
+ let x_910 : f32 = *(x_209);
+ *(x_209) = 0.0;
+ *(x_209) = x_910;
let x_911 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_911;
let x_513 : vec3<f32> = vec3<f32>(x_505.z, x_505.x, x_448.x);
- let x_912 : i32 = x_300;
- x_300 = 0;
- x_300 = x_912;
+ let x_912 : i32 = *(x_300);
+ *(x_300) = 0;
+ *(x_300) = x_912;
let x_317 : i32 = obj.numbers[9u];
let x_514 : vec3<f32> = vec3<f32>(x_474.y, x_474.y, x_474.y);
- let x_913 : f32 = x_260;
- x_260 = 0.0;
- x_260 = x_913;
+ let x_913 : f32 = *(x_260);
+ *(x_260) = 0.0;
+ *(x_260) = x_913;
let x_320 : f32 = color.x;
- let x_914 : f32 = x_286;
- x_286 = 0.0;
- x_286 = x_914;
+ let x_914 : f32 = *(x_286);
+ *(x_286) = 0.0;
+ *(x_286) = x_914;
let x_515 : vec2<f32> = vec2<f32>(x_502.x, x_502.y);
- let x_915 : f32 = x_205;
- x_205 = 0.0;
- x_205 = x_915;
+ let x_915 : f32 = *(x_205);
+ *(x_205) = 0.0;
+ *(x_205) = x_915;
let x_916 : vec3<f32> = color;
color = vec3<f32>(0.0, 0.0, 0.0);
color = x_916;
@@ -1435,60 +1435,60 @@
let x_917 : vec2<f32> = uv;
uv = vec2<f32>(0.0, 0.0);
uv = x_917;
- let x_322 : ptr<function, f32> = color.x;
- let x_918 : f32 = x_209;
- x_209 = 0.0;
- x_209 = x_918;
+ let x_322 : ptr<function, f32> = &(color.x);
+ let x_918 : f32 = *(x_209);
+ *(x_209) = 0.0;
+ *(x_209) = x_918;
let x_517 : vec3<f32> = vec3<f32>(vec2<f32>(0.0, 0.0).x, vec2<f32>(0.0, 0.0).x, vec2<f32>(0.0, 0.0).y);
- x_322 = (f32(x_317) + x_320);
- let x_919 : f32 = x_322;
- x_322 = 0.0;
- x_322 = x_919;
+ *(x_322) = (f32(x_317) + x_320);
+ let x_919 : f32 = *(x_322);
+ *(x_322) = 0.0;
+ *(x_322) = x_919;
let x_518 : vec3<f32> = vec3<f32>(x_480.y, x_508.x, x_480.x);
- let x_920 : f32 = x_205;
- x_205 = 0.0;
- x_205 = x_920;
+ let x_920 : f32 = *(x_205);
+ *(x_205) = 0.0;
+ *(x_205) = x_920;
}
- let x_921 : f32 = x_309;
- x_309 = 0.0;
- x_309 = x_921;
+ let x_921 : f32 = *(x_309);
+ *(x_309) = 0.0;
+ *(x_309) = x_921;
let x_325 : vec3<f32> = color;
- let x_922 : f32 = x_237;
- x_237 = 0.0;
- x_237 = x_922;
+ let x_922 : f32 = *(x_237);
+ *(x_237) = 0.0;
+ *(x_237) = x_922;
let x_519 : vec3<f32> = vec3<f32>(x_447.x, x_446.x, x_446.y);
let x_326 : vec3<f32> = normalize(x_325);
- let x_923 : f32 = x_209;
- x_209 = 0.0;
- x_209 = x_923;
+ let x_923 : f32 = *(x_209);
+ *(x_209) = 0.0;
+ *(x_209) = x_923;
let x_924 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_924;
let x_925 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_925;
- let x_926 : f32 = x_259;
- x_259 = 0.0;
- x_259 = x_926;
+ let x_926 : f32 = *(x_259);
+ *(x_259) = 0.0;
+ *(x_259) = x_926;
let x_520 : vec2<f32> = vec2<f32>(x_506.y, x_519.y);
- let x_927 : f32 = x_259;
- x_259 = 0.0;
- x_259 = x_927;
+ let x_927 : f32 = *(x_259);
+ *(x_259) = 0.0;
+ *(x_259) = x_927;
let x_330 : vec4<f32> = vec4<f32>(x_326.x, x_326.y, x_326.z, 1.0);
- let x_928 : f32 = x_309;
- x_309 = 0.0;
- x_309 = x_928;
+ let x_928 : f32 = *(x_309);
+ *(x_309) = 0.0;
+ *(x_309) = x_928;
let x_521 : vec3<f32> = vec3<f32>(vec3<f32>(1.0, 2.0, 3.0).y, vec3<f32>(1.0, 2.0, 3.0).y, x_520.y);
- let x_929 : f32 = x_222;
- x_222 = 0.0;
- x_222 = x_929;
+ let x_929 : f32 = *(x_222);
+ *(x_222) = 0.0;
+ *(x_222) = x_929;
x_GLF_color = x_330;
let x_930 : QuicksortObject = obj;
obj = QuicksortObject(array<i32, 10>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
obj = x_930;
let x_522 : vec3<f32> = vec3<f32>(x_330.w, x_330.y, x_493.x);
- let x_931 : f32 = x_208;
- x_208 = 0.0;
- x_208 = x_931;
+ let x_931 : f32 = *(x_208);
+ *(x_208) = 0.0;
+ *(x_208) = x_931;
return;
}
diff --git a/test/intrinsics/arrayLength.wgsl b/test/intrinsics/arrayLength.wgsl
new file mode 100644
index 0000000..6ee6828
--- /dev/null
+++ b/test/intrinsics/arrayLength.wgsl
@@ -0,0 +1,12 @@
+[[block]]
+struct S {
+ a : array<i32>;
+};
+
+[[group(0), binding(0)]] var<storage> G : [[access(read)]] S;
+
+[[stage(compute)]]
+fn main() {
+ // TODO(crbug.com/tint/806): arrayLength signature is currently wrong
+ // let l : i32 = arrayLength(&G.a);
+}
diff --git a/test/intrinsics/arrayLength.wgsl.expected.hlsl b/test/intrinsics/arrayLength.wgsl.expected.hlsl
new file mode 100644
index 0000000..b3fc631
--- /dev/null
+++ b/test/intrinsics/arrayLength.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+
+[numthreads(1, 1, 1)]
+void main() {
+ return;
+}
+
diff --git a/test/intrinsics/arrayLength.wgsl.expected.msl b/test/intrinsics/arrayLength.wgsl.expected.msl
new file mode 100644
index 0000000..a43de5c
--- /dev/null
+++ b/test/intrinsics/arrayLength.wgsl.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct S {
+ /* 0x0000 */ int a[1];
+};
+
+kernel void tint_symbol() {
+ return;
+}
+
diff --git a/test/intrinsics/arrayLength.wgsl.expected.spvasm b/test/intrinsics/arrayLength.wgsl.expected.spvasm
new file mode 100644
index 0000000..bf2a83a
--- /dev/null
+++ b/test/intrinsics/arrayLength.wgsl.expected.spvasm
@@ -0,0 +1,30 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 10
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %S "S"
+ OpMemberName %S 0 "a"
+ OpName %G "G"
+ OpName %main "main"
+ OpDecorate %S Block
+ OpMemberDecorate %S 0 Offset 0
+ OpDecorate %_runtimearr_int ArrayStride 4
+ OpDecorate %G NonWritable
+ OpDecorate %G DescriptorSet 0
+ OpDecorate %G Binding 0
+ %int = OpTypeInt 32 1
+%_runtimearr_int = OpTypeRuntimeArray %int
+ %S = OpTypeStruct %_runtimearr_int
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+ %G = OpVariable %_ptr_StorageBuffer_S StorageBuffer
+ %void = OpTypeVoid
+ %6 = OpTypeFunction %void
+ %main = OpFunction %void None %6
+ %9 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/intrinsics/arrayLength.wgsl.expected.wgsl b/test/intrinsics/arrayLength.wgsl.expected.wgsl
new file mode 100644
index 0000000..5f75515
--- /dev/null
+++ b/test/intrinsics/arrayLength.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+[[block]]
+struct S {
+ a : array<i32>;
+};
+
+[[group(0), binding(0)]] var<storage> G : [[access(read)]] S;
+
+[[stage(compute)]]
+fn main() {
+}
diff --git a/test/intrinsics/frexp.wgsl b/test/intrinsics/frexp.wgsl
new file mode 100644
index 0000000..2e0ea4b
--- /dev/null
+++ b/test/intrinsics/frexp.wgsl
@@ -0,0 +1,5 @@
+[[stage(compute)]]
+fn main() {
+ var exponent : i32;
+ let significand : f32 = frexp(1.23, &exponent);
+}
diff --git a/test/intrinsics/frexp.wgsl.expected.hlsl b/test/intrinsics/frexp.wgsl.expected.hlsl
new file mode 100644
index 0000000..e0f2632
--- /dev/null
+++ b/test/intrinsics/frexp.wgsl.expected.hlsl
@@ -0,0 +1 @@
+SKIP: Failed to generate: error: Unknown builtin method: frexp
diff --git a/test/intrinsics/frexp.wgsl.expected.msl b/test/intrinsics/frexp.wgsl.expected.msl
new file mode 100644
index 0000000..06c7a47
--- /dev/null
+++ b/test/intrinsics/frexp.wgsl.expected.msl
@@ -0,0 +1 @@
+SKIP: Failed to generate: error: Unknown import method: frexp
\ No newline at end of file
diff --git a/test/intrinsics/frexp.wgsl.expected.spvasm b/test/intrinsics/frexp.wgsl.expected.spvasm
new file mode 100644
index 0000000..7d6543e
--- /dev/null
+++ b/test/intrinsics/frexp.wgsl.expected.spvasm
@@ -0,0 +1,25 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 14
+; Schema: 0
+ OpCapability Shader
+ %11 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %exponent "exponent"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+ %8 = OpConstantNull %int
+ %float = OpTypeFloat 32
+%float_1_23000002 = OpConstant %float 1.23000002
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %exponent = OpVariable %_ptr_Function_int Function %8
+ %9 = OpExtInst %float %11 Frexp %float_1_23000002 %exponent
+ OpReturn
+ OpFunctionEnd
diff --git a/test/intrinsics/frexp.wgsl.expected.wgsl b/test/intrinsics/frexp.wgsl.expected.wgsl
new file mode 100644
index 0000000..9a8ad1d
--- /dev/null
+++ b/test/intrinsics/frexp.wgsl.expected.wgsl
@@ -0,0 +1,5 @@
+[[stage(compute)]]
+fn main() {
+ var exponent : i32;
+ let significand : f32 = frexp(1.230000019, &(exponent));
+}
diff --git a/test/intrinsics/modf.wgsl b/test/intrinsics/modf.wgsl
new file mode 100644
index 0000000..735c360
--- /dev/null
+++ b/test/intrinsics/modf.wgsl
@@ -0,0 +1,5 @@
+[[stage(compute)]]
+fn main() {
+ var whole : f32;
+ let frac : f32 = modf(1.23, &whole);
+}
diff --git a/test/intrinsics/modf.wgsl.expected.hlsl b/test/intrinsics/modf.wgsl.expected.hlsl
new file mode 100644
index 0000000..e0f2632
--- /dev/null
+++ b/test/intrinsics/modf.wgsl.expected.hlsl
@@ -0,0 +1 @@
+SKIP: Failed to generate: error: Unknown builtin method: frexp
diff --git a/test/intrinsics/modf.wgsl.expected.msl b/test/intrinsics/modf.wgsl.expected.msl
new file mode 100644
index 0000000..06c7a47
--- /dev/null
+++ b/test/intrinsics/modf.wgsl.expected.msl
@@ -0,0 +1 @@
+SKIP: Failed to generate: error: Unknown import method: frexp
\ No newline at end of file
diff --git a/test/intrinsics/modf.wgsl.expected.spvasm b/test/intrinsics/modf.wgsl.expected.spvasm
new file mode 100644
index 0000000..090d8b8
--- /dev/null
+++ b/test/intrinsics/modf.wgsl.expected.spvasm
@@ -0,0 +1,24 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 13
+; Schema: 0
+ OpCapability Shader
+ %10 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %whole "whole"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+%_ptr_Function_float = OpTypePointer Function %float
+ %8 = OpConstantNull %float
+%float_1_23000002 = OpConstant %float 1.23000002
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %whole = OpVariable %_ptr_Function_float Function %8
+ %9 = OpExtInst %float %10 Modf %float_1_23000002 %whole
+ OpReturn
+ OpFunctionEnd
diff --git a/test/intrinsics/modf.wgsl.expected.wgsl b/test/intrinsics/modf.wgsl.expected.wgsl
new file mode 100644
index 0000000..9f7ea1f
--- /dev/null
+++ b/test/intrinsics/modf.wgsl.expected.wgsl
@@ -0,0 +1,5 @@
+[[stage(compute)]]
+fn main() {
+ var whole : f32;
+ let frac : f32 = modf(1.230000019, &(whole));
+}
diff --git a/test/ptr_ref/access/matrix.spvasm b/test/ptr_ref/access/matrix.spvasm
new file mode 100644
index 0000000..f29e412
--- /dev/null
+++ b/test/ptr_ref/access/matrix.spvasm
@@ -0,0 +1,43 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 31
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %m "m"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %11 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %float_6 = OpConstant %float 6
+ %15 = OpConstantComposite %v3float %float_4 %float_5 %float_6
+ %float_7 = OpConstant %float 7
+ %float_8 = OpConstant %float 8
+ %float_9 = OpConstant %float 9
+ %19 = OpConstantComposite %v3float %float_7 %float_8 %float_9
+ %20 = OpConstantComposite %mat3v3float %11 %15 %19
+%_ptr_Function_mat3v3float = OpTypePointer Function %mat3v3float
+ %23 = OpConstantNull %mat3v3float
+ %int = OpTypeInt 32 1
+ %int_1 = OpConstant %int 1
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+ %30 = OpConstantComposite %v3float %float_5 %float_5 %float_5
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %m = OpVariable %_ptr_Function_mat3v3float Function %23
+ OpStore %m %20
+ %28 = OpAccessChain %_ptr_Function_v3float %m %int_1
+ OpStore %28 %30
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/access/matrix.spvasm.expected.hlsl b/test/ptr_ref/access/matrix.spvasm.expected.hlsl
new file mode 100644
index 0000000..b3db42f
--- /dev/null
+++ b/test/ptr_ref/access/matrix.spvasm.expected.hlsl
@@ -0,0 +1 @@
+SKIP: Failed to generate: error: pointers not supported in HLSL
diff --git a/test/ptr_ref/access/matrix.spvasm.expected.msl b/test/ptr_ref/access/matrix.spvasm.expected.msl
new file mode 100644
index 0000000..beac5b5
--- /dev/null
+++ b/test/ptr_ref/access/matrix.spvasm.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol() {
+ float3x3 m = float3x3(float3(0.0f, 0.0f, 0.0f), float3(0.0f, 0.0f, 0.0f), float3(0.0f, 0.0f, 0.0f));
+ m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
+ m[1] = float3(5.0f, 5.0f, 5.0f);
+ return;
+}
+
diff --git a/test/ptr_ref/access/matrix.spvasm.expected.spvasm b/test/ptr_ref/access/matrix.spvasm.expected.spvasm
new file mode 100644
index 0000000..762777b
--- /dev/null
+++ b/test/ptr_ref/access/matrix.spvasm.expected.spvasm
@@ -0,0 +1,47 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 32
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %m "m"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+ %float_0 = OpConstant %float 0
+ %9 = OpConstantComposite %v3float %float_0 %float_0 %float_0
+ %10 = OpConstantComposite %mat3v3float %9 %9 %9
+%_ptr_Function_mat3v3float = OpTypePointer Function %mat3v3float
+ %13 = OpConstantNull %mat3v3float
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %17 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %float_6 = OpConstant %float 6
+ %21 = OpConstantComposite %v3float %float_4 %float_5 %float_6
+ %float_7 = OpConstant %float 7
+ %float_8 = OpConstant %float 8
+ %float_9 = OpConstant %float 9
+ %25 = OpConstantComposite %v3float %float_7 %float_8 %float_9
+ %26 = OpConstantComposite %mat3v3float %17 %21 %25
+ %int = OpTypeInt 32 1
+ %int_1 = OpConstant %int 1
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+ %31 = OpConstantComposite %v3float %float_5 %float_5 %float_5
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %m = OpVariable %_ptr_Function_mat3v3float Function %13
+ OpStore %m %10
+ OpStore %m %26
+ %30 = OpAccessChain %_ptr_Function_v3float %m %int_1
+ OpStore %30 %31
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/access/matrix.spvasm.expected.wgsl b/test/ptr_ref/access/matrix.spvasm.expected.wgsl
new file mode 100644
index 0000000..dabe5d4
--- /dev/null
+++ b/test/ptr_ref/access/matrix.spvasm.expected.wgsl
@@ -0,0 +1,7 @@
+[[stage(compute)]]
+fn main() {
+ var m : mat3x3<f32> = mat3x3<f32>(vec3<f32>(0.0, 0.0, 0.0), vec3<f32>(0.0, 0.0, 0.0), vec3<f32>(0.0, 0.0, 0.0));
+ m = mat3x3<f32>(vec3<f32>(1.0, 2.0, 3.0), vec3<f32>(4.0, 5.0, 6.0), vec3<f32>(7.0, 8.0, 9.0));
+ m[1] = vec3<f32>(5.0, 5.0, 5.0);
+ return;
+}
diff --git a/test/ptr_ref/access/matrix.wgsl b/test/ptr_ref/access/matrix.wgsl
new file mode 100644
index 0000000..5ec6915
--- /dev/null
+++ b/test/ptr_ref/access/matrix.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute)]]
+fn main() {
+ var m : mat3x3<f32> = mat3x3<f32>(vec3<f32>(1., 2., 3.), vec3<f32>(4., 5., 6.), vec3<f32>(7., 8., 9.));
+ let v : ptr<function, vec3<f32>> = &m[1];
+ *v = vec3<f32>(5., 5., 5.);
+}
diff --git a/test/ptr_ref/access/matrix.wgsl.expected.hlsl b/test/ptr_ref/access/matrix.wgsl.expected.hlsl
new file mode 100644
index 0000000..b3db42f
--- /dev/null
+++ b/test/ptr_ref/access/matrix.wgsl.expected.hlsl
@@ -0,0 +1 @@
+SKIP: Failed to generate: error: pointers not supported in HLSL
diff --git a/test/ptr_ref/access/matrix.wgsl.expected.msl b/test/ptr_ref/access/matrix.wgsl.expected.msl
new file mode 100644
index 0000000..5bf9bb9
--- /dev/null
+++ b/test/ptr_ref/access/matrix.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol() {
+ float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
+ float3* const v = &(m[1]);
+ *(v) = float3(5.0f, 5.0f, 5.0f);
+ return;
+}
+
diff --git a/test/ptr_ref/access/matrix.wgsl.expected.spvasm b/test/ptr_ref/access/matrix.wgsl.expected.spvasm
new file mode 100644
index 0000000..f29e412
--- /dev/null
+++ b/test/ptr_ref/access/matrix.wgsl.expected.spvasm
@@ -0,0 +1,43 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 31
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %m "m"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %11 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %float_6 = OpConstant %float 6
+ %15 = OpConstantComposite %v3float %float_4 %float_5 %float_6
+ %float_7 = OpConstant %float 7
+ %float_8 = OpConstant %float 8
+ %float_9 = OpConstant %float 9
+ %19 = OpConstantComposite %v3float %float_7 %float_8 %float_9
+ %20 = OpConstantComposite %mat3v3float %11 %15 %19
+%_ptr_Function_mat3v3float = OpTypePointer Function %mat3v3float
+ %23 = OpConstantNull %mat3v3float
+ %int = OpTypeInt 32 1
+ %int_1 = OpConstant %int 1
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+ %30 = OpConstantComposite %v3float %float_5 %float_5 %float_5
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %m = OpVariable %_ptr_Function_mat3v3float Function %23
+ OpStore %m %20
+ %28 = OpAccessChain %_ptr_Function_v3float %m %int_1
+ OpStore %28 %30
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/access/matrix.wgsl.expected.wgsl b/test/ptr_ref/access/matrix.wgsl.expected.wgsl
new file mode 100644
index 0000000..f38b714
--- /dev/null
+++ b/test/ptr_ref/access/matrix.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute)]]
+fn main() {
+ var m : mat3x3<f32> = mat3x3<f32>(vec3<f32>(1.0, 2.0, 3.0), vec3<f32>(4.0, 5.0, 6.0), vec3<f32>(7.0, 8.0, 9.0));
+ let v : ptr<function, vec3<f32>> = &(m[1]);
+ *(v) = vec3<f32>(5.0, 5.0, 5.0);
+}
diff --git a/test/ptr_ref/access/vector.spvasm b/test/ptr_ref/access/vector.spvasm
new file mode 100644
index 0000000..deada33
--- /dev/null
+++ b/test/ptr_ref/access/vector.spvasm
@@ -0,0 +1,33 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 21
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %v "v"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %10 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+ %13 = OpConstantNull %v3float
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 1
+%_ptr_Function_float = OpTypePointer Function %float
+ %float_5 = OpConstant %float 5
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %v = OpVariable %_ptr_Function_v3float Function %13
+ OpStore %v %10
+ %18 = OpAccessChain %_ptr_Function_float %v %uint_1
+ OpStore %18 %float_5
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/access/vector.spvasm.expected.hlsl b/test/ptr_ref/access/vector.spvasm.expected.hlsl
new file mode 100644
index 0000000..b3db42f
--- /dev/null
+++ b/test/ptr_ref/access/vector.spvasm.expected.hlsl
@@ -0,0 +1 @@
+SKIP: Failed to generate: error: pointers not supported in HLSL
diff --git a/test/ptr_ref/access/vector.spvasm.expected.msl b/test/ptr_ref/access/vector.spvasm.expected.msl
new file mode 100644
index 0000000..650c752
--- /dev/null
+++ b/test/ptr_ref/access/vector.spvasm.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol() {
+ float3 v = float3(0.0f, 0.0f, 0.0f);
+ v = float3(1.0f, 2.0f, 3.0f);
+ v.y = 5.0f;
+ return;
+}
+
diff --git a/test/ptr_ref/access/vector.spvasm.expected.spvasm b/test/ptr_ref/access/vector.spvasm.expected.spvasm
new file mode 100644
index 0000000..5d2c915
--- /dev/null
+++ b/test/ptr_ref/access/vector.spvasm.expected.spvasm
@@ -0,0 +1,36 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 21
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %v "v"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
+ %float_0 = OpConstant %float 0
+ %8 = OpConstantComposite %v3float %float_0 %float_0 %float_0
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+ %11 = OpConstantNull %v3float
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %15 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 1
+%_ptr_Function_float = OpTypePointer Function %float
+ %float_5 = OpConstant %float 5
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %v = OpVariable %_ptr_Function_v3float Function %11
+ OpStore %v %8
+ OpStore %v %15
+ %19 = OpAccessChain %_ptr_Function_float %v %uint_1
+ OpStore %19 %float_5
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/access/vector.spvasm.expected.wgsl b/test/ptr_ref/access/vector.spvasm.expected.wgsl
new file mode 100644
index 0000000..dce7b8f
--- /dev/null
+++ b/test/ptr_ref/access/vector.spvasm.expected.wgsl
@@ -0,0 +1,7 @@
+[[stage(compute)]]
+fn main() {
+ var v : vec3<f32> = vec3<f32>(0.0, 0.0, 0.0);
+ v = vec3<f32>(1.0, 2.0, 3.0);
+ v.y = 5.0;
+ return;
+}
diff --git a/test/ptr_ref/access/vector.wgsl b/test/ptr_ref/access/vector.wgsl
new file mode 100644
index 0000000..779ebad
--- /dev/null
+++ b/test/ptr_ref/access/vector.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute)]]
+fn main() {
+ var v : vec3<f32> = vec3<f32>(1., 2., 3.);
+ let f : ptr<function, f32> = &v.y;
+ *f = 5.0;
+}
diff --git a/test/ptr_ref/access/vector.wgsl.expected.hlsl b/test/ptr_ref/access/vector.wgsl.expected.hlsl
new file mode 100644
index 0000000..b3db42f
--- /dev/null
+++ b/test/ptr_ref/access/vector.wgsl.expected.hlsl
@@ -0,0 +1 @@
+SKIP: Failed to generate: error: pointers not supported in HLSL
diff --git a/test/ptr_ref/access/vector.wgsl.expected.msl b/test/ptr_ref/access/vector.wgsl.expected.msl
new file mode 100644
index 0000000..88a1b99
--- /dev/null
+++ b/test/ptr_ref/access/vector.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol() {
+ float3 v = float3(1.0f, 2.0f, 3.0f);
+ float* const f = &(v.y);
+ *(f) = 5.0f;
+ return;
+}
+
diff --git a/test/ptr_ref/access/vector.wgsl.expected.spvasm b/test/ptr_ref/access/vector.wgsl.expected.spvasm
new file mode 100644
index 0000000..deada33
--- /dev/null
+++ b/test/ptr_ref/access/vector.wgsl.expected.spvasm
@@ -0,0 +1,33 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 21
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %v "v"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %10 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+ %13 = OpConstantNull %v3float
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 1
+%_ptr_Function_float = OpTypePointer Function %float
+ %float_5 = OpConstant %float 5
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %v = OpVariable %_ptr_Function_v3float Function %13
+ OpStore %v %10
+ %18 = OpAccessChain %_ptr_Function_float %v %uint_1
+ OpStore %18 %float_5
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/access/vector.wgsl.expected.wgsl b/test/ptr_ref/access/vector.wgsl.expected.wgsl
new file mode 100644
index 0000000..730c386
--- /dev/null
+++ b/test/ptr_ref/access/vector.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute)]]
+fn main() {
+ var v : vec3<f32> = vec3<f32>(1.0, 2.0, 3.0);
+ let f : ptr<function, f32> = &(v.y);
+ *(f) = 5.0;
+}
diff --git a/test/ptr_ref/copy/ptr_copy.spvasm b/test/ptr_ref/copy/ptr_copy.spvasm
new file mode 100644
index 0000000..1163cb1
--- /dev/null
+++ b/test/ptr_ref/copy/ptr_copy.spvasm
@@ -0,0 +1,15 @@
+ OpCapability Shader
+ OpMemoryModel Logical Simple
+ OpEntryPoint GLCompute %100 "main"
+ OpExecutionMode %100 LocalSize 1 1 1
+ %uint = OpTypeInt 32 0
+ %void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+ %ptr = OpTypePointer Function %uint
+ %100 = OpFunction %void None %voidfn
+ %entry = OpLabel
+ %10 = OpVariable %ptr Function
+ %1 = OpCopyObject %ptr %10
+ %2 = OpCopyObject %ptr %1
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/copy/ptr_copy.spvasm.expected.hlsl b/test/ptr_ref/copy/ptr_copy.spvasm.expected.hlsl
new file mode 100644
index 0000000..16f9b25
--- /dev/null
+++ b/test/ptr_ref/copy/ptr_copy.spvasm.expected.hlsl
@@ -0,0 +1 @@
+SKIP: error: pointers not supported in HLSL
diff --git a/test/ptr_ref/copy/ptr_copy.spvasm.expected.msl b/test/ptr_ref/copy/ptr_copy.spvasm.expected.msl
new file mode 100644
index 0000000..ec58031
--- /dev/null
+++ b/test/ptr_ref/copy/ptr_copy.spvasm.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol() {
+ uint x_10 = 0u;
+ uint* const x_1 = &(x_10);
+ uint* const x_2 = x_1;
+ return;
+}
+
diff --git a/test/ptr_ref/copy/ptr_copy.spvasm.expected.spvasm b/test/ptr_ref/copy/ptr_copy.spvasm.expected.spvasm
new file mode 100644
index 0000000..eeebd89
--- /dev/null
+++ b/test/ptr_ref/copy/ptr_copy.spvasm.expected.spvasm
@@ -0,0 +1,21 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 10
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %x_10 "x_10"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+%_ptr_Function_uint = OpTypePointer Function %uint
+ %8 = OpConstantNull %uint
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %x_10 = OpVariable %_ptr_Function_uint Function %8
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/copy/ptr_copy.spvasm.expected.wgsl b/test/ptr_ref/copy/ptr_copy.spvasm.expected.wgsl
new file mode 100644
index 0000000..ef4c546
--- /dev/null
+++ b/test/ptr_ref/copy/ptr_copy.spvasm.expected.wgsl
@@ -0,0 +1,7 @@
+[[stage(compute)]]
+fn main() {
+ var x_10 : u32;
+ let x_1 : ptr<function, u32> = &(x_10);
+ let x_2 : ptr<function, u32> = x_1;
+ return;
+}
diff --git a/test/ptr_ref/load/global/i32.spvasm b/test/ptr_ref/load/global/i32.spvasm
new file mode 100644
index 0000000..aace167
--- /dev/null
+++ b/test/ptr_ref/load/global/i32.spvasm
@@ -0,0 +1,19 @@
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %I "I"
+ OpName %main "main"
+ %int = OpTypeInt 32 1
+%_ptr_Private_int = OpTypePointer Private %int
+ %4 = OpConstantNull %int
+ %I = OpVariable %_ptr_Private_int Private %4
+ %void = OpTypeVoid
+ %5 = OpTypeFunction %void
+ %int_1 = OpConstant %int 1
+ %main = OpFunction %void None %5
+ %8 = OpLabel
+ %9 = OpLoad %int %I
+ %11 = OpIAdd %int %9 %int_1
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/load/global/i32.spvasm.expected.hlsl b/test/ptr_ref/load/global/i32.spvasm.expected.hlsl
new file mode 100644
index 0000000..86cdfa8
--- /dev/null
+++ b/test/ptr_ref/load/global/i32.spvasm.expected.hlsl
@@ -0,0 +1,9 @@
+int I = 0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int x_9 = I;
+ const int x_11 = (x_9 + 1);
+ return;
+}
+
diff --git a/test/ptr_ref/load/global/i32.spvasm.expected.msl b/test/ptr_ref/load/global/i32.spvasm.expected.msl
new file mode 100644
index 0000000..1b2d3db
--- /dev/null
+++ b/test/ptr_ref/load/global/i32.spvasm.expected.msl
@@ -0,0 +1 @@
+SKIP: TINT_UNIMPLEMENTED crbug.com/tint/726: module-scope private and workgroup variables not yet implemented
diff --git a/test/ptr_ref/load/global/i32.spvasm.expected.spvasm b/test/ptr_ref/load/global/i32.spvasm.expected.spvasm
new file mode 100644
index 0000000..df45400
--- /dev/null
+++ b/test/ptr_ref/load/global/i32.spvasm.expected.spvasm
@@ -0,0 +1,24 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 12
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %I "I"
+ OpName %main "main"
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+%_ptr_Private_int = OpTypePointer Private %int
+ %I = OpVariable %_ptr_Private_int Private %int_0
+ %void = OpTypeVoid
+ %5 = OpTypeFunction %void
+ %int_1 = OpConstant %int 1
+ %main = OpFunction %void None %5
+ %8 = OpLabel
+ %9 = OpLoad %int %I
+ %11 = OpIAdd %int %9 %int_1
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/load/global/i32.spvasm.expected.wgsl b/test/ptr_ref/load/global/i32.spvasm.expected.wgsl
new file mode 100644
index 0000000..ba8f551
--- /dev/null
+++ b/test/ptr_ref/load/global/i32.spvasm.expected.wgsl
@@ -0,0 +1,8 @@
+var<private> I : i32 = 0;
+
+[[stage(compute)]]
+fn main() {
+ let x_9 : i32 = I;
+ let x_11 : i32 = (x_9 + 1);
+ return;
+}
diff --git a/test/ptr_ref/load/global/i32.wgsl b/test/ptr_ref/load/global/i32.wgsl
new file mode 100644
index 0000000..728faf0
--- /dev/null
+++ b/test/ptr_ref/load/global/i32.wgsl
@@ -0,0 +1,7 @@
+var<private> I : i32;
+
+[[stage(compute)]]
+fn main() {
+ let i : i32 = I;
+ let use : i32 = i + 1;
+}
diff --git a/test/ptr_ref/load/global/i32.wgsl.expected.hlsl b/test/ptr_ref/load/global/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..4a6e9e6
--- /dev/null
+++ b/test/ptr_ref/load/global/i32.wgsl.expected.hlsl
@@ -0,0 +1,9 @@
+int I;
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int i = I;
+ const int use = (i + 1);
+ return;
+}
+
diff --git a/test/ptr_ref/load/global/i32.wgsl.expected.msl b/test/ptr_ref/load/global/i32.wgsl.expected.msl
new file mode 100644
index 0000000..1b2d3db
--- /dev/null
+++ b/test/ptr_ref/load/global/i32.wgsl.expected.msl
@@ -0,0 +1 @@
+SKIP: TINT_UNIMPLEMENTED crbug.com/tint/726: module-scope private and workgroup variables not yet implemented
diff --git a/test/ptr_ref/load/global/i32.wgsl.expected.spvasm b/test/ptr_ref/load/global/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..1d701c5
--- /dev/null
+++ b/test/ptr_ref/load/global/i32.wgsl.expected.spvasm
@@ -0,0 +1,24 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 12
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %I "I"
+ OpName %main "main"
+ %int = OpTypeInt 32 1
+%_ptr_Private_int = OpTypePointer Private %int
+ %4 = OpConstantNull %int
+ %I = OpVariable %_ptr_Private_int Private %4
+ %void = OpTypeVoid
+ %5 = OpTypeFunction %void
+ %int_1 = OpConstant %int 1
+ %main = OpFunction %void None %5
+ %8 = OpLabel
+ %9 = OpLoad %int %I
+ %11 = OpIAdd %int %9 %int_1
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/load/global/i32.wgsl.expected.wgsl b/test/ptr_ref/load/global/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..c656f8e
--- /dev/null
+++ b/test/ptr_ref/load/global/i32.wgsl.expected.wgsl
@@ -0,0 +1,7 @@
+var<private> I : i32;
+
+[[stage(compute)]]
+fn main() {
+ let i : i32 = I;
+ let use : i32 = (i + 1);
+}
diff --git a/test/ptr_ref/load/global/struct_field.spvasm b/test/ptr_ref/load/global/struct_field.spvasm
new file mode 100644
index 0000000..149aeae
--- /dev/null
+++ b/test/ptr_ref/load/global/struct_field.spvasm
@@ -0,0 +1,33 @@
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpSource GLSL 450
+ OpName %main "main"
+ OpName %i "i"
+ OpName %S "S"
+ OpMemberName %S 0 "i"
+ OpName %V "V"
+ OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+ %S = OpTypeStruct %int
+ %_ptr_Private_S = OpTypePointer Private %S
+ %V = OpVariable %_ptr_Private_S Private
+ %int_0 = OpConstant %int 0
+ %_ptr_Private_int = OpTypePointer Private %int
+ %uint = OpTypeInt 32 0
+ %v3uint = OpTypeVector %uint 3
+ %uint_1 = OpConstant %uint 1
+ %gl_WorkGroupSize = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function
+ %14 = OpAccessChain %_ptr_Private_int %V %int_0
+ %15 = OpLoad %int %14
+ OpStore %i %15
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/load/global/struct_field.spvasm.expected.hlsl b/test/ptr_ref/load/global/struct_field.spvasm.expected.hlsl
new file mode 100644
index 0000000..16f9b25
--- /dev/null
+++ b/test/ptr_ref/load/global/struct_field.spvasm.expected.hlsl
@@ -0,0 +1 @@
+SKIP: error: pointers not supported in HLSL
diff --git a/test/ptr_ref/load/global/struct_field.spvasm.expected.msl b/test/ptr_ref/load/global/struct_field.spvasm.expected.msl
new file mode 100644
index 0000000..1b2d3db
--- /dev/null
+++ b/test/ptr_ref/load/global/struct_field.spvasm.expected.msl
@@ -0,0 +1 @@
+SKIP: TINT_UNIMPLEMENTED crbug.com/tint/726: module-scope private and workgroup variables not yet implemented
diff --git a/test/ptr_ref/load/global/struct_field.spvasm.expected.spvasm b/test/ptr_ref/load/global/struct_field.spvasm.expected.spvasm
new file mode 100644
index 0000000..2a1da68
--- /dev/null
+++ b/test/ptr_ref/load/global/struct_field.spvasm.expected.spvasm
@@ -0,0 +1,35 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %S "S"
+ OpMemberName %S 0 "i"
+ OpName %V "V"
+ OpName %main "main"
+ OpName %i "i"
+ OpMemberDecorate %S 0 Offset 0
+ %int = OpTypeInt 32 1
+ %S = OpTypeStruct %int
+%_ptr_Private_S = OpTypePointer Private %S
+ %5 = OpConstantNull %S
+ %V = OpVariable %_ptr_Private_S Private %5
+ %void = OpTypeVoid
+ %6 = OpTypeFunction %void
+%_ptr_Function_int = OpTypePointer Function %int
+ %12 = OpConstantNull %int
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Private_int = OpTypePointer Private %int
+ %main = OpFunction %void None %6
+ %9 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %12
+ %16 = OpAccessChain %_ptr_Private_int %V %uint_0
+ %17 = OpLoad %int %16
+ OpStore %i %17
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/load/global/struct_field.spvasm.expected.wgsl b/test/ptr_ref/load/global/struct_field.spvasm.expected.wgsl
new file mode 100644
index 0000000..e3f4540
--- /dev/null
+++ b/test/ptr_ref/load/global/struct_field.spvasm.expected.wgsl
@@ -0,0 +1,13 @@
+struct S {
+ i : i32;
+};
+
+var<private> V : S;
+
+[[stage(compute)]]
+fn main() {
+ var i : i32;
+ let x_15 : i32 = V.i;
+ i = x_15;
+ return;
+}
diff --git a/test/ptr_ref/load/global/struct_field.wgsl b/test/ptr_ref/load/global/struct_field.wgsl
new file mode 100644
index 0000000..e35154b
--- /dev/null
+++ b/test/ptr_ref/load/global/struct_field.wgsl
@@ -0,0 +1,10 @@
+struct S {
+ i : i32;
+};
+
+var<private> V : S;
+
+[[stage(compute)]]
+fn main() {
+ let i : i32 = V.i;
+}
diff --git a/test/ptr_ref/load/global/struct_field.wgsl.expected.hlsl b/test/ptr_ref/load/global/struct_field.wgsl.expected.hlsl
new file mode 100644
index 0000000..80e03bb
--- /dev/null
+++ b/test/ptr_ref/load/global/struct_field.wgsl.expected.hlsl
@@ -0,0 +1,12 @@
+struct S {
+ int i;
+};
+
+S V;
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int i = V.i;
+ return;
+}
+
diff --git a/test/ptr_ref/load/global/struct_field.wgsl.expected.msl b/test/ptr_ref/load/global/struct_field.wgsl.expected.msl
new file mode 100644
index 0000000..1b2d3db
--- /dev/null
+++ b/test/ptr_ref/load/global/struct_field.wgsl.expected.msl
@@ -0,0 +1 @@
+SKIP: TINT_UNIMPLEMENTED crbug.com/tint/726: module-scope private and workgroup variables not yet implemented
diff --git a/test/ptr_ref/load/global/struct_field.wgsl.expected.spvasm b/test/ptr_ref/load/global/struct_field.wgsl.expected.spvasm
new file mode 100644
index 0000000..471fa58
--- /dev/null
+++ b/test/ptr_ref/load/global/struct_field.wgsl.expected.spvasm
@@ -0,0 +1,30 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 15
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %S "S"
+ OpMemberName %S 0 "i"
+ OpName %V "V"
+ OpName %main "main"
+ OpMemberDecorate %S 0 Offset 0
+ %int = OpTypeInt 32 1
+ %S = OpTypeStruct %int
+%_ptr_Private_S = OpTypePointer Private %S
+ %5 = OpConstantNull %S
+ %V = OpVariable %_ptr_Private_S Private %5
+ %void = OpTypeVoid
+ %6 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Private_int = OpTypePointer Private %int
+ %main = OpFunction %void None %6
+ %9 = OpLabel
+ %13 = OpAccessChain %_ptr_Private_int %V %uint_0
+ %14 = OpLoad %int %13
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/load/global/struct_field.wgsl.expected.wgsl b/test/ptr_ref/load/global/struct_field.wgsl.expected.wgsl
new file mode 100644
index 0000000..e35154b
--- /dev/null
+++ b/test/ptr_ref/load/global/struct_field.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+struct S {
+ i : i32;
+};
+
+var<private> V : S;
+
+[[stage(compute)]]
+fn main() {
+ let i : i32 = V.i;
+}
diff --git a/test/ptr_ref/load/local/i32.spvasm b/test/ptr_ref/load/local/i32.spvasm
new file mode 100644
index 0000000..c44fdd0
--- /dev/null
+++ b/test/ptr_ref/load/local/i32.spvasm
@@ -0,0 +1,26 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 13
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %i "i"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %int_123 = OpConstant %int 123
+%_ptr_Function_int = OpTypePointer Function %int
+ %9 = OpConstantNull %int
+ %int_1 = OpConstant %int 1
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %9
+ OpStore %i %int_123
+ %10 = OpLoad %int %i
+ %12 = OpIAdd %int %10 %int_1
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/load/local/i32.spvasm.expected.hlsl b/test/ptr_ref/load/local/i32.spvasm.expected.hlsl
new file mode 100644
index 0000000..6a1180f
--- /dev/null
+++ b/test/ptr_ref/load/local/i32.spvasm.expected.hlsl
@@ -0,0 +1,9 @@
+[numthreads(1, 1, 1)]
+void main() {
+ int i = 0;
+ i = 123;
+ const int x_10 = i;
+ const int x_12 = (x_10 + 1);
+ return;
+}
+
diff --git a/test/ptr_ref/load/local/i32.spvasm.expected.msl b/test/ptr_ref/load/local/i32.spvasm.expected.msl
new file mode 100644
index 0000000..738dfea
--- /dev/null
+++ b/test/ptr_ref/load/local/i32.spvasm.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol() {
+ int i = 0;
+ i = 123;
+ int const x_10 = i;
+ int const x_12 = (x_10 + 1);
+ return;
+}
+
diff --git a/test/ptr_ref/load/local/i32.spvasm.expected.spvasm b/test/ptr_ref/load/local/i32.spvasm.expected.spvasm
new file mode 100644
index 0000000..bc6f467
--- /dev/null
+++ b/test/ptr_ref/load/local/i32.spvasm.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 14
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %i "i"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+%_ptr_Function_int = OpTypePointer Function %int
+ %9 = OpConstantNull %int
+ %int_123 = OpConstant %int 123
+ %int_1 = OpConstant %int 1
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %9
+ OpStore %i %int_0
+ OpStore %i %int_123
+ %11 = OpLoad %int %i
+ %13 = OpIAdd %int %11 %int_1
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/load/local/i32.spvasm.expected.wgsl b/test/ptr_ref/load/local/i32.spvasm.expected.wgsl
new file mode 100644
index 0000000..60551cd
--- /dev/null
+++ b/test/ptr_ref/load/local/i32.spvasm.expected.wgsl
@@ -0,0 +1,8 @@
+[[stage(compute)]]
+fn main() {
+ var i : i32 = 0;
+ i = 123;
+ let x_10 : i32 = i;
+ let x_12 : i32 = (x_10 + 1);
+ return;
+}
diff --git a/test/ptr_ref/load/local/i32.wgsl b/test/ptr_ref/load/local/i32.wgsl
new file mode 100644
index 0000000..1890fd4
--- /dev/null
+++ b/test/ptr_ref/load/local/i32.wgsl
@@ -0,0 +1,5 @@
+[[stage(compute)]]
+fn main() {
+ var i : i32 = 123;
+ let use : i32 = i + 1;
+}
diff --git a/test/ptr_ref/load/local/i32.wgsl.expected.hlsl b/test/ptr_ref/load/local/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..fd57280
--- /dev/null
+++ b/test/ptr_ref/load/local/i32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void main() {
+ int i = 123;
+ const int use = (i + 1);
+ return;
+}
+
diff --git a/test/ptr_ref/load/local/i32.wgsl.expected.msl b/test/ptr_ref/load/local/i32.wgsl.expected.msl
new file mode 100644
index 0000000..e7b87bb
--- /dev/null
+++ b/test/ptr_ref/load/local/i32.wgsl.expected.msl
@@ -0,0 +1,9 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol() {
+ int i = 123;
+ int const use = (i + 1);
+ return;
+}
+
diff --git a/test/ptr_ref/load/local/i32.wgsl.expected.spvasm b/test/ptr_ref/load/local/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..c44fdd0
--- /dev/null
+++ b/test/ptr_ref/load/local/i32.wgsl.expected.spvasm
@@ -0,0 +1,26 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 13
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %i "i"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %int_123 = OpConstant %int 123
+%_ptr_Function_int = OpTypePointer Function %int
+ %9 = OpConstantNull %int
+ %int_1 = OpConstant %int 1
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %9
+ OpStore %i %int_123
+ %10 = OpLoad %int %i
+ %12 = OpIAdd %int %10 %int_1
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/load/local/i32.wgsl.expected.wgsl b/test/ptr_ref/load/local/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..e15d6e0
--- /dev/null
+++ b/test/ptr_ref/load/local/i32.wgsl.expected.wgsl
@@ -0,0 +1,5 @@
+[[stage(compute)]]
+fn main() {
+ var i : i32 = 123;
+ let use : i32 = (i + 1);
+}
diff --git a/test/ptr_ref/load/local/struct_field.spvasm b/test/ptr_ref/load/local/struct_field.spvasm
new file mode 100644
index 0000000..fa124c5
--- /dev/null
+++ b/test/ptr_ref/load/local/struct_field.spvasm
@@ -0,0 +1,32 @@
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpSource GLSL 450
+ OpName %main "main"
+ OpName %i "i"
+ OpName %S "S"
+ OpMemberName %S 0 "i"
+ OpName %V "V"
+ OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+ %S = OpTypeStruct %int
+ %_ptr_Function_S = OpTypePointer Function %S
+ %int_0 = OpConstant %int 0
+ %uint = OpTypeInt 32 0
+ %v3uint = OpTypeVector %uint 3
+ %uint_1 = OpConstant %uint 1
+ %gl_WorkGroupSize = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function
+ %V = OpVariable %_ptr_Function_S Function
+ %13 = OpAccessChain %_ptr_Function_int %V %int_0
+ %14 = OpLoad %int %13
+ OpStore %i %14
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/load/local/struct_field.spvasm.expected.hlsl b/test/ptr_ref/load/local/struct_field.spvasm.expected.hlsl
new file mode 100644
index 0000000..342340a
--- /dev/null
+++ b/test/ptr_ref/load/local/struct_field.spvasm.expected.hlsl
@@ -0,0 +1,13 @@
+struct S {
+ int i;
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+ int i = 0;
+ S V = {0};
+ const int x_14 = V.i;
+ i = x_14;
+ return;
+}
+
diff --git a/test/ptr_ref/load/local/struct_field.spvasm.expected.msl b/test/ptr_ref/load/local/struct_field.spvasm.expected.msl
new file mode 100644
index 0000000..185bd72
--- /dev/null
+++ b/test/ptr_ref/load/local/struct_field.spvasm.expected.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct S {
+ int i;
+};
+
+kernel void tint_symbol() {
+ int i = 0;
+ S V = {};
+ int const x_14 = V.i;
+ i = x_14;
+ return;
+}
+
diff --git a/test/ptr_ref/load/local/struct_field.spvasm.expected.spvasm b/test/ptr_ref/load/local/struct_field.spvasm.expected.spvasm
new file mode 100644
index 0000000..814dd1b
--- /dev/null
+++ b/test/ptr_ref/load/local/struct_field.spvasm.expected.spvasm
@@ -0,0 +1,34 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %i "i"
+ OpName %S "S"
+ OpMemberName %S 0 "i"
+ OpName %V "V"
+ OpMemberDecorate %S 0 Offset 0
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+ %8 = OpConstantNull %int
+ %S = OpTypeStruct %int
+%_ptr_Function_S = OpTypePointer Function %S
+ %12 = OpConstantNull %S
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %8
+ %V = OpVariable %_ptr_Function_S Function %12
+ %15 = OpAccessChain %_ptr_Function_int %V %uint_0
+ %16 = OpLoad %int %15
+ OpStore %i %16
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/load/local/struct_field.spvasm.expected.wgsl b/test/ptr_ref/load/local/struct_field.spvasm.expected.wgsl
new file mode 100644
index 0000000..ae1c95e
--- /dev/null
+++ b/test/ptr_ref/load/local/struct_field.spvasm.expected.wgsl
@@ -0,0 +1,12 @@
+struct S {
+ i : i32;
+};
+
+[[stage(compute)]]
+fn main() {
+ var i : i32;
+ var V : S;
+ let x_14 : i32 = V.i;
+ i = x_14;
+ return;
+}
diff --git a/test/ptr_ref/load/local/struct_field.wgsl b/test/ptr_ref/load/local/struct_field.wgsl
new file mode 100644
index 0000000..2242ebb
--- /dev/null
+++ b/test/ptr_ref/load/local/struct_field.wgsl
@@ -0,0 +1,10 @@
+struct S {
+ i : i32;
+};
+
+[[stage(compute)]]
+fn main() {
+ var V : S;
+ var i : i32 = V.i;
+ return;
+}
diff --git a/test/ptr_ref/load/local/struct_field.wgsl.expected.hlsl b/test/ptr_ref/load/local/struct_field.wgsl.expected.hlsl
new file mode 100644
index 0000000..efe9eb6
--- /dev/null
+++ b/test/ptr_ref/load/local/struct_field.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+struct S {
+ int i;
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+ S V = {0};
+ int i = V.i;
+ return;
+}
+
diff --git a/test/ptr_ref/load/local/struct_field.wgsl.expected.msl b/test/ptr_ref/load/local/struct_field.wgsl.expected.msl
new file mode 100644
index 0000000..e6c6fb2
--- /dev/null
+++ b/test/ptr_ref/load/local/struct_field.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct S {
+ int i;
+};
+
+kernel void tint_symbol() {
+ S V = {};
+ int i = V.i;
+ return;
+}
+
diff --git a/test/ptr_ref/load/local/struct_field.wgsl.expected.spvasm b/test/ptr_ref/load/local/struct_field.wgsl.expected.spvasm
new file mode 100644
index 0000000..52c8d56
--- /dev/null
+++ b/test/ptr_ref/load/local/struct_field.wgsl.expected.spvasm
@@ -0,0 +1,34 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %S "S"
+ OpMemberName %S 0 "i"
+ OpName %V "V"
+ OpName %i "i"
+ OpMemberDecorate %S 0 Offset 0
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %S = OpTypeStruct %int
+%_ptr_Function_S = OpTypePointer Function %S
+ %9 = OpConstantNull %S
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Function_int = OpTypePointer Function %int
+ %16 = OpConstantNull %int
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %V = OpVariable %_ptr_Function_S Function %9
+ %i = OpVariable %_ptr_Function_int Function %16
+ %13 = OpAccessChain %_ptr_Function_int %V %uint_0
+ %14 = OpLoad %int %13
+ OpStore %i %14
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/load/local/struct_field.wgsl.expected.wgsl b/test/ptr_ref/load/local/struct_field.wgsl.expected.wgsl
new file mode 100644
index 0000000..2242ebb
--- /dev/null
+++ b/test/ptr_ref/load/local/struct_field.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+struct S {
+ i : i32;
+};
+
+[[stage(compute)]]
+fn main() {
+ var V : S;
+ var i : i32 = V.i;
+ return;
+}
diff --git a/test/ptr_ref/load/param/ptr.spvasm b/test/ptr_ref/load/param/ptr.spvasm
new file mode 100644
index 0000000..bf904d1
--- /dev/null
+++ b/test/ptr_ref/load/param/ptr.spvasm
@@ -0,0 +1,37 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 21
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %func "func"
+ OpName %value "value"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpName %i "i"
+ %int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+ %1 = OpTypeFunction %int %int %_ptr_Function_int
+ %void = OpTypeVoid
+ %11 = OpTypeFunction %void
+ %int_123 = OpConstant %int 123
+ %17 = OpConstantNull %int
+ %func = OpFunction %int None %1
+ %value = OpFunctionParameter %int
+ %pointer = OpFunctionParameter %_ptr_Function_int
+ %7 = OpLabel
+ %9 = OpLoad %int %pointer
+ %10 = OpIAdd %int %value %9
+ OpReturnValue %10
+ OpFunctionEnd
+ %main = OpFunction %void None %11
+ %14 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %17
+ OpStore %i %int_123
+ %19 = OpLoad %int %i
+ %18 = OpFunctionCall %int %func %19 %i
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/load/param/ptr.spvasm.expected.hlsl b/test/ptr_ref/load/param/ptr.spvasm.expected.hlsl
new file mode 100644
index 0000000..16f9b25
--- /dev/null
+++ b/test/ptr_ref/load/param/ptr.spvasm.expected.hlsl
@@ -0,0 +1 @@
+SKIP: error: pointers not supported in HLSL
diff --git a/test/ptr_ref/load/param/ptr.spvasm.expected.msl b/test/ptr_ref/load/param/ptr.spvasm.expected.msl
new file mode 100644
index 0000000..cbe0a55
--- /dev/null
+++ b/test/ptr_ref/load/param/ptr.spvasm.expected.msl
@@ -0,0 +1,16 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int func(int value, int* pointer) {
+ int const x_9 = *(pointer);
+ return (value + x_9);
+}
+
+kernel void tint_symbol() {
+ int i = 0;
+ i = 123;
+ int const x_19 = i;
+ int const x_18 = func(x_19, &(i));
+ return;
+}
+
diff --git a/test/ptr_ref/load/param/ptr.spvasm.expected.spvasm b/test/ptr_ref/load/param/ptr.spvasm.expected.spvasm
new file mode 100644
index 0000000..967e2a6
--- /dev/null
+++ b/test/ptr_ref/load/param/ptr.spvasm.expected.spvasm
@@ -0,0 +1,39 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 22
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %func "func"
+ OpName %value "value"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpName %i "i"
+ %int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+ %1 = OpTypeFunction %int %int %_ptr_Function_int
+ %void = OpTypeVoid
+ %11 = OpTypeFunction %void
+ %int_0 = OpConstant %int 0
+ %17 = OpConstantNull %int
+ %int_123 = OpConstant %int 123
+ %func = OpFunction %int None %1
+ %value = OpFunctionParameter %int
+ %pointer = OpFunctionParameter %_ptr_Function_int
+ %7 = OpLabel
+ %9 = OpLoad %int %pointer
+ %10 = OpIAdd %int %value %9
+ OpReturnValue %10
+ OpFunctionEnd
+ %main = OpFunction %void None %11
+ %14 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %17
+ OpStore %i %int_0
+ OpStore %i %int_123
+ %19 = OpLoad %int %i
+ %20 = OpFunctionCall %int %func %19 %i
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/load/param/ptr.spvasm.expected.wgsl b/test/ptr_ref/load/param/ptr.spvasm.expected.wgsl
new file mode 100644
index 0000000..e74bd4e
--- /dev/null
+++ b/test/ptr_ref/load/param/ptr.spvasm.expected.wgsl
@@ -0,0 +1,13 @@
+fn func(value : i32, pointer : ptr<function, i32>) -> i32 {
+ let x_9 : i32 = *(pointer);
+ return (value + x_9);
+}
+
+[[stage(compute)]]
+fn main() {
+ var i : i32 = 0;
+ i = 123;
+ let x_19 : i32 = i;
+ let x_18 : i32 = func(x_19, &(i));
+ return;
+}
diff --git a/test/ptr_ref/load/param/ptr.wgsl b/test/ptr_ref/load/param/ptr.wgsl
new file mode 100644
index 0000000..d57e057
--- /dev/null
+++ b/test/ptr_ref/load/param/ptr.wgsl
@@ -0,0 +1,9 @@
+fn func(value : i32, pointer : ptr<function, i32>) -> i32 {
+ return value + *pointer;
+}
+
+[[stage(compute)]]
+fn main() {
+ var i : i32 = 123;
+ let r : i32 = func(i, &i);
+}
diff --git a/test/ptr_ref/load/param/ptr.wgsl.expected.hlsl b/test/ptr_ref/load/param/ptr.wgsl.expected.hlsl
new file mode 100644
index 0000000..16f9b25
--- /dev/null
+++ b/test/ptr_ref/load/param/ptr.wgsl.expected.hlsl
@@ -0,0 +1 @@
+SKIP: error: pointers not supported in HLSL
diff --git a/test/ptr_ref/load/param/ptr.wgsl.expected.msl b/test/ptr_ref/load/param/ptr.wgsl.expected.msl
new file mode 100644
index 0000000..48556e1
--- /dev/null
+++ b/test/ptr_ref/load/param/ptr.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int func(int value, int* pointer) {
+ return (value + *(pointer));
+}
+
+kernel void tint_symbol() {
+ int i = 123;
+ int const r = func(i, &(i));
+ return;
+}
+
diff --git a/test/ptr_ref/load/param/ptr.wgsl.expected.spvasm b/test/ptr_ref/load/param/ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..bf904d1
--- /dev/null
+++ b/test/ptr_ref/load/param/ptr.wgsl.expected.spvasm
@@ -0,0 +1,37 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 21
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %func "func"
+ OpName %value "value"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpName %i "i"
+ %int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+ %1 = OpTypeFunction %int %int %_ptr_Function_int
+ %void = OpTypeVoid
+ %11 = OpTypeFunction %void
+ %int_123 = OpConstant %int 123
+ %17 = OpConstantNull %int
+ %func = OpFunction %int None %1
+ %value = OpFunctionParameter %int
+ %pointer = OpFunctionParameter %_ptr_Function_int
+ %7 = OpLabel
+ %9 = OpLoad %int %pointer
+ %10 = OpIAdd %int %value %9
+ OpReturnValue %10
+ OpFunctionEnd
+ %main = OpFunction %void None %11
+ %14 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %17
+ OpStore %i %int_123
+ %19 = OpLoad %int %i
+ %18 = OpFunctionCall %int %func %19 %i
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/load/param/ptr.wgsl.expected.wgsl b/test/ptr_ref/load/param/ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..bcfc824
--- /dev/null
+++ b/test/ptr_ref/load/param/ptr.wgsl.expected.wgsl
@@ -0,0 +1,9 @@
+fn func(value : i32, pointer : ptr<function, i32>) -> i32 {
+ return (value + *(pointer));
+}
+
+[[stage(compute)]]
+fn main() {
+ var i : i32 = 123;
+ let r : i32 = func(i, &(i));
+}
diff --git a/test/ptr_ref/store/global/i32.spvasm b/test/ptr_ref/store/global/i32.spvasm
new file mode 100644
index 0000000..8c25a15
--- /dev/null
+++ b/test/ptr_ref/store/global/i32.spvasm
@@ -0,0 +1,29 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 15
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %I "I"
+ OpName %main "main"
+ %int = OpTypeInt 32 1
+%_ptr_Private_int = OpTypePointer Private %int
+ %4 = OpConstantNull %int
+ %I = OpVariable %_ptr_Private_int Private %4
+ %void = OpTypeVoid
+ %5 = OpTypeFunction %void
+ %int_123 = OpConstant %int 123
+ %int_100 = OpConstant %int 100
+ %int_20 = OpConstant %int 20
+ %int_3 = OpConstant %int 3
+ %main = OpFunction %void None %5
+ %8 = OpLabel
+ OpStore %I %int_123
+ %12 = OpIAdd %int %int_100 %int_20
+ %14 = OpIAdd %int %12 %int_3
+ OpStore %I %14
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/store/global/i32.spvasm.expected.hlsl b/test/ptr_ref/store/global/i32.spvasm.expected.hlsl
new file mode 100644
index 0000000..104200b
--- /dev/null
+++ b/test/ptr_ref/store/global/i32.spvasm.expected.hlsl
@@ -0,0 +1,9 @@
+int I = 0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ I = 123;
+ I = ((100 + 20) + 3);
+ return;
+}
+
diff --git a/test/ptr_ref/store/global/i32.spvasm.expected.msl b/test/ptr_ref/store/global/i32.spvasm.expected.msl
new file mode 100644
index 0000000..1b2d3db
--- /dev/null
+++ b/test/ptr_ref/store/global/i32.spvasm.expected.msl
@@ -0,0 +1 @@
+SKIP: TINT_UNIMPLEMENTED crbug.com/tint/726: module-scope private and workgroup variables not yet implemented
diff --git a/test/ptr_ref/store/global/i32.spvasm.expected.spvasm b/test/ptr_ref/store/global/i32.spvasm.expected.spvasm
new file mode 100644
index 0000000..786fc8a
--- /dev/null
+++ b/test/ptr_ref/store/global/i32.spvasm.expected.spvasm
@@ -0,0 +1,29 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 15
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %I "I"
+ OpName %main "main"
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+%_ptr_Private_int = OpTypePointer Private %int
+ %I = OpVariable %_ptr_Private_int Private %int_0
+ %void = OpTypeVoid
+ %5 = OpTypeFunction %void
+ %int_123 = OpConstant %int 123
+ %int_100 = OpConstant %int 100
+ %int_20 = OpConstant %int 20
+ %int_3 = OpConstant %int 3
+ %main = OpFunction %void None %5
+ %8 = OpLabel
+ OpStore %I %int_123
+ %12 = OpIAdd %int %int_100 %int_20
+ %14 = OpIAdd %int %12 %int_3
+ OpStore %I %14
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/store/global/i32.spvasm.expected.wgsl b/test/ptr_ref/store/global/i32.spvasm.expected.wgsl
new file mode 100644
index 0000000..9d7722f
--- /dev/null
+++ b/test/ptr_ref/store/global/i32.spvasm.expected.wgsl
@@ -0,0 +1,8 @@
+var<private> I : i32 = 0;
+
+[[stage(compute)]]
+fn main() {
+ I = 123;
+ I = ((100 + 20) + 3);
+ return;
+}
diff --git a/test/ptr_ref/store/global/i32.wgsl b/test/ptr_ref/store/global/i32.wgsl
new file mode 100644
index 0000000..009f457
--- /dev/null
+++ b/test/ptr_ref/store/global/i32.wgsl
@@ -0,0 +1,7 @@
+var<private> I : i32;
+
+[[stage(compute)]]
+fn main() {
+ I = 123; // constant
+ I = 100 + 20 + 3; // dynamic
+}
diff --git a/test/ptr_ref/store/global/i32.wgsl.expected.hlsl b/test/ptr_ref/store/global/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..44c1654
--- /dev/null
+++ b/test/ptr_ref/store/global/i32.wgsl.expected.hlsl
@@ -0,0 +1,9 @@
+int I;
+
+[numthreads(1, 1, 1)]
+void main() {
+ I = 123;
+ I = ((100 + 20) + 3);
+ return;
+}
+
diff --git a/test/ptr_ref/store/global/i32.wgsl.expected.msl b/test/ptr_ref/store/global/i32.wgsl.expected.msl
new file mode 100644
index 0000000..1b2d3db
--- /dev/null
+++ b/test/ptr_ref/store/global/i32.wgsl.expected.msl
@@ -0,0 +1 @@
+SKIP: TINT_UNIMPLEMENTED crbug.com/tint/726: module-scope private and workgroup variables not yet implemented
diff --git a/test/ptr_ref/store/global/i32.wgsl.expected.spvasm b/test/ptr_ref/store/global/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..8c25a15
--- /dev/null
+++ b/test/ptr_ref/store/global/i32.wgsl.expected.spvasm
@@ -0,0 +1,29 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 15
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %I "I"
+ OpName %main "main"
+ %int = OpTypeInt 32 1
+%_ptr_Private_int = OpTypePointer Private %int
+ %4 = OpConstantNull %int
+ %I = OpVariable %_ptr_Private_int Private %4
+ %void = OpTypeVoid
+ %5 = OpTypeFunction %void
+ %int_123 = OpConstant %int 123
+ %int_100 = OpConstant %int 100
+ %int_20 = OpConstant %int 20
+ %int_3 = OpConstant %int 3
+ %main = OpFunction %void None %5
+ %8 = OpLabel
+ OpStore %I %int_123
+ %12 = OpIAdd %int %int_100 %int_20
+ %14 = OpIAdd %int %12 %int_3
+ OpStore %I %14
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/store/global/i32.wgsl.expected.wgsl b/test/ptr_ref/store/global/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..b995990
--- /dev/null
+++ b/test/ptr_ref/store/global/i32.wgsl.expected.wgsl
@@ -0,0 +1,7 @@
+var<private> I : i32;
+
+[[stage(compute)]]
+fn main() {
+ I = 123;
+ I = ((100 + 20) + 3);
+}
diff --git a/test/ptr_ref/store/global/struct_field.spvasm b/test/ptr_ref/store/global/struct_field.spvasm
new file mode 100644
index 0000000..b3ca86b
--- /dev/null
+++ b/test/ptr_ref/store/global/struct_field.spvasm
@@ -0,0 +1,30 @@
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpSource GLSL 450
+ OpName %main "main"
+ OpName %S "S"
+ OpMemberName %S 0 "i"
+ OpName %V "V"
+ OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %S = OpTypeStruct %int
+ %_ptr_Private_S = OpTypePointer Private %S
+ %V = OpVariable %_ptr_Private_S Private
+ %int_0 = OpConstant %int 0
+ %int_5 = OpConstant %int 5
+%_ptr_Private_int = OpTypePointer Private %int
+ %uint = OpTypeInt 32 0
+ %v3uint = OpTypeVector %uint 3
+ %uint_1 = OpConstant %uint 1
+%gl_WorkGroupSize = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %13 = OpAccessChain %_ptr_Private_int %V %int_0
+ OpStore %13 %int_5
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/store/global/struct_field.spvasm.expected.hlsl b/test/ptr_ref/store/global/struct_field.spvasm.expected.hlsl
new file mode 100644
index 0000000..16f9b25
--- /dev/null
+++ b/test/ptr_ref/store/global/struct_field.spvasm.expected.hlsl
@@ -0,0 +1 @@
+SKIP: error: pointers not supported in HLSL
diff --git a/test/ptr_ref/store/global/struct_field.spvasm.expected.msl b/test/ptr_ref/store/global/struct_field.spvasm.expected.msl
new file mode 100644
index 0000000..1b2d3db
--- /dev/null
+++ b/test/ptr_ref/store/global/struct_field.spvasm.expected.msl
@@ -0,0 +1 @@
+SKIP: TINT_UNIMPLEMENTED crbug.com/tint/726: module-scope private and workgroup variables not yet implemented
diff --git a/test/ptr_ref/store/global/struct_field.spvasm.expected.spvasm b/test/ptr_ref/store/global/struct_field.spvasm.expected.spvasm
new file mode 100644
index 0000000..e63c070
--- /dev/null
+++ b/test/ptr_ref/store/global/struct_field.spvasm.expected.spvasm
@@ -0,0 +1,31 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 15
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %S "S"
+ OpMemberName %S 0 "i"
+ OpName %V "V"
+ OpName %main "main"
+ OpMemberDecorate %S 0 Offset 0
+ %int = OpTypeInt 32 1
+ %S = OpTypeStruct %int
+%_ptr_Private_S = OpTypePointer Private %S
+ %5 = OpConstantNull %S
+ %V = OpVariable %_ptr_Private_S Private %5
+ %void = OpTypeVoid
+ %6 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Private_int = OpTypePointer Private %int
+ %int_5 = OpConstant %int 5
+ %main = OpFunction %void None %6
+ %9 = OpLabel
+ %13 = OpAccessChain %_ptr_Private_int %V %uint_0
+ OpStore %13 %int_5
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/store/global/struct_field.spvasm.expected.wgsl b/test/ptr_ref/store/global/struct_field.spvasm.expected.wgsl
new file mode 100644
index 0000000..50cb6f4
--- /dev/null
+++ b/test/ptr_ref/store/global/struct_field.spvasm.expected.wgsl
@@ -0,0 +1,11 @@
+struct S {
+ i : i32;
+};
+
+var<private> V : S;
+
+[[stage(compute)]]
+fn main() {
+ V.i = 5;
+ return;
+}
diff --git a/test/ptr_ref/store/local/i32.spvasm b/test/ptr_ref/store/local/i32.spvasm
new file mode 100644
index 0000000..30df9e1
--- /dev/null
+++ b/test/ptr_ref/store/local/i32.spvasm
@@ -0,0 +1,30 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %i "i"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %int_123 = OpConstant %int 123
+%_ptr_Function_int = OpTypePointer Function %int
+ %9 = OpConstantNull %int
+ %int_100 = OpConstant %int 100
+ %int_20 = OpConstant %int 20
+ %int_3 = OpConstant %int 3
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %9
+ OpStore %i %int_123
+ OpStore %i %int_123
+ %15 = OpIAdd %int %int_100 %int_20
+ %17 = OpIAdd %int %15 %int_3
+ OpStore %i %17
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/store/local/i32.spvasm.expected.hlsl b/test/ptr_ref/store/local/i32.spvasm.expected.hlsl
new file mode 100644
index 0000000..c6dc7c5
--- /dev/null
+++ b/test/ptr_ref/store/local/i32.spvasm.expected.hlsl
@@ -0,0 +1,9 @@
+[numthreads(1, 1, 1)]
+void main() {
+ int i = 0;
+ i = 123;
+ i = 123;
+ i = ((100 + 20) + 3);
+ return;
+}
+
diff --git a/test/ptr_ref/store/local/i32.spvasm.expected.msl b/test/ptr_ref/store/local/i32.spvasm.expected.msl
new file mode 100644
index 0000000..21174ae
--- /dev/null
+++ b/test/ptr_ref/store/local/i32.spvasm.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol() {
+ int i = 0;
+ i = 123;
+ i = 123;
+ i = ((100 + 20) + 3);
+ return;
+}
+
diff --git a/test/ptr_ref/store/local/i32.spvasm.expected.spvasm b/test/ptr_ref/store/local/i32.spvasm.expected.spvasm
new file mode 100644
index 0000000..5a05b5e
--- /dev/null
+++ b/test/ptr_ref/store/local/i32.spvasm.expected.spvasm
@@ -0,0 +1,32 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %i "i"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+%_ptr_Function_int = OpTypePointer Function %int
+ %9 = OpConstantNull %int
+ %int_123 = OpConstant %int 123
+ %int_100 = OpConstant %int 100
+ %int_20 = OpConstant %int 20
+ %int_3 = OpConstant %int 3
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %9
+ OpStore %i %int_0
+ OpStore %i %int_123
+ OpStore %i %int_123
+ %13 = OpIAdd %int %int_100 %int_20
+ %15 = OpIAdd %int %13 %int_3
+ OpStore %i %15
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/store/local/i32.spvasm.expected.wgsl b/test/ptr_ref/store/local/i32.spvasm.expected.wgsl
new file mode 100644
index 0000000..ebc870a
--- /dev/null
+++ b/test/ptr_ref/store/local/i32.spvasm.expected.wgsl
@@ -0,0 +1,8 @@
+[[stage(compute)]]
+fn main() {
+ var i : i32 = 0;
+ i = 123;
+ i = 123;
+ i = ((100 + 20) + 3);
+ return;
+}
diff --git a/test/ptr_ref/store/local/i32.wgsl b/test/ptr_ref/store/local/i32.wgsl
new file mode 100644
index 0000000..ccfe0d6
--- /dev/null
+++ b/test/ptr_ref/store/local/i32.wgsl
@@ -0,0 +1,7 @@
+[[stage(compute)]]
+fn main() {
+ var i : i32 = 123;
+ let p : ptr<function, i32> = &i;
+ *p = 123; // constant
+ *p = 100 + 20 + 3; // dynamic
+}
diff --git a/test/ptr_ref/store/local/i32.wgsl.expected.hlsl b/test/ptr_ref/store/local/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..16f9b25
--- /dev/null
+++ b/test/ptr_ref/store/local/i32.wgsl.expected.hlsl
@@ -0,0 +1 @@
+SKIP: error: pointers not supported in HLSL
diff --git a/test/ptr_ref/store/local/i32.wgsl.expected.msl b/test/ptr_ref/store/local/i32.wgsl.expected.msl
new file mode 100644
index 0000000..6674f82
--- /dev/null
+++ b/test/ptr_ref/store/local/i32.wgsl.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol() {
+ int i = 123;
+ int* const p = &(i);
+ *(p) = 123;
+ *(p) = ((100 + 20) + 3);
+ return;
+}
+
diff --git a/test/ptr_ref/store/local/i32.wgsl.expected.spvasm b/test/ptr_ref/store/local/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..30df9e1
--- /dev/null
+++ b/test/ptr_ref/store/local/i32.wgsl.expected.spvasm
@@ -0,0 +1,30 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %i "i"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %int_123 = OpConstant %int 123
+%_ptr_Function_int = OpTypePointer Function %int
+ %9 = OpConstantNull %int
+ %int_100 = OpConstant %int 100
+ %int_20 = OpConstant %int 20
+ %int_3 = OpConstant %int 3
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %9
+ OpStore %i %int_123
+ OpStore %i %int_123
+ %15 = OpIAdd %int %int_100 %int_20
+ %17 = OpIAdd %int %15 %int_3
+ OpStore %i %17
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/store/local/i32.wgsl.expected.wgsl b/test/ptr_ref/store/local/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..36391d6
--- /dev/null
+++ b/test/ptr_ref/store/local/i32.wgsl.expected.wgsl
@@ -0,0 +1,7 @@
+[[stage(compute)]]
+fn main() {
+ var i : i32 = 123;
+ let p : ptr<function, i32> = &(i);
+ *(p) = 123;
+ *(p) = ((100 + 20) + 3);
+}
diff --git a/test/ptr_ref/store/local/struct_field.spvasm b/test/ptr_ref/store/local/struct_field.spvasm
new file mode 100644
index 0000000..1c850d1
--- /dev/null
+++ b/test/ptr_ref/store/local/struct_field.spvasm
@@ -0,0 +1,30 @@
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpSource GLSL 450
+ OpName %main "main"
+ OpName %S "S"
+ OpMemberName %S 0 "i"
+ OpName %V "V"
+ OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %S = OpTypeStruct %int
+ %_ptr_Function_S = OpTypePointer Function %S
+ %int_0 = OpConstant %int 0
+ %int_5 = OpConstant %int 5
+%_ptr_Function_int = OpTypePointer Function %int
+ %uint = OpTypeInt 32 0
+ %v3uint = OpTypeVector %uint 3
+ %uint_1 = OpConstant %uint 1
+ %gl_WorkGroupSize = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ %V = OpVariable %_ptr_Function_S Function
+ %13 = OpAccessChain %_ptr_Function_int %V %int_0
+ OpStore %13 %int_5
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/store/local/struct_field.spvasm.expected.hlsl b/test/ptr_ref/store/local/struct_field.spvasm.expected.hlsl
new file mode 100644
index 0000000..247388a
--- /dev/null
+++ b/test/ptr_ref/store/local/struct_field.spvasm.expected.hlsl
@@ -0,0 +1,11 @@
+struct S {
+ int i;
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+ S V = {0};
+ V.i = 5;
+ return;
+}
+
diff --git a/test/ptr_ref/store/local/struct_field.spvasm.expected.msl b/test/ptr_ref/store/local/struct_field.spvasm.expected.msl
new file mode 100644
index 0000000..2e6989d
--- /dev/null
+++ b/test/ptr_ref/store/local/struct_field.spvasm.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct S {
+ int i;
+};
+
+kernel void tint_symbol() {
+ S V = {};
+ V.i = 5;
+ return;
+}
+
diff --git a/test/ptr_ref/store/local/struct_field.spvasm.expected.spvasm b/test/ptr_ref/store/local/struct_field.spvasm.expected.spvasm
new file mode 100644
index 0000000..255c691
--- /dev/null
+++ b/test/ptr_ref/store/local/struct_field.spvasm.expected.spvasm
@@ -0,0 +1,31 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 15
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %S "S"
+ OpMemberName %S 0 "i"
+ OpName %V "V"
+ OpMemberDecorate %S 0 Offset 0
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %S = OpTypeStruct %int
+%_ptr_Function_S = OpTypePointer Function %S
+ %9 = OpConstantNull %S
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Function_int = OpTypePointer Function %int
+ %int_5 = OpConstant %int 5
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %V = OpVariable %_ptr_Function_S Function %9
+ %13 = OpAccessChain %_ptr_Function_int %V %uint_0
+ OpStore %13 %int_5
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/store/local/struct_field.spvasm.expected.wgsl b/test/ptr_ref/store/local/struct_field.spvasm.expected.wgsl
new file mode 100644
index 0000000..77d7681
--- /dev/null
+++ b/test/ptr_ref/store/local/struct_field.spvasm.expected.wgsl
@@ -0,0 +1,10 @@
+struct S {
+ i : i32;
+};
+
+[[stage(compute)]]
+fn main() {
+ var V : S;
+ V.i = 5;
+ return;
+}
diff --git a/test/ptr_ref/store/param/ptr.spvasm b/test/ptr_ref/store/param/ptr.spvasm
new file mode 100644
index 0000000..e750538
--- /dev/null
+++ b/test/ptr_ref/store/param/ptr.spvasm
@@ -0,0 +1,35 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %func "func"
+ OpName %value "value"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpName %i "i"
+ %void = OpTypeVoid
+ %int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+ %1 = OpTypeFunction %void %int %_ptr_Function_int
+ %10 = OpTypeFunction %void
+ %int_123 = OpConstant %int 123
+ %15 = OpConstantNull %int
+ %func = OpFunction %void None %1
+ %value = OpFunctionParameter %int
+ %pointer = OpFunctionParameter %_ptr_Function_int
+ %8 = OpLabel
+ OpStore %pointer %value
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %10
+ %12 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %15
+ OpStore %i %int_123
+ %16 = OpFunctionCall %void %func %int_123 %i
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/store/param/ptr.spvasm.expected.hlsl b/test/ptr_ref/store/param/ptr.spvasm.expected.hlsl
new file mode 100644
index 0000000..16f9b25
--- /dev/null
+++ b/test/ptr_ref/store/param/ptr.spvasm.expected.hlsl
@@ -0,0 +1 @@
+SKIP: error: pointers not supported in HLSL
diff --git a/test/ptr_ref/store/param/ptr.spvasm.expected.msl b/test/ptr_ref/store/param/ptr.spvasm.expected.msl
new file mode 100644
index 0000000..5d459da
--- /dev/null
+++ b/test/ptr_ref/store/param/ptr.spvasm.expected.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void func(int value, int* pointer) {
+ *(pointer) = value;
+ return;
+}
+
+kernel void tint_symbol() {
+ int i = 0;
+ i = 123;
+ func(123, &(i));
+ return;
+}
+
diff --git a/test/ptr_ref/store/param/ptr.spvasm.expected.spvasm b/test/ptr_ref/store/param/ptr.spvasm.expected.spvasm
new file mode 100644
index 0000000..8126ab6
--- /dev/null
+++ b/test/ptr_ref/store/param/ptr.spvasm.expected.spvasm
@@ -0,0 +1,37 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 19
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %func "func"
+ OpName %value "value"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpName %i "i"
+ %void = OpTypeVoid
+ %int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+ %1 = OpTypeFunction %void %int %_ptr_Function_int
+ %10 = OpTypeFunction %void
+ %int_0 = OpConstant %int 0
+ %15 = OpConstantNull %int
+ %int_123 = OpConstant %int 123
+ %func = OpFunction %void None %1
+ %value = OpFunctionParameter %int
+ %pointer = OpFunctionParameter %_ptr_Function_int
+ %8 = OpLabel
+ OpStore %pointer %value
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %10
+ %12 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %15
+ OpStore %i %int_0
+ OpStore %i %int_123
+ %17 = OpFunctionCall %void %func %int_123 %i
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/store/param/ptr.spvasm.expected.wgsl b/test/ptr_ref/store/param/ptr.spvasm.expected.wgsl
new file mode 100644
index 0000000..b3de2eb
--- /dev/null
+++ b/test/ptr_ref/store/param/ptr.spvasm.expected.wgsl
@@ -0,0 +1,12 @@
+fn func(value : i32, pointer : ptr<function, i32>) {
+ *(pointer) = value;
+ return;
+}
+
+[[stage(compute)]]
+fn main() {
+ var i : i32 = 0;
+ i = 123;
+ func(123, &(i));
+ return;
+}
diff --git a/test/ptr_ref/store/param/ptr.wgsl b/test/ptr_ref/store/param/ptr.wgsl
new file mode 100644
index 0000000..6cba3d3
--- /dev/null
+++ b/test/ptr_ref/store/param/ptr.wgsl
@@ -0,0 +1,9 @@
+fn func(value : i32, pointer : ptr<function, i32>) {
+ *pointer = value;
+}
+
+[[stage(compute)]]
+fn main() {
+ var i : i32 = 123;
+ func(123, &i);
+}
diff --git a/test/ptr_ref/store/param/ptr.wgsl.expected.hlsl b/test/ptr_ref/store/param/ptr.wgsl.expected.hlsl
new file mode 100644
index 0000000..16f9b25
--- /dev/null
+++ b/test/ptr_ref/store/param/ptr.wgsl.expected.hlsl
@@ -0,0 +1 @@
+SKIP: error: pointers not supported in HLSL
diff --git a/test/ptr_ref/store/param/ptr.wgsl.expected.msl b/test/ptr_ref/store/param/ptr.wgsl.expected.msl
new file mode 100644
index 0000000..517183a
--- /dev/null
+++ b/test/ptr_ref/store/param/ptr.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void func(int value, int* pointer) {
+ *(pointer) = value;
+}
+
+kernel void tint_symbol() {
+ int i = 123;
+ func(123, &(i));
+ return;
+}
+
diff --git a/test/ptr_ref/store/param/ptr.wgsl.expected.spvasm b/test/ptr_ref/store/param/ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..e750538
--- /dev/null
+++ b/test/ptr_ref/store/param/ptr.wgsl.expected.spvasm
@@ -0,0 +1,35 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %func "func"
+ OpName %value "value"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpName %i "i"
+ %void = OpTypeVoid
+ %int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+ %1 = OpTypeFunction %void %int %_ptr_Function_int
+ %10 = OpTypeFunction %void
+ %int_123 = OpConstant %int 123
+ %15 = OpConstantNull %int
+ %func = OpFunction %void None %1
+ %value = OpFunctionParameter %int
+ %pointer = OpFunctionParameter %_ptr_Function_int
+ %8 = OpLabel
+ OpStore %pointer %value
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %10
+ %12 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %15
+ OpStore %i %int_123
+ %16 = OpFunctionCall %void %func %int_123 %i
+ OpReturn
+ OpFunctionEnd
diff --git a/test/ptr_ref/store/param/ptr.wgsl.expected.wgsl b/test/ptr_ref/store/param/ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..78b3392
--- /dev/null
+++ b/test/ptr_ref/store/param/ptr.wgsl.expected.wgsl
@@ -0,0 +1,9 @@
+fn func(value : i32, pointer : ptr<function, i32>) {
+ *(pointer) = value;
+}
+
+[[stage(compute)]]
+fn main() {
+ var i : i32 = 123;
+ func(123, &(i));
+}
diff --git a/test/samples/compute_boids.wgsl.expected.msl b/test/samples/compute_boids.wgsl.expected.msl
index 05afb51..8b7f485 100644
--- a/test/samples/compute_boids.wgsl.expected.msl
+++ b/test/samples/compute_boids.wgsl.expected.msl
@@ -33,9 +33,9 @@
};
vertex tint_symbol_2 vert_main(tint_symbol_1 tint_symbol [[stage_in]]) {
- const float2 a_particlePos = tint_symbol.a_particlePos;
- const float2 a_particleVel = tint_symbol.a_particleVel;
- const float2 a_pos = tint_symbol.a_pos;
+ float2 const a_particlePos = tint_symbol.a_particlePos;
+ float2 const a_particleVel = tint_symbol.a_particleVel;
+ float2 const a_pos = tint_symbol.a_pos;
float angle = -( atan2(a_particleVel.x, a_particleVel.y));
float2 pos = float2(((a_pos.x * cos(angle)) - (a_pos.y * sin(angle))), ((a_pos.x * sin(angle)) + (a_pos.y * cos(angle))));
return {float4((pos + a_particlePos), 0.0f, 1.0f)};
@@ -46,7 +46,7 @@
}
kernel void comp_main(tint_symbol_5 tint_symbol_4 [[stage_in]], constant SimParams& params [[buffer(0)]], device Particles& particlesA [[buffer(1)]], device Particles& particlesB [[buffer(2)]]) {
- const uint3 gl_GlobalInvocationID = tint_symbol_4.gl_GlobalInvocationID;
+ uint3 const gl_GlobalInvocationID = tint_symbol_4.gl_GlobalInvocationID;
uint index = gl_GlobalInvocationID.x;
if ((index >= 5u)) {
return;
diff --git a/test/samples/cube.wgsl.expected.msl b/test/samples/cube.wgsl.expected.msl
index 4d86279..80dc476 100644
--- a/test/samples/cube.wgsl.expected.msl
+++ b/test/samples/cube.wgsl.expected.msl
@@ -28,7 +28,7 @@
};
vertex tint_symbol_2 vtx_main(tint_symbol_1 tint_symbol [[stage_in]], constant Uniforms& uniforms [[buffer(0)]]) {
- const VertexInput input = {tint_symbol.cur_position, tint_symbol.color};
+ VertexInput const input = {tint_symbol.cur_position, tint_symbol.color};
VertexOutput output = {};
output.Position = (uniforms.modelViewProjectionMatrix * input.cur_position);
output.vtxFragColor = input.color;
@@ -36,7 +36,7 @@
}
fragment tint_symbol_5 frag_main(tint_symbol_4 tint_symbol_3 [[stage_in]]) {
- const float4 fragColor = tint_symbol_3.fragColor;
+ float4 const fragColor = tint_symbol_3.fragColor;
return {fragColor};
}
diff --git a/test/samples/triangle.wgsl.expected.msl b/test/samples/triangle.wgsl.expected.msl
index 00638c3..7c4039b 100644
--- a/test/samples/triangle.wgsl.expected.msl
+++ b/test/samples/triangle.wgsl.expected.msl
@@ -13,7 +13,7 @@
constant float2 pos[3] = {float2(0.0f, 0.5f), float2(-0.5f, -0.5f), float2(0.5f, -0.5f)};
vertex tint_symbol_2 vtx_main(tint_symbol_1 tint_symbol [[stage_in]]) {
- const int VertexIndex = tint_symbol.VertexIndex;
+ int const VertexIndex = tint_symbol.VertexIndex;
return {float4(pos[VertexIndex], 0.0f, 1.0f)};
}