tint: Add DirectVariableAccess transform
Enables the 'chromium_experimental_full_ptr_parameters' extension to
allow passing of uniform, storage and workgroup address-spaced
pointers as parameters, as well as pointers into sub-objects.
Bug: tint:1758
Change-Id: I8c85e6104ef4f2b9a177dec2857b1bf7f5148212
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/103860
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Ben Clayton <bclayton@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index a51de7b..3d10a06 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -502,6 +502,8 @@
"transform/decompose_strided_matrix.h",
"transform/demote_to_helper.cc",
"transform/demote_to_helper.h",
+ "transform/direct_variable_access.cc",
+ "transform/direct_variable_access.h",
"transform/disable_uniformity_analysis.cc",
"transform/disable_uniformity_analysis.h",
"transform/expand_compound_assignment.cc",
@@ -1227,6 +1229,7 @@
"transform/decompose_strided_array_test.cc",
"transform/decompose_strided_matrix_test.cc",
"transform/demote_to_helper_test.cc",
+ "transform/direct_variable_access_test.cc",
"transform/disable_uniformity_analysis_test.cc",
"transform/expand_compound_assignment_test.cc",
"transform/first_index_offset_test.cc",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 4f193b5..cb9c96e 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -425,6 +425,8 @@
transform/decompose_strided_matrix.h
transform/demote_to_helper.cc
transform/demote_to_helper.h
+ transform/direct_variable_access.cc
+ transform/direct_variable_access.h
transform/disable_uniformity_analysis.cc
transform/disable_uniformity_analysis.h
transform/expand_compound_assignment.cc
@@ -1195,6 +1197,7 @@
transform/decompose_strided_array_test.cc
transform/decompose_strided_matrix_test.cc
transform/demote_to_helper_test.cc
+ transform/direct_variable_access_test.cc
transform/disable_uniformity_analysis_test.cc
transform/expand_compound_assignment_test.cc
transform/first_index_offset_test.cc
diff --git a/src/tint/transform/direct_variable_access.cc b/src/tint/transform/direct_variable_access.cc
new file mode 100644
index 0000000..d1c1339
--- /dev/null
+++ b/src/tint/transform/direct_variable_access.cc
@@ -0,0 +1,1216 @@
+// Copyright 2022 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/tint/transform/direct_variable_access.h"
+
+#include <algorithm>
+#include <string>
+#include <utility>
+
+#include "src/tint/ast/traverse_expressions.h"
+#include "src/tint/program_builder.h"
+#include "src/tint/sem/abstract_int.h"
+#include "src/tint/sem/call.h"
+#include "src/tint/sem/function.h"
+#include "src/tint/sem/index_accessor_expression.h"
+#include "src/tint/sem/member_accessor_expression.h"
+#include "src/tint/sem/module.h"
+#include "src/tint/sem/statement.h"
+#include "src/tint/sem/struct.h"
+#include "src/tint/sem/variable.h"
+#include "src/tint/transform/utils/hoist_to_decl_before.h"
+#include "src/tint/utils/reverse.h"
+#include "src/tint/utils/scoped_assignment.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::transform::DirectVariableAccess);
+TINT_INSTANTIATE_TYPEINFO(tint::transform::DirectVariableAccess::Config);
+
+using namespace tint::number_suffixes; // NOLINT
+
+namespace {
+
+/// AccessRoot describes the root of an AccessShape.
+struct AccessRoot {
+ /// The pointer-unwrapped type of the *transformed* variable.
+ /// This may be different for pointers in 'private' and 'function' address space, as the pointer
+ /// parameter type is to the *base object* instead of the input pointer type.
+ tint::sem::Type const* type = nullptr;
+ /// The originating module-scope variable ('private', 'storage', 'uniform', 'workgroup'),
+ /// function-scope variable ('function'), or pointer parameter in the source program.
+ tint::sem::Variable const* variable = nullptr;
+ /// The address space of the variable or pointer type.
+ tint::ast::AddressSpace address_space = tint::ast::AddressSpace::kUndefined;
+};
+
+/// Inequality operator for AccessRoot
+bool operator!=(const AccessRoot& a, const AccessRoot& b) {
+ return a.type != b.type || a.variable != b.variable;
+}
+
+/// DynamicIndex is used by DirectVariableAccess::State::AccessOp to indicate an array, matrix or
+/// vector index.
+struct DynamicIndex {
+ /// The index of the expression in DirectVariableAccess::State::AccessChain::dynamic_indices
+ size_t slot = 0;
+};
+
+/// Inequality operator for DynamicIndex
+bool operator!=(const DynamicIndex& a, const DynamicIndex& b) {
+ return a.slot != b.slot;
+}
+
+/// AccessOp describes a single access in an access chain.
+/// The access is one of:
+/// Symbol - a struct member access.
+/// DynamicIndex - a runtime index on an array, matrix column, or vector element.
+using AccessOp = std::variant<tint::Symbol, DynamicIndex>;
+
+/// A vector of AccessOp. Describes the static "path" from a root variable to an element
+/// within the variable. Array accessors index expressions are held externally to the
+/// AccessShape, so AccessShape will be considered equal even if the array, matrix or vector
+/// index values differ.
+///
+/// For example, consider the following:
+///
+/// ```
+/// struct A {
+/// x : array<i32, 8>,
+/// y : u32,
+/// };
+/// struct B {
+/// x : i32,
+/// y : array<A, 4>
+/// };
+/// var<workgroup> C : B;
+/// ```
+///
+/// The following AccessShape would describe the following:
+///
+/// +==============================+===============+=================================+
+/// | AccessShape | Type | Expression |
+/// +==============================+===============+=================================+
+/// | [ Variable 'C', Symbol 'x' ] | i32 | C.x |
+/// +------------------------------+---------------+---------------------------------+
+/// | [ Variable 'C', Symbol 'y' ] | array<A, 4> | C.y |
+/// +------------------------------+---------------+---------------------------------+
+/// | [ Variable 'C', Symbol 'y', | A | C.y[dyn_idx[0]] |
+/// | DynamicIndex ] | | |
+/// +------------------------------+---------------+---------------------------------+
+/// | [ Variable 'C', Symbol 'y', | array<i32, 8> | C.y[dyn_idx[0]].x |
+/// | DynamicIndex, Symbol 'x' ] | | |
+/// +------------------------------+---------------+---------------------------------+
+/// | [ Variable 'C', Symbol 'y', | i32 | C.y[dyn_idx[0]].x[dyn_idx[1]] |
+/// | DynamicIndex, Symbol 'x', | | |
+/// | DynamicIndex ] | | |
+/// +------------------------------+---------------+---------------------------------+
+/// | [ Variable 'C', Symbol 'y', | u32 | C.y[dyn_idx[0]].y |
+/// | DynamicIndex, Symbol 'y' ] | | |
+/// +------------------------------+---------------+---------------------------------+
+///
+/// Where: `dyn_idx` is the AccessChain::dynamic_indices.
+struct AccessShape {
+ // The originating variable.
+ AccessRoot root;
+ /// The chain of access ops.
+ tint::utils::Vector<AccessOp, 8> ops;
+
+ /// @returns the number of DynamicIndex operations in #ops.
+ uint32_t NumDynamicIndices() const {
+ uint32_t count = 0;
+ for (auto& op : ops) {
+ if (std::holds_alternative<DynamicIndex>(op)) {
+ count++;
+ }
+ }
+ return count;
+ }
+};
+
+/// Equality operator for AccessShape
+bool operator==(const AccessShape& a, const AccessShape& b) {
+ return !(a.root != b.root) && a.ops == b.ops;
+}
+
+/// Inequality operator for AccessShape
+bool operator!=(const AccessShape& a, const AccessShape& b) {
+ return !(a == b);
+}
+
+/// AccessChain describes a chain of access expressions originating from a variable.
+struct AccessChain : AccessShape {
+ /// The array accessor index expressions. This vector is indexed by the `DynamicIndex`s in
+ /// #indices.
+ tint::utils::Vector<const tint::sem::Expression*, 8> dynamic_indices;
+ /// If true, then this access chain is used as an argument to call a variant.
+ bool used_in_call = false;
+};
+
+} // namespace
+
+namespace tint::utils {
+
+/// Hasher specialization for AccessRoot
+template <>
+struct Hasher<AccessRoot> {
+ /// The hash function for the AccessRoot
+ /// @param d the AccessRoot to hash
+ /// @return the hash for the given AccessRoot
+ size_t operator()(const AccessRoot& d) const { return utils::Hash(d.type, d.variable); }
+};
+
+/// Hasher specialization for DynamicIndex
+template <>
+struct Hasher<DynamicIndex> {
+ /// The hash function for the DynamicIndex
+ /// @param d the DynamicIndex to hash
+ /// @return the hash for the given DynamicIndex
+ size_t operator()(const DynamicIndex& d) const { return utils::Hash(d.slot); }
+};
+
+/// Hasher specialization for AccessShape
+template <>
+struct Hasher<AccessShape> {
+ /// The hash function for the AccessShape
+ /// @param s the AccessShape to hash
+ /// @return the hash for the given AccessShape
+ size_t operator()(const AccessShape& s) const { return utils::Hash(s.root, s.ops); }
+};
+
+} // namespace tint::utils
+
+namespace tint::transform {
+
+/// The PIMPL state for the DirectVariableAccess transform
+struct DirectVariableAccess::State {
+ /// Constructor
+ /// @param src the source Program
+ /// @param options the transform options
+ State(const Program* src, const Options& options)
+ : ctx{&b, src, /* auto_clone_symbols */ true}, opts(options) {}
+
+ /// The main function for the transform.
+ /// @returns the ApplyResult
+ ApplyResult Run() {
+ if (!ctx.src->Sem().Module()->Extensions().Contains(
+ ast::Extension::kChromiumExperimentalFullPtrParameters)) {
+ // If the 'chromium_experimental_full_ptr_parameters' extension is not enabled, then
+ // there's nothing for this transform to do.
+ return SkipTransform;
+ }
+
+ // Stage 1:
+ // Walk all the expressions of the program, starting with the expression leaves.
+ // Whenever we find an identifier resolving to a var, pointer parameter or pointer let to
+ // another chain, start constructing an access chain. When chains are accessed, these chains
+ // are grown and moved up the expression tree. After this stage, we are left with all the
+ // expression access chains to variables that we may need to transform.
+ for (auto* node : ctx.src->ASTNodes().Objects()) {
+ if (auto* expr = sem.Get<sem::Expression>(node)) {
+ AppendAccessChain(expr);
+ }
+ }
+
+ // Stage 2:
+ // Walk the functions in dependency order, starting with the entry points.
+ // Construct the set of function 'variants' by examining the calls made by each function to
+ // their call target. Each variant holds a map of pointer parameter to access chains, and
+ // will have the pointer parameters replaced with an array of u32s, used to perform the
+ // pointer indexing in the variant.
+ // Function call pointer arguments are replaced with an array of these dynamic indices.
+ for (auto* decl : utils::Reverse(sem.Module()->DependencyOrderedDeclarations())) {
+ if (auto* fn = sem.Get<sem::Function>(decl)) {
+ auto* fn_info = FnInfoFor(fn);
+ ProcessFunction(fn, fn_info);
+ TransformFunction(fn, fn_info);
+ }
+ }
+
+ // Stage 3:
+ // Filter out access chains that do not need transforming.
+ // Ensure that chain dynamic index expressions are evaluated once at the correct place
+ ProcessAccessChains();
+
+ // Stage 4:
+ // Replace all the access chain expressions in all functions with reconstructed expression
+ // using the originating global variable, and any dynamic indices passed in to the function
+ // variant.
+ TransformAccessChainExpressions();
+
+ // Stage 5:
+ // Actually kick the clone.
+ CloneState state;
+ clone_state = &state;
+ ctx.Clone();
+ return Program(std::move(*ctx.dst));
+ }
+
+ private:
+ /// Holds symbols of the transformed pointer parameter.
+ /// If both symbols are valid, then #base_ptr and #indices are both program-unique symbols
+ /// derived from the original parameter name.
+ /// If only one symbol is valid, then this is the original parameter symbol.
+ struct PtrParamSymbols {
+ /// The symbol of the base pointer parameter.
+ Symbol base_ptr;
+ /// The symbol of the dynamic indicies parameter.
+ Symbol indices;
+ };
+
+ /// FnVariant describes a unique variant of a function, specialized by the AccessShape of the
+ /// pointer arguments - also known as the variant's "signature".
+ ///
+ /// To help understand what a variant is, consider the following WGSL:
+ ///
+ /// ```
+ /// fn F(a : ptr<storage, u32>, b : u32, c : ptr<storage, u32>) {
+ /// return *a + b + *c;
+ /// }
+ ///
+ /// @group(0) @binding(0) var<storage> S0 : u32;
+ /// @group(0) @binding(0) var<storage> S1 : array<u32, 64>;
+ ///
+ /// fn x() {
+ /// F(&S0, 0, &S0); // (A)
+ /// F(&S0, 0, &S0); // (B)
+ /// F(&S1[0], 1, &S0); // (C)
+ /// F(&S1[5], 2, &S0); // (D)
+ /// F(&S1[5], 3, &S1[3]); // (E)
+ /// F(&S1[7], 4, &S1[2]); // (F)
+ /// }
+ /// ```
+ ///
+ /// Given the calls in x(), function F() will have 3 variants:
+ /// (1) F<S0,S0> - called by (A) and (B).
+ /// Note that only 'uniform', 'storage' and 'workgroup' pointer
+ /// parameters are considered for a variant signature, and so
+ /// the argument for parameter 'b' is not included in the
+ /// signature.
+ /// (2) F<S1[dyn_idx],S0> - called by (C) and (D).
+ /// Note that the array index value is external to the
+ /// AccessShape, and so is not part of the variant signature.
+ /// (3) F<S1[dyn_idx],S1[dyn_idx]> - called by (E) and (F).
+ ///
+ /// Each variant of the function will be emitted as a separate function by the transform, and
+ /// would look something like:
+ ///
+ /// ```
+ /// // variant F<S0,S0> (1)
+ /// fn F_S0_S0(b : u32) {
+ /// return S0 + b + S0;
+ /// }
+ ///
+ /// type S1_X = array<u32, 1>;
+ ///
+ /// // variant F<S1[dyn_idx],S0> (2)
+ /// fn F_S1_X_S0(a : S1_X, b : u32) {
+ /// return S1[a[0]] + b + S0;
+ /// }
+ ///
+ /// // variant F<S1[dyn_idx],S1[dyn_idx]> (3)
+ /// fn F_S1_X_S1_X(a : S1_X, b : u32, c : S1_X) {
+ /// return S1[a[0]] + b + S1[c[0]];
+ /// }
+ ///
+ /// @group(0) @binding(0) var<storage> S0 : u32;
+ /// @group(0) @binding(0) var<storage> S1 : array<u32, 64>;
+ ///
+ /// fn x() {
+ /// F_S0_S0(0); // (A)
+ /// F(&S0, 0, &S0); // (B)
+ /// F_S1_X_S0(S1_X(0), 1); // (C)
+ /// F_S1_X_S0(S1_X(5), 2); // (D)
+ /// F_S1_X_S1_X(S1_X(5), 3, S1_X(3)); // (E)
+ /// F_S1_X_S1_X(S1_X(7), 4, S1_X(2)); // (F)
+ /// }
+ /// ```
+ struct FnVariant {
+ /// The signature of the variant is a map of each of the function's 'uniform', 'storage' and
+ /// 'workgroup' pointer parameters to the caller's AccessShape.
+ using Signature = utils::Hashmap<const sem::Parameter*, AccessShape, 4>;
+
+ /// The unique name of the variant.
+ /// The symbol is in the `ctx.dst` program namespace.
+ Symbol name;
+
+ /// A map of direct calls made by this variant to the name of other function variants.
+ utils::Hashmap<const sem::Call*, Symbol, 4> calls;
+
+ /// A map of input program parameter to output parameter symbols.
+ utils::Hashmap<const sem::Parameter*, PtrParamSymbols, 4> ptr_param_symbols;
+
+ /// The declaration order of the variant, in relation to other variants of the same
+ /// function. Used to ensure deterministic ordering of the transform, as map iteration is
+ /// not deterministic between compilers.
+ size_t order = 0;
+ };
+
+ /// FnInfo holds information about a function in the input program.
+ struct FnInfo {
+ /// A map of variant signature to the variant data.
+ utils::Hashmap<FnVariant::Signature, FnVariant, 8> variants;
+ /// A map of expressions that have been hoisted to a 'let' declaration in the function.
+ utils::Hashmap<const sem::Expression*, Symbol, 8> hoisted_exprs;
+
+ /// @returns the variants of the function in a deterministically ordered vector.
+ utils::Vector<std::pair<const FnVariant::Signature*, FnVariant*>, 8> SortedVariants() {
+ utils::Vector<std::pair<const FnVariant::Signature*, FnVariant*>, 8> out;
+ out.Reserve(variants.Count());
+ for (auto it : variants) {
+ out.Push({&it.key, &it.value});
+ }
+ out.Sort([&](auto& va, auto& vb) { return va.second->order < vb.second->order; });
+ return out;
+ }
+ };
+
+ /// The program builder
+ ProgramBuilder b;
+ /// The clone context
+ CloneContext ctx;
+ /// The transform options
+ const Options& opts;
+ /// Alias to the semantic info in ctx.src
+ const sem::Info& sem = ctx.src->Sem();
+ /// Alias to the symbols in ctx.src
+ const SymbolTable& sym = ctx.src->Symbols();
+ /// Map of semantic function to the function info
+ utils::Hashmap<const sem::Function*, FnInfo*, 8> fns;
+ /// Map of AccessShape to the name of a type alias for the an array<u32, N> used for the
+ /// dynamic indices of an access chain, passed down as the transformed type of a variant's
+ /// pointer parameter.
+ utils::Hashmap<AccessShape, Symbol, 8> dynamic_index_array_aliases;
+ /// Map of semantic expression to AccessChain
+ utils::Hashmap<const sem::Expression*, AccessChain*, 32> access_chains;
+ /// Allocator for FnInfo
+ utils::BlockAllocator<FnInfo> fn_info_allocator;
+ /// Allocator for AccessChain
+ utils::BlockAllocator<AccessChain> access_chain_allocator;
+ /// Helper used for hoisting expressions to lets
+ HoistToDeclBefore hoist{ctx};
+ /// Map of string to unique symbol (no collisions in output program).
+ utils::Hashmap<std::string, Symbol, 8> unique_symbols;
+
+ /// CloneState holds pointers to the current function, variant and variant's parameters.
+ struct CloneState {
+ /// The current function being cloned
+ FnInfo* current_function = nullptr;
+ /// The current function variant being built
+ FnVariant* current_variant = nullptr;
+ /// The signature of the current function variant being built
+ const FnVariant::Signature* current_variant_sig = nullptr;
+ };
+
+ /// The clone state.
+ /// Only valid during the lifetime of the CloneContext::Clone().
+ CloneState* clone_state = nullptr;
+
+ /// AppendAccessChain creates or extends an existing AccessChain for the given expression,
+ /// modifying the #access_chains map.
+ void AppendAccessChain(const sem::Expression* expr) {
+ // take_chain moves the AccessChain from the expression `from` to the expression `expr`.
+ // Returns nullptr if `from` did not hold an access chain.
+ auto take_chain = [&](const sem::Expression* from) -> AccessChain* {
+ if (auto* chain = AccessChainFor(from)) {
+ access_chains.Remove(from);
+ access_chains.Add(expr, chain);
+ return chain;
+ }
+ return nullptr;
+ };
+
+ Switch(
+ expr,
+ [&](const sem::VariableUser* user) {
+ // Expression resolves to a variable.
+ auto* variable = user->Variable();
+
+ auto create_new_chain = [&] {
+ auto* chain = access_chain_allocator.Create();
+ chain->root.variable = variable;
+ chain->root.type = variable->Type();
+ chain->root.address_space = variable->AddressSpace();
+ if (auto* ptr = chain->root.type->As<sem::Pointer>()) {
+ chain->root.address_space = ptr->AddressSpace();
+ }
+ access_chains.Add(expr, chain);
+ };
+
+ Switch(
+ variable->Declaration(),
+ [&](const ast::Var*) {
+ if (variable->AddressSpace() != ast::AddressSpace::kHandle) {
+ // Start a new access chain for the non-handle 'var' access
+ create_new_chain();
+ }
+ },
+ [&](const ast::Parameter*) {
+ if (variable->Type()->Is<sem::Pointer>()) {
+ // Start a new access chain for the pointer parameter access
+ create_new_chain();
+ }
+ },
+ [&](const ast::Let*) {
+ if (variable->Type()->Is<sem::Pointer>()) {
+ // variable is a pointer-let.
+ auto* init = sem.Get(variable->Declaration()->initializer);
+ // Note: We do not use take_chain() here, as we need to preserve the
+ // AccessChain on the let's initializer, as the let needs its
+ // initializer updated, and the let may be used multiple times. Instead
+ // we copy the let's AccessChain into a a new AccessChain.
+ if (auto* init_chain = AccessChainFor(init)) {
+ access_chains.Add(expr, access_chain_allocator.Create(*init_chain));
+ }
+ }
+ });
+ },
+ [&](const sem::StructMemberAccess* a) {
+ // Structure member access.
+ // Append the Symbol of the member name to the chain, and move the chain to the
+ // member access expression.
+ if (auto* chain = take_chain(a->Object())) {
+ chain->ops.Push(a->Member()->Name());
+ }
+ },
+ [&](const sem::IndexAccessorExpression* a) {
+ // Array, matrix or vector index.
+ // Store the index expression into AccessChain::dynamic_indices, append a
+ // DynamicIndex to the chain, and move the chain to the index accessor expression.
+ if (auto* chain = take_chain(a->Object())) {
+ chain->ops.Push(DynamicIndex{chain->dynamic_indices.Length()});
+ chain->dynamic_indices.Push(a->Index());
+ }
+ },
+ [&](const sem::Expression* e) {
+ if (auto* unary = e->Declaration()->As<ast::UnaryOpExpression>()) {
+ // Unary op.
+ // If this is a '&' or '*', simply move the chain to the unary op expression.
+ if (unary->op == ast::UnaryOp::kAddressOf ||
+ unary->op == ast::UnaryOp::kIndirection) {
+ take_chain(sem.Get(unary->expr));
+ }
+ }
+ });
+ }
+
+ /// MaybeHoistDynamicIndices examines the AccessChain::dynamic_indices member of @p chain,
+ /// hoisting all expressions to their own uniquely named 'let' if none of the following are
+ /// true:
+ /// 1. The index expression is a constant value.
+ /// 2. The index expression's statement is the same as @p usage.
+ /// 3. The index expression is an identifier resolving to a 'let', 'const' or parameter, AND
+ /// that identifier resolves to the same variable at @p usage.
+ ///
+ /// A dynamic index will only be hoisted once. The hoisting applies to all variants of the
+ /// function that holds the dynamic index expression.
+ void MaybeHoistDynamicIndices(AccessChain* chain, const sem::Statement* usage) {
+ for (auto& idx : chain->dynamic_indices) {
+ if (idx->ConstantValue()) {
+ // Dynamic index is constant.
+ continue; // Hoisting not required.
+ }
+
+ if (idx->Stmt() == usage) {
+ // The index expression is owned by the statement of usage.
+ continue; // Hoisting not required
+ }
+
+ if (auto* idx_variable_user = idx->UnwrapMaterialize()->As<sem::VariableUser>()) {
+ auto* idx_variable = idx_variable_user->Variable();
+ if (idx_variable->Declaration()->IsAnyOf<ast::Let, ast::Parameter>()) {
+ // Dynamic index is an immutable variable
+ continue; // Hoisting not required.
+ }
+ }
+
+ // The dynamic index needs to be hoisted (if it hasn't been already).
+ auto fn = FnInfoFor(idx->Stmt()->Function());
+ fn->hoisted_exprs.GetOrCreate(idx, [=] {
+ // Create a name for the new 'let'
+ auto name = b.Symbols().New("ptr_index_save");
+ // Insert a new 'let' just above the dynamic index statement.
+ hoist.InsertBefore(idx->Stmt(), [this, idx, name] {
+ return b.Decl(b.Let(name, ctx.CloneWithoutTransform(idx->Declaration())));
+ });
+ return name;
+ });
+ }
+ }
+
+ /// BuildDynamicIndex builds the AST expression node for the dynamic index expression used in an
+ /// AccessChain. This is similar to just cloning the expression, but BuildDynamicIndex()
+ /// also:
+ /// * Collapses constant value index expressions down to the computed value. This acts as an
+ /// constant folding optimization and reduces noise from the transform.
+ /// * Casts the resulting expression to a u32 if @p cast_to_u32 is true, and the expression type
+ /// isn't implicitly usable as a u32. This is to help feed the expression into a
+ /// `array<u32, N>` argument passed to a callee variant function.
+ const ast::Expression* BuildDynamicIndex(const sem::Expression* idx, bool cast_to_u32) {
+ if (auto* val = idx->ConstantValue()) {
+ // Expression evaluated to a constant value. Just emit that constant.
+ return b.Expr(val->As<AInt>());
+ }
+
+ // Expression is not a constant, clone the expression.
+ // Note: If the dynamic index expression was hoisted to a let, then cloning will return an
+ // identifier expression to the hoisted let.
+ auto* expr = ctx.Clone(idx->Declaration());
+
+ if (cast_to_u32) {
+ // The index may be fed to a dynamic index array<u32, N> argument, so the index
+ // expression may need casting to u32.
+ if (!idx->UnwrapMaterialize()
+ ->Type()
+ ->UnwrapRef()
+ ->IsAnyOf<sem::U32, sem::AbstractInt>()) {
+ expr = b.Construct(b.ty.u32(), expr);
+ }
+ }
+
+ return expr;
+ }
+
+ /// ProcessFunction scans the direct calls made by the function @p fn, adding new variants to
+ /// the callee functions and transforming the call expression to pass dynamic indices instead of
+ /// true pointers.
+ /// If the function @p fn has pointer parameters that must be transformed to a caller variant,
+ /// and the function is not called, then the function is dropped from the output of the
+ /// transform, as it cannot be generated.
+ /// @note ProcessFunction must be called in dependency order for the program, starting with the
+ /// entry points.
+ void ProcessFunction(const sem::Function* fn, FnInfo* fn_info) {
+ if (fn_info->variants.IsEmpty()) {
+ // Function has no variants pre-generated by callers.
+ if (MustBeCalled(fn)) {
+ // Drop the function, as it wasn't called and cannot be generated.
+ ctx.Remove(ctx.src->AST().GlobalDeclarations(), fn->Declaration());
+ return;
+ }
+
+ // Function was not called. Create a single variant with an empty signature.
+ FnVariant variant;
+ variant.name = ctx.Clone(fn->Declaration()->symbol);
+ variant.order = 0; // Unaltered comes first.
+ fn_info->variants.Add(FnVariant::Signature{}, std::move(variant));
+ }
+
+ // Process each of the direct calls made by this function.
+ for (auto* call : fn->DirectCalls()) {
+ ProcessCall(fn_info, call);
+ }
+ }
+
+ /// ProcessCall creates new variants of the callee function by permuting the call for each of
+ /// the variants of @p caller. ProcessCall also registers the clone callback to transform the
+ /// call expression to pass dynamic indices instead of true pointers.
+ void ProcessCall(FnInfo* caller, const sem::Call* call) {
+ auto* target = call->Target()->As<sem::Function>();
+ if (!target) {
+ // Call target is not a user-declared function.
+ return; // Not interested in this call.
+ }
+
+ if (!HasPointerParameter(target)) {
+ return; // Not interested in this call.
+ }
+
+ bool call_needs_transforming = false;
+
+ // Build the call target function variant for each variant of the caller.
+ for (auto caller_variant_it : caller->SortedVariants()) {
+ auto& caller_signature = *caller_variant_it.first;
+ auto& caller_variant = *caller_variant_it.second;
+
+ // Build the target variant's signature.
+ FnVariant::Signature target_signature;
+ for (size_t i = 0; i < call->Arguments().Length(); i++) {
+ const auto* arg = call->Arguments()[i];
+ const auto* param = target->Parameters()[i];
+ const auto* param_ty = param->Type()->As<sem::Pointer>();
+ if (!param_ty) {
+ continue; // Parameter type is not a pointer.
+ }
+
+ // Fetch the access chain for the argument.
+ auto* arg_chain = AccessChainFor(arg);
+ if (!arg_chain) {
+ continue; // Argument does not have an access chain
+ }
+
+ // Construct the absolute AccessShape by considering the AccessShape of the caller
+ // variant's argument. This will propagate back through pointer parameters, to the
+ // outermost caller.
+ auto absolute = AbsoluteAccessShape(caller_signature, *arg_chain);
+
+ // If the address space of the root variable of the access chain does not require
+ // transformation, then there's nothing to do.
+ if (!AddressSpaceRequiresTransform(absolute.root.address_space)) {
+ continue;
+ }
+
+ // Record that this chain was used in a function call.
+ // This preserves the chain during the access chain filtering stage.
+ arg_chain->used_in_call = true;
+
+ if (IsPrivateOrFunction(absolute.root.address_space)) {
+ // Pointers in 'private' and 'function' address spaces need to be passed by
+ // pointer argument.
+ absolute.root.variable = param;
+ }
+
+ // Add the parameter's absolute AccessShape to the target's signature.
+ target_signature.Add(param, std::move(absolute));
+ }
+
+ // Construct a new FnVariant if this is the first caller of the target signature
+ auto* target_info = FnInfoFor(target);
+ auto& target_variant = target_info->variants.GetOrCreate(target_signature, [&] {
+ if (target_signature.IsEmpty()) {
+ // Call target does not require any argument changes.
+ FnVariant variant;
+ variant.name = ctx.Clone(target->Declaration()->symbol);
+ variant.order = 0; // Unaltered comes first.
+ return variant;
+ }
+
+ // Build an appropriate variant function name.
+ // This is derived from the original function name and the pointer parameter
+ // chains.
+ std::stringstream ss;
+ ss << ctx.src->Symbols().NameFor(target->Declaration()->symbol);
+ for (auto* param : target->Parameters()) {
+ if (auto indices = target_signature.Find(param)) {
+ ss << "_" << AccessShapeName(*indices);
+ }
+ }
+
+ // Build the pointer parameter symbols.
+ utils::Hashmap<const sem::Parameter*, PtrParamSymbols, 4> ptr_param_symbols;
+ for (auto param_it : target_signature) {
+ auto* param = param_it.key;
+ auto& shape = param_it.value;
+
+ // Parameter needs replacing with either zero, one or two parameters:
+ // If the parameter is in the 'private' or 'function' address space, then the
+ // originating pointer is always passed down. This always comes first.
+ // If the access chain has dynamic indices, then we create an array<u32, N>
+ // parameter to hold the dynamic indices.
+ bool requires_base_ptr_param = IsPrivateOrFunction(shape.root.address_space);
+ bool requires_indices_param = shape.NumDynamicIndices() > 0;
+
+ PtrParamSymbols symbols;
+ if (requires_base_ptr_param && requires_indices_param) {
+ auto original_name = param->Declaration()->symbol;
+ symbols.base_ptr = UniqueSymbolWithSuffix(original_name, "_base");
+ symbols.indices = UniqueSymbolWithSuffix(original_name, "_indices");
+ } else if (requires_base_ptr_param) {
+ symbols.base_ptr = ctx.Clone(param->Declaration()->symbol);
+ } else if (requires_indices_param) {
+ symbols.indices = ctx.Clone(param->Declaration()->symbol);
+ }
+
+ // Remember this base pointer name.
+ ptr_param_symbols.Add(param, symbols);
+ }
+
+ // Build the variant.
+ FnVariant variant;
+ variant.name = b.Symbols().New(ss.str());
+ variant.order = target_info->variants.Count() + 1;
+ variant.ptr_param_symbols = std::move(ptr_param_symbols);
+ return variant;
+ });
+
+ // Record the call made by caller variant to the target variant.
+ caller_variant.calls.Add(call, target_variant.name);
+ if (!target_signature.IsEmpty()) {
+ // The call expression will need transforming for at least one caller variant.
+ call_needs_transforming = true;
+ }
+ }
+
+ if (call_needs_transforming) {
+ // Register the clone callback to correctly transform the call expression into the
+ // appropriate variant calls.
+ TransformCall(call);
+ }
+ }
+
+ /// @returns true if the address space @p address_space requires transforming given the
+ /// transform's options.
+ bool AddressSpaceRequiresTransform(ast::AddressSpace address_space) const {
+ switch (address_space) {
+ case ast::AddressSpace::kUniform:
+ case ast::AddressSpace::kStorage:
+ case ast::AddressSpace::kWorkgroup:
+ return true;
+ case ast::AddressSpace::kPrivate:
+ return opts.transform_private;
+ case ast::AddressSpace::kFunction:
+ return opts.transform_function;
+ default:
+ return false;
+ }
+ }
+
+ /// @returns the AccessChain for the expression @p expr, or nullptr if the expression does
+ /// not hold an access chain.
+ AccessChain* AccessChainFor(const sem::Expression* expr) const {
+ if (auto chain = access_chains.Find(expr)) {
+ return *chain;
+ }
+ return nullptr;
+ }
+
+ /// @returns the absolute AccessShape for @p indices, by replacing the originating pointer
+ /// parameter with the AccessChain of variant's signature.
+ AccessShape AbsoluteAccessShape(const FnVariant::Signature& signature,
+ const AccessShape& shape) const {
+ if (auto* root_param = shape.root.variable->As<sem::Parameter>()) {
+ if (auto incoming_chain = signature.Find(root_param)) {
+ // Access chain originates from a parameter, which will be transformed into an array
+ // of dynamic indices. Concatenate the signature's AccessShape for the parameter
+ // to the chain's indices, skipping over the chain's initial parameter index.
+ auto absolute = *incoming_chain;
+ for (auto& op : shape.ops) {
+ absolute.ops.Push(op);
+ }
+ return absolute;
+ }
+ }
+
+ // Chain does not originate from a parameter, so is already absolute.
+ return shape;
+ }
+
+ /// TransformFunction registers the clone callback to transform the function @p fn into the
+ /// (potentially multiple) function's variants. TransformFunction will assign the current
+ /// function and variant to #clone_state, which can be used by the other clone callbacks.
+ void TransformFunction(const sem::Function* fn, FnInfo* fn_info) {
+ // Register a custom handler for the specific function
+ ctx.Replace(fn->Declaration(), [this, fn, fn_info] {
+ // For the scope of this lambda, assign current_function to fn_info.
+ TINT_SCOPED_ASSIGNMENT(clone_state->current_function, fn_info);
+
+ // This callback expects a single function returned. As we're generating potentially
+ // many variant functions, keep a record of the last created variant, and explicitly add
+ // this to the module if it isn't the last. We'll return the last created variant,
+ // taking the place of the original function.
+ const ast::Function* pending_variant = nullptr;
+
+ // For each variant of fn...
+ for (auto variant_it : fn_info->SortedVariants()) {
+ if (pending_variant) {
+ b.AST().AddFunction(pending_variant);
+ }
+
+ auto& variant_sig = *variant_it.first;
+ auto& variant = *variant_it.second;
+
+ // For the rest of this scope, assign the current variant and variant signature.
+ TINT_SCOPED_ASSIGNMENT(clone_state->current_variant_sig, &variant_sig);
+ TINT_SCOPED_ASSIGNMENT(clone_state->current_variant, &variant);
+
+ // Build the variant's parameters.
+ // Pointer parameters in the 'uniform', 'storage' or 'workgroup' address space are
+ // either replaced with an array of dynamic indices, or are dropped (if there are no
+ // dynamic indices).
+ utils::Vector<const ast::Parameter*, 8> params;
+ for (auto* param : fn->Parameters()) {
+ if (auto incoming_shape = variant_sig.Find(param)) {
+ auto& symbols = *variant.ptr_param_symbols.Find(param);
+ if (symbols.base_ptr.IsValid()) {
+ auto* base_ptr_ty =
+ b.ty.pointer(CreateASTTypeFor(ctx, incoming_shape->root.type),
+ incoming_shape->root.address_space);
+ params.Push(b.Param(symbols.base_ptr, base_ptr_ty));
+ }
+ if (symbols.indices.IsValid()) {
+ // Variant has dynamic indices for this variant, replace it.
+ auto* dyn_idx_arr_type = DynamicIndexArrayType(*incoming_shape);
+ params.Push(b.Param(symbols.indices, dyn_idx_arr_type));
+ }
+ } else {
+ // Just a regular parameter. Just clone the original parameter.
+ params.Push(ctx.Clone(param->Declaration()));
+ }
+ }
+
+ // Build the variant by cloning the source function. The other clone callbacks will
+ // use clone_state->current_variant and clone_state->current_variant_sig to produce
+ // the variant.
+ auto* ret_ty = ctx.Clone(fn->Declaration()->return_type);
+ auto body = ctx.Clone(fn->Declaration()->body);
+ auto attrs = ctx.Clone(fn->Declaration()->attributes);
+ auto ret_attrs = ctx.Clone(fn->Declaration()->return_type_attributes);
+ pending_variant =
+ b.create<ast::Function>(variant.name, std::move(params), ret_ty, body,
+ std::move(attrs), std::move(ret_attrs));
+ }
+
+ return pending_variant;
+ });
+ }
+
+ /// TransformCall registers the clone callback to transform the call expression @p call to call
+ /// the correct target variant, and to replace pointers arguments with an array of dynamic
+ /// indices.
+ void TransformCall(const sem::Call* call) {
+ // Register a custom handler for the specific call expression
+ ctx.Replace(call->Declaration(), [this, call]() {
+ auto target_variant = clone_state->current_variant->calls.Find(call);
+ if (!target_variant) {
+ // The current variant does not need to transform this call.
+ return ctx.CloneWithoutTransform(call->Declaration());
+ }
+
+ // Build the new call expressions's arguments.
+ utils::Vector<const ast::Expression*, 8> new_args;
+ for (size_t arg_idx = 0; arg_idx < call->Arguments().Length(); arg_idx++) {
+ auto* arg = call->Arguments()[arg_idx];
+ auto* param = call->Target()->Parameters()[arg_idx];
+ auto* param_ty = param->Type()->As<sem::Pointer>();
+ if (!param_ty) {
+ // Parameter is not a pointer.
+ // Just clone the unaltered argument.
+ new_args.Push(ctx.Clone(arg->Declaration()));
+ continue; // Parameter is not a pointer
+ }
+
+ auto* chain = AccessChainFor(arg);
+ if (!chain) {
+ // No access chain means the argument is not a pointer that needs transforming.
+ // Just clone the unaltered argument.
+ new_args.Push(ctx.Clone(arg->Declaration()));
+ continue;
+ }
+
+ // Construct the absolute AccessShape by considering the AccessShape of the caller
+ // variant's argument. This will propagate back through pointer parameters, to the
+ // outermost caller.
+ auto full_indices = AbsoluteAccessShape(*clone_state->current_variant_sig, *chain);
+
+ // If the parameter is a pointer in the 'private' or 'function' address space, then
+ // we need to pass an additional pointer argument to the base object.
+ if (IsPrivateOrFunction(param_ty->AddressSpace())) {
+ auto* root_expr = BuildAccessRootExpr(chain->root, /* deref */ false);
+ if (!chain->root.variable->Is<sem::Parameter>()) {
+ root_expr = b.AddressOf(root_expr);
+ }
+ new_args.Push(root_expr);
+ }
+
+ // Get or create the dynamic indices array.
+ if (auto* dyn_idx_arr_ty = DynamicIndexArrayType(full_indices)) {
+ // Build an array of dynamic indices to pass as the replacement for the pointer.
+ utils::Vector<const ast::Expression*, 8> dyn_idx_args;
+ if (auto* root_param = chain->root.variable->As<sem::Parameter>()) {
+ // Access chain originates from a pointer parameter.
+ if (auto incoming_chain =
+ clone_state->current_variant_sig->Find(root_param)) {
+ auto indices =
+ clone_state->current_variant->ptr_param_symbols.Find(root_param)
+ ->indices;
+
+ // This pointer parameter will have been replaced with a array<u32, N>
+ // holding the variant's dynamic indices for the pointer. Unpack these
+ // directly into the array constructor's arguments.
+ auto N = incoming_chain->NumDynamicIndices();
+ for (uint32_t i = 0; i < N; i++) {
+ dyn_idx_args.Push(b.IndexAccessor(indices, u32(i)));
+ }
+ }
+ }
+ // Pass the dynamic indices of the access chain into the array constructor.
+ for (auto& dyn_idx : chain->dynamic_indices) {
+ dyn_idx_args.Push(BuildDynamicIndex(dyn_idx, /* cast_to_u32 */ true));
+ }
+ // Construct the dynamic index array, and push as an argument.
+ new_args.Push(b.Construct(dyn_idx_arr_ty, std::move(dyn_idx_args)));
+ }
+ }
+
+ // Make the call to the target's variant.
+ return b.Call(*target_variant, std::move(new_args));
+ });
+ }
+
+ /// ProcessAccessChains performs the following:
+ /// * Removes all AccessChains from expressions that are not either used as a pointer argument
+ /// in a call, or originates from a pointer parameter.
+ /// * Hoists the dynamic index expressions of AccessChains to 'let' statements, to prevent
+ /// multiple evaluation of the expressions, and avoid expressions resolving to different
+ /// variables based on lexical scope.
+ void ProcessAccessChains() {
+ auto chain_exprs = access_chains.Keys();
+ chain_exprs.Sort([](const auto& expr_a, const auto& expr_b) {
+ return expr_a->Declaration()->node_id.value < expr_b->Declaration()->node_id.value;
+ });
+
+ for (auto* expr : chain_exprs) {
+ auto* chain = *access_chains.Get(expr);
+ if (!chain->used_in_call && !chain->root.variable->Is<sem::Parameter>()) {
+ // Chain was not used in a function call, and does not originate from a
+ // parameter. This chain does not need transforming. Drop it.
+ access_chains.Remove(expr);
+ continue;
+ }
+
+ // Chain requires transforming.
+
+ // We need to be careful that the chain does not use expressions with side-effects which
+ // cannot be repeatedly evaluated. In this situation we can hoist the dynamic index
+ // expressions to their own uniquely named lets (if required).
+ MaybeHoistDynamicIndices(chain, expr->Stmt());
+ }
+ }
+
+ /// TransformAccessChainExpressions registers the clone callback to:
+ /// * Transform all expressions that have an AccessChain (which aren't arguments to function
+ /// calls, these are handled by TransformCall()), into the equivalent expression using a
+ /// module-scope variable.
+ /// * Replace expressions that have been hoisted to a let, with an identifier expression to that
+ /// let.
+ void TransformAccessChainExpressions() {
+ // Register a custom handler for all non-function call expressions
+ ctx.ReplaceAll([this](const ast::Expression* ast_expr) -> const ast::Expression* {
+ if (!clone_state->current_variant) {
+ // Expression does not belong to a function variant.
+ return nullptr; // Just clone the expression.
+ }
+
+ auto* expr = sem.Get<sem::Expression>(ast_expr);
+ if (!expr) {
+ // No semantic node for the expression.
+ return nullptr; // Just clone the expression.
+ }
+
+ // If the expression has been hoisted to a 'let', then replace the expression with an
+ // identifier to the hoisted let.
+ if (auto hoisted = clone_state->current_function->hoisted_exprs.Find(expr)) {
+ return b.Expr(*hoisted);
+ }
+
+ auto* chain = AccessChainFor(expr);
+ if (!chain) {
+ // The expression does not have an AccessChain.
+ return nullptr; // Just clone the expression.
+ }
+
+ auto* root_param = chain->root.variable->As<sem::Parameter>();
+ if (!root_param) {
+ // The expression has an access chain, but does not originate with a pointer
+ // parameter. We don't need to change anything here.
+ return nullptr; // Just clone the expression.
+ }
+
+ auto incoming_shape = clone_state->current_variant_sig->Find(root_param);
+ if (!incoming_shape) {
+ // The root parameter of the access chain is not part of the variant's signature.
+ return nullptr; // Just clone the expression.
+ }
+
+ // Expression holds an access chain to a pointer parameter that needs transforming.
+ // Reconstruct the expression using the variant's incoming shape.
+
+ auto* chain_expr = BuildAccessRootExpr(incoming_shape->root, /* deref */ true);
+
+ // Chain starts with a pointer parameter.
+ // Replace this with the variant's incoming shape. This will bring the expression up to
+ // the incoming pointer.
+ auto indices =
+ clone_state->current_variant->ptr_param_symbols.Find(root_param)->indices;
+ for (auto param_access : incoming_shape->ops) {
+ chain_expr = BuildAccessExpr(chain_expr, param_access, [&](size_t i) {
+ return b.IndexAccessor(indices, AInt(i));
+ });
+ }
+
+ // Now build the expression chain within the function.
+
+ // For each access in the chain (excluding the pointer parameter)...
+ for (auto& op : chain->ops) {
+ chain_expr = BuildAccessExpr(chain_expr, op, [&](size_t i) {
+ return BuildDynamicIndex(chain->dynamic_indices[i], false);
+ });
+ }
+
+ // BuildAccessExpr() always returns a non-pointer.
+ // If the expression we're replacing is a pointer, take the address.
+ if (expr->Type()->Is<sem::Pointer>()) {
+ chain_expr = b.AddressOf(chain_expr);
+ }
+
+ return chain_expr;
+ });
+ }
+
+ /// @returns the FnInfo for the given function, constructing a new FnInfo if @p fn doesn't
+ /// already have one.
+ FnInfo* FnInfoFor(const sem::Function* fn) {
+ return fns.GetOrCreate(fn, [this] { return fn_info_allocator.Create(); });
+ }
+
+ /// @returns the type alias used to hold the dynamic indices for @p shape, declaring a new alias
+ /// if this is the first call for the given shape.
+ const ast::TypeName* DynamicIndexArrayType(const AccessShape& shape) {
+ auto name = dynamic_index_array_aliases.GetOrCreate(shape, [&] {
+ // Count the number of dynamic indices
+ uint32_t num_dyn_indices = shape.NumDynamicIndices();
+ if (num_dyn_indices == 0) {
+ return Symbol{};
+ }
+ auto symbol = b.Symbols().New(AccessShapeName(shape));
+ b.Alias(symbol, b.ty.array(b.ty.u32(), u32(num_dyn_indices)));
+ return symbol;
+ });
+ return name.IsValid() ? b.ty.type_name(name) : nullptr;
+ }
+
+ /// @returns a name describing the given shape
+ std::string AccessShapeName(const AccessShape& shape) {
+ std::stringstream ss;
+
+ if (IsPrivateOrFunction(shape.root.address_space)) {
+ ss << "F";
+ } else {
+ ss << ctx.src->Symbols().NameFor(shape.root.variable->Declaration()->symbol);
+ }
+
+ for (auto& op : shape.ops) {
+ ss << "_";
+
+ if (std::holds_alternative<DynamicIndex>(op)) {
+ /// The op uses a dynamic (runtime-expression) index.
+ ss << "X";
+ continue;
+ }
+
+ if (auto* member = std::get_if<Symbol>(&op)) {
+ ss << sym.NameFor(*member);
+ continue;
+ }
+
+ TINT_ICE(Transform, b.Diagnostics()) << "unhandled variant for access chain";
+ break;
+ }
+ return ss.str();
+ }
+
+ /// Builds an expresion to the root of an access, returning the new expression.
+ /// @param root the AccessRoot
+ /// @param deref if true, the returned expression will always be a reference type.
+ const ast::Expression* BuildAccessRootExpr(const AccessRoot& root, bool deref) {
+ if (auto* param = root.variable->As<sem::Parameter>()) {
+ if (auto symbols = clone_state->current_variant->ptr_param_symbols.Find(param)) {
+ if (deref) {
+ return b.Deref(b.Expr(symbols->base_ptr));
+ }
+ return b.Expr(symbols->base_ptr);
+ }
+ }
+
+ const ast::Expression* expr = b.Expr(ctx.Clone(root.variable->Declaration()->symbol));
+ if (deref) {
+ if (root.variable->Type()->Is<sem::Pointer>()) {
+ expr = b.Deref(expr);
+ }
+ }
+ return expr;
+ }
+
+ /// Builds a single access in an access chain, returning the new expression.
+ /// The returned expression will always be of a reference type.
+ /// @param expr the input expression
+ /// @param access the access to perform on the current expression
+ /// @param dynamic_index a function that obtains the i'th dynamic index
+ const ast::Expression* BuildAccessExpr(
+ const ast::Expression* expr,
+ const AccessOp& access,
+ std::function<const ast::Expression*(size_t)> dynamic_index) {
+ if (auto* dyn_idx = std::get_if<DynamicIndex>(&access)) {
+ /// The access uses a dynamic (runtime-expression) index.
+ auto* idx = dynamic_index(dyn_idx->slot);
+ return b.IndexAccessor(expr, idx);
+ }
+
+ if (auto* member = std::get_if<Symbol>(&access)) {
+ /// The access is a member access.
+ return b.MemberAccessor(expr, ctx.Clone(*member));
+ }
+
+ TINT_ICE(Transform, b.Diagnostics()) << "unhandled variant type for access chain";
+ return nullptr;
+ }
+
+ /// @returns a new Symbol starting with @p symbol concatenated with @p suffix, and possibly an
+ /// underscore and number, if the symbol is already taken.
+ Symbol UniqueSymbolWithSuffix(Symbol symbol, const std::string& suffix) {
+ auto str = ctx.src->Symbols().NameFor(symbol) + suffix;
+ return unique_symbols.GetOrCreate(str, [&] { return b.Symbols().New(str); });
+ }
+
+ /// @returns true if the function @p fn has at least one pointer parameter.
+ static bool HasPointerParameter(const sem::Function* fn) {
+ for (auto* param : fn->Parameters()) {
+ if (param->Type()->Is<sem::Pointer>()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /// @returns true if the function @p fn has at least one pointer parameter in an address space
+ /// that must be replaced. If this function is not called, then the function cannot be sensibly
+ /// generated, and must be stripped.
+ static bool MustBeCalled(const sem::Function* fn) {
+ for (auto* param : fn->Parameters()) {
+ if (auto* ptr = param->Type()->As<sem::Pointer>()) {
+ switch (ptr->AddressSpace()) {
+ case ast::AddressSpace::kUniform:
+ case ast::AddressSpace::kStorage:
+ case ast::AddressSpace::kWorkgroup:
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+ return false;
+ }
+
+ /// @returns true if the given address space is 'private' or 'function'.
+ static bool IsPrivateOrFunction(const ast::AddressSpace sc) {
+ return sc == ast::AddressSpace::kPrivate || sc == ast::AddressSpace::kFunction;
+ }
+};
+
+DirectVariableAccess::Config::Config(const Options& opt) : options(opt) {}
+
+DirectVariableAccess::Config::~Config() = default;
+
+DirectVariableAccess::DirectVariableAccess() = default;
+
+DirectVariableAccess::~DirectVariableAccess() = default;
+
+Transform::ApplyResult DirectVariableAccess::Apply(const Program* program,
+ const DataMap& inputs,
+ DataMap&) const {
+ Options options;
+ if (auto* cfg = inputs.Get<Config>()) {
+ options = cfg->options;
+ }
+ return State(program, options).Run();
+}
+
+} // namespace tint::transform
diff --git a/src/tint/transform/direct_variable_access.h b/src/tint/transform/direct_variable_access.h
new file mode 100644
index 0000000..34b6e91
--- /dev/null
+++ b/src/tint/transform/direct_variable_access.h
@@ -0,0 +1,74 @@
+// Copyright 2022 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.
+
+#ifndef SRC_TINT_TRANSFORM_DIRECT_VARIABLE_ACCESS_H_
+#define SRC_TINT_TRANSFORM_DIRECT_VARIABLE_ACCESS_H_
+
+#include "src/tint/transform/transform.h"
+
+namespace tint::transform {
+
+/// DirectVariableAccess is a transform that allows usage of pointer parameters in the 'storage',
+/// 'uniform' and 'workgroup' address space, and passing of pointers to sub-objects. These pointers
+/// are only allowed by the resolver when the `chromium_experimental_full_ptr_parameters` extension
+/// is enabled.
+///
+/// DirectVariableAccess works by creating specializations of functions that have pointer
+/// parameters, one specialization for each pointer argument's unique access chain 'shape' from a
+/// unique variable. Calls to specialized functions are transformed so that the pointer arguments
+/// are replaced with an array of access-chain indicies, and if the pointer is in the 'function' or
+/// 'private' address space, also with a pointer to the root object. For more information, see the
+/// comments in src/tint/transform/direct_variable_access.cc.
+///
+/// @note DirectVariableAccess requires the transform::Unshadow transform to have been run first.
+class DirectVariableAccess final : public Castable<DirectVariableAccess, Transform> {
+ public:
+ /// Constructor
+ DirectVariableAccess();
+ /// Destructor
+ ~DirectVariableAccess() override;
+
+ /// Options adjusts the behaviour of the transform.
+ struct Options {
+ /// If true, then 'private' sub-object pointer arguments will be transformed.
+ bool transform_private = false;
+ /// If true, then 'function' sub-object pointer arguments will be transformed.
+ bool transform_function = false;
+ };
+
+ /// Config is consumed by the DirectVariableAccess transform.
+ /// Config specifies the behavior of the transform.
+ struct Config final : public Castable<Data, transform::Data> {
+ /// Constructor
+ /// @param options behavior of the transform
+ explicit Config(const Options& options);
+ /// Destructor
+ ~Config() override;
+
+ /// The transform behavior options
+ const Options options;
+ };
+
+ /// @copydoc Transform::Apply
+ ApplyResult Apply(const Program* program,
+ const DataMap& inputs,
+ DataMap& outputs) const override;
+
+ private:
+ struct State;
+};
+
+} // namespace tint::transform
+
+#endif // SRC_TINT_TRANSFORM_DIRECT_VARIABLE_ACCESS_H_
diff --git a/src/tint/transform/direct_variable_access_test.cc b/src/tint/transform/direct_variable_access_test.cc
new file mode 100644
index 0000000..4c112d4
--- /dev/null
+++ b/src/tint/transform/direct_variable_access_test.cc
@@ -0,0 +1,2697 @@
+// Copyright 2022 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/tint/transform/direct_variable_access.h"
+
+#include <memory>
+#include <utility>
+
+#include "src/tint/transform/test_helper.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::transform {
+namespace {
+
+/// @returns a DataMap with DirectVariableAccess::Config::transform_private enabled.
+static DataMap EnablePrivate() {
+ DirectVariableAccess::Options opts;
+ opts.transform_private = true;
+
+ DataMap inputs;
+ inputs.Add<DirectVariableAccess::Config>(opts);
+ return inputs;
+}
+
+/// @returns a DataMap with DirectVariableAccess::Config::transform_function enabled.
+static DataMap EnableFunction() {
+ DirectVariableAccess::Options opts;
+ opts.transform_function = true;
+
+ DataMap inputs;
+ inputs.Add<DirectVariableAccess::Config>(opts);
+ return inputs;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ShouldRun tests
+////////////////////////////////////////////////////////////////////////////////
+namespace should_run {
+
+using DirectVariableAccessShouldRunTest = TransformTest;
+
+TEST_F(DirectVariableAccessShouldRunTest, EmptyModule) {
+ auto* src = R"()";
+
+ EXPECT_FALSE(ShouldRun<DirectVariableAccess>(src));
+}
+
+} // namespace should_run
+
+////////////////////////////////////////////////////////////////////////////////
+// remove uncalled
+////////////////////////////////////////////////////////////////////////////////
+namespace remove_uncalled {
+
+using DirectVariableAccessRemoveUncalledTest = TransformTest;
+
+TEST_F(DirectVariableAccessRemoveUncalledTest, PtrUniform) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+var<private> keep_me = 42;
+
+fn u(pre : i32, p : ptr<uniform, i32>, post : i32) -> i32 {
+ return *(p);
+}
+
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+var<private> keep_me = 42;
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessRemoveUncalledTest, PtrStorage) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+var<private> keep_me = 42;
+
+fn s(pre : i32, p : ptr<storage, i32>, post : i32) -> i32 {
+ return *(p);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+var<private> keep_me = 42;
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessRemoveUncalledTest, PtrWorkgroup) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+var<private> keep_me = 42;
+
+fn w(pre : i32, p : ptr<workgroup, i32>, post : i32) -> i32 {
+ return *(p);
+}
+
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+var<private> keep_me = 42;
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessRemoveUncalledTest, PtrPrivate_Disabled) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+var<private> keep_me = 42;
+
+fn f(pre : i32, p : ptr<private, i32>, post : i32) -> i32 {
+ return *(p);
+}
+)";
+
+ auto* expect = src;
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessRemoveUncalledTest, PtrPrivate_Enabled) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+var<private> keep_me = 42;
+)";
+
+ auto* expect = src;
+
+ auto got = Run<DirectVariableAccess>(src, EnablePrivate());
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessRemoveUncalledTest, PtrFunction_Disabled) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+var<private> keep_me = 42;
+
+fn f(pre : i32, p : ptr<function, i32>, post : i32) -> i32 {
+ return *(p);
+}
+)";
+
+ auto* expect = src;
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessRemoveUncalledTest, PtrFunction_Enabled) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+var<private> keep_me = 42;
+)";
+
+ auto* expect = src;
+
+ auto got = Run<DirectVariableAccess>(src, EnableFunction());
+
+ EXPECT_EQ(expect, str(got));
+}
+
+} // namespace remove_uncalled
+
+////////////////////////////////////////////////////////////////////////////////
+// pointer chains
+////////////////////////////////////////////////////////////////////////////////
+namespace pointer_chains_tests {
+
+using DirectVariableAccessPtrChainsTest = TransformTest;
+
+TEST_F(DirectVariableAccessPtrChainsTest, ConstantIndices) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> U : array<array<array<vec4<i32>, 8>, 8>, 8>;
+
+fn a(pre : i32, p : ptr<uniform, vec4<i32>>, post : i32) -> vec4<i32> {
+ return *p;
+}
+
+fn b() {
+ let p0 = &U;
+ let p1 = &(*p0)[1];
+ let p2 = &(*p1)[1+1];
+ let p3 = &(*p2)[2*2 - 1];
+ a(10, p3, 20);
+}
+
+fn c(p : ptr<uniform, array<array<array<vec4<i32>, 8>, 8>, 8>>) {
+ let p0 = p;
+ let p1 = &(*p0)[1];
+ let p2 = &(*p1)[1+1];
+ let p3 = &(*p2)[2*2 - 1];
+ a(10, p3, 20);
+}
+
+fn d() {
+ c(&U);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> U : array<array<array<vec4<i32>, 8>, 8>, 8>;
+
+type U_X_X_X = array<u32, 3u>;
+
+fn a_U_X_X_X(pre : i32, p : U_X_X_X, post : i32) -> vec4<i32> {
+ return U[p[0]][p[1]][p[2]];
+}
+
+fn b() {
+ let p0 = &(U);
+ let p1 = &((*(p0))[1]);
+ let p2 = &((*(p1))[(1 + 1)]);
+ let p3 = &((*(p2))[((2 * 2) - 1)]);
+ a_U_X_X_X(10, U_X_X_X(1, 2, 3), 20);
+}
+
+fn c_U() {
+ let p0 = &(U);
+ let p1 = &(U[1]);
+ let p2 = &(U[1][2]);
+ let p3 = &(U[1][2][3]);
+ a_U_X_X_X(10, U_X_X_X(1, 2, 3), 20);
+}
+
+fn d() {
+ c_U();
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessPtrChainsTest, HoistIndices) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> U : array<array<array<vec4<i32>, 8>, 8>, 8>;
+
+var<private> i : i32;
+fn first() -> i32 {
+ i++;
+ return i;
+}
+fn second() -> i32 {
+ i++;
+ return i;
+}
+fn third() -> i32 {
+ i++;
+ return i;
+}
+
+fn a(pre : i32, p : ptr<uniform, vec4<i32>>, post : i32) -> vec4<i32> {
+ return *p;
+}
+
+fn b() {
+ let p0 = &U;
+ let p1 = &(*p0)[first()];
+ let p2 = &(*p1)[second()][third()];
+ a(10, p2, 20);
+}
+
+fn c(p : ptr<uniform, array<array<array<vec4<i32>, 8>, 8>, 8>>) {
+ let p0 = &U;
+ let p1 = &(*p0)[first()];
+ let p2 = &(*p1)[second()][third()];
+ a(10, p2, 20);
+}
+
+fn d() {
+ c(&U);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> U : array<array<array<vec4<i32>, 8>, 8>, 8>;
+
+var<private> i : i32;
+
+fn first() -> i32 {
+ i++;
+ return i;
+}
+
+fn second() -> i32 {
+ i++;
+ return i;
+}
+
+fn third() -> i32 {
+ i++;
+ return i;
+}
+
+type U_X_X_X = array<u32, 3u>;
+
+fn a_U_X_X_X(pre : i32, p : U_X_X_X, post : i32) -> vec4<i32> {
+ return U[p[0]][p[1]][p[2]];
+}
+
+fn b() {
+ let p0 = &(U);
+ let ptr_index_save = first();
+ let p1 = &((*(p0))[ptr_index_save]);
+ let ptr_index_save_1 = second();
+ let ptr_index_save_2 = third();
+ let p2 = &((*(p1))[ptr_index_save_1][ptr_index_save_2]);
+ a_U_X_X_X(10, U_X_X_X(u32(ptr_index_save), u32(ptr_index_save_1), u32(ptr_index_save_2)), 20);
+}
+
+fn c_U() {
+ let p0 = &(U);
+ let ptr_index_save_3 = first();
+ let p1 = &((*(p0))[ptr_index_save_3]);
+ let ptr_index_save_4 = second();
+ let ptr_index_save_5 = third();
+ let p2 = &((*(p1))[ptr_index_save_4][ptr_index_save_5]);
+ a_U_X_X_X(10, U_X_X_X(u32(ptr_index_save_3), u32(ptr_index_save_4), u32(ptr_index_save_5)), 20);
+}
+
+fn d() {
+ c_U();
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessPtrChainsTest, HoistInForLoopInit) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> U : array<array<vec4<i32>, 8>, 8>;
+
+var<private> i : i32;
+fn first() -> i32 {
+ i++;
+ return i;
+}
+fn second() -> i32 {
+ i++;
+ return i;
+}
+
+fn a(pre : i32, p : ptr<uniform, vec4<i32>>, post : i32) -> vec4<i32> {
+ return *p;
+}
+
+fn b() {
+ for (let p1 = &U[first()]; true; ) {
+ a(10, &(*p1)[second()], 20);
+ }
+}
+
+fn c(p : ptr<uniform, array<array<vec4<i32>, 8>, 8>>) {
+ for (let p1 = &(*p)[first()]; true; ) {
+ a(10, &(*p1)[second()], 20);
+ }
+}
+
+fn d() {
+ c(&U);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> U : array<array<vec4<i32>, 8>, 8>;
+
+var<private> i : i32;
+
+fn first() -> i32 {
+ i++;
+ return i;
+}
+
+fn second() -> i32 {
+ i++;
+ return i;
+}
+
+type U_X_X = array<u32, 2u>;
+
+fn a_U_X_X(pre : i32, p : U_X_X, post : i32) -> vec4<i32> {
+ return U[p[0]][p[1]];
+}
+
+fn b() {
+ let ptr_index_save = first();
+ for(let p1 = &(U[ptr_index_save]); true; ) {
+ a_U_X_X(10, U_X_X(u32(ptr_index_save), u32(second())), 20);
+ }
+}
+
+fn c_U() {
+ let ptr_index_save_1 = first();
+ for(let p1 = &(U[ptr_index_save_1]); true; ) {
+ a_U_X_X(10, U_X_X(u32(ptr_index_save_1), u32(second())), 20);
+ }
+}
+
+fn d() {
+ c_U();
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessPtrChainsTest, HoistInForLoopCond) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> U : array<array<vec4<i32>, 8>, 8>;
+
+var<private> i : i32;
+fn first() -> i32 {
+ i++;
+ return i;
+}
+fn second() -> i32 {
+ i++;
+ return i;
+}
+
+fn a(pre : i32, p : ptr<uniform, vec4<i32>>, post : i32) -> vec4<i32> {
+ return *p;
+}
+
+fn b() {
+ let p = &U[first()][second()];
+ for (; a(10, p, 20).x < 4; ) {
+ let body = 1;
+ }
+}
+
+fn c(p : ptr<uniform, array<array<vec4<i32>, 8>, 8>>) {
+ let p2 = &(*p)[first()][second()];
+ for (; a(10, p2, 20).x < 4; ) {
+ let body = 1;
+ }
+}
+
+fn d() {
+ c(&U);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> U : array<array<vec4<i32>, 8>, 8>;
+
+var<private> i : i32;
+
+fn first() -> i32 {
+ i++;
+ return i;
+}
+
+fn second() -> i32 {
+ i++;
+ return i;
+}
+
+type U_X_X = array<u32, 2u>;
+
+fn a_U_X_X(pre : i32, p : U_X_X, post : i32) -> vec4<i32> {
+ return U[p[0]][p[1]];
+}
+
+fn b() {
+ let ptr_index_save = first();
+ let ptr_index_save_1 = second();
+ let p = &(U[ptr_index_save][ptr_index_save_1]);
+ for(; (a_U_X_X(10, U_X_X(u32(ptr_index_save), u32(ptr_index_save_1)), 20).x < 4); ) {
+ let body = 1;
+ }
+}
+
+fn c_U() {
+ let ptr_index_save_2 = first();
+ let ptr_index_save_3 = second();
+ let p2 = &(U[ptr_index_save_2][ptr_index_save_3]);
+ for(; (a_U_X_X(10, U_X_X(u32(ptr_index_save_2), u32(ptr_index_save_3)), 20).x < 4); ) {
+ let body = 1;
+ }
+}
+
+fn d() {
+ c_U();
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessPtrChainsTest, HoistInForLoopCont) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> U : array<array<vec4<i32>, 8>, 8>;
+
+var<private> i : i32;
+fn first() -> i32 {
+ i++;
+ return i;
+}
+fn second() -> i32 {
+ i++;
+ return i;
+}
+
+fn a(pre : i32, p : ptr<uniform, vec4<i32>>, post : i32) -> vec4<i32> {
+ return *p;
+}
+
+fn b() {
+ let p = &U[first()][second()];
+ for (var i = 0; i < 3; a(10, p, 20)) {
+ i++;
+ }
+}
+
+fn c(p : ptr<uniform, array<array<vec4<i32>, 8>, 8>>) {
+ let p2 = &(*p)[first()][second()];
+ for (var i = 0; i < 3; a(10, p2, 20)) {
+ i++;
+ }
+}
+
+fn d() {
+ c(&U);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> U : array<array<vec4<i32>, 8>, 8>;
+
+var<private> i : i32;
+
+fn first() -> i32 {
+ i++;
+ return i;
+}
+
+fn second() -> i32 {
+ i++;
+ return i;
+}
+
+type U_X_X = array<u32, 2u>;
+
+fn a_U_X_X(pre : i32, p : U_X_X, post : i32) -> vec4<i32> {
+ return U[p[0]][p[1]];
+}
+
+fn b() {
+ let ptr_index_save = first();
+ let ptr_index_save_1 = second();
+ let p = &(U[ptr_index_save][ptr_index_save_1]);
+ for(var i = 0; (i < 3); a_U_X_X(10, U_X_X(u32(ptr_index_save), u32(ptr_index_save_1)), 20)) {
+ i++;
+ }
+}
+
+fn c_U() {
+ let ptr_index_save_2 = first();
+ let ptr_index_save_3 = second();
+ let p2 = &(U[ptr_index_save_2][ptr_index_save_3]);
+ for(var i = 0; (i < 3); a_U_X_X(10, U_X_X(u32(ptr_index_save_2), u32(ptr_index_save_3)), 20)) {
+ i++;
+ }
+}
+
+fn d() {
+ c_U();
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessPtrChainsTest, HoistInWhileCond) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> U : array<array<vec4<i32>, 8>, 8>;
+
+var<private> i : i32;
+fn first() -> i32 {
+ i++;
+ return i;
+}
+fn second() -> i32 {
+ i++;
+ return i;
+}
+
+fn a(pre : i32, p : ptr<uniform, vec4<i32>>, post : i32) -> vec4<i32> {
+ return *p;
+}
+
+fn b() {
+ let p = &U[first()][second()];
+ while (a(10, p, 20).x < 4) {
+ let body = 1;
+ }
+}
+
+fn c(p : ptr<uniform, array<array<vec4<i32>, 8>, 8>>) {
+ let p2 = &(*p)[first()][second()];
+ while (a(10, p2, 20).x < 4) {
+ let body = 1;
+ }
+}
+
+fn d() {
+ c(&U);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> U : array<array<vec4<i32>, 8>, 8>;
+
+var<private> i : i32;
+
+fn first() -> i32 {
+ i++;
+ return i;
+}
+
+fn second() -> i32 {
+ i++;
+ return i;
+}
+
+type U_X_X = array<u32, 2u>;
+
+fn a_U_X_X(pre : i32, p : U_X_X, post : i32) -> vec4<i32> {
+ return U[p[0]][p[1]];
+}
+
+fn b() {
+ let ptr_index_save = first();
+ let ptr_index_save_1 = second();
+ let p = &(U[ptr_index_save][ptr_index_save_1]);
+ while((a_U_X_X(10, U_X_X(u32(ptr_index_save), u32(ptr_index_save_1)), 20).x < 4)) {
+ let body = 1;
+ }
+}
+
+fn c_U() {
+ let ptr_index_save_2 = first();
+ let ptr_index_save_3 = second();
+ let p2 = &(U[ptr_index_save_2][ptr_index_save_3]);
+ while((a_U_X_X(10, U_X_X(u32(ptr_index_save_2), u32(ptr_index_save_3)), 20).x < 4)) {
+ let body = 1;
+ }
+}
+
+fn d() {
+ c_U();
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+} // namespace pointer_chains_tests
+
+////////////////////////////////////////////////////////////////////////////////
+// 'uniform' address space
+////////////////////////////////////////////////////////////////////////////////
+namespace uniform_as_tests {
+
+using DirectVariableAccessUniformASTest = TransformTest;
+
+TEST_F(DirectVariableAccessUniformASTest, Param_ptr_i32_read) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> U : i32;
+
+fn a(pre : i32, p : ptr<uniform, i32>, post : i32) -> i32 {
+ return *p;
+}
+
+fn b() {
+ a(10, &U, 20);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> U : i32;
+
+fn a_U(pre : i32, post : i32) -> i32 {
+ return U;
+}
+
+fn b() {
+ a_U(10, 20);
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessUniformASTest, Param_ptr_vec4i32_Via_array_DynamicRead) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> U : array<vec4<i32>, 8>;
+
+fn a(pre : i32, p : ptr<uniform, vec4<i32>>, post : i32) -> vec4<i32> {
+ return *p;
+}
+
+fn b() {
+ let I = 3;
+ a(10, &U[I], 20);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> U : array<vec4<i32>, 8>;
+
+type U_X = array<u32, 1u>;
+
+fn a_U_X(pre : i32, p : U_X, post : i32) -> vec4<i32> {
+ return U[p[0]];
+}
+
+fn b() {
+ let I = 3;
+ a_U_X(10, U_X(u32(I)), 20);
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessUniformASTest, CallChaining) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct Inner {
+ mat : mat3x4<f32>,
+};
+
+type InnerArr = array<Inner, 4>;
+
+struct Outer {
+ arr : InnerArr,
+ mat : mat3x4<f32>,
+};
+
+@group(0) @binding(0) var<uniform> U : Outer;
+
+fn f0(p : ptr<uniform, vec4<f32>>) -> f32 {
+ return (*p).x;
+}
+
+fn f1(p : ptr<uniform, mat3x4<f32>>) -> f32 {
+ var res : f32;
+ {
+ // call f0() with inline usage of p
+ res += f0(&(*p)[1]);
+ }
+ {
+ // call f0() with pointer-let usage of p
+ let p_vec = &(*p)[1];
+ res += f0(p_vec);
+ }
+ {
+ // call f0() with inline usage of U
+ res += f0(&U.arr[2].mat[1]);
+ }
+ {
+ // call f0() with pointer-let usage of U
+ let p_vec = &U.arr[2].mat[1];
+ res += f0(p_vec);
+ }
+ return res;
+}
+
+fn f2(p : ptr<uniform, Inner>) -> f32 {
+ let p_mat = &(*p).mat;
+ return f1(p_mat);
+}
+
+fn f3(p0 : ptr<uniform, InnerArr>, p1 : ptr<uniform, mat3x4<f32>>) -> f32 {
+ let p0_inner = &(*p0)[3];
+ return f2(p0_inner) + f1(p1);
+}
+
+fn f4(p : ptr<uniform, Outer>) -> f32 {
+ return f3(&(*p).arr, &U.mat);
+}
+
+fn b() {
+ f4(&U);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct Inner {
+ mat : mat3x4<f32>,
+}
+
+type InnerArr = array<Inner, 4>;
+
+struct Outer {
+ arr : InnerArr,
+ mat : mat3x4<f32>,
+}
+
+@group(0) @binding(0) var<uniform> U : Outer;
+
+type U_mat_X = array<u32, 1u>;
+
+fn f0_U_mat_X(p : U_mat_X) -> f32 {
+ return U.mat[p[0]].x;
+}
+
+type U_arr_X_mat_X = array<u32, 2u>;
+
+fn f0_U_arr_X_mat_X(p : U_arr_X_mat_X) -> f32 {
+ return U.arr[p[0]].mat[p[0]].x;
+}
+
+type U_arr_X_mat_X_1 = array<u32, 2u>;
+
+fn f0_U_arr_X_mat_X_1(p : U_arr_X_mat_X_1) -> f32 {
+ return U.arr[p[0]].mat[p[1]].x;
+}
+
+fn f1_U_mat() -> f32 {
+ var res : f32;
+ {
+ res += f0_U_mat_X(U_mat_X(1));
+ }
+ {
+ let p_vec = &(U.mat[1]);
+ res += f0_U_mat_X(U_mat_X(1));
+ }
+ {
+ res += f0_U_arr_X_mat_X_1(U_arr_X_mat_X_1(2, 1));
+ }
+ {
+ let p_vec = &(U.arr[2].mat[1]);
+ res += f0_U_arr_X_mat_X_1(U_arr_X_mat_X_1(2, 1));
+ }
+ return res;
+}
+
+type U_arr_X_mat = array<u32, 1u>;
+
+fn f1_U_arr_X_mat(p : U_arr_X_mat) -> f32 {
+ var res : f32;
+ {
+ res += f0_U_arr_X_mat_X(U_arr_X_mat_X(p[0u], 1));
+ }
+ {
+ let p_vec = &(U.arr[p[0]].mat[1]);
+ res += f0_U_arr_X_mat_X(U_arr_X_mat_X(p[0u], 1));
+ }
+ {
+ res += f0_U_arr_X_mat_X_1(U_arr_X_mat_X_1(2, 1));
+ }
+ {
+ let p_vec = &(U.arr[2].mat[1]);
+ res += f0_U_arr_X_mat_X_1(U_arr_X_mat_X_1(2, 1));
+ }
+ return res;
+}
+
+type U_arr_X = array<u32, 1u>;
+
+fn f2_U_arr_X(p : U_arr_X) -> f32 {
+ let p_mat = &(U.arr[p[0]].mat);
+ return f1_U_arr_X_mat(U_arr_X_mat(p[0u]));
+}
+
+fn f3_U_arr_U_mat() -> f32 {
+ let p0_inner = &(U.arr[3]);
+ return (f2_U_arr_X(U_arr_X(3)) + f1_U_mat());
+}
+
+fn f4_U() -> f32 {
+ return f3_U_arr_U_mat();
+}
+
+fn b() {
+ f4_U();
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+} // namespace uniform_as_tests
+
+////////////////////////////////////////////////////////////////////////////////
+// 'storage' address space
+////////////////////////////////////////////////////////////////////////////////
+namespace storage_as_tests {
+
+using DirectVariableAccessStorageASTest = TransformTest;
+
+TEST_F(DirectVariableAccessStorageASTest, Param_ptr_i32_Via_struct_read) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+@group(0) @binding(0) var<storage> S : str;
+
+fn a(pre : i32, p : ptr<storage, i32>, post : i32) -> i32 {
+ return *p;
+}
+
+fn b() {
+ a(10, &S.i, 20);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+@group(0) @binding(0) var<storage> S : str;
+
+fn a_S_i(pre : i32, post : i32) -> i32 {
+ return S.i;
+}
+
+fn b() {
+ a_S_i(10, 20);
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessStorageASTest, Param_ptr_arr_i32_Via_struct_write) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+};
+
+@group(0) @binding(0) var<storage, read_write> S : str;
+
+fn a(pre : i32, p : ptr<storage, array<i32, 4>, read_write>, post : i32) {
+ *p = array<i32, 4>();
+}
+
+fn b() {
+ a(10, &S.arr, 20);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> S : str;
+
+fn a_S_arr(pre : i32, post : i32) {
+ S.arr = array<i32, 4>();
+}
+
+fn b() {
+ a_S_arr(10, 20);
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessStorageASTest, Param_ptr_vec4i32_Via_array_DynamicWrite) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage, read_write> S : array<vec4<i32>, 8>;
+
+fn a(pre : i32, p : ptr<storage, vec4<i32>, read_write>, post : i32) {
+ *p = vec4<i32>();
+}
+
+fn b() {
+ let I = 3;
+ a(10, &S[I], 20);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage, read_write> S : array<vec4<i32>, 8>;
+
+type S_X = array<u32, 1u>;
+
+fn a_S_X(pre : i32, p : S_X, post : i32) {
+ S[p[0]] = vec4<i32>();
+}
+
+fn b() {
+ let I = 3;
+ a_S_X(10, S_X(u32(I)), 20);
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessStorageASTest, CallChaining) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct Inner {
+ mat : mat3x4<f32>,
+};
+
+type InnerArr = array<Inner, 4>;
+
+struct Outer {
+ arr : InnerArr,
+ mat : mat3x4<f32>,
+};
+
+@group(0) @binding(0) var<storage> S : Outer;
+
+fn f0(p : ptr<storage, vec4<f32>>) -> f32 {
+ return (*p).x;
+}
+
+fn f1(p : ptr<storage, mat3x4<f32>>) -> f32 {
+ var res : f32;
+ {
+ // call f0() with inline usage of p
+ res += f0(&(*p)[1]);
+ }
+ {
+ // call f0() with pointer-let usage of p
+ let p_vec = &(*p)[1];
+ res += f0(p_vec);
+ }
+ {
+ // call f0() with inline usage of S
+ res += f0(&S.arr[2].mat[1]);
+ }
+ {
+ // call f0() with pointer-let usage of S
+ let p_vec = &S.arr[2].mat[1];
+ res += f0(p_vec);
+ }
+ return res;
+}
+
+fn f2(p : ptr<storage, Inner>) -> f32 {
+ let p_mat = &(*p).mat;
+ return f1(p_mat);
+}
+
+fn f3(p0 : ptr<storage, InnerArr>, p1 : ptr<storage, mat3x4<f32>>) -> f32 {
+ let p0_inner = &(*p0)[3];
+ return f2(p0_inner) + f1(p1);
+}
+
+fn f4(p : ptr<storage, Outer>) -> f32 {
+ return f3(&(*p).arr, &S.mat);
+}
+
+fn b() {
+ f4(&S);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct Inner {
+ mat : mat3x4<f32>,
+}
+
+type InnerArr = array<Inner, 4>;
+
+struct Outer {
+ arr : InnerArr,
+ mat : mat3x4<f32>,
+}
+
+@group(0) @binding(0) var<storage> S : Outer;
+
+type S_mat_X = array<u32, 1u>;
+
+fn f0_S_mat_X(p : S_mat_X) -> f32 {
+ return S.mat[p[0]].x;
+}
+
+type S_arr_X_mat_X = array<u32, 2u>;
+
+fn f0_S_arr_X_mat_X(p : S_arr_X_mat_X) -> f32 {
+ return S.arr[p[0]].mat[p[0]].x;
+}
+
+type S_arr_X_mat_X_1 = array<u32, 2u>;
+
+fn f0_S_arr_X_mat_X_1(p : S_arr_X_mat_X_1) -> f32 {
+ return S.arr[p[0]].mat[p[1]].x;
+}
+
+fn f1_S_mat() -> f32 {
+ var res : f32;
+ {
+ res += f0_S_mat_X(S_mat_X(1));
+ }
+ {
+ let p_vec = &(S.mat[1]);
+ res += f0_S_mat_X(S_mat_X(1));
+ }
+ {
+ res += f0_S_arr_X_mat_X_1(S_arr_X_mat_X_1(2, 1));
+ }
+ {
+ let p_vec = &(S.arr[2].mat[1]);
+ res += f0_S_arr_X_mat_X_1(S_arr_X_mat_X_1(2, 1));
+ }
+ return res;
+}
+
+type S_arr_X_mat = array<u32, 1u>;
+
+fn f1_S_arr_X_mat(p : S_arr_X_mat) -> f32 {
+ var res : f32;
+ {
+ res += f0_S_arr_X_mat_X(S_arr_X_mat_X(p[0u], 1));
+ }
+ {
+ let p_vec = &(S.arr[p[0]].mat[1]);
+ res += f0_S_arr_X_mat_X(S_arr_X_mat_X(p[0u], 1));
+ }
+ {
+ res += f0_S_arr_X_mat_X_1(S_arr_X_mat_X_1(2, 1));
+ }
+ {
+ let p_vec = &(S.arr[2].mat[1]);
+ res += f0_S_arr_X_mat_X_1(S_arr_X_mat_X_1(2, 1));
+ }
+ return res;
+}
+
+type S_arr_X = array<u32, 1u>;
+
+fn f2_S_arr_X(p : S_arr_X) -> f32 {
+ let p_mat = &(S.arr[p[0]].mat);
+ return f1_S_arr_X_mat(S_arr_X_mat(p[0u]));
+}
+
+fn f3_S_arr_S_mat() -> f32 {
+ let p0_inner = &(S.arr[3]);
+ return (f2_S_arr_X(S_arr_X(3)) + f1_S_mat());
+}
+
+fn f4_S() -> f32 {
+ return f3_S_arr_S_mat();
+}
+
+fn b() {
+ f4_S();
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+} // namespace storage_as_tests
+
+////////////////////////////////////////////////////////////////////////////////
+// 'workgroup' address space
+////////////////////////////////////////////////////////////////////////////////
+namespace workgroup_as_tests {
+
+using DirectVariableAccessWorkgroupASTest = TransformTest;
+
+TEST_F(DirectVariableAccessWorkgroupASTest, Param_ptr_vec4i32_Via_array_StaticRead) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> W : array<vec4<i32>, 8>;
+
+fn a(pre : i32, p : ptr<workgroup, vec4<i32>>, post : i32) -> vec4<i32> {
+ return *p;
+}
+
+fn b() {
+ a(10, &W[3], 20);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> W : array<vec4<i32>, 8>;
+
+type W_X = array<u32, 1u>;
+
+fn a_W_X(pre : i32, p : W_X, post : i32) -> vec4<i32> {
+ return W[p[0]];
+}
+
+fn b() {
+ a_W_X(10, W_X(3), 20);
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessWorkgroupASTest, Param_ptr_vec4i32_Via_array_StaticWrite) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> W : array<vec4<i32>, 8>;
+
+fn a(pre : i32, p : ptr<workgroup, vec4<i32>>, post : i32) {
+ *p = vec4<i32>();
+}
+
+fn b() {
+ a(10, &W[3], 20);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> W : array<vec4<i32>, 8>;
+
+type W_X = array<u32, 1u>;
+
+fn a_W_X(pre : i32, p : W_X, post : i32) {
+ W[p[0]] = vec4<i32>();
+}
+
+fn b() {
+ a_W_X(10, W_X(3), 20);
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessWorkgroupASTest, CallChaining) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct Inner {
+ mat : mat3x4<f32>,
+};
+
+type InnerArr = array<Inner, 4>;
+
+struct Outer {
+ arr : InnerArr,
+ mat : mat3x4<f32>,
+};
+
+var<workgroup> W : Outer;
+
+fn f0(p : ptr<workgroup, vec4<f32>>) -> f32 {
+ return (*p).x;
+}
+
+fn f1(p : ptr<workgroup, mat3x4<f32>>) -> f32 {
+ var res : f32;
+ {
+ // call f0() with inline usage of p
+ res += f0(&(*p)[1]);
+ }
+ {
+ // call f0() with pointer-let usage of p
+ let p_vec = &(*p)[1];
+ res += f0(p_vec);
+ }
+ {
+ // call f0() with inline usage of W
+ res += f0(&W.arr[2].mat[1]);
+ }
+ {
+ // call f0() with pointer-let usage of W
+ let p_vec = &W.arr[2].mat[1];
+ res += f0(p_vec);
+ }
+ return res;
+}
+
+fn f2(p : ptr<workgroup, Inner>) -> f32 {
+ let p_mat = &(*p).mat;
+ return f1(p_mat);
+}
+
+fn f3(p0 : ptr<workgroup, InnerArr>, p1 : ptr<workgroup, mat3x4<f32>>) -> f32 {
+ let p0_inner = &(*p0)[3];
+ return f2(p0_inner) + f1(p1);
+}
+
+fn f4(p : ptr<workgroup, Outer>) -> f32 {
+ return f3(&(*p).arr, &W.mat);
+}
+
+fn b() {
+ f4(&W);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct Inner {
+ mat : mat3x4<f32>,
+}
+
+type InnerArr = array<Inner, 4>;
+
+struct Outer {
+ arr : InnerArr,
+ mat : mat3x4<f32>,
+}
+
+var<workgroup> W : Outer;
+
+type W_mat_X = array<u32, 1u>;
+
+fn f0_W_mat_X(p : W_mat_X) -> f32 {
+ return W.mat[p[0]].x;
+}
+
+type W_arr_X_mat_X = array<u32, 2u>;
+
+fn f0_W_arr_X_mat_X(p : W_arr_X_mat_X) -> f32 {
+ return W.arr[p[0]].mat[p[0]].x;
+}
+
+type W_arr_X_mat_X_1 = array<u32, 2u>;
+
+fn f0_W_arr_X_mat_X_1(p : W_arr_X_mat_X_1) -> f32 {
+ return W.arr[p[0]].mat[p[1]].x;
+}
+
+fn f1_W_mat() -> f32 {
+ var res : f32;
+ {
+ res += f0_W_mat_X(W_mat_X(1));
+ }
+ {
+ let p_vec = &(W.mat[1]);
+ res += f0_W_mat_X(W_mat_X(1));
+ }
+ {
+ res += f0_W_arr_X_mat_X_1(W_arr_X_mat_X_1(2, 1));
+ }
+ {
+ let p_vec = &(W.arr[2].mat[1]);
+ res += f0_W_arr_X_mat_X_1(W_arr_X_mat_X_1(2, 1));
+ }
+ return res;
+}
+
+type W_arr_X_mat = array<u32, 1u>;
+
+fn f1_W_arr_X_mat(p : W_arr_X_mat) -> f32 {
+ var res : f32;
+ {
+ res += f0_W_arr_X_mat_X(W_arr_X_mat_X(p[0u], 1));
+ }
+ {
+ let p_vec = &(W.arr[p[0]].mat[1]);
+ res += f0_W_arr_X_mat_X(W_arr_X_mat_X(p[0u], 1));
+ }
+ {
+ res += f0_W_arr_X_mat_X_1(W_arr_X_mat_X_1(2, 1));
+ }
+ {
+ let p_vec = &(W.arr[2].mat[1]);
+ res += f0_W_arr_X_mat_X_1(W_arr_X_mat_X_1(2, 1));
+ }
+ return res;
+}
+
+type W_arr_X = array<u32, 1u>;
+
+fn f2_W_arr_X(p : W_arr_X) -> f32 {
+ let p_mat = &(W.arr[p[0]].mat);
+ return f1_W_arr_X_mat(W_arr_X_mat(p[0u]));
+}
+
+fn f3_W_arr_W_mat() -> f32 {
+ let p0_inner = &(W.arr[3]);
+ return (f2_W_arr_X(W_arr_X(3)) + f1_W_mat());
+}
+
+fn f4_W() -> f32 {
+ return f3_W_arr_W_mat();
+}
+
+fn b() {
+ f4_W();
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+} // namespace workgroup_as_tests
+
+////////////////////////////////////////////////////////////////////////////////
+// 'private' address space
+////////////////////////////////////////////////////////////////////////////////
+namespace private_as_tests {
+
+using DirectVariableAccessPrivateASTest = TransformTest;
+
+TEST_F(DirectVariableAccessPrivateASTest, Enabled_Param_ptr_i32_read) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+fn a(pre : i32, p : ptr<private, i32>, post : i32) -> i32 {
+ return *(p);
+}
+
+var<private> P : i32;
+
+fn b() {
+ a(10, &(P), 20);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+fn a_F(pre : i32, p : ptr<private, i32>, post : i32) -> i32 {
+ return *(p);
+}
+
+var<private> P : i32;
+
+fn b() {
+ a_F(10, &(P), 20);
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src, EnablePrivate());
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessPrivateASTest, Enabled_Param_ptr_i32_write) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+fn a(pre : i32, p : ptr<private, i32>, post : i32) {
+ *(p) = 42;
+}
+
+var<private> P : i32;
+
+fn b() {
+ a(10, &(P), 20);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+fn a_F(pre : i32, p : ptr<private, i32>, post : i32) {
+ *(p) = 42;
+}
+
+var<private> P : i32;
+
+fn b() {
+ a_F(10, &(P), 20);
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src, EnablePrivate());
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessPrivateASTest, Enabled_Param_ptr_i32_Via_struct_read) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+fn a(pre : i32, p : ptr<private, i32>, post : i32) -> i32 {
+ return *p;
+}
+
+var<private> P : str;
+
+fn b() {
+ a(10, &P.i, 20);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+fn a_F_i(pre : i32, p : ptr<private, str>, post : i32) -> i32 {
+ return (*(p)).i;
+}
+
+var<private> P : str;
+
+fn b() {
+ a_F_i(10, &(P), 20);
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src, EnablePrivate());
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessPrivateASTest, Disabled_Param_ptr_i32_Via_struct_read) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+fn a(pre : i32, p : ptr<private, i32>, post : i32) -> i32 {
+ return *(p);
+}
+
+var<private> P : str;
+
+fn b() {
+ a(10, &(P.i), 20);
+}
+)";
+
+ auto* expect = src;
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessPrivateASTest, Enabled_Param_ptr_arr_i32_Via_struct_write) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+};
+
+fn a(pre : i32, p : ptr<private, array<i32, 4>>, post : i32) {
+ *p = array<i32, 4>();
+}
+
+var<private> P : str;
+
+fn b() {
+ a(10, &P.arr, 20);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+}
+
+fn a_F_arr(pre : i32, p : ptr<private, str>, post : i32) {
+ (*(p)).arr = array<i32, 4>();
+}
+
+var<private> P : str;
+
+fn b() {
+ a_F_arr(10, &(P), 20);
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src, EnablePrivate());
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessPrivateASTest, Disabled_Param_ptr_arr_i32_Via_struct_write) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+}
+
+fn a(pre : i32, p : ptr<private, array<i32, 4>>, post : i32) {
+ *(p) = array<i32, 4>();
+}
+
+var<private> P : str;
+
+fn b() {
+ a(10, &(P.arr), 20);
+}
+)";
+
+ auto* expect = src;
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessPrivateASTest, Enabled_Param_ptr_i32_mixed) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+fn a(pre : i32, p : ptr<private, i32>, post : i32) -> i32 {
+ return *p;
+}
+
+var<private> Pi : i32;
+var<private> Ps : str;
+var<private> Pa : array<i32, 4>;
+
+fn b() {
+ a(10, &Pi, 20);
+ a(30, &Ps.i, 40);
+ a(50, &Pa[2], 60);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+fn a_F(pre : i32, p : ptr<private, i32>, post : i32) -> i32 {
+ return *(p);
+}
+
+fn a_F_i(pre : i32, p : ptr<private, str>, post : i32) -> i32 {
+ return (*(p)).i;
+}
+
+type F_X = array<u32, 1u>;
+
+fn a_F_X(pre : i32, p_base : ptr<private, array<i32, 4u>>, p_indices : F_X, post : i32) -> i32 {
+ return (*(p_base))[p_indices[0]];
+}
+
+var<private> Pi : i32;
+
+var<private> Ps : str;
+
+var<private> Pa : array<i32, 4>;
+
+type F_X_1 = array<u32, 1u>;
+
+fn b() {
+ a_F(10, &(Pi), 20);
+ a_F_i(30, &(Ps), 40);
+ a_F_X(50, &(Pa), F_X_1(2), 60);
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src, EnablePrivate());
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessPrivateASTest, Disabled_Param_ptr_i32_mixed) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+fn a(pre : i32, p : ptr<private, i32>, post : i32) -> i32 {
+ return *(p);
+}
+
+var<private> Pi : i32;
+
+var<private> Ps : str;
+
+var<private> Pa : array<i32, 4>;
+
+fn b() {
+ a(10, &(Pi), 20);
+ a(10, &(Ps.i), 20);
+ a(10, &(Pa[2]), 20);
+}
+)";
+
+ auto* expect = src;
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessPrivateASTest, Enabled_CallChaining) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct Inner {
+ mat : mat3x4<f32>,
+};
+
+type InnerArr = array<Inner, 4>;
+
+struct Outer {
+ arr : InnerArr,
+ mat : mat3x4<f32>,
+};
+
+var<private> P : Outer;
+
+fn f0(p : ptr<private, vec4<f32>>) -> f32 {
+ return (*p).x;
+}
+
+fn f1(p : ptr<private, mat3x4<f32>>) -> f32 {
+ var res : f32;
+ {
+ // call f0() with inline usage of p
+ res += f0(&(*p)[1]);
+ }
+ {
+ // call f0() with pointer-let usage of p
+ let p_vec = &(*p)[1];
+ res += f0(p_vec);
+ }
+ {
+ // call f0() with inline usage of P
+ res += f0(&P.arr[2].mat[1]);
+ }
+ {
+ // call f0() with pointer-let usage of P
+ let p_vec = &P.arr[2].mat[1];
+ res += f0(p_vec);
+ }
+ return res;
+}
+
+fn f2(p : ptr<private, Inner>) -> f32 {
+ let p_mat = &(*p).mat;
+ return f1(p_mat);
+}
+
+fn f3(p0 : ptr<private, InnerArr>, p1 : ptr<private, mat3x4<f32>>) -> f32 {
+ let p0_inner = &(*p0)[3];
+ return f2(p0_inner) + f1(p1);
+}
+
+fn f4(p : ptr<private, Outer>) -> f32 {
+ return f3(&(*p).arr, &P.mat);
+}
+
+fn b() {
+ f4(&P);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct Inner {
+ mat : mat3x4<f32>,
+}
+
+type InnerArr = array<Inner, 4>;
+
+struct Outer {
+ arr : InnerArr,
+ mat : mat3x4<f32>,
+}
+
+var<private> P : Outer;
+
+type F_mat_X = array<u32, 1u>;
+
+fn f0_F_mat_X(p_base : ptr<private, Outer>, p_indices : F_mat_X) -> f32 {
+ return (*(p_base)).mat[p_indices[0]].x;
+}
+
+type F_arr_X_mat_X = array<u32, 2u>;
+
+fn f0_F_arr_X_mat_X(p_base : ptr<private, Outer>, p_indices : F_arr_X_mat_X) -> f32 {
+ return (*(p_base)).arr[p_indices[0]].mat[p_indices[0]].x;
+}
+
+type F_arr_X_mat_X_1 = array<u32, 2u>;
+
+fn f0_F_arr_X_mat_X_1(p_base : ptr<private, Outer>, p_indices : F_arr_X_mat_X_1) -> f32 {
+ return (*(p_base)).arr[p_indices[0]].mat[p_indices[1]].x;
+}
+
+type F_mat_X_1 = array<u32, 1u>;
+
+type F_arr_X_mat_X_2 = array<u32, 2u>;
+
+fn f1_F_mat(p : ptr<private, Outer>) -> f32 {
+ var res : f32;
+ {
+ res += f0_F_mat_X(p, F_mat_X_1(1));
+ }
+ {
+ let p_vec = &((*(p)).mat[1]);
+ res += f0_F_mat_X(p, F_mat_X_1(1));
+ }
+ {
+ res += f0_F_arr_X_mat_X_1(&(P), F_arr_X_mat_X_2(2, 1));
+ }
+ {
+ let p_vec = &(P.arr[2].mat[1]);
+ res += f0_F_arr_X_mat_X_1(&(P), F_arr_X_mat_X_2(2, 1));
+ }
+ return res;
+}
+
+type F_arr_X_mat = array<u32, 1u>;
+
+type F_arr_X_mat_X_3 = array<u32, 2u>;
+
+fn f1_F_arr_X_mat(p_base : ptr<private, Outer>, p_indices : F_arr_X_mat) -> f32 {
+ var res : f32;
+ {
+ res += f0_F_arr_X_mat_X(p_base, F_arr_X_mat_X_3(p_indices[0u], 1));
+ }
+ {
+ let p_vec = &((*(p_base)).arr[p_indices[0]].mat[1]);
+ res += f0_F_arr_X_mat_X(p_base, F_arr_X_mat_X_3(p_indices[0u], 1));
+ }
+ {
+ res += f0_F_arr_X_mat_X_1(&(P), F_arr_X_mat_X_2(2, 1));
+ }
+ {
+ let p_vec = &(P.arr[2].mat[1]);
+ res += f0_F_arr_X_mat_X_1(&(P), F_arr_X_mat_X_2(2, 1));
+ }
+ return res;
+}
+
+type F_arr_X = array<u32, 1u>;
+
+type F_arr_X_mat_1 = array<u32, 1u>;
+
+fn f2_F_arr_X(p_base : ptr<private, Outer>, p_indices : F_arr_X) -> f32 {
+ let p_mat = &((*(p_base)).arr[p_indices[0]].mat);
+ return f1_F_arr_X_mat(p_base, F_arr_X_mat_1(p_indices[0u]));
+}
+
+type F_arr_X_1 = array<u32, 1u>;
+
+fn f3_F_arr_F_mat(p0 : ptr<private, Outer>, p1 : ptr<private, Outer>) -> f32 {
+ let p0_inner = &((*(p0)).arr[3]);
+ return (f2_F_arr_X(p0, F_arr_X_1(3)) + f1_F_mat(p1));
+}
+
+fn f4_F(p : ptr<private, Outer>) -> f32 {
+ return f3_F_arr_F_mat(p, &(P));
+}
+
+fn b() {
+ f4_F(&(P));
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src, EnablePrivate());
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessPrivateASTest, Disabled_CallChaining) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct Inner {
+ mat : mat3x4<f32>,
+}
+
+type InnerArr = array<Inner, 4>;
+
+struct Outer {
+ arr : InnerArr,
+ mat : mat3x4<f32>,
+}
+
+var<private> P : Outer;
+
+fn f0(p : ptr<private, vec4<f32>>) -> f32 {
+ return (*(p)).x;
+}
+
+fn f1(p : ptr<private, mat3x4<f32>>) -> f32 {
+ var res : f32;
+ {
+ res += f0(&((*(p))[1]));
+ }
+ {
+ let p_vec = &((*(p))[1]);
+ res += f0(p_vec);
+ }
+ {
+ res += f0(&(P.arr[2].mat[1]));
+ }
+ {
+ let p_vec = &(P.arr[2].mat[1]);
+ res += f0(p_vec);
+ }
+ return res;
+}
+
+fn f2(p : ptr<private, Inner>) -> f32 {
+ let p_mat = &((*(p)).mat);
+ return f1(p_mat);
+}
+
+fn f3(p0 : ptr<private, InnerArr>, p1 : ptr<private, mat3x4<f32>>) -> f32 {
+ let p0_inner = &((*(p0))[3]);
+ return (f2(p0_inner) + f1(p1));
+}
+
+fn f4(p : ptr<private, Outer>) -> f32 {
+ return f3(&((*(p)).arr), &(P.mat));
+}
+
+fn b() {
+ f4(&(P));
+}
+)";
+
+ auto* expect = src;
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+} // namespace private_as_tests
+
+////////////////////////////////////////////////////////////////////////////////
+// 'function' address space
+////////////////////////////////////////////////////////////////////////////////
+namespace function_as_tests {
+
+using DirectVariableAccessFunctionASTest = TransformTest;
+
+TEST_F(DirectVariableAccessFunctionASTest, Enabled_LocalPtr) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+fn f() {
+ var v : i32;
+ let p : ptr<function, i32> = &(v);
+ var x : i32 = *(p);
+}
+)";
+
+ auto* expect = src; // Nothing changes
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessFunctionASTest, Enabled_Param_ptr_i32_read) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+fn a(pre : i32, p : ptr<function, i32>, post : i32) -> i32 {
+ return *(p);
+}
+
+fn b() {
+ var F : i32;
+ a(10, &(F), 20);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+fn a_F(pre : i32, p : ptr<function, i32>, post : i32) -> i32 {
+ return *(p);
+}
+
+fn b() {
+ var F : i32;
+ a_F(10, &(F), 20);
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src, EnableFunction());
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessFunctionASTest, Enabled_Param_ptr_i32_write) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+fn a(pre : i32, p : ptr<function, i32>, post : i32) {
+ *(p) = 42;
+}
+
+fn b() {
+ var F : i32;
+ a(10, &(F), 20);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+fn a_F(pre : i32, p : ptr<function, i32>, post : i32) {
+ *(p) = 42;
+}
+
+fn b() {
+ var F : i32;
+ a_F(10, &(F), 20);
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src, EnableFunction());
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessFunctionASTest, Enabled_Param_ptr_i32_Via_struct_read) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+fn a(pre : i32, p : ptr<function, i32>, post : i32) -> i32 {
+ return *p;
+}
+
+fn b() {
+ var F : str;
+ a(10, &F.i, 20);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+fn a_F_i(pre : i32, p : ptr<function, str>, post : i32) -> i32 {
+ return (*(p)).i;
+}
+
+fn b() {
+ var F : str;
+ a_F_i(10, &(F), 20);
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src, EnableFunction());
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessFunctionASTest, Enabled_Param_ptr_arr_i32_Via_struct_write) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+};
+
+fn a(pre : i32, p : ptr<function, array<i32, 4>>, post : i32) {
+ *p = array<i32, 4>();
+}
+
+fn b() {
+ var F : str;
+ a(10, &F.arr, 20);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+}
+
+fn a_F_arr(pre : i32, p : ptr<function, str>, post : i32) {
+ (*(p)).arr = array<i32, 4>();
+}
+
+fn b() {
+ var F : str;
+ a_F_arr(10, &(F), 20);
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src, EnableFunction());
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessFunctionASTest, Enabled_Param_ptr_i32_mixed) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+fn a(pre : i32, p : ptr<function, i32>, post : i32) -> i32 {
+ return *p;
+}
+
+fn b() {
+ var Fi : i32;
+ var Fs : str;
+ var Fa : array<i32, 4>;
+
+ a(10, &Fi, 20);
+ a(30, &Fs.i, 40);
+ a(50, &Fa[2], 60);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+fn a_F(pre : i32, p : ptr<function, i32>, post : i32) -> i32 {
+ return *(p);
+}
+
+fn a_F_i(pre : i32, p : ptr<function, str>, post : i32) -> i32 {
+ return (*(p)).i;
+}
+
+type F_X = array<u32, 1u>;
+
+fn a_F_X(pre : i32, p_base : ptr<function, array<i32, 4u>>, p_indices : F_X, post : i32) -> i32 {
+ return (*(p_base))[p_indices[0]];
+}
+
+type F_X_1 = array<u32, 1u>;
+
+fn b() {
+ var Fi : i32;
+ var Fs : str;
+ var Fa : array<i32, 4>;
+ a_F(10, &(Fi), 20);
+ a_F_i(30, &(Fs), 40);
+ a_F_X(50, &(Fa), F_X_1(2), 60);
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src, EnableFunction());
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessFunctionASTest, Disabled_Param_ptr_i32_Via_struct_read) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+fn a(pre : i32, p : ptr<function, i32>, post : i32) -> i32 {
+ return *(p);
+}
+
+fn b() {
+ var F : str;
+ a(10, &(F.i), 20);
+}
+)";
+
+ auto* expect = src;
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessFunctionASTest, Disabled_Param_ptr_arr_i32_Via_struct_write) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+}
+
+fn a(pre : i32, p : ptr<function, array<i32, 4>>, post : i32) {
+ *(p) = array<i32, 4>();
+}
+
+fn b() {
+ var F : str;
+ a(10, &(F.arr), 20);
+}
+)";
+
+ auto* expect = src;
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+} // namespace function_as_tests
+
+////////////////////////////////////////////////////////////////////////////////
+// complex tests
+////////////////////////////////////////////////////////////////////////////////
+namespace complex_tests {
+
+using DirectVariableAccessComplexTest = TransformTest;
+
+TEST_F(DirectVariableAccessComplexTest, Param_ptr_mixed_vec4i32_ViaMultiple) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<i32>,
+};
+
+@group(0) @binding(0) var<uniform> U : vec4<i32>;
+@group(0) @binding(1) var<uniform> U_str : str;
+@group(0) @binding(2) var<uniform> U_arr : array<vec4<i32>, 8>;
+@group(0) @binding(3) var<uniform> U_arr_arr : array<array<vec4<i32>, 8>, 4>;
+
+@group(1) @binding(0) var<storage> S : vec4<i32>;
+@group(1) @binding(1) var<storage> S_str : str;
+@group(1) @binding(2) var<storage> S_arr : array<vec4<i32>, 8>;
+@group(1) @binding(3) var<storage> S_arr_arr : array<array<vec4<i32>, 8>, 4>;
+
+ var<workgroup> W : vec4<i32>;
+ var<workgroup> W_str : str;
+ var<workgroup> W_arr : array<vec4<i32>, 8>;
+ var<workgroup> W_arr_arr : array<array<vec4<i32>, 8>, 4>;
+
+fn fn_u(p : ptr<uniform, vec4<i32>>) -> vec4<i32> {
+ return *p;
+}
+
+fn fn_s(p : ptr<storage, vec4<i32>>) -> vec4<i32> {
+ return *p;
+}
+
+fn fn_w(p : ptr<workgroup, vec4<i32>>) -> vec4<i32> {
+ return *p;
+}
+
+fn b() {
+ let I = 3;
+ let J = 4;
+
+ let u = fn_u(&U);
+ let u_str = fn_u(&U_str.i);
+ let u_arr0 = fn_u(&U_arr[0]);
+ let u_arr1 = fn_u(&U_arr[1]);
+ let u_arrI = fn_u(&U_arr[I]);
+ let u_arr1_arr0 = fn_u(&U_arr_arr[1][0]);
+ let u_arr2_arrI = fn_u(&U_arr_arr[2][I]);
+ let u_arrI_arr2 = fn_u(&U_arr_arr[I][2]);
+ let u_arrI_arrJ = fn_u(&U_arr_arr[I][J]);
+
+ let s = fn_s(&S);
+ let s_str = fn_s(&S_str.i);
+ let s_arr0 = fn_s(&S_arr[0]);
+ let s_arr1 = fn_s(&S_arr[1]);
+ let s_arrI = fn_s(&S_arr[I]);
+ let s_arr1_arr0 = fn_s(&S_arr_arr[1][0]);
+ let s_arr2_arrI = fn_s(&S_arr_arr[2][I]);
+ let s_arrI_arr2 = fn_s(&S_arr_arr[I][2]);
+ let s_arrI_arrJ = fn_s(&S_arr_arr[I][J]);
+
+ let w = fn_w(&W);
+ let w_str = fn_w(&W_str.i);
+ let w_arr0 = fn_w(&W_arr[0]);
+ let w_arr1 = fn_w(&W_arr[1]);
+ let w_arrI = fn_w(&W_arr[I]);
+ let w_arr1_arr0 = fn_w(&W_arr_arr[1][0]);
+ let w_arr2_arrI = fn_w(&W_arr_arr[2][I]);
+ let w_arrI_arr2 = fn_w(&W_arr_arr[I][2]);
+ let w_arrI_arrJ = fn_w(&W_arr_arr[I][J]);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<i32>,
+}
+
+@group(0) @binding(0) var<uniform> U : vec4<i32>;
+
+@group(0) @binding(1) var<uniform> U_str : str;
+
+@group(0) @binding(2) var<uniform> U_arr : array<vec4<i32>, 8>;
+
+@group(0) @binding(3) var<uniform> U_arr_arr : array<array<vec4<i32>, 8>, 4>;
+
+@group(1) @binding(0) var<storage> S : vec4<i32>;
+
+@group(1) @binding(1) var<storage> S_str : str;
+
+@group(1) @binding(2) var<storage> S_arr : array<vec4<i32>, 8>;
+
+@group(1) @binding(3) var<storage> S_arr_arr : array<array<vec4<i32>, 8>, 4>;
+
+var<workgroup> W : vec4<i32>;
+
+var<workgroup> W_str : str;
+
+var<workgroup> W_arr : array<vec4<i32>, 8>;
+
+var<workgroup> W_arr_arr : array<array<vec4<i32>, 8>, 4>;
+
+fn fn_u_U() -> vec4<i32> {
+ return U;
+}
+
+fn fn_u_U_str_i() -> vec4<i32> {
+ return U_str.i;
+}
+
+type U_arr_X = array<u32, 1u>;
+
+fn fn_u_U_arr_X(p : U_arr_X) -> vec4<i32> {
+ return U_arr[p[0]];
+}
+
+type U_arr_arr_X_X = array<u32, 2u>;
+
+fn fn_u_U_arr_arr_X_X(p : U_arr_arr_X_X) -> vec4<i32> {
+ return U_arr_arr[p[0]][p[1]];
+}
+
+fn fn_s_S() -> vec4<i32> {
+ return S;
+}
+
+fn fn_s_S_str_i() -> vec4<i32> {
+ return S_str.i;
+}
+
+type S_arr_X = array<u32, 1u>;
+
+fn fn_s_S_arr_X(p : S_arr_X) -> vec4<i32> {
+ return S_arr[p[0]];
+}
+
+type S_arr_arr_X_X = array<u32, 2u>;
+
+fn fn_s_S_arr_arr_X_X(p : S_arr_arr_X_X) -> vec4<i32> {
+ return S_arr_arr[p[0]][p[1]];
+}
+
+fn fn_w_W() -> vec4<i32> {
+ return W;
+}
+
+fn fn_w_W_str_i() -> vec4<i32> {
+ return W_str.i;
+}
+
+type W_arr_X = array<u32, 1u>;
+
+fn fn_w_W_arr_X(p : W_arr_X) -> vec4<i32> {
+ return W_arr[p[0]];
+}
+
+type W_arr_arr_X_X = array<u32, 2u>;
+
+fn fn_w_W_arr_arr_X_X(p : W_arr_arr_X_X) -> vec4<i32> {
+ return W_arr_arr[p[0]][p[1]];
+}
+
+fn b() {
+ let I = 3;
+ let J = 4;
+ let u = fn_u_U();
+ let u_str = fn_u_U_str_i();
+ let u_arr0 = fn_u_U_arr_X(U_arr_X(0));
+ let u_arr1 = fn_u_U_arr_X(U_arr_X(1));
+ let u_arrI = fn_u_U_arr_X(U_arr_X(u32(I)));
+ let u_arr1_arr0 = fn_u_U_arr_arr_X_X(U_arr_arr_X_X(1, 0));
+ let u_arr2_arrI = fn_u_U_arr_arr_X_X(U_arr_arr_X_X(2, u32(I)));
+ let u_arrI_arr2 = fn_u_U_arr_arr_X_X(U_arr_arr_X_X(u32(I), 2));
+ let u_arrI_arrJ = fn_u_U_arr_arr_X_X(U_arr_arr_X_X(u32(I), u32(J)));
+ let s = fn_s_S();
+ let s_str = fn_s_S_str_i();
+ let s_arr0 = fn_s_S_arr_X(S_arr_X(0));
+ let s_arr1 = fn_s_S_arr_X(S_arr_X(1));
+ let s_arrI = fn_s_S_arr_X(S_arr_X(u32(I)));
+ let s_arr1_arr0 = fn_s_S_arr_arr_X_X(S_arr_arr_X_X(1, 0));
+ let s_arr2_arrI = fn_s_S_arr_arr_X_X(S_arr_arr_X_X(2, u32(I)));
+ let s_arrI_arr2 = fn_s_S_arr_arr_X_X(S_arr_arr_X_X(u32(I), 2));
+ let s_arrI_arrJ = fn_s_S_arr_arr_X_X(S_arr_arr_X_X(u32(I), u32(J)));
+ let w = fn_w_W();
+ let w_str = fn_w_W_str_i();
+ let w_arr0 = fn_w_W_arr_X(W_arr_X(0));
+ let w_arr1 = fn_w_W_arr_X(W_arr_X(1));
+ let w_arrI = fn_w_W_arr_X(W_arr_X(u32(I)));
+ let w_arr1_arr0 = fn_w_W_arr_arr_X_X(W_arr_arr_X_X(1, 0));
+ let w_arr2_arrI = fn_w_W_arr_arr_X_X(W_arr_arr_X_X(2, u32(I)));
+ let w_arrI_arr2 = fn_w_W_arr_arr_X_X(W_arr_arr_X_X(u32(I), 2));
+ let w_arrI_arrJ = fn_w_W_arr_arr_X_X(W_arr_arr_X_X(u32(I), u32(J)));
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessComplexTest, Indexing) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage> S : array<array<array<array<i32, 9>, 9>, 9>, 50>;
+
+fn a(i : i32) -> i32 { return i; }
+
+fn b(p : ptr<storage, array<array<array<i32, 9>, 9>, 9>>) -> i32 {
+ return (*p) [ a( (*p)[0][1][2] )]
+ [ a( (*p)[a(3)][4][5] )]
+ [ a( (*p)[6][a(7)][8] )];
+}
+
+fn c() {
+ let v = b(&S[42]);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage> S : array<array<array<array<i32, 9>, 9>, 9>, 50>;
+
+fn a(i : i32) -> i32 {
+ return i;
+}
+
+type S_X = array<u32, 1u>;
+
+fn b_S_X(p : S_X) -> i32 {
+ return S[p[0]][a(S[p[0]][0][1][2])][a(S[p[0]][a(3)][4][5])][a(S[p[0]][6][a(7)][8])];
+}
+
+fn c() {
+ let v = b_S_X(S_X(42));
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessComplexTest, IndexingInPtrCall) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage> S : array<array<array<array<i32, 9>, 9>, 9>, 50>;
+
+fn a(pre : i32, i : ptr<storage, i32>, post : i32) -> i32 {
+ return *i;
+}
+
+fn b(p : ptr<storage, array<array<array<i32, 9>, 9>, 9>>) -> i32 {
+ return a(10, &(*p)[ a( 20, &(*p)[0][1][2], 30 )]
+ [ a( 40, &(*p)[3][4][5], 50 )]
+ [ a( 60, &(*p)[6][7][8], 70 )], 80);
+}
+
+fn c() {
+ let v = b(&S[42]);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage> S : array<array<array<array<i32, 9>, 9>, 9>, 50>;
+
+type S_X_X_X_X = array<u32, 4u>;
+
+fn a_S_X_X_X_X(pre : i32, i : S_X_X_X_X, post : i32) -> i32 {
+ return S[i[0]][i[0]][i[1]][i[2]];
+}
+
+type S_X = array<u32, 1u>;
+
+fn b_S_X(p : S_X) -> i32 {
+ return a_S_X_X_X_X(10, S_X_X_X_X(p[0u], u32(a_S_X_X_X_X(20, S_X_X_X_X(p[0u], 0, 1, 2), 30)), u32(a_S_X_X_X_X(40, S_X_X_X_X(p[0u], 3, 4, 5), 50)), u32(a_S_X_X_X_X(60, S_X_X_X_X(p[0u], 6, 7, 8), 70))), 80);
+}
+
+fn c() {
+ let v = b_S_X(S_X(42));
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DirectVariableAccessComplexTest, IndexingDualPointers) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage> S : array<array<array<i32, 9>, 9>, 50>;
+@group(0) @binding(0) var<uniform> U : array<array<array<vec4<i32>, 9>, 9>, 50>;
+
+fn a(i : i32) -> i32 { return i; }
+
+fn b(s : ptr<storage, array<array<i32, 9>, 9>>,
+ u : ptr<uniform, array<array<vec4<i32>, 9>, 9>>) -> i32 {
+ return (*s) [ a( (*u)[0][1].x )]
+ [ a( (*u)[a(3)][4].y )];
+}
+
+fn c() {
+ let v = b(&S[42], &U[24]);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage> S : array<array<array<i32, 9>, 9>, 50>;
+
+@group(0) @binding(0) var<uniform> U : array<array<array<vec4<i32>, 9>, 9>, 50>;
+
+fn a(i : i32) -> i32 {
+ return i;
+}
+
+type S_X = array<u32, 1u>;
+
+type U_X = array<u32, 1u>;
+
+fn b_S_X_U_X(s : S_X, u : U_X) -> i32 {
+ return S[s[0]][a(U[u[0]][0][1].x)][a(U[u[0]][a(3)][4].y)];
+}
+
+fn c() {
+ let v = b_S_X_U_X(S_X(42), U_X(24));
+}
+)";
+
+ auto got = Run<DirectVariableAccess>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+} // namespace complex_tests
+
+} // namespace
+} // namespace tint::transform
diff --git a/src/tint/transform/unshadow.h b/src/tint/transform/unshadow.h
index 8ebf105..9030006 100644
--- a/src/tint/transform/unshadow.h
+++ b/src/tint/transform/unshadow.h
@@ -19,8 +19,7 @@
namespace tint::transform {
-/// Unshadow is a Transform that renames any variables that shadow another
-/// variable.
+/// Unshadow is a Transform that renames any variables that shadow another variable.
class Unshadow final : public Castable<Unshadow, Transform> {
public:
/// Constructor
diff --git a/src/tint/utils/block_allocator.h b/src/tint/utils/block_allocator.h
index 91a8a53..e75a0c6 100644
--- a/src/tint/utils/block_allocator.h
+++ b/src/tint/utils/block_allocator.h
@@ -39,6 +39,7 @@
static constexpr size_t kMax = 32;
std::array<T*, kMax> ptrs;
Pointers* next;
+ Pointers* prev;
};
/// Block is linked list of memory blocks.
@@ -55,7 +56,7 @@
class TView;
/// An iterator for the objects owned by the BlockAllocator.
- template <bool IS_CONST>
+ template <bool IS_CONST, bool FORWARD>
class TIterator {
using PointerTy = std::conditional_t<IS_CONST, const T*, T*>;
@@ -72,15 +73,24 @@
/// @returns true if this iterator is not equal to other
bool operator!=(const TIterator& other) const { return !(*this == other); }
- /// Advances the iterator
+ /// Progress the iterator forward one element
/// @returns this iterator
TIterator& operator++() {
- if (ptrs != nullptr) {
- ++idx;
- if (idx == Pointers::kMax) {
- idx = 0;
- ptrs = ptrs->next;
- }
+ if (FORWARD) {
+ ProgressForward();
+ } else {
+ ProgressBackwards();
+ }
+ return *this;
+ }
+
+ /// Progress the iterator backwards one element
+ /// @returns this iterator
+ TIterator& operator--() {
+ if (FORWARD) {
+ ProgressBackwards();
+ } else {
+ ProgressForward();
}
return *this;
}
@@ -92,6 +102,27 @@
friend TView<IS_CONST>; // Keep internal iterator impl private.
explicit TIterator(const Pointers* p, size_t i) : ptrs(p), idx(i) {}
+ /// Progresses the iterator forwards
+ void ProgressForward() {
+ if (ptrs != nullptr) {
+ ++idx;
+ if (idx == Pointers::kMax) {
+ idx = 0;
+ ptrs = ptrs->next;
+ }
+ }
+ }
+ /// Progresses the iterator backwards
+ void ProgressBackwards() {
+ if (ptrs != nullptr) {
+ if (idx == 0) {
+ idx = Pointers::kMax - 1;
+ ptrs = ptrs->prev;
+ }
+ --idx;
+ }
+ }
+
const Pointers* ptrs;
size_t idx;
};
@@ -102,16 +133,25 @@
class TView {
public:
/// @returns an iterator to the beginning of the view
- TIterator<IS_CONST> begin() const {
- return TIterator<IS_CONST>{allocator_->data.pointers.root, 0};
+ TIterator<IS_CONST, true> begin() const {
+ return TIterator<IS_CONST, true>{allocator_->data.pointers.root, 0};
}
/// @returns an iterator to the end of the view
- TIterator<IS_CONST> end() const {
+ TIterator<IS_CONST, true> end() const {
return allocator_->data.pointers.current_index >= Pointers::kMax
- ? TIterator<IS_CONST>(nullptr, 0)
- : TIterator<IS_CONST>(allocator_->data.pointers.current,
- allocator_->data.pointers.current_index);
+ ? TIterator<IS_CONST, true>{nullptr, 0}
+ : TIterator<IS_CONST, true>{allocator_->data.pointers.current,
+ allocator_->data.pointers.current_index};
+ }
+
+ /// @returns an iterator to the beginning of the view
+ TIterator<IS_CONST, false> rbegin() const { return TIterator<IS_CONST, false>{nullptr, 0}; }
+
+ /// @returns an iterator to the end of the view
+ TIterator<IS_CONST, false> rend() const {
+ return TIterator<IS_CONST, false>{allocator_->data.pointers.current,
+ allocator_->data.pointers.current_index};
}
private:
@@ -121,11 +161,17 @@
};
public:
- /// An iterator type over the objects of the BlockAllocator
- using Iterator = TIterator<false>;
+ /// A forward-iterator type over the objects of the BlockAllocator
+ using Iterator = TIterator</* const */ false, /* forward */ true>;
- /// An immutable iterator type over the objects of the BlockAllocator
- using ConstIterator = TIterator<true>;
+ /// An immutable forward-iterator type over the objects of the BlockAllocator
+ using ConstIterator = TIterator</* const */ true, /* forward */ true>;
+
+ /// A reverse-iterator type over the objects of the BlockAllocator
+ using ReverseIterator = TIterator</* const */ false, /* forward */ false>;
+
+ /// An immutable reverse-iterator type over the objects of the BlockAllocator
+ using ReverseConstIterator = TIterator</* const */ true, /* forward */ false>;
/// View provides begin() and end() methods for looping over the objects owned by the
/// BlockAllocator.
@@ -248,6 +294,7 @@
return; // out of memory
}
pointers.current->next = nullptr;
+ pointers.current->prev = prev_pointers;
pointers.current_index = 0;
if (prev_pointers) {
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index 86ba657..f304d82 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -54,6 +54,7 @@
#include "src/tint/transform/combine_samplers.h"
#include "src/tint/transform/decompose_memory_access.h"
#include "src/tint/transform/demote_to_helper.h"
+#include "src/tint/transform/direct_variable_access.h"
#include "src/tint/transform/disable_uniformity_analysis.h"
#include "src/tint/transform/expand_compound_assignment.h"
#include "src/tint/transform/manager.h"
@@ -209,7 +210,8 @@
manager.Add<transform::Renamer>();
data.Add<transform::Renamer::Config>(transform::Renamer::Target::kGlslKeywords,
/* preserve_unicode */ false);
- manager.Add<transform::Unshadow>();
+ manager.Add<transform::Unshadow>(); // Must come before DirectVariableAccess
+ manager.Add<transform::DirectVariableAccess>();
if (!options.disable_workgroup_init) {
// ZeroInitWorkgroupMemory must come before CanonicalizeEntryPointIO as
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index 1e786da..9d09795 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -54,6 +54,7 @@
#include "src/tint/transform/canonicalize_entry_point_io.h"
#include "src/tint/transform/decompose_memory_access.h"
#include "src/tint/transform/demote_to_helper.h"
+#include "src/tint/transform/direct_variable_access.h"
#include "src/tint/transform/disable_uniformity_analysis.h"
#include "src/tint/transform/expand_compound_assignment.h"
#include "src/tint/transform/localize_struct_array_assignment.h"
@@ -194,7 +195,9 @@
}
manager.Add<transform::MultiplanarExternalTexture>();
- manager.Add<transform::Unshadow>();
+ manager.Add<transform::Unshadow>(); // Must come before DirectVariableAccess
+
+ manager.Add<transform::DirectVariableAccess>();
// LocalizeStructArrayAssignment must come after:
// * SimplifyPointers, because it assumes assignment to arrays in structs are
@@ -291,6 +294,7 @@
utils::Vector{
ast::Extension::kChromiumDisableUniformityAnalysis,
ast::Extension::kChromiumExperimentalDp4A,
+ ast::Extension::kChromiumExperimentalFullPtrParameters,
ast::Extension::kChromiumExperimentalPushConstant,
ast::Extension::kF16,
})) {
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index 10efd59..9d06439 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -266,6 +266,7 @@
if (!CheckSupportedExtensions("MSL", program_->AST(), diagnostics_,
utils::Vector{
ast::Extension::kChromiumDisableUniformityAnalysis,
+ ast::Extension::kChromiumExperimentalFullPtrParameters,
ast::Extension::kChromiumExperimentalPushConstant,
ast::Extension::kF16,
})) {
diff --git a/src/tint/writer/spirv/builder.cc b/src/tint/writer/spirv/builder.cc
index c5e4a38..f2db430 100644
--- a/src/tint/writer/spirv/builder.cc
+++ b/src/tint/writer/spirv/builder.cc
@@ -260,6 +260,7 @@
utils::Vector{
ast::Extension::kChromiumDisableUniformityAnalysis,
ast::Extension::kChromiumExperimentalDp4A,
+ ast::Extension::kChromiumExperimentalFullPtrParameters,
ast::Extension::kChromiumExperimentalPushConstant,
ast::Extension::kF16,
})) {
diff --git a/src/tint/writer/spirv/generator_impl.cc b/src/tint/writer/spirv/generator_impl.cc
index 18c7511..b6bb0ff 100644
--- a/src/tint/writer/spirv/generator_impl.cc
+++ b/src/tint/writer/spirv/generator_impl.cc
@@ -22,6 +22,7 @@
#include "src/tint/transform/builtin_polyfill.h"
#include "src/tint/transform/canonicalize_entry_point_io.h"
#include "src/tint/transform/demote_to_helper.h"
+#include "src/tint/transform/direct_variable_access.h"
#include "src/tint/transform/disable_uniformity_analysis.h"
#include "src/tint/transform/expand_compound_assignment.h"
#include "src/tint/transform/for_loop_to_loop.h"
@@ -77,12 +78,21 @@
}
manager.Add<transform::MultiplanarExternalTexture>();
- manager.Add<transform::Unshadow>();
+ manager.Add<transform::Unshadow>(); // Must come before DirectVariableAccess
bool disable_workgroup_init_in_sanitizer =
options.disable_workgroup_init || options.use_zero_initialize_workgroup_memory_extension;
if (!disable_workgroup_init_in_sanitizer) {
manager.Add<transform::ZeroInitWorkgroupMemory>();
}
+
+ {
+ transform::DirectVariableAccess::Options opts;
+ opts.transform_private = true;
+ opts.transform_function = true;
+ data.Add<transform::DirectVariableAccess::Config>(opts);
+ manager.Add<transform::DirectVariableAccess>();
+ }
+
manager.Add<transform::RemoveUnreachableStatements>();
manager.Add<transform::PromoteSideEffectsToDecl>();
manager.Add<transform::SimplifyPointers>(); // Required for arrayLength()
diff --git a/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl b/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl
new file mode 100644
index 0000000..4053c2a
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl
@@ -0,0 +1,15 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+};
+
+fn func(pointer : ptr<function, array<i32, 4>>) -> array<i32, 4> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : str;
+ let r = func(&F.arr);
+}
diff --git a/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..f5feba0
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,15 @@
+struct str {
+ int arr[4];
+};
+
+typedef int func_ret[4];
+func_ret func(inout int pointer[4]) {
+ return pointer;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ str F = (str)0;
+ const int r[4] = func(F.arr);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..f5feba0
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,15 @@
+struct str {
+ int arr[4];
+};
+
+typedef int func_ret[4];
+func_ret func(inout int pointer[4]) {
+ return pointer;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ str F = (str)0;
+ const int r[4] = func(F.arr);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..63655fa
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+struct str {
+ int arr[4];
+};
+
+int[4] func(inout int pointer[4]) {
+ return pointer;
+}
+
+void tint_symbol() {
+ str F = str(int[4](0, 0, 0, 0));
+ int r[4] = func(F.arr);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..58faac8
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl.expected.msl
@@ -0,0 +1,30 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+struct str {
+ tint_array<int, 4> arr;
+};
+
+tint_array<int, 4> func(thread tint_array<int, 4>* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol() {
+ str F = {};
+ tint_array<int, 4> const r = func(&(F.arr));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..7ed320b
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,42 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 24
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %str "str"
+ OpMemberName %str 0 "arr"
+ OpName %func_F_arr "func_F_arr"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpName %F "F"
+ OpDecorate %_arr_int_uint_4 ArrayStride 4
+ OpMemberDecorate %str 0 Offset 0
+ %int = OpTypeInt 32 1
+ %uint = OpTypeInt 32 0
+ %uint_4 = OpConstant %uint 4
+%_arr_int_uint_4 = OpTypeArray %int %uint_4
+ %str = OpTypeStruct %_arr_int_uint_4
+%_ptr_Function_str = OpTypePointer Function %str
+ %1 = OpTypeFunction %_arr_int_uint_4 %_ptr_Function_str
+ %uint_0 = OpConstant %uint 0
+%_ptr_Function__arr_int_uint_4 = OpTypePointer Function %_arr_int_uint_4
+ %void = OpTypeVoid
+ %16 = OpTypeFunction %void
+ %21 = OpConstantNull %str
+ %func_F_arr = OpFunction %_arr_int_uint_4 None %1
+ %pointer = OpFunctionParameter %_ptr_Function_str
+ %10 = OpLabel
+ %14 = OpAccessChain %_ptr_Function__arr_int_uint_4 %pointer %uint_0
+ %15 = OpLoad %_arr_int_uint_4 %14
+ OpReturnValue %15
+ OpFunctionEnd
+ %main = OpFunction %void None %16
+ %19 = OpLabel
+ %F = OpVariable %_ptr_Function_str Function %21
+ %22 = OpFunctionCall %_arr_int_uint_4 %func_F_arr %F
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..8bd5276
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/array_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,15 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+}
+
+fn func(pointer : ptr<function, array<i32, 4>>) -> array<i32, 4> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : str;
+ let r = func(&(F.arr));
+}
diff --git a/test/tint/ptr_ref/load/param/function/i32.wgsl b/test/tint/ptr_ref/load/param/function/i32.wgsl
new file mode 100644
index 0000000..177b0ce
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/i32.wgsl
@@ -0,0 +1,9 @@
+fn func(pointer : ptr<function, i32>) -> i32 {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : i32;
+ let r = func(&F);
+}
diff --git a/test/tint/ptr_ref/load/param/function/i32.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/function/i32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..fa36f9e
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/i32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,10 @@
+int func(inout int pointer) {
+ return pointer;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ int F = 0;
+ const int r = func(F);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/i32.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/function/i32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..fa36f9e
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/i32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,10 @@
+int func(inout int pointer) {
+ return pointer;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ int F = 0;
+ const int r = func(F);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/i32.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/function/i32.wgsl.expected.glsl
new file mode 100644
index 0000000..c02a1da
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/i32.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+int func(inout int pointer) {
+ return pointer;
+}
+
+void tint_symbol() {
+ int F = 0;
+ int r = func(F);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/i32.wgsl.expected.msl b/test/tint/ptr_ref/load/param/function/i32.wgsl.expected.msl
new file mode 100644
index 0000000..672f345
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/i32.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int func(thread int* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol() {
+ int F = 0;
+ int const r = func(&(F));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/function/i32.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/function/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..d25f603
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/i32.wgsl.expected.spvasm
@@ -0,0 +1,31 @@
+; 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 %func "func"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpName %F "F"
+ %int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+ %1 = OpTypeFunction %int %_ptr_Function_int
+ %void = OpTypeVoid
+ %9 = OpTypeFunction %void
+ %14 = OpConstantNull %int
+ %func = OpFunction %int None %1
+ %pointer = OpFunctionParameter %_ptr_Function_int
+ %6 = OpLabel
+ %8 = OpLoad %int %pointer
+ OpReturnValue %8
+ OpFunctionEnd
+ %main = OpFunction %void None %9
+ %12 = OpLabel
+ %F = OpVariable %_ptr_Function_int Function %14
+ %15 = OpFunctionCall %int %func %F
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/function/i32.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/function/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..805ee79
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/i32.wgsl.expected.wgsl
@@ -0,0 +1,9 @@
+fn func(pointer : ptr<function, i32>) -> i32 {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : i32;
+ let r = func(&(F));
+}
diff --git a/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl b/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl
new file mode 100644
index 0000000..c3b7d55
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl
@@ -0,0 +1,15 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+fn func(pointer : ptr<function, i32>) -> i32 {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : str;
+ let r = func(&F.i);
+}
diff --git a/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..f726064
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,14 @@
+struct str {
+ int i;
+};
+
+int func(inout int pointer) {
+ return pointer;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ str F = (str)0;
+ const int r = func(F.i);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..f726064
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,14 @@
+struct str {
+ int i;
+};
+
+int func(inout int pointer) {
+ return pointer;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ str F = (str)0;
+ const int r = func(F.i);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..7a0bfb7
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+struct str {
+ int i;
+};
+
+int func(inout int pointer) {
+ return pointer;
+}
+
+void tint_symbol() {
+ str F = str(0);
+ int r = func(F.i);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..ccbfc42
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct str {
+ int i;
+};
+
+int func(thread int* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol() {
+ str F = {};
+ int const r = func(&(F.i));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..91e9a98
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl.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 %str "str"
+ OpMemberName %str 0 "i"
+ OpName %func_F_i "func_F_i"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpName %F "F"
+ OpMemberDecorate %str 0 Offset 0
+ %int = OpTypeInt 32 1
+ %str = OpTypeStruct %int
+%_ptr_Function_str = OpTypePointer Function %str
+ %1 = OpTypeFunction %int %_ptr_Function_str
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Function_int = OpTypePointer Function %int
+ %void = OpTypeVoid
+ %14 = OpTypeFunction %void
+ %19 = OpConstantNull %str
+ %func_F_i = OpFunction %int None %1
+ %pointer = OpFunctionParameter %_ptr_Function_str
+ %7 = OpLabel
+ %12 = OpAccessChain %_ptr_Function_int %pointer %uint_0
+ %13 = OpLoad %int %12
+ OpReturnValue %13
+ OpFunctionEnd
+ %main = OpFunction %void None %14
+ %17 = OpLabel
+ %F = OpVariable %_ptr_Function_str Function %19
+ %20 = OpFunctionCall %int %func_F_i %F
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..e5ecd70
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/i32_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,15 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+fn func(pointer : ptr<function, i32>) -> i32 {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : str;
+ let r = func(&(F.i));
+}
diff --git a/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl b/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl
new file mode 100644
index 0000000..103a3dd
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl
@@ -0,0 +1,15 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+fn func(pointer : ptr<function, str>) -> str {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : array<str, 4>;
+ let r = func(&F[2]);
+}
diff --git a/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c166cc2
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl.expected.dxc.hlsl
@@ -0,0 +1,14 @@
+struct str {
+ int i;
+};
+
+str func(inout str pointer) {
+ return pointer;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ str F[4] = (str[4])0;
+ const str r = func(F[2]);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c166cc2
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl.expected.fxc.hlsl
@@ -0,0 +1,14 @@
+struct str {
+ int i;
+};
+
+str func(inout str pointer) {
+ return pointer;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ str F[4] = (str[4])0;
+ const str r = func(F[2]);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl.expected.glsl
new file mode 100644
index 0000000..8fc6fcd
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+struct str {
+ int i;
+};
+
+str func(inout str pointer) {
+ return pointer;
+}
+
+void tint_symbol() {
+ str F[4] = str[4](str(0), str(0), str(0), str(0));
+ str r = func(F[2]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl.expected.msl b/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl.expected.msl
new file mode 100644
index 0000000..8205c73
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl.expected.msl
@@ -0,0 +1,30 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+struct str {
+ int i;
+};
+
+str func(thread str* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol() {
+ tint_array<str, 4> F = {};
+ str const r = func(&(F[2]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl.expected.spvasm
new file mode 100644
index 0000000..2d239bd
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl.expected.spvasm
@@ -0,0 +1,50 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 30
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %func_F_X "func_F_X"
+ OpName %pointer_base "pointer_base"
+ OpName %pointer_indices "pointer_indices"
+ OpName %main "main"
+ OpName %F "F"
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %_arr_str_uint_4 ArrayStride 4
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %int = OpTypeInt 32 1
+ %str = OpTypeStruct %int
+ %uint = OpTypeInt 32 0
+ %uint_4 = OpConstant %uint 4
+%_arr_str_uint_4 = OpTypeArray %str %uint_4
+%_ptr_Function__arr_str_uint_4 = OpTypePointer Function %_arr_str_uint_4
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %1 = OpTypeFunction %str %_ptr_Function__arr_str_uint_4 %_arr_uint_uint_1
+ %15 = OpConstantNull %int
+%_ptr_Function_str = OpTypePointer Function %str
+ %void = OpTypeVoid
+ %20 = OpTypeFunction %void
+ %25 = OpConstantNull %_arr_str_uint_4
+ %uint_2 = OpConstant %uint 2
+ %29 = OpConstantComposite %_arr_uint_uint_1 %uint_2
+ %func_F_X = OpFunction %str None %1
+%pointer_base = OpFunctionParameter %_ptr_Function__arr_str_uint_4
+%pointer_indices = OpFunctionParameter %_arr_uint_uint_1
+ %13 = OpLabel
+ %16 = OpCompositeExtract %uint %pointer_indices 0
+ %18 = OpAccessChain %_ptr_Function_str %pointer_base %16
+ %19 = OpLoad %str %18
+ OpReturnValue %19
+ OpFunctionEnd
+ %main = OpFunction %void None %20
+ %23 = OpLabel
+ %F = OpVariable %_ptr_Function__arr_str_uint_4 Function %25
+ %26 = OpFunctionCall %str %func_F_X %F %29
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl.expected.wgsl
new file mode 100644
index 0000000..2d4edb3
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/struct_in_array.wgsl.expected.wgsl
@@ -0,0 +1,15 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+fn func(pointer : ptr<function, str>) -> str {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : array<str, 4>;
+ let r = func(&(F[2]));
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl b/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl
new file mode 100644
index 0000000..afe82bc
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl
@@ -0,0 +1,11 @@
+enable chromium_experimental_full_ptr_parameters;
+
+fn func(pointer : ptr<function, vec2<f32>>) -> vec2<f32> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : mat2x2<f32>;
+ let r = func(&F[1]);
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8bc0349
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl
@@ -0,0 +1,10 @@
+float2 func(inout float2 pointer) {
+ return pointer;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ float2x2 F = float2x2(0.0f, 0.0f, 0.0f, 0.0f);
+ const float2 r = func(F[1]);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8bc0349
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl
@@ -0,0 +1,10 @@
+float2 func(inout float2 pointer) {
+ return pointer;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ float2x2 F = float2x2(0.0f, 0.0f, 0.0f, 0.0f);
+ const float2 r = func(F[1]);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl.expected.glsl
new file mode 100644
index 0000000..b50f64b
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+vec2 func(inout vec2 pointer) {
+ return pointer;
+}
+
+void tint_symbol() {
+ mat2 F = mat2(0.0f, 0.0f, 0.0f, 0.0f);
+ vec2 r = func(F[1]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl.expected.msl b/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl.expected.msl
new file mode 100644
index 0000000..e582ee2
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+float2 func(thread float2* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol() {
+ float2x2 F = float2x2(0.0f);
+ float2 const r = func(&(F[1]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl.expected.spvasm
new file mode 100644
index 0000000..f738c43
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl.expected.spvasm
@@ -0,0 +1,45 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 29
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %func_F_X "func_F_X"
+ OpName %pointer_base "pointer_base"
+ OpName %pointer_indices "pointer_indices"
+ OpName %main "main"
+ OpName %F "F"
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %float = OpTypeFloat 32
+ %v2float = OpTypeVector %float 2
+%mat2v2float = OpTypeMatrix %v2float 2
+%_ptr_Function_mat2v2float = OpTypePointer Function %mat2v2float
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %1 = OpTypeFunction %v2float %_ptr_Function_mat2v2float %_arr_uint_uint_1
+ %int = OpTypeInt 32 1
+ %15 = OpConstantNull %int
+%_ptr_Function_v2float = OpTypePointer Function %v2float
+ %void = OpTypeVoid
+ %20 = OpTypeFunction %void
+ %25 = OpConstantNull %mat2v2float
+ %28 = OpConstantComposite %_arr_uint_uint_1 %uint_1
+ %func_F_X = OpFunction %v2float None %1
+%pointer_base = OpFunctionParameter %_ptr_Function_mat2v2float
+%pointer_indices = OpFunctionParameter %_arr_uint_uint_1
+ %12 = OpLabel
+ %16 = OpCompositeExtract %uint %pointer_indices 0
+ %18 = OpAccessChain %_ptr_Function_v2float %pointer_base %16
+ %19 = OpLoad %v2float %18
+ OpReturnValue %19
+ OpFunctionEnd
+ %main = OpFunction %void None %20
+ %23 = OpLabel
+ %F = OpVariable %_ptr_Function_mat2v2float Function %25
+ %26 = OpFunctionCall %v2float %func_F_X %F %28
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl.expected.wgsl
new file mode 100644
index 0000000..2c61e24
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec2_f32_in_mat2x2.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+enable chromium_experimental_full_ptr_parameters;
+
+fn func(pointer : ptr<function, vec2<f32>>) -> vec2<f32> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : mat2x2<f32>;
+ let r = func(&(F[1]));
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl b/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl
new file mode 100644
index 0000000..01aa487
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl
@@ -0,0 +1,9 @@
+fn func(pointer : ptr<function, vec4<f32>>) -> vec4<f32> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : vec4<f32>;
+ let r = func(&F);
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..67932df
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,10 @@
+float4 func(inout float4 pointer) {
+ return pointer;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ float4 F = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ const float4 r = func(F);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..67932df
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,10 @@
+float4 func(inout float4 pointer) {
+ return pointer;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ float4 F = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ const float4 r = func(F);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..a3cff7b
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+vec4 func(inout vec4 pointer) {
+ return pointer;
+}
+
+void tint_symbol() {
+ vec4 F = vec4(0.0f, 0.0f, 0.0f, 0.0f);
+ vec4 r = func(F);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl.expected.msl b/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl.expected.msl
new file mode 100644
index 0000000..a5f8113
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+float4 func(thread float4* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol() {
+ float4 F = 0.0f;
+ float4 const r = func(&(F));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..51c798e
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl.expected.spvasm
@@ -0,0 +1,32 @@
+; 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 %pointer "pointer"
+ OpName %main "main"
+ OpName %F "F"
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+ %1 = OpTypeFunction %v4float %_ptr_Function_v4float
+ %void = OpTypeVoid
+ %10 = OpTypeFunction %void
+ %15 = OpConstantNull %v4float
+ %func = OpFunction %v4float None %1
+ %pointer = OpFunctionParameter %_ptr_Function_v4float
+ %7 = OpLabel
+ %9 = OpLoad %v4float %pointer
+ OpReturnValue %9
+ OpFunctionEnd
+ %main = OpFunction %void None %10
+ %13 = OpLabel
+ %F = OpVariable %_ptr_Function_v4float Function %15
+ %16 = OpFunctionCall %v4float %func %F
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..d7e7a55
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32.wgsl.expected.wgsl
@@ -0,0 +1,9 @@
+fn func(pointer : ptr<function, vec4<f32>>) -> vec4<f32> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : vec4<f32>;
+ let r = func(&(F));
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl b/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl
new file mode 100644
index 0000000..8b95569
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl
@@ -0,0 +1,11 @@
+enable chromium_experimental_full_ptr_parameters;
+
+fn func(pointer : ptr<function, vec4<f32>>) -> vec4<f32> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : mat2x4<f32>;
+ let r = func(&F[1]);
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..aec4b25
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl
@@ -0,0 +1,10 @@
+float4 func(inout float4 pointer) {
+ return pointer;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ float2x4 F = float2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+ const float4 r = func(F[1]);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..aec4b25
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl
@@ -0,0 +1,10 @@
+float4 func(inout float4 pointer) {
+ return pointer;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ float2x4 F = float2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+ const float4 r = func(F[1]);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl.expected.glsl
new file mode 100644
index 0000000..1819b4f
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+vec4 func(inout vec4 pointer) {
+ return pointer;
+}
+
+void tint_symbol() {
+ mat2x4 F = mat2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+ vec4 r = func(F[1]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl.expected.msl b/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl.expected.msl
new file mode 100644
index 0000000..284613c
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+float4 func(thread float4* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol() {
+ float2x4 F = float2x4(0.0f);
+ float4 const r = func(&(F[1]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl.expected.spvasm
new file mode 100644
index 0000000..e2b9a41
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl.expected.spvasm
@@ -0,0 +1,45 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 29
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %func_F_X "func_F_X"
+ OpName %pointer_base "pointer_base"
+ OpName %pointer_indices "pointer_indices"
+ OpName %main "main"
+ OpName %F "F"
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+%_ptr_Function_mat2v4float = OpTypePointer Function %mat2v4float
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %1 = OpTypeFunction %v4float %_ptr_Function_mat2v4float %_arr_uint_uint_1
+ %int = OpTypeInt 32 1
+ %15 = OpConstantNull %int
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+ %void = OpTypeVoid
+ %20 = OpTypeFunction %void
+ %25 = OpConstantNull %mat2v4float
+ %28 = OpConstantComposite %_arr_uint_uint_1 %uint_1
+ %func_F_X = OpFunction %v4float None %1
+%pointer_base = OpFunctionParameter %_ptr_Function_mat2v4float
+%pointer_indices = OpFunctionParameter %_arr_uint_uint_1
+ %12 = OpLabel
+ %16 = OpCompositeExtract %uint %pointer_indices 0
+ %18 = OpAccessChain %_ptr_Function_v4float %pointer_base %16
+ %19 = OpLoad %v4float %18
+ OpReturnValue %19
+ OpFunctionEnd
+ %main = OpFunction %void None %20
+ %23 = OpLabel
+ %F = OpVariable %_ptr_Function_mat2v4float Function %25
+ %26 = OpFunctionCall %v4float %func_F_X %F %28
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl.expected.wgsl
new file mode 100644
index 0000000..e5a91d7
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32_in_mat2x4.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+enable chromium_experimental_full_ptr_parameters;
+
+fn func(pointer : ptr<function, vec4<f32>>) -> vec4<f32> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : mat2x4<f32>;
+ let r = func(&(F[1]));
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl b/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl
new file mode 100644
index 0000000..f1167ac
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl
@@ -0,0 +1,15 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<f32>,
+};
+
+fn func(pointer : ptr<function, vec4<f32>>) -> vec4<f32> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : str;
+ let r = func(&F.i);
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8cbef3d
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,14 @@
+struct str {
+ float4 i;
+};
+
+float4 func(inout float4 pointer) {
+ return pointer;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ str F = (str)0;
+ const float4 r = func(F.i);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8cbef3d
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,14 @@
+struct str {
+ float4 i;
+};
+
+float4 func(inout float4 pointer) {
+ return pointer;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ str F = (str)0;
+ const float4 r = func(F.i);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..5848312
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+struct str {
+ vec4 i;
+};
+
+vec4 func(inout vec4 pointer) {
+ return pointer;
+}
+
+void tint_symbol() {
+ str F = str(vec4(0.0f, 0.0f, 0.0f, 0.0f));
+ vec4 r = func(F.i);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..738a398
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct str {
+ float4 i;
+};
+
+float4 func(thread float4* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol() {
+ str F = {};
+ float4 const r = func(&(F.i));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..840f20e
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,40 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 23
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %func_F_i "func_F_i"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpName %F "F"
+ OpMemberDecorate %str 0 Offset 0
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %str = OpTypeStruct %v4float
+%_ptr_Function_str = OpTypePointer Function %str
+ %1 = OpTypeFunction %v4float %_ptr_Function_str
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+ %void = OpTypeVoid
+ %15 = OpTypeFunction %void
+ %20 = OpConstantNull %str
+ %func_F_i = OpFunction %v4float None %1
+ %pointer = OpFunctionParameter %_ptr_Function_str
+ %8 = OpLabel
+ %13 = OpAccessChain %_ptr_Function_v4float %pointer %uint_0
+ %14 = OpLoad %v4float %13
+ OpReturnValue %14
+ OpFunctionEnd
+ %main = OpFunction %void None %15
+ %18 = OpLabel
+ %F = OpVariable %_ptr_Function_str Function %20
+ %21 = OpFunctionCall %v4float %func_F_i %F
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..f35fc26
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/function/vec4_f32_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,15 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<f32>,
+}
+
+fn func(pointer : ptr<function, vec4<f32>>) -> vec4<f32> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : str;
+ let r = func(&(F.i));
+}
diff --git a/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl b/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl
new file mode 100644
index 0000000..867e62b
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+};
+
+fn func(pointer : ptr<private, array<i32, 4>>) -> array<i32, 4> {
+ return *pointer;
+}
+
+var<private> P : str;
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&P.arr);
+}
diff --git a/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..6fc7d6c
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,16 @@
+struct str {
+ int arr[4];
+};
+
+typedef int func_ret[4];
+func_ret func(inout int pointer[4]) {
+ return pointer;
+}
+
+static str P = (str)0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int r[4] = func(P.arr);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..6fc7d6c
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,16 @@
+struct str {
+ int arr[4];
+};
+
+typedef int func_ret[4];
+func_ret func(inout int pointer[4]) {
+ return pointer;
+}
+
+static str P = (str)0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int r[4] = func(P.arr);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..b4dc836
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+struct str {
+ int arr[4];
+};
+
+int[4] func(inout int pointer[4]) {
+ return pointer;
+}
+
+str P = str(int[4](0, 0, 0, 0));
+void tint_symbol() {
+ int r[4] = func(P.arr);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..86e77bc
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl.expected.msl
@@ -0,0 +1,30 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+struct str {
+ tint_array<int, 4> arr;
+};
+
+tint_array<int, 4> func(thread tint_array<int, 4>* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol() {
+ thread str tint_symbol_1 = {};
+ tint_array<int, 4> const r = func(&(tint_symbol_1.arr));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..ac1c5af
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,42 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 24
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %str "str"
+ OpMemberName %str 0 "arr"
+ OpName %P "P"
+ OpName %func_F_arr "func_F_arr"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %_arr_int_uint_4 ArrayStride 4
+ %int = OpTypeInt 32 1
+ %uint = OpTypeInt 32 0
+ %uint_4 = OpConstant %uint 4
+%_arr_int_uint_4 = OpTypeArray %int %uint_4
+ %str = OpTypeStruct %_arr_int_uint_4
+%_ptr_Private_str = OpTypePointer Private %str
+ %8 = OpConstantNull %str
+ %P = OpVariable %_ptr_Private_str Private %8
+ %9 = OpTypeFunction %_arr_int_uint_4 %_ptr_Private_str
+ %uint_0 = OpConstant %uint 0
+%_ptr_Private__arr_int_uint_4 = OpTypePointer Private %_arr_int_uint_4
+ %void = OpTypeVoid
+ %18 = OpTypeFunction %void
+ %func_F_arr = OpFunction %_arr_int_uint_4 None %9
+ %pointer = OpFunctionParameter %_ptr_Private_str
+ %12 = OpLabel
+ %16 = OpAccessChain %_ptr_Private__arr_int_uint_4 %pointer %uint_0
+ %17 = OpLoad %_arr_int_uint_4 %16
+ OpReturnValue %17
+ OpFunctionEnd
+ %main = OpFunction %void None %18
+ %21 = OpLabel
+ %22 = OpFunctionCall %_arr_int_uint_4 %func_F_arr %P
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..1db57bb
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/array_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+}
+
+fn func(pointer : ptr<private, array<i32, 4>>) -> array<i32, 4> {
+ return *(pointer);
+}
+
+var<private> P : str;
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(P.arr));
+}
diff --git a/test/tint/ptr_ref/load/param/private/i32.wgsl b/test/tint/ptr_ref/load/param/private/i32.wgsl
new file mode 100644
index 0000000..ddbeb18
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/i32.wgsl
@@ -0,0 +1,10 @@
+fn func(pointer : ptr<private, i32>) -> i32 {
+ return *pointer;
+}
+
+var<private> P : i32;
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&P);
+}
diff --git a/test/tint/ptr_ref/load/param/private/i32.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/private/i32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..1813860
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/i32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,11 @@
+int func(inout int pointer) {
+ return pointer;
+}
+
+static int P = 0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int r = func(P);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/i32.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/private/i32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..1813860
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/i32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,11 @@
+int func(inout int pointer) {
+ return pointer;
+}
+
+static int P = 0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int r = func(P);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/i32.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/private/i32.wgsl.expected.glsl
new file mode 100644
index 0000000..5472203
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/i32.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+int func(inout int pointer) {
+ return pointer;
+}
+
+int P = 0;
+void tint_symbol() {
+ int r = func(P);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/i32.wgsl.expected.msl b/test/tint/ptr_ref/load/param/private/i32.wgsl.expected.msl
new file mode 100644
index 0000000..7fa4197
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/i32.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int func(thread int* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol() {
+ thread int tint_symbol_1 = 0;
+ int const r = func(&(tint_symbol_1));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/private/i32.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/private/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..66b4e2f
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/i32.wgsl.expected.spvasm
@@ -0,0 +1,31 @@
+; 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 %P "P"
+ OpName %func "func"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ %int = OpTypeInt 32 1
+%_ptr_Private_int = OpTypePointer Private %int
+ %4 = OpConstantNull %int
+ %P = OpVariable %_ptr_Private_int Private %4
+ %5 = OpTypeFunction %int %_ptr_Private_int
+ %void = OpTypeVoid
+ %11 = OpTypeFunction %void
+ %func = OpFunction %int None %5
+ %pointer = OpFunctionParameter %_ptr_Private_int
+ %8 = OpLabel
+ %10 = OpLoad %int %pointer
+ OpReturnValue %10
+ OpFunctionEnd
+ %main = OpFunction %void None %11
+ %14 = OpLabel
+ %15 = OpFunctionCall %int %func %P
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/private/i32.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/private/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..f049dce
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/i32.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+fn func(pointer : ptr<private, i32>) -> i32 {
+ return *(pointer);
+}
+
+var<private> P : i32;
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(P));
+}
diff --git a/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl b/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl
new file mode 100644
index 0000000..3db15dc
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+fn func(pointer : ptr<private, i32>) -> i32 {
+ return *pointer;
+}
+
+var<private> P : str;
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&P.i);
+}
diff --git a/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a2027f1
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,15 @@
+struct str {
+ int i;
+};
+
+int func(inout int pointer) {
+ return pointer;
+}
+
+static str P = (str)0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int r = func(P.i);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a2027f1
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,15 @@
+struct str {
+ int i;
+};
+
+int func(inout int pointer) {
+ return pointer;
+}
+
+static str P = (str)0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int r = func(P.i);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..6b9c34b
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+struct str {
+ int i;
+};
+
+int func(inout int pointer) {
+ return pointer;
+}
+
+str P = str(0);
+void tint_symbol() {
+ int r = func(P.i);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..8ab2385
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct str {
+ int i;
+};
+
+int func(thread int* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol() {
+ thread str tint_symbol_1 = {};
+ int const r = func(&(tint_symbol_1.i));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..1678d7e
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl.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 %str "str"
+ OpMemberName %str 0 "i"
+ OpName %P "P"
+ OpName %func_F_i "func_F_i"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpMemberDecorate %str 0 Offset 0
+ %int = OpTypeInt 32 1
+ %str = OpTypeStruct %int
+%_ptr_Private_str = OpTypePointer Private %str
+ %5 = OpConstantNull %str
+ %P = OpVariable %_ptr_Private_str Private %5
+ %6 = OpTypeFunction %int %_ptr_Private_str
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Private_int = OpTypePointer Private %int
+ %void = OpTypeVoid
+ %16 = OpTypeFunction %void
+ %func_F_i = OpFunction %int None %6
+ %pointer = OpFunctionParameter %_ptr_Private_str
+ %9 = OpLabel
+ %14 = OpAccessChain %_ptr_Private_int %pointer %uint_0
+ %15 = OpLoad %int %14
+ OpReturnValue %15
+ OpFunctionEnd
+ %main = OpFunction %void None %16
+ %19 = OpLabel
+ %20 = OpFunctionCall %int %func_F_i %P
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..bda048a
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/i32_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+fn func(pointer : ptr<private, i32>) -> i32 {
+ return *(pointer);
+}
+
+var<private> P : str;
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(P.i));
+}
diff --git a/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl b/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl
new file mode 100644
index 0000000..b7b8f90
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+fn func(pointer : ptr<private, str>) -> str {
+ return *pointer;
+}
+
+var<private> P : array<str, 4>;
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&P[2]);
+}
diff --git a/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..077d5c3
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl.expected.dxc.hlsl
@@ -0,0 +1,15 @@
+struct str {
+ int i;
+};
+
+str func(inout str pointer) {
+ return pointer;
+}
+
+static str P[4] = (str[4])0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ const str r = func(P[2]);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..077d5c3
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl.expected.fxc.hlsl
@@ -0,0 +1,15 @@
+struct str {
+ int i;
+};
+
+str func(inout str pointer) {
+ return pointer;
+}
+
+static str P[4] = (str[4])0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ const str r = func(P[2]);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl.expected.glsl
new file mode 100644
index 0000000..d7225dd
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+struct str {
+ int i;
+};
+
+str func(inout str pointer) {
+ return pointer;
+}
+
+str P[4] = str[4](str(0), str(0), str(0), str(0));
+void tint_symbol() {
+ str r = func(P[2]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl.expected.msl b/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl.expected.msl
new file mode 100644
index 0000000..e3794a9
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl.expected.msl
@@ -0,0 +1,30 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+struct str {
+ int i;
+};
+
+str func(thread str* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol() {
+ thread tint_array<str, 4> tint_symbol_1 = {};
+ str const r = func(&(tint_symbol_1[2]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl.expected.spvasm
new file mode 100644
index 0000000..e96ddde
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl.expected.spvasm
@@ -0,0 +1,50 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 30
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %P "P"
+ OpName %func_F_X "func_F_X"
+ OpName %pointer_base "pointer_base"
+ OpName %pointer_indices "pointer_indices"
+ OpName %main "main"
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %_arr_str_uint_4 ArrayStride 4
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %int = OpTypeInt 32 1
+ %str = OpTypeStruct %int
+ %uint = OpTypeInt 32 0
+ %uint_4 = OpConstant %uint 4
+%_arr_str_uint_4 = OpTypeArray %str %uint_4
+%_ptr_Private__arr_str_uint_4 = OpTypePointer Private %_arr_str_uint_4
+ %8 = OpConstantNull %_arr_str_uint_4
+ %P = OpVariable %_ptr_Private__arr_str_uint_4 Private %8
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %9 = OpTypeFunction %str %_ptr_Private__arr_str_uint_4 %_arr_uint_uint_1
+ %17 = OpConstantNull %int
+%_ptr_Private_str = OpTypePointer Private %str
+ %void = OpTypeVoid
+ %22 = OpTypeFunction %void
+ %uint_2 = OpConstant %uint 2
+ %29 = OpConstantComposite %_arr_uint_uint_1 %uint_2
+ %func_F_X = OpFunction %str None %9
+%pointer_base = OpFunctionParameter %_ptr_Private__arr_str_uint_4
+%pointer_indices = OpFunctionParameter %_arr_uint_uint_1
+ %15 = OpLabel
+ %18 = OpCompositeExtract %uint %pointer_indices 0
+ %20 = OpAccessChain %_ptr_Private_str %pointer_base %18
+ %21 = OpLoad %str %20
+ OpReturnValue %21
+ OpFunctionEnd
+ %main = OpFunction %void None %22
+ %25 = OpLabel
+ %26 = OpFunctionCall %str %func_F_X %P %29
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl.expected.wgsl
new file mode 100644
index 0000000..839270e
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/struct_in_array.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+fn func(pointer : ptr<private, str>) -> str {
+ return *(pointer);
+}
+
+var<private> P : array<str, 4>;
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(P[2]));
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl b/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl
new file mode 100644
index 0000000..7dc8a0b
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+fn func(pointer : ptr<private, vec2<f32>>) -> vec2<f32> {
+ return *pointer;
+}
+
+var<private> P : mat2x2<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&P[1]);
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..eb92433
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl
@@ -0,0 +1,11 @@
+float2 func(inout float2 pointer) {
+ return pointer;
+}
+
+static float2x2 P = float2x2(0.0f, 0.0f, 0.0f, 0.0f);
+
+[numthreads(1, 1, 1)]
+void main() {
+ const float2 r = func(P[1]);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..eb92433
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl
@@ -0,0 +1,11 @@
+float2 func(inout float2 pointer) {
+ return pointer;
+}
+
+static float2x2 P = float2x2(0.0f, 0.0f, 0.0f, 0.0f);
+
+[numthreads(1, 1, 1)]
+void main() {
+ const float2 r = func(P[1]);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl.expected.glsl
new file mode 100644
index 0000000..f1b7b79
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+vec2 func(inout vec2 pointer) {
+ return pointer;
+}
+
+mat2 P = mat2(0.0f, 0.0f, 0.0f, 0.0f);
+void tint_symbol() {
+ vec2 r = func(P[1]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl.expected.msl b/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl.expected.msl
new file mode 100644
index 0000000..27b7a26
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+float2 func(thread float2* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol() {
+ thread float2x2 tint_symbol_1 = float2x2(0.0f);
+ float2 const r = func(&(tint_symbol_1[1]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl.expected.spvasm
new file mode 100644
index 0000000..8908962
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl.expected.spvasm
@@ -0,0 +1,45 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 29
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %P "P"
+ OpName %func_F_X "func_F_X"
+ OpName %pointer_base "pointer_base"
+ OpName %pointer_indices "pointer_indices"
+ OpName %main "main"
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %float = OpTypeFloat 32
+ %v2float = OpTypeVector %float 2
+%mat2v2float = OpTypeMatrix %v2float 2
+%_ptr_Private_mat2v2float = OpTypePointer Private %mat2v2float
+ %6 = OpConstantNull %mat2v2float
+ %P = OpVariable %_ptr_Private_mat2v2float Private %6
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %7 = OpTypeFunction %v2float %_ptr_Private_mat2v2float %_arr_uint_uint_1
+ %int = OpTypeInt 32 1
+ %17 = OpConstantNull %int
+%_ptr_Private_v2float = OpTypePointer Private %v2float
+ %void = OpTypeVoid
+ %22 = OpTypeFunction %void
+ %28 = OpConstantComposite %_arr_uint_uint_1 %uint_1
+ %func_F_X = OpFunction %v2float None %7
+%pointer_base = OpFunctionParameter %_ptr_Private_mat2v2float
+%pointer_indices = OpFunctionParameter %_arr_uint_uint_1
+ %14 = OpLabel
+ %18 = OpCompositeExtract %uint %pointer_indices 0
+ %20 = OpAccessChain %_ptr_Private_v2float %pointer_base %18
+ %21 = OpLoad %v2float %20
+ OpReturnValue %21
+ OpFunctionEnd
+ %main = OpFunction %void None %22
+ %25 = OpLabel
+ %26 = OpFunctionCall %v2float %func_F_X %P %28
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl.expected.wgsl
new file mode 100644
index 0000000..dbc825a
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec2_f32_in_mat2x2.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+fn func(pointer : ptr<private, vec2<f32>>) -> vec2<f32> {
+ return *(pointer);
+}
+
+var<private> P : mat2x2<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(P[1]));
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl b/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl
new file mode 100644
index 0000000..2acc575
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl
@@ -0,0 +1,10 @@
+fn func(pointer : ptr<private, vec4<f32>>) -> vec4<f32> {
+ return *pointer;
+}
+
+var<private> P : vec4<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&P);
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e7456b1
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,11 @@
+float4 func(inout float4 pointer) {
+ return pointer;
+}
+
+static float4 P = float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+[numthreads(1, 1, 1)]
+void main() {
+ const float4 r = func(P);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e7456b1
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,11 @@
+float4 func(inout float4 pointer) {
+ return pointer;
+}
+
+static float4 P = float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+[numthreads(1, 1, 1)]
+void main() {
+ const float4 r = func(P);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..2ac5fd1
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+vec4 func(inout vec4 pointer) {
+ return pointer;
+}
+
+vec4 P = vec4(0.0f, 0.0f, 0.0f, 0.0f);
+void tint_symbol() {
+ vec4 r = func(P);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl.expected.msl b/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl.expected.msl
new file mode 100644
index 0000000..5b17645
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+float4 func(thread float4* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol() {
+ thread float4 tint_symbol_1 = 0.0f;
+ float4 const r = func(&(tint_symbol_1));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..dfe4930
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl.expected.spvasm
@@ -0,0 +1,32 @@
+; 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 %P "P"
+ OpName %func "func"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%_ptr_Private_v4float = OpTypePointer Private %v4float
+ %5 = OpConstantNull %v4float
+ %P = OpVariable %_ptr_Private_v4float Private %5
+ %6 = OpTypeFunction %v4float %_ptr_Private_v4float
+ %void = OpTypeVoid
+ %12 = OpTypeFunction %void
+ %func = OpFunction %v4float None %6
+ %pointer = OpFunctionParameter %_ptr_Private_v4float
+ %9 = OpLabel
+ %11 = OpLoad %v4float %pointer
+ OpReturnValue %11
+ OpFunctionEnd
+ %main = OpFunction %void None %12
+ %15 = OpLabel
+ %16 = OpFunctionCall %v4float %func %P
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..824d5fd
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+fn func(pointer : ptr<private, vec4<f32>>) -> vec4<f32> {
+ return *(pointer);
+}
+
+var<private> P : vec4<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(P));
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl b/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl
new file mode 100644
index 0000000..07dfea9
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+fn func(pointer : ptr<private, vec4<f32>>) -> vec4<f32> {
+ return *pointer;
+}
+
+var<private> P : mat2x4<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&P[1]);
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e0bb62e
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl
@@ -0,0 +1,11 @@
+float4 func(inout float4 pointer) {
+ return pointer;
+}
+
+static float2x4 P = float2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+
+[numthreads(1, 1, 1)]
+void main() {
+ const float4 r = func(P[1]);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e0bb62e
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl
@@ -0,0 +1,11 @@
+float4 func(inout float4 pointer) {
+ return pointer;
+}
+
+static float2x4 P = float2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+
+[numthreads(1, 1, 1)]
+void main() {
+ const float4 r = func(P[1]);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl.expected.glsl
new file mode 100644
index 0000000..ba1b4b9
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+vec4 func(inout vec4 pointer) {
+ return pointer;
+}
+
+mat2x4 P = mat2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+void tint_symbol() {
+ vec4 r = func(P[1]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl.expected.msl b/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl.expected.msl
new file mode 100644
index 0000000..f2112e8
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+float4 func(thread float4* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol() {
+ thread float2x4 tint_symbol_1 = float2x4(0.0f);
+ float4 const r = func(&(tint_symbol_1[1]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl.expected.spvasm
new file mode 100644
index 0000000..2694e57
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl.expected.spvasm
@@ -0,0 +1,45 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 29
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %P "P"
+ OpName %func_F_X "func_F_X"
+ OpName %pointer_base "pointer_base"
+ OpName %pointer_indices "pointer_indices"
+ OpName %main "main"
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+%_ptr_Private_mat2v4float = OpTypePointer Private %mat2v4float
+ %6 = OpConstantNull %mat2v4float
+ %P = OpVariable %_ptr_Private_mat2v4float Private %6
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %7 = OpTypeFunction %v4float %_ptr_Private_mat2v4float %_arr_uint_uint_1
+ %int = OpTypeInt 32 1
+ %17 = OpConstantNull %int
+%_ptr_Private_v4float = OpTypePointer Private %v4float
+ %void = OpTypeVoid
+ %22 = OpTypeFunction %void
+ %28 = OpConstantComposite %_arr_uint_uint_1 %uint_1
+ %func_F_X = OpFunction %v4float None %7
+%pointer_base = OpFunctionParameter %_ptr_Private_mat2v4float
+%pointer_indices = OpFunctionParameter %_arr_uint_uint_1
+ %14 = OpLabel
+ %18 = OpCompositeExtract %uint %pointer_indices 0
+ %20 = OpAccessChain %_ptr_Private_v4float %pointer_base %18
+ %21 = OpLoad %v4float %20
+ OpReturnValue %21
+ OpFunctionEnd
+ %main = OpFunction %void None %22
+ %25 = OpLabel
+ %26 = OpFunctionCall %v4float %func_F_X %P %28
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl.expected.wgsl
new file mode 100644
index 0000000..c0cf801
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32_in_mat2x4.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+fn func(pointer : ptr<private, vec4<f32>>) -> vec4<f32> {
+ return *(pointer);
+}
+
+var<private> P : mat2x4<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(P[1]));
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl b/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl
new file mode 100644
index 0000000..90f325e
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<f32>,
+};
+
+fn func(pointer : ptr<private, vec4<f32>>) -> vec4<f32> {
+ return *pointer;
+}
+
+var<private> P : str;
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&P.i);
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..d489348
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,15 @@
+struct str {
+ float4 i;
+};
+
+float4 func(inout float4 pointer) {
+ return pointer;
+}
+
+static str P = (str)0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ const float4 r = func(P.i);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..d489348
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,15 @@
+struct str {
+ float4 i;
+};
+
+float4 func(inout float4 pointer) {
+ return pointer;
+}
+
+static str P = (str)0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ const float4 r = func(P.i);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..58fdade
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+struct str {
+ vec4 i;
+};
+
+vec4 func(inout vec4 pointer) {
+ return pointer;
+}
+
+str P = str(vec4(0.0f, 0.0f, 0.0f, 0.0f));
+void tint_symbol() {
+ vec4 r = func(P.i);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..256f2a4
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct str {
+ float4 i;
+};
+
+float4 func(thread float4* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol() {
+ thread str tint_symbol_1 = {};
+ float4 const r = func(&(tint_symbol_1.i));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..ff7b019
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,40 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 23
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %P "P"
+ OpName %func_F_i "func_F_i"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpMemberDecorate %str 0 Offset 0
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %str = OpTypeStruct %v4float
+%_ptr_Private_str = OpTypePointer Private %str
+ %6 = OpConstantNull %str
+ %P = OpVariable %_ptr_Private_str Private %6
+ %7 = OpTypeFunction %v4float %_ptr_Private_str
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Private_v4float = OpTypePointer Private %v4float
+ %void = OpTypeVoid
+ %17 = OpTypeFunction %void
+ %func_F_i = OpFunction %v4float None %7
+ %pointer = OpFunctionParameter %_ptr_Private_str
+ %10 = OpLabel
+ %15 = OpAccessChain %_ptr_Private_v4float %pointer %uint_0
+ %16 = OpLoad %v4float %15
+ OpReturnValue %16
+ OpFunctionEnd
+ %main = OpFunction %void None %17
+ %20 = OpLabel
+ %21 = OpFunctionCall %v4float %func_F_i %P
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..2c488a9
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/private/vec4_f32_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<f32>,
+}
+
+fn func(pointer : ptr<private, vec4<f32>>) -> vec4<f32> {
+ return *(pointer);
+}
+
+var<private> P : str;
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(P.i));
+}
diff --git a/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl b/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl
new file mode 100644
index 0000000..eed9668
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+};
+
+@group(0) @binding(0) var<storage> S : str;
+
+fn func(pointer : ptr<storage, array<i32, 4>>) -> array<i32, 4> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S.arr);
+}
diff --git a/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a3f14af
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,23 @@
+ByteAddressBuffer S : register(t0, space0);
+
+typedef int tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(ByteAddressBuffer buffer, uint offset) {
+ int arr_1[4] = (int[4])0;
+ {
+ for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+ arr_1[i] = asint(buffer.Load((offset + (i * 4u))));
+ }
+ }
+ return arr_1;
+}
+
+typedef int func_S_arr_ret[4];
+func_S_arr_ret func_S_arr() {
+ return tint_symbol(S, 0u);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int r[4] = func_S_arr();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a3f14af
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,23 @@
+ByteAddressBuffer S : register(t0, space0);
+
+typedef int tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(ByteAddressBuffer buffer, uint offset) {
+ int arr_1[4] = (int[4])0;
+ {
+ for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+ arr_1[i] = asint(buffer.Load((offset + (i * 4u))));
+ }
+ }
+ return arr_1;
+}
+
+typedef int func_S_arr_ret[4];
+func_S_arr_ret func_S_arr() {
+ return tint_symbol(S, 0u);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int r[4] = func_S_arr();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..478f625
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+
+struct str {
+ int arr[4];
+};
+
+layout(binding = 0, std430) buffer S_block_ssbo {
+ str inner;
+} S;
+
+int[4] func_S_arr() {
+ return S.inner.arr;
+}
+
+void tint_symbol() {
+ int r[4] = func_S_arr();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..7f08b7b
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl.expected.msl
@@ -0,0 +1,29 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+struct str {
+ /* 0x0000 */ tint_array<int, 4> arr;
+};
+
+tint_array<int, 4> func(const device tint_array<int, 4>* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol(const device str* tint_symbol_1 [[buffer(0)]]) {
+ tint_array<int, 4> const r = func(&((*(tint_symbol_1)).arr));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..ca7d725
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,47 @@
+; 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 %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %str "str"
+ OpMemberName %str 0 "arr"
+ OpName %S "S"
+ OpName %func_S_arr "func_S_arr"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %_arr_int_uint_4 ArrayStride 4
+ OpDecorate %S NonWritable
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ %int = OpTypeInt 32 1
+ %uint = OpTypeInt 32 0
+ %uint_4 = OpConstant %uint 4
+%_arr_int_uint_4 = OpTypeArray %int %uint_4
+ %str = OpTypeStruct %_arr_int_uint_4
+ %S_block = OpTypeStruct %str
+%_ptr_StorageBuffer_S_block = OpTypePointer StorageBuffer %S_block
+ %S = OpVariable %_ptr_StorageBuffer_S_block StorageBuffer
+ %9 = OpTypeFunction %_arr_int_uint_4
+ %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_int_uint_4 = OpTypePointer StorageBuffer %_arr_int_uint_4
+ %void = OpTypeVoid
+ %16 = OpTypeFunction %void
+ %func_S_arr = OpFunction %_arr_int_uint_4 None %9
+ %11 = OpLabel
+ %14 = OpAccessChain %_ptr_StorageBuffer__arr_int_uint_4 %S %uint_0 %uint_0
+ %15 = OpLoad %_arr_int_uint_4 %14
+ OpReturnValue %15
+ OpFunctionEnd
+ %main = OpFunction %void None %16
+ %19 = OpLabel
+ %20 = OpFunctionCall %_arr_int_uint_4 %func_S_arr
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..033d9b1
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/array_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+}
+
+@group(0) @binding(0) var<storage> S : str;
+
+fn func(pointer : ptr<storage, array<i32, 4>>) -> array<i32, 4> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S.arr));
+}
diff --git a/test/tint/ptr_ref/load/param/storage/i32.wgsl b/test/tint/ptr_ref/load/param/storage/i32.wgsl
new file mode 100644
index 0000000..ac2a585
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/i32.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage> S : i32;
+
+fn func(pointer : ptr<storage, i32>) -> i32 {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S);
+}
diff --git a/test/tint/ptr_ref/load/param/storage/i32.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/storage/i32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8322bbc
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/i32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,11 @@
+ByteAddressBuffer S : register(t0, space0);
+
+int func_S() {
+ return asint(S.Load(0u));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int r = func_S();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/i32.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/storage/i32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8322bbc
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/i32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,11 @@
+ByteAddressBuffer S : register(t0, space0);
+
+int func_S() {
+ return asint(S.Load(0u));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int r = func_S();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/i32.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/storage/i32.wgsl.expected.glsl
new file mode 100644
index 0000000..a9a51fc
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/i32.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer S_block_ssbo {
+ int inner;
+} S;
+
+int func_S() {
+ return S.inner;
+}
+
+void tint_symbol() {
+ int r = func_S();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/i32.wgsl.expected.msl b/test/tint/ptr_ref/load/param/storage/i32.wgsl.expected.msl
new file mode 100644
index 0000000..c0bac8c
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/i32.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int func(const device int* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol(const device int* tint_symbol_1 [[buffer(0)]]) {
+ int const r = func(tint_symbol_1);
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/storage/i32.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/storage/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..571ba3e
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/i32.wgsl.expected.spvasm
@@ -0,0 +1,40 @@
+; 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_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %S "S"
+ OpName %func_S "func_S"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpDecorate %S NonWritable
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ %int = OpTypeInt 32 1
+ %S_block = OpTypeStruct %int
+%_ptr_StorageBuffer_S_block = OpTypePointer StorageBuffer %S_block
+ %S = OpVariable %_ptr_StorageBuffer_S_block StorageBuffer
+ %5 = OpTypeFunction %int
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
+ %void = OpTypeVoid
+ %13 = OpTypeFunction %void
+ %func_S = OpFunction %int None %5
+ %7 = OpLabel
+ %11 = OpAccessChain %_ptr_StorageBuffer_int %S %uint_0
+ %12 = OpLoad %int %11
+ OpReturnValue %12
+ OpFunctionEnd
+ %main = OpFunction %void None %13
+ %16 = OpLabel
+ %17 = OpFunctionCall %int %func_S
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/storage/i32.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/storage/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..b9a422c
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/i32.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage> S : i32;
+
+fn func(pointer : ptr<storage, i32>) -> i32 {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S));
+}
diff --git a/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl b/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl
new file mode 100644
index 0000000..05631d2
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+@group(0) @binding(0) var<storage> S : str;
+
+fn func(pointer : ptr<storage, i32>) -> i32 {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S.i);
+}
diff --git a/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c314820
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,11 @@
+ByteAddressBuffer S : register(t0, space0);
+
+int func_S_i() {
+ return asint(S.Load(0u));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int r = func_S_i();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c314820
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,11 @@
+ByteAddressBuffer S : register(t0, space0);
+
+int func_S_i() {
+ return asint(S.Load(0u));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int r = func_S_i();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..5cfc748
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+
+struct str {
+ int i;
+};
+
+layout(binding = 0, std430) buffer S_block_ssbo {
+ str inner;
+} S;
+
+int func_S_i() {
+ return S.inner.i;
+}
+
+void tint_symbol() {
+ int r = func_S_i();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..e26f656
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl.expected.msl
@@ -0,0 +1,16 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct str {
+ /* 0x0000 */ int i;
+};
+
+int func(const device int* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol(const device str* tint_symbol_1 [[buffer(0)]]) {
+ int const r = func(&((*(tint_symbol_1)).i));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..5feaca5
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,44 @@
+; 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 %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %S "S"
+ OpName %func_S_i "func_S_i"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %S NonWritable
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ %int = OpTypeInt 32 1
+ %str = OpTypeStruct %int
+ %S_block = OpTypeStruct %str
+%_ptr_StorageBuffer_S_block = OpTypePointer StorageBuffer %S_block
+ %S = OpVariable %_ptr_StorageBuffer_S_block StorageBuffer
+ %6 = OpTypeFunction %int
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
+ %void = OpTypeVoid
+ %14 = OpTypeFunction %void
+ %func_S_i = OpFunction %int None %6
+ %8 = OpLabel
+ %12 = OpAccessChain %_ptr_StorageBuffer_int %S %uint_0 %uint_0
+ %13 = OpLoad %int %12
+ OpReturnValue %13
+ OpFunctionEnd
+ %main = OpFunction %void None %14
+ %17 = OpLabel
+ %18 = OpFunctionCall %int %func_S_i
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..21763e0
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/i32_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+@group(0) @binding(0) var<storage> S : str;
+
+fn func(pointer : ptr<storage, i32>) -> i32 {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S.i));
+}
diff --git a/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl b/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl
new file mode 100644
index 0000000..5616c9a
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+@group(0) @binding(0) var<storage> S : array<str, 4>;
+
+fn func(pointer : ptr<storage, str>) -> str {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S[2]);
+}
diff --git a/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..05f09cb
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl.expected.dxc.hlsl
@@ -0,0 +1,21 @@
+struct str {
+ int i;
+};
+
+ByteAddressBuffer S : register(t0, space0);
+
+str tint_symbol(ByteAddressBuffer buffer, uint offset) {
+ const str tint_symbol_2 = {asint(buffer.Load((offset + 0u)))};
+ return tint_symbol_2;
+}
+
+str func_S_X(uint pointer[1]) {
+ return tint_symbol(S, (4u * pointer[0]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const uint tint_symbol_3[1] = {2u};
+ const str r = func_S_X(tint_symbol_3);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..05f09cb
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl.expected.fxc.hlsl
@@ -0,0 +1,21 @@
+struct str {
+ int i;
+};
+
+ByteAddressBuffer S : register(t0, space0);
+
+str tint_symbol(ByteAddressBuffer buffer, uint offset) {
+ const str tint_symbol_2 = {asint(buffer.Load((offset + 0u)))};
+ return tint_symbol_2;
+}
+
+str func_S_X(uint pointer[1]) {
+ return tint_symbol(S, (4u * pointer[0]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const uint tint_symbol_3[1] = {2u};
+ const str r = func_S_X(tint_symbol_3);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl.expected.glsl
new file mode 100644
index 0000000..911d7c4
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl.expected.glsl
@@ -0,0 +1,24 @@
+#version 310 es
+
+struct str {
+ int i;
+};
+
+layout(binding = 0, std430) buffer S_block_ssbo {
+ str inner[4];
+} S;
+
+str func_S_X(uint pointer[1]) {
+ return S.inner[pointer[0]];
+}
+
+void tint_symbol() {
+ uint tint_symbol_1[1] = uint[1](2u);
+ str r = func_S_X(tint_symbol_1);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl.expected.msl b/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl.expected.msl
new file mode 100644
index 0000000..437bc2a
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl.expected.msl
@@ -0,0 +1,29 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+struct str {
+ /* 0x0000 */ int i;
+};
+
+str func(const device str* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol(const device tint_array<str, 4>* tint_symbol_1 [[buffer(0)]]) {
+ str const r = func(&((*(tint_symbol_1))[2]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl.expected.spvasm
new file mode 100644
index 0000000..6472fd8
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl.expected.spvasm
@@ -0,0 +1,56 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 28
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %S "S"
+ OpName %func_S_X "func_S_X"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %_arr_str_uint_4 ArrayStride 4
+ OpDecorate %S NonWritable
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %int = OpTypeInt 32 1
+ %str = OpTypeStruct %int
+ %uint = OpTypeInt 32 0
+ %uint_4 = OpConstant %uint 4
+%_arr_str_uint_4 = OpTypeArray %str %uint_4
+ %S_block = OpTypeStruct %_arr_str_uint_4
+%_ptr_StorageBuffer_S_block = OpTypePointer StorageBuffer %S_block
+ %S = OpVariable %_ptr_StorageBuffer_S_block StorageBuffer
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %9 = OpTypeFunction %str %_arr_uint_uint_1
+ %uint_0 = OpConstant %uint 0
+ %16 = OpConstantNull %int
+%_ptr_StorageBuffer_str = OpTypePointer StorageBuffer %str
+ %void = OpTypeVoid
+ %21 = OpTypeFunction %void
+ %uint_2 = OpConstant %uint 2
+ %27 = OpConstantComposite %_arr_uint_uint_1 %uint_2
+ %func_S_X = OpFunction %str None %9
+ %pointer = OpFunctionParameter %_arr_uint_uint_1
+ %14 = OpLabel
+ %17 = OpCompositeExtract %uint %pointer 0
+ %19 = OpAccessChain %_ptr_StorageBuffer_str %S %uint_0 %17
+ %20 = OpLoad %str %19
+ OpReturnValue %20
+ OpFunctionEnd
+ %main = OpFunction %void None %21
+ %24 = OpLabel
+ %25 = OpFunctionCall %str %func_S_X %27
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl.expected.wgsl
new file mode 100644
index 0000000..e16f195
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/struct_in_array.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+@group(0) @binding(0) var<storage> S : array<str, 4>;
+
+fn func(pointer : ptr<storage, str>) -> str {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S[2]));
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl b/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl
new file mode 100644
index 0000000..180f5ce
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage> S : mat2x2<f32>;
+
+fn func(pointer : ptr<storage, vec2<f32>>) -> vec2<f32> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S[1]);
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..809f70e
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl
@@ -0,0 +1,12 @@
+ByteAddressBuffer S : register(t0, space0);
+
+float2 func_S_X(uint pointer[1]) {
+ return asfloat(S.Load2((8u * pointer[0])));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const uint tint_symbol_1[1] = {1u};
+ const float2 r = func_S_X(tint_symbol_1);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..809f70e
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl
@@ -0,0 +1,12 @@
+ByteAddressBuffer S : register(t0, space0);
+
+float2 func_S_X(uint pointer[1]) {
+ return asfloat(S.Load2((8u * pointer[0])));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const uint tint_symbol_1[1] = {1u};
+ const float2 r = func_S_X(tint_symbol_1);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl.expected.glsl
new file mode 100644
index 0000000..35baf18
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer S_block_ssbo {
+ mat2 inner;
+} S;
+
+vec2 func_S_X(uint pointer[1]) {
+ return S.inner[pointer[0]];
+}
+
+void tint_symbol() {
+ uint tint_symbol_1[1] = uint[1](1u);
+ vec2 r = func_S_X(tint_symbol_1);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl.expected.msl b/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl.expected.msl
new file mode 100644
index 0000000..5155ddd
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+float2 func(const device float2* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol(const device float2x2* tint_symbol_1 [[buffer(0)]]) {
+ float2 const r = func(&((*(tint_symbol_1))[1]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl.expected.spvasm
new file mode 100644
index 0000000..82bc42c
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl.expected.spvasm
@@ -0,0 +1,53 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 27
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %S "S"
+ OpName %func_S_X "func_S_X"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpMemberDecorate %S_block 0 ColMajor
+ OpMemberDecorate %S_block 0 MatrixStride 8
+ OpDecorate %S NonWritable
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %float = OpTypeFloat 32
+ %v2float = OpTypeVector %float 2
+%mat2v2float = OpTypeMatrix %v2float 2
+ %S_block = OpTypeStruct %mat2v2float
+%_ptr_StorageBuffer_S_block = OpTypePointer StorageBuffer %S_block
+ %S = OpVariable %_ptr_StorageBuffer_S_block StorageBuffer
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %7 = OpTypeFunction %v2float %_arr_uint_uint_1
+ %uint_0 = OpConstant %uint 0
+ %int = OpTypeInt 32 1
+ %16 = OpConstantNull %int
+%_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
+ %void = OpTypeVoid
+ %21 = OpTypeFunction %void
+ %26 = OpConstantComposite %_arr_uint_uint_1 %uint_1
+ %func_S_X = OpFunction %v2float None %7
+ %pointer = OpFunctionParameter %_arr_uint_uint_1
+ %13 = OpLabel
+ %17 = OpCompositeExtract %uint %pointer 0
+ %19 = OpAccessChain %_ptr_StorageBuffer_v2float %S %uint_0 %17
+ %20 = OpLoad %v2float %19
+ OpReturnValue %20
+ OpFunctionEnd
+ %main = OpFunction %void None %21
+ %24 = OpLabel
+ %25 = OpFunctionCall %v2float %func_S_X %26
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl.expected.wgsl
new file mode 100644
index 0000000..889c31b
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec2_f32_in_mat2x2.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage> S : mat2x2<f32>;
+
+fn func(pointer : ptr<storage, vec2<f32>>) -> vec2<f32> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S[1]));
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl b/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl
new file mode 100644
index 0000000..2a08b41
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage> S : vec4<f32>;
+
+fn func(pointer : ptr<storage, vec4<f32>>) -> vec4<f32> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S);
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..eca7796
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,11 @@
+ByteAddressBuffer S : register(t0, space0);
+
+float4 func_S() {
+ return asfloat(S.Load4(0u));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const float4 r = func_S();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..eca7796
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,11 @@
+ByteAddressBuffer S : register(t0, space0);
+
+float4 func_S() {
+ return asfloat(S.Load4(0u));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const float4 r = func_S();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..9db47b7
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer S_block_ssbo {
+ vec4 inner;
+} S;
+
+vec4 func_S() {
+ return S.inner;
+}
+
+void tint_symbol() {
+ vec4 r = func_S();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl.expected.msl b/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl.expected.msl
new file mode 100644
index 0000000..5ae6156
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+float4 func(const device float4* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol(const device float4* tint_symbol_1 [[buffer(0)]]) {
+ float4 const r = func(tint_symbol_1);
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..1a72aae
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl.expected.spvasm
@@ -0,0 +1,41 @@
+; 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 %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %S "S"
+ OpName %func_S "func_S"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpDecorate %S NonWritable
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %S_block = OpTypeStruct %v4float
+%_ptr_StorageBuffer_S_block = OpTypePointer StorageBuffer %S_block
+ %S = OpVariable %_ptr_StorageBuffer_S_block StorageBuffer
+ %6 = OpTypeFunction %v4float
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+ %void = OpTypeVoid
+ %14 = OpTypeFunction %void
+ %func_S = OpFunction %v4float None %6
+ %8 = OpLabel
+ %12 = OpAccessChain %_ptr_StorageBuffer_v4float %S %uint_0
+ %13 = OpLoad %v4float %12
+ OpReturnValue %13
+ OpFunctionEnd
+ %main = OpFunction %void None %14
+ %17 = OpLabel
+ %18 = OpFunctionCall %v4float %func_S
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..a1bcaca
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage> S : vec4<f32>;
+
+fn func(pointer : ptr<storage, vec4<f32>>) -> vec4<f32> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S));
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl
new file mode 100644
index 0000000..35ef536
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage> S : mat2x4<f32>;
+
+fn func(pointer : ptr<storage, vec4<f32>>) -> vec4<f32> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S[1]);
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..10793c7
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl
@@ -0,0 +1,12 @@
+ByteAddressBuffer S : register(t0, space0);
+
+float4 func_S_X(uint pointer[1]) {
+ return asfloat(S.Load4((16u * pointer[0])));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const uint tint_symbol_1[1] = {1u};
+ const float4 r = func_S_X(tint_symbol_1);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..10793c7
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl
@@ -0,0 +1,12 @@
+ByteAddressBuffer S : register(t0, space0);
+
+float4 func_S_X(uint pointer[1]) {
+ return asfloat(S.Load4((16u * pointer[0])));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const uint tint_symbol_1[1] = {1u};
+ const float4 r = func_S_X(tint_symbol_1);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl.expected.glsl
new file mode 100644
index 0000000..7e4c0b6
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer S_block_ssbo {
+ mat2x4 inner;
+} S;
+
+vec4 func_S_X(uint pointer[1]) {
+ return S.inner[pointer[0]];
+}
+
+void tint_symbol() {
+ uint tint_symbol_1[1] = uint[1](1u);
+ vec4 r = func_S_X(tint_symbol_1);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl.expected.msl b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl.expected.msl
new file mode 100644
index 0000000..1948f6e
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+float4 func(const device float4* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol(const device float2x4* tint_symbol_1 [[buffer(0)]]) {
+ float4 const r = func(&((*(tint_symbol_1))[1]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl.expected.spvasm
new file mode 100644
index 0000000..8d13b84
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl.expected.spvasm
@@ -0,0 +1,53 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 27
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %S "S"
+ OpName %func_S_X "func_S_X"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpMemberDecorate %S_block 0 ColMajor
+ OpMemberDecorate %S_block 0 MatrixStride 16
+ OpDecorate %S NonWritable
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+ %S_block = OpTypeStruct %mat2v4float
+%_ptr_StorageBuffer_S_block = OpTypePointer StorageBuffer %S_block
+ %S = OpVariable %_ptr_StorageBuffer_S_block StorageBuffer
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %7 = OpTypeFunction %v4float %_arr_uint_uint_1
+ %uint_0 = OpConstant %uint 0
+ %int = OpTypeInt 32 1
+ %16 = OpConstantNull %int
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+ %void = OpTypeVoid
+ %21 = OpTypeFunction %void
+ %26 = OpConstantComposite %_arr_uint_uint_1 %uint_1
+ %func_S_X = OpFunction %v4float None %7
+ %pointer = OpFunctionParameter %_arr_uint_uint_1
+ %13 = OpLabel
+ %17 = OpCompositeExtract %uint %pointer 0
+ %19 = OpAccessChain %_ptr_StorageBuffer_v4float %S %uint_0 %17
+ %20 = OpLoad %v4float %19
+ OpReturnValue %20
+ OpFunctionEnd
+ %main = OpFunction %void None %21
+ %24 = OpLabel
+ %25 = OpFunctionCall %v4float %func_S_X %26
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl.expected.wgsl
new file mode 100644
index 0000000..a11814a
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_mat2x4.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage> S : mat2x4<f32>;
+
+fn func(pointer : ptr<storage, vec4<f32>>) -> vec4<f32> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S[1]));
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl
new file mode 100644
index 0000000..5fe26b3
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<f32>,
+};
+
+@group(0) @binding(0) var<storage> S : str;
+
+fn func(pointer : ptr<storage, vec4<f32>>) -> vec4<f32> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S.i);
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..1fd53b9
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,11 @@
+ByteAddressBuffer S : register(t0, space0);
+
+float4 func_S_i() {
+ return asfloat(S.Load4(0u));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const float4 r = func_S_i();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..1fd53b9
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,11 @@
+ByteAddressBuffer S : register(t0, space0);
+
+float4 func_S_i() {
+ return asfloat(S.Load4(0u));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const float4 r = func_S_i();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..d98d91d
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+
+struct str {
+ vec4 i;
+};
+
+layout(binding = 0, std430) buffer S_block_ssbo {
+ str inner;
+} S;
+
+vec4 func_S_i() {
+ return S.inner.i;
+}
+
+void tint_symbol() {
+ vec4 r = func_S_i();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..1a2a590
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl.expected.msl
@@ -0,0 +1,16 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct str {
+ /* 0x0000 */ float4 i;
+};
+
+float4 func(const device float4* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol(const device str* tint_symbol_1 [[buffer(0)]]) {
+ float4 const r = func(&((*(tint_symbol_1)).i));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..7abeef3
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,45 @@
+; SPIR-V
+; Version: 1.3
+; 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 %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %S "S"
+ OpName %func_S_i "func_S_i"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %S NonWritable
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %str = OpTypeStruct %v4float
+ %S_block = OpTypeStruct %str
+%_ptr_StorageBuffer_S_block = OpTypePointer StorageBuffer %S_block
+ %S = OpVariable %_ptr_StorageBuffer_S_block StorageBuffer
+ %7 = OpTypeFunction %v4float
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+ %void = OpTypeVoid
+ %15 = OpTypeFunction %void
+ %func_S_i = OpFunction %v4float None %7
+ %9 = OpLabel
+ %13 = OpAccessChain %_ptr_StorageBuffer_v4float %S %uint_0 %uint_0
+ %14 = OpLoad %v4float %13
+ OpReturnValue %14
+ OpFunctionEnd
+ %main = OpFunction %void None %15
+ %18 = OpLabel
+ %19 = OpFunctionCall %v4float %func_S_i
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..bb2f4cc
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/storage/vec4_f32_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<f32>,
+}
+
+@group(0) @binding(0) var<storage> S : str;
+
+fn func(pointer : ptr<storage, vec4<f32>>) -> vec4<f32> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S.i));
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl b/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl
new file mode 100644
index 0000000..cccfea0
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<vec4<i32>, 4>,
+};
+
+@group(0) @binding(0) var<uniform> S : str;
+
+fn func(pointer : ptr<uniform, array<vec4<i32>, 4>>) -> array<vec4<i32>, 4> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S.arr);
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..df6d009
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,26 @@
+cbuffer cbuffer_S : register(b0, space0) {
+ uint4 S[4];
+};
+
+typedef int4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+ int4 arr_1[4] = (int4[4])0;
+ {
+ for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+ const uint scalar_offset = ((offset + (i * 16u))) / 4;
+ arr_1[i] = asint(buffer[scalar_offset / 4]);
+ }
+ }
+ return arr_1;
+}
+
+typedef int4 func_S_arr_ret[4];
+func_S_arr_ret func_S_arr() {
+ return tint_symbol(S, 0u);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int4 r[4] = func_S_arr();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..df6d009
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,26 @@
+cbuffer cbuffer_S : register(b0, space0) {
+ uint4 S[4];
+};
+
+typedef int4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+ int4 arr_1[4] = (int4[4])0;
+ {
+ for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+ const uint scalar_offset = ((offset + (i * 16u))) / 4;
+ arr_1[i] = asint(buffer[scalar_offset / 4]);
+ }
+ }
+ return arr_1;
+}
+
+typedef int4 func_S_arr_ret[4];
+func_S_arr_ret func_S_arr() {
+ return tint_symbol(S, 0u);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int4 r[4] = func_S_arr();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..3de54f2
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+
+struct str {
+ ivec4 arr[4];
+};
+
+layout(binding = 0, std140) uniform S_block_ubo {
+ str inner;
+} S;
+
+ivec4[4] func_S_arr() {
+ return S.inner.arr;
+}
+
+void tint_symbol() {
+ ivec4 r[4] = func_S_arr();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..ff667b2
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl.expected.msl
@@ -0,0 +1,29 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+struct str {
+ /* 0x0000 */ tint_array<int4, 4> arr;
+};
+
+tint_array<int4, 4> func(const constant tint_array<int4, 4>* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol(const constant str* tint_symbol_1 [[buffer(0)]]) {
+ tint_array<int4, 4> const r = func(&((*(tint_symbol_1)).arr));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..ba3211f
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,48 @@
+; 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 %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %str "str"
+ OpMemberName %str 0 "arr"
+ OpName %S "S"
+ OpName %func_S_arr "func_S_arr"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %_arr_v4int_uint_4 ArrayStride 16
+ OpDecorate %S NonWritable
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ %int = OpTypeInt 32 1
+ %v4int = OpTypeVector %int 4
+ %uint = OpTypeInt 32 0
+ %uint_4 = OpConstant %uint 4
+%_arr_v4int_uint_4 = OpTypeArray %v4int %uint_4
+ %str = OpTypeStruct %_arr_v4int_uint_4
+ %S_block = OpTypeStruct %str
+%_ptr_Uniform_S_block = OpTypePointer Uniform %S_block
+ %S = OpVariable %_ptr_Uniform_S_block Uniform
+ %10 = OpTypeFunction %_arr_v4int_uint_4
+ %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_v4int_uint_4 = OpTypePointer Uniform %_arr_v4int_uint_4
+ %void = OpTypeVoid
+ %17 = OpTypeFunction %void
+ %func_S_arr = OpFunction %_arr_v4int_uint_4 None %10
+ %12 = OpLabel
+ %15 = OpAccessChain %_ptr_Uniform__arr_v4int_uint_4 %S %uint_0 %uint_0
+ %16 = OpLoad %_arr_v4int_uint_4 %15
+ OpReturnValue %16
+ OpFunctionEnd
+ %main = OpFunction %void None %17
+ %20 = OpLabel
+ %21 = OpFunctionCall %_arr_v4int_uint_4 %func_S_arr
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..c2b203e
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/array_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<vec4<i32>, 4>,
+}
+
+@group(0) @binding(0) var<uniform> S : str;
+
+fn func(pointer : ptr<uniform, array<vec4<i32>, 4>>) -> array<vec4<i32>, 4> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S.arr));
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/i32.wgsl b/test/tint/ptr_ref/load/param/uniform/i32.wgsl
new file mode 100644
index 0000000..8e37001
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/i32.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> S : i32;
+
+fn func(pointer : ptr<uniform, i32>) -> i32 {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S);
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/i32.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/uniform/i32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..1c68252
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/i32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,13 @@
+cbuffer cbuffer_S : register(b0, space0) {
+ uint4 S[1];
+};
+
+int func_S() {
+ return asint(S[0].x);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int r = func_S();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/i32.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/uniform/i32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..1c68252
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/i32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,13 @@
+cbuffer cbuffer_S : register(b0, space0) {
+ uint4 S[1];
+};
+
+int func_S() {
+ return asint(S[0].x);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int r = func_S();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/i32.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/uniform/i32.wgsl.expected.glsl
new file mode 100644
index 0000000..e30a7db
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/i32.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform S_block_ubo {
+ int inner;
+} S;
+
+int func_S() {
+ return S.inner;
+}
+
+void tint_symbol() {
+ int r = func_S();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/i32.wgsl.expected.msl b/test/tint/ptr_ref/load/param/uniform/i32.wgsl.expected.msl
new file mode 100644
index 0000000..8bb0365
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/i32.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int func(const constant int* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol(const constant int* tint_symbol_1 [[buffer(0)]]) {
+ int const r = func(tint_symbol_1);
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/uniform/i32.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/uniform/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..7efbd09
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/i32.wgsl.expected.spvasm
@@ -0,0 +1,40 @@
+; 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_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %S "S"
+ OpName %func_S "func_S"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpDecorate %S NonWritable
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ %int = OpTypeInt 32 1
+ %S_block = OpTypeStruct %int
+%_ptr_Uniform_S_block = OpTypePointer Uniform %S_block
+ %S = OpVariable %_ptr_Uniform_S_block Uniform
+ %5 = OpTypeFunction %int
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_int = OpTypePointer Uniform %int
+ %void = OpTypeVoid
+ %13 = OpTypeFunction %void
+ %func_S = OpFunction %int None %5
+ %7 = OpLabel
+ %11 = OpAccessChain %_ptr_Uniform_int %S %uint_0
+ %12 = OpLoad %int %11
+ OpReturnValue %12
+ OpFunctionEnd
+ %main = OpFunction %void None %13
+ %16 = OpLabel
+ %17 = OpFunctionCall %int %func_S
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/uniform/i32.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/uniform/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..b8a873f
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/i32.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> S : i32;
+
+fn func(pointer : ptr<uniform, i32>) -> i32 {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S));
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl b/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl
new file mode 100644
index 0000000..6db13e0
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+@group(0) @binding(0) var<uniform> S : str;
+
+fn func(pointer : ptr<uniform, i32>) -> i32 {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S.i);
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..f5f2ed2
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,13 @@
+cbuffer cbuffer_S : register(b0, space0) {
+ uint4 S[1];
+};
+
+int func_S_i() {
+ return asint(S[0].x);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int r = func_S_i();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..f5f2ed2
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,13 @@
+cbuffer cbuffer_S : register(b0, space0) {
+ uint4 S[1];
+};
+
+int func_S_i() {
+ return asint(S[0].x);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const int r = func_S_i();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..284adc1
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl.expected.glsl
@@ -0,0 +1,26 @@
+#version 310 es
+
+struct str {
+ int i;
+ uint pad;
+ uint pad_1;
+ uint pad_2;
+};
+
+layout(binding = 0, std140) uniform S_block_ubo {
+ str inner;
+} S;
+
+int func_S_i() {
+ return S.inner.i;
+}
+
+void tint_symbol() {
+ int r = func_S_i();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..f4a643f
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl.expected.msl
@@ -0,0 +1,16 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct str {
+ /* 0x0000 */ int i;
+};
+
+int func(const constant int* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol(const constant str* tint_symbol_1 [[buffer(0)]]) {
+ int const r = func(&((*(tint_symbol_1)).i));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..2f1702d
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,44 @@
+; 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 %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %S "S"
+ OpName %func_S_i "func_S_i"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %S NonWritable
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ %int = OpTypeInt 32 1
+ %str = OpTypeStruct %int
+ %S_block = OpTypeStruct %str
+%_ptr_Uniform_S_block = OpTypePointer Uniform %S_block
+ %S = OpVariable %_ptr_Uniform_S_block Uniform
+ %6 = OpTypeFunction %int
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_int = OpTypePointer Uniform %int
+ %void = OpTypeVoid
+ %14 = OpTypeFunction %void
+ %func_S_i = OpFunction %int None %6
+ %8 = OpLabel
+ %12 = OpAccessChain %_ptr_Uniform_int %S %uint_0 %uint_0
+ %13 = OpLoad %int %12
+ OpReturnValue %13
+ OpFunctionEnd
+ %main = OpFunction %void None %14
+ %17 = OpLabel
+ %18 = OpFunctionCall %int %func_S_i
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..c44d00b
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/i32_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+@group(0) @binding(0) var<uniform> S : str;
+
+fn func(pointer : ptr<uniform, i32>) -> i32 {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S.i));
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl b/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl
new file mode 100644
index 0000000..f0c98a4
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<i32>,
+};
+
+@group(0) @binding(0) var<uniform> S : array<str, 4>;
+
+fn func(pointer : ptr<uniform, str>) -> str {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S[2]);
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..cea8a9a
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl.expected.dxc.hlsl
@@ -0,0 +1,24 @@
+struct str {
+ int4 i;
+};
+
+cbuffer cbuffer_S : register(b0, space0) {
+ uint4 S[4];
+};
+
+str tint_symbol(uint4 buffer[4], uint offset) {
+ const uint scalar_offset = ((offset + 0u)) / 4;
+ const str tint_symbol_2 = {asint(buffer[scalar_offset / 4])};
+ return tint_symbol_2;
+}
+
+str func_S_X(uint pointer[1]) {
+ return tint_symbol(S, (16u * pointer[0]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const uint tint_symbol_3[1] = {2u};
+ const str r = func_S_X(tint_symbol_3);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..cea8a9a
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl.expected.fxc.hlsl
@@ -0,0 +1,24 @@
+struct str {
+ int4 i;
+};
+
+cbuffer cbuffer_S : register(b0, space0) {
+ uint4 S[4];
+};
+
+str tint_symbol(uint4 buffer[4], uint offset) {
+ const uint scalar_offset = ((offset + 0u)) / 4;
+ const str tint_symbol_2 = {asint(buffer[scalar_offset / 4])};
+ return tint_symbol_2;
+}
+
+str func_S_X(uint pointer[1]) {
+ return tint_symbol(S, (16u * pointer[0]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const uint tint_symbol_3[1] = {2u};
+ const str r = func_S_X(tint_symbol_3);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl.expected.glsl
new file mode 100644
index 0000000..c1620ec
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl.expected.glsl
@@ -0,0 +1,24 @@
+#version 310 es
+
+struct str {
+ ivec4 i;
+};
+
+layout(binding = 0, std140) uniform S_block_ubo {
+ str inner[4];
+} S;
+
+str func_S_X(uint pointer[1]) {
+ return S.inner[pointer[0]];
+}
+
+void tint_symbol() {
+ uint tint_symbol_1[1] = uint[1](2u);
+ str r = func_S_X(tint_symbol_1);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl.expected.msl b/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl.expected.msl
new file mode 100644
index 0000000..83554f0
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl.expected.msl
@@ -0,0 +1,29 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+struct str {
+ /* 0x0000 */ int4 i;
+};
+
+str func(const constant str* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol(const constant tint_array<str, 4>* tint_symbol_1 [[buffer(0)]]) {
+ str const r = func(&((*(tint_symbol_1))[2]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl.expected.spvasm
new file mode 100644
index 0000000..273b5bd
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl.expected.spvasm
@@ -0,0 +1,57 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 29
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %S "S"
+ OpName %func_S_X "func_S_X"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %_arr_str_uint_4 ArrayStride 16
+ OpDecorate %S NonWritable
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %int = OpTypeInt 32 1
+ %v4int = OpTypeVector %int 4
+ %str = OpTypeStruct %v4int
+ %uint = OpTypeInt 32 0
+ %uint_4 = OpConstant %uint 4
+%_arr_str_uint_4 = OpTypeArray %str %uint_4
+ %S_block = OpTypeStruct %_arr_str_uint_4
+%_ptr_Uniform_S_block = OpTypePointer Uniform %S_block
+ %S = OpVariable %_ptr_Uniform_S_block Uniform
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %10 = OpTypeFunction %str %_arr_uint_uint_1
+ %uint_0 = OpConstant %uint 0
+ %17 = OpConstantNull %int
+%_ptr_Uniform_str = OpTypePointer Uniform %str
+ %void = OpTypeVoid
+ %22 = OpTypeFunction %void
+ %uint_2 = OpConstant %uint 2
+ %28 = OpConstantComposite %_arr_uint_uint_1 %uint_2
+ %func_S_X = OpFunction %str None %10
+ %pointer = OpFunctionParameter %_arr_uint_uint_1
+ %15 = OpLabel
+ %18 = OpCompositeExtract %uint %pointer 0
+ %20 = OpAccessChain %_ptr_Uniform_str %S %uint_0 %18
+ %21 = OpLoad %str %20
+ OpReturnValue %21
+ OpFunctionEnd
+ %main = OpFunction %void None %22
+ %25 = OpLabel
+ %26 = OpFunctionCall %str %func_S_X %28
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl.expected.wgsl
new file mode 100644
index 0000000..be885de
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/struct_in_array.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<i32>,
+}
+
+@group(0) @binding(0) var<uniform> S : array<str, 4>;
+
+fn func(pointer : ptr<uniform, str>) -> str {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S[2]));
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl b/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl
new file mode 100644
index 0000000..e84f1a1
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> S : mat2x2<f32>;
+
+fn func(pointer : ptr<uniform, vec2<f32>>) -> vec2<f32> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S[1]);
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..7718f57
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl
@@ -0,0 +1,16 @@
+cbuffer cbuffer_S : register(b0, space0) {
+ uint4 S[1];
+};
+
+float2 func_S_X(uint pointer[1]) {
+ const uint scalar_offset = ((8u * pointer[0])) / 4;
+ uint4 ubo_load = S[scalar_offset / 4];
+ return asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const uint tint_symbol_1[1] = {1u};
+ const float2 r = func_S_X(tint_symbol_1);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7718f57
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl
@@ -0,0 +1,16 @@
+cbuffer cbuffer_S : register(b0, space0) {
+ uint4 S[1];
+};
+
+float2 func_S_X(uint pointer[1]) {
+ const uint scalar_offset = ((8u * pointer[0])) / 4;
+ uint4 ubo_load = S[scalar_offset / 4];
+ return asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const uint tint_symbol_1[1] = {1u};
+ const float2 r = func_S_X(tint_symbol_1);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl.expected.glsl
new file mode 100644
index 0000000..744936c
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl.expected.glsl
@@ -0,0 +1,38 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform S_block_std140_ubo {
+ vec2 inner_0;
+ vec2 inner_1;
+} S;
+
+vec2 load_S_inner_p0(uint p0) {
+ switch(p0) {
+ case 0u: {
+ return S.inner_0;
+ break;
+ }
+ case 1u: {
+ return S.inner_1;
+ break;
+ }
+ default: {
+ return vec2(0.0f);
+ break;
+ }
+ }
+}
+
+vec2 func_S_X(uint pointer[1]) {
+ return load_S_inner_p0(uint(pointer[0]));
+}
+
+void tint_symbol() {
+ uint tint_symbol_1[1] = uint[1](1u);
+ vec2 r = func_S_X(tint_symbol_1);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl.expected.msl b/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl.expected.msl
new file mode 100644
index 0000000..47d02ac
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+float2 func(const constant float2* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol(const constant float2x2* tint_symbol_1 [[buffer(0)]]) {
+ float2 const r = func(&((*(tint_symbol_1))[1]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl.expected.spvasm
new file mode 100644
index 0000000..4025051
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl.expected.spvasm
@@ -0,0 +1,73 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 39
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %S_block_std140 "S_block_std140"
+ OpMemberName %S_block_std140 0 "inner_0"
+ OpMemberName %S_block_std140 1 "inner_1"
+ OpName %S "S"
+ OpName %load_S_inner_p0 "load_S_inner_p0"
+ OpName %p0 "p0"
+ OpName %func_S_X "func_S_X"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpDecorate %S_block_std140 Block
+ OpMemberDecorate %S_block_std140 0 Offset 0
+ OpMemberDecorate %S_block_std140 1 Offset 8
+ OpDecorate %S NonWritable
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %float = OpTypeFloat 32
+ %v2float = OpTypeVector %float 2
+%S_block_std140 = OpTypeStruct %v2float %v2float
+%_ptr_Uniform_S_block_std140 = OpTypePointer Uniform %S_block_std140
+ %S = OpVariable %_ptr_Uniform_S_block_std140 Uniform
+ %uint = OpTypeInt 32 0
+ %6 = OpTypeFunction %v2float %uint
+ %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+ %uint_1 = OpConstant %uint 1
+ %22 = OpConstantNull %v2float
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %23 = OpTypeFunction %v2float %_arr_uint_uint_1
+ %int = OpTypeInt 32 1
+ %31 = OpConstantNull %int
+ %void = OpTypeVoid
+ %33 = OpTypeFunction %void
+ %38 = OpConstantComposite %_arr_uint_uint_1 %uint_1
+%load_S_inner_p0 = OpFunction %v2float None %6
+ %p0 = OpFunctionParameter %uint
+ %10 = OpLabel
+ OpSelectionMerge %11 None
+ OpSwitch %p0 %12 0 %13 1 %14
+ %13 = OpLabel
+ %17 = OpAccessChain %_ptr_Uniform_v2float %S %uint_0
+ %18 = OpLoad %v2float %17
+ OpReturnValue %18
+ %14 = OpLabel
+ %20 = OpAccessChain %_ptr_Uniform_v2float %S %uint_1
+ %21 = OpLoad %v2float %20
+ OpReturnValue %21
+ %12 = OpLabel
+ OpReturnValue %22
+ %11 = OpLabel
+ OpReturnValue %22
+ OpFunctionEnd
+ %func_S_X = OpFunction %v2float None %23
+ %pointer = OpFunctionParameter %_arr_uint_uint_1
+ %27 = OpLabel
+ %32 = OpCompositeExtract %uint %pointer 0
+ %28 = OpFunctionCall %v2float %load_S_inner_p0 %32
+ OpReturnValue %28
+ OpFunctionEnd
+ %main = OpFunction %void None %33
+ %36 = OpLabel
+ %37 = OpFunctionCall %v2float %func_S_X %38
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl.expected.wgsl
new file mode 100644
index 0000000..1891f2a
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec2_f32_in_mat2x2.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> S : mat2x2<f32>;
+
+fn func(pointer : ptr<uniform, vec2<f32>>) -> vec2<f32> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S[1]));
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl b/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl
new file mode 100644
index 0000000..68e7949
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> S : vec4<f32>;
+
+fn func(pointer : ptr<uniform, vec4<f32>>) -> vec4<f32> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S);
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..cd31c23
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,13 @@
+cbuffer cbuffer_S : register(b0, space0) {
+ uint4 S[1];
+};
+
+float4 func_S() {
+ return asfloat(S[0]);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const float4 r = func_S();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..cd31c23
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,13 @@
+cbuffer cbuffer_S : register(b0, space0) {
+ uint4 S[1];
+};
+
+float4 func_S() {
+ return asfloat(S[0]);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const float4 r = func_S();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..69cd92e
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform S_block_ubo {
+ vec4 inner;
+} S;
+
+vec4 func_S() {
+ return S.inner;
+}
+
+void tint_symbol() {
+ vec4 r = func_S();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl.expected.msl b/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl.expected.msl
new file mode 100644
index 0000000..6c0dc2c
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+float4 func(const constant float4* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol(const constant float4* tint_symbol_1 [[buffer(0)]]) {
+ float4 const r = func(tint_symbol_1);
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..d99abfc
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl.expected.spvasm
@@ -0,0 +1,41 @@
+; 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 %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %S "S"
+ OpName %func_S "func_S"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpDecorate %S NonWritable
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %S_block = OpTypeStruct %v4float
+%_ptr_Uniform_S_block = OpTypePointer Uniform %S_block
+ %S = OpVariable %_ptr_Uniform_S_block Uniform
+ %6 = OpTypeFunction %v4float
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+ %void = OpTypeVoid
+ %14 = OpTypeFunction %void
+ %func_S = OpFunction %v4float None %6
+ %8 = OpLabel
+ %12 = OpAccessChain %_ptr_Uniform_v4float %S %uint_0
+ %13 = OpLoad %v4float %12
+ OpReturnValue %13
+ OpFunctionEnd
+ %main = OpFunction %void None %14
+ %17 = OpLabel
+ %18 = OpFunctionCall %v4float %func_S
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..c5e8e6a
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> S : vec4<f32>;
+
+fn func(pointer : ptr<uniform, vec4<f32>>) -> vec4<f32> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S));
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl
new file mode 100644
index 0000000..a77ca7c
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> S : mat2x4<f32>;
+
+fn func(pointer : ptr<uniform, vec4<f32>>) -> vec4<f32> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S[1]);
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8aeba47
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl
@@ -0,0 +1,15 @@
+cbuffer cbuffer_S : register(b0, space0) {
+ uint4 S[2];
+};
+
+float4 func_S_X(uint pointer[1]) {
+ const uint scalar_offset = ((16u * pointer[0])) / 4;
+ return asfloat(S[scalar_offset / 4]);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const uint tint_symbol_1[1] = {1u};
+ const float4 r = func_S_X(tint_symbol_1);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8aeba47
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl
@@ -0,0 +1,15 @@
+cbuffer cbuffer_S : register(b0, space0) {
+ uint4 S[2];
+};
+
+float4 func_S_X(uint pointer[1]) {
+ const uint scalar_offset = ((16u * pointer[0])) / 4;
+ return asfloat(S[scalar_offset / 4]);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const uint tint_symbol_1[1] = {1u};
+ const float4 r = func_S_X(tint_symbol_1);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl.expected.glsl
new file mode 100644
index 0000000..0852e33
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform S_block_ubo {
+ mat2x4 inner;
+} S;
+
+vec4 func_S_X(uint pointer[1]) {
+ return S.inner[pointer[0]];
+}
+
+void tint_symbol() {
+ uint tint_symbol_1[1] = uint[1](1u);
+ vec4 r = func_S_X(tint_symbol_1);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl.expected.msl b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl.expected.msl
new file mode 100644
index 0000000..2b30f33
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+float4 func(const constant float4* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol(const constant float2x4* tint_symbol_1 [[buffer(0)]]) {
+ float4 const r = func(&((*(tint_symbol_1))[1]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl.expected.spvasm
new file mode 100644
index 0000000..6cdd4c0
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl.expected.spvasm
@@ -0,0 +1,53 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 27
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %S "S"
+ OpName %func_S_X "func_S_X"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpMemberDecorate %S_block 0 ColMajor
+ OpMemberDecorate %S_block 0 MatrixStride 16
+ OpDecorate %S NonWritable
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+ %S_block = OpTypeStruct %mat2v4float
+%_ptr_Uniform_S_block = OpTypePointer Uniform %S_block
+ %S = OpVariable %_ptr_Uniform_S_block Uniform
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %7 = OpTypeFunction %v4float %_arr_uint_uint_1
+ %uint_0 = OpConstant %uint 0
+ %int = OpTypeInt 32 1
+ %16 = OpConstantNull %int
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+ %void = OpTypeVoid
+ %21 = OpTypeFunction %void
+ %26 = OpConstantComposite %_arr_uint_uint_1 %uint_1
+ %func_S_X = OpFunction %v4float None %7
+ %pointer = OpFunctionParameter %_arr_uint_uint_1
+ %13 = OpLabel
+ %17 = OpCompositeExtract %uint %pointer 0
+ %19 = OpAccessChain %_ptr_Uniform_v4float %S %uint_0 %17
+ %20 = OpLoad %v4float %19
+ OpReturnValue %20
+ OpFunctionEnd
+ %main = OpFunction %void None %21
+ %24 = OpLabel
+ %25 = OpFunctionCall %v4float %func_S_X %26
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl.expected.wgsl
new file mode 100644
index 0000000..7f010b8
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_mat2x4.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> S : mat2x4<f32>;
+
+fn func(pointer : ptr<uniform, vec4<f32>>) -> vec4<f32> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S[1]));
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl
new file mode 100644
index 0000000..7059df4
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<f32>,
+};
+
+@group(0) @binding(0) var<uniform> S : str;
+
+fn func(pointer : ptr<uniform, vec4<f32>>) -> vec4<f32> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S.i);
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8861303
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,13 @@
+cbuffer cbuffer_S : register(b0, space0) {
+ uint4 S[1];
+};
+
+float4 func_S_i() {
+ return asfloat(S[0]);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const float4 r = func_S_i();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8861303
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,13 @@
+cbuffer cbuffer_S : register(b0, space0) {
+ uint4 S[1];
+};
+
+float4 func_S_i() {
+ return asfloat(S[0]);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const float4 r = func_S_i();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..46120ee
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+
+struct str {
+ vec4 i;
+};
+
+layout(binding = 0, std140) uniform S_block_ubo {
+ str inner;
+} S;
+
+vec4 func_S_i() {
+ return S.inner.i;
+}
+
+void tint_symbol() {
+ vec4 r = func_S_i();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..68870b6
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl.expected.msl
@@ -0,0 +1,16 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct str {
+ /* 0x0000 */ float4 i;
+};
+
+float4 func(const constant float4* const pointer) {
+ return *(pointer);
+}
+
+kernel void tint_symbol(const constant str* tint_symbol_1 [[buffer(0)]]) {
+ float4 const r = func(&((*(tint_symbol_1)).i));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..9586d0b
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,45 @@
+; SPIR-V
+; Version: 1.3
+; 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 %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %S "S"
+ OpName %func_S_i "func_S_i"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %S NonWritable
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %str = OpTypeStruct %v4float
+ %S_block = OpTypeStruct %str
+%_ptr_Uniform_S_block = OpTypePointer Uniform %S_block
+ %S = OpVariable %_ptr_Uniform_S_block Uniform
+ %7 = OpTypeFunction %v4float
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+ %void = OpTypeVoid
+ %15 = OpTypeFunction %void
+ %func_S_i = OpFunction %v4float None %7
+ %9 = OpLabel
+ %13 = OpAccessChain %_ptr_Uniform_v4float %S %uint_0 %uint_0
+ %14 = OpLoad %v4float %13
+ OpReturnValue %14
+ OpFunctionEnd
+ %main = OpFunction %void None %15
+ %18 = OpLabel
+ %19 = OpFunctionCall %v4float %func_S_i
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..f08290a
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/uniform/vec4_f32_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<f32>,
+}
+
+@group(0) @binding(0) var<uniform> S : str;
+
+fn func(pointer : ptr<uniform, vec4<f32>>) -> vec4<f32> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S.i));
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl b/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl
new file mode 100644
index 0000000..55a558a
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+};
+
+var<workgroup> S : str;
+
+fn func(pointer : ptr<workgroup, array<i32, 4>>) -> array<i32, 4> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S.arr);
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..14498cd
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,31 @@
+struct str {
+ int arr[4];
+};
+
+groupshared str S;
+
+typedef int func_S_arr_ret[4];
+func_S_arr_ret func_S_arr() {
+ return S.arr;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+ const uint i = idx;
+ S.arr[i] = 0;
+ }
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const int r[4] = func_S_arr();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..14498cd
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,31 @@
+struct str {
+ int arr[4];
+};
+
+groupshared str S;
+
+typedef int func_S_arr_ret[4];
+func_S_arr_ret func_S_arr() {
+ return S.arr;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+ const uint i = idx;
+ S.arr[i] = 0;
+ }
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const int r[4] = func_S_arr();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..ce8bf4d
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl.expected.glsl
@@ -0,0 +1,27 @@
+#version 310 es
+
+struct str {
+ int arr[4];
+};
+
+shared str S;
+int[4] func_S_arr() {
+ return S.arr;
+}
+
+void tint_symbol(uint local_invocation_index) {
+ {
+ for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+ uint i = idx;
+ S.arr[i] = 0;
+ }
+ }
+ barrier();
+ int r[4] = func_S_arr();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol(gl_LocalInvocationIndex);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..e8f0b1f
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl.expected.msl
@@ -0,0 +1,39 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+struct str {
+ tint_array<int, 4> arr;
+};
+
+tint_array<int, 4> func(threadgroup tint_array<int, 4>* const pointer) {
+ return *(pointer);
+}
+
+void tint_symbol_inner(uint local_invocation_index, threadgroup str* const tint_symbol_1) {
+ for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+ uint const i = idx;
+ (*(tint_symbol_1)).arr[i] = 0;
+ }
+ threadgroup_barrier(mem_flags::mem_threadgroup);
+ tint_array<int, 4> const r = func(&((*(tint_symbol_1)).arr));
+}
+
+kernel void tint_symbol(uint local_invocation_index [[thread_index_in_threadgroup]]) {
+ threadgroup str tint_symbol_2;
+ tint_symbol_inner(local_invocation_index, &(tint_symbol_2));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..687e862
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,88 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 51
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %local_invocation_index_1
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %local_invocation_index_1 "local_invocation_index_1"
+ OpName %str "str"
+ OpMemberName %str 0 "arr"
+ OpName %S "S"
+ OpName %func_S_arr "func_S_arr"
+ OpName %main_inner "main_inner"
+ OpName %local_invocation_index "local_invocation_index"
+ OpName %idx "idx"
+ OpName %main "main"
+ OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %_arr_int_uint_4 ArrayStride 4
+ %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+ %int = OpTypeInt 32 1
+ %uint_4 = OpConstant %uint 4
+%_arr_int_uint_4 = OpTypeArray %int %uint_4
+ %str = OpTypeStruct %_arr_int_uint_4
+%_ptr_Workgroup_str = OpTypePointer Workgroup %str
+ %S = OpVariable %_ptr_Workgroup_str Workgroup
+ %10 = OpTypeFunction %_arr_int_uint_4
+ %uint_0 = OpConstant %uint 0
+%_ptr_Workgroup__arr_int_uint_4 = OpTypePointer Workgroup %_arr_int_uint_4
+ %void = OpTypeVoid
+ %17 = OpTypeFunction %void %uint
+%_ptr_Function_uint = OpTypePointer Function %uint
+ %24 = OpConstantNull %uint
+ %bool = OpTypeBool
+%_ptr_Workgroup_int = OpTypePointer Workgroup %int
+ %38 = OpConstantNull %int
+ %uint_1 = OpConstant %uint 1
+ %uint_2 = OpConstant %uint 2
+ %uint_264 = OpConstant %uint 264
+ %46 = OpTypeFunction %void
+ %func_S_arr = OpFunction %_arr_int_uint_4 None %10
+ %12 = OpLabel
+ %15 = OpAccessChain %_ptr_Workgroup__arr_int_uint_4 %S %uint_0
+ %16 = OpLoad %_arr_int_uint_4 %15
+ OpReturnValue %16
+ OpFunctionEnd
+ %main_inner = OpFunction %void None %17
+%local_invocation_index = OpFunctionParameter %uint
+ %21 = OpLabel
+ %idx = OpVariable %_ptr_Function_uint Function %24
+ OpStore %idx %local_invocation_index
+ OpBranch %25
+ %25 = OpLabel
+ OpLoopMerge %26 %27 None
+ OpBranch %28
+ %28 = OpLabel
+ %30 = OpLoad %uint %idx
+ %31 = OpULessThan %bool %30 %uint_4
+ %29 = OpLogicalNot %bool %31
+ OpSelectionMerge %33 None
+ OpBranchConditional %29 %34 %33
+ %34 = OpLabel
+ OpBranch %26
+ %33 = OpLabel
+ %35 = OpLoad %uint %idx
+ %37 = OpAccessChain %_ptr_Workgroup_int %S %uint_0 %35
+ OpStore %37 %38
+ OpBranch %27
+ %27 = OpLabel
+ %39 = OpLoad %uint %idx
+ %41 = OpIAdd %uint %39 %uint_1
+ OpStore %idx %41
+ OpBranch %25
+ %26 = OpLabel
+ OpControlBarrier %uint_2 %uint_2 %uint_264
+ %45 = OpFunctionCall %_arr_int_uint_4 %func_S_arr
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %46
+ %48 = OpLabel
+ %50 = OpLoad %uint %local_invocation_index_1
+ %49 = OpFunctionCall %void %main_inner %50
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..1368900c
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/array_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+}
+
+var<workgroup> S : str;
+
+fn func(pointer : ptr<workgroup, array<i32, 4>>) -> array<i32, 4> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S.arr));
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/i32.wgsl b/test/tint/ptr_ref/load/param/workgroup/i32.wgsl
new file mode 100644
index 0000000..f0b1be9
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/i32.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> S : i32;
+
+fn func(pointer : ptr<workgroup, i32>) -> i32 {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S);
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/i32.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/workgroup/i32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..b3368a2
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/i32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,23 @@
+groupshared int S;
+
+int func_S() {
+ return S;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ S = 0;
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const int r = func_S();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/i32.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/workgroup/i32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b3368a2
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/i32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,23 @@
+groupshared int S;
+
+int func_S() {
+ return S;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ S = 0;
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const int r = func_S();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/i32.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/workgroup/i32.wgsl.expected.glsl
new file mode 100644
index 0000000..fdab385
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/i32.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+shared int S;
+int func_S() {
+ return S;
+}
+
+void tint_symbol(uint local_invocation_index) {
+ {
+ S = 0;
+ }
+ barrier();
+ int r = func_S();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol(gl_LocalInvocationIndex);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/i32.wgsl.expected.msl b/test/tint/ptr_ref/load/param/workgroup/i32.wgsl.expected.msl
new file mode 100644
index 0000000..d438840
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/i32.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int func(threadgroup int* const pointer) {
+ return *(pointer);
+}
+
+void tint_symbol_inner(uint local_invocation_index, threadgroup int* const tint_symbol_1) {
+ {
+ *(tint_symbol_1) = 0;
+ }
+ threadgroup_barrier(mem_flags::mem_threadgroup);
+ int const r = func(tint_symbol_1);
+}
+
+kernel void tint_symbol(uint local_invocation_index [[thread_index_in_threadgroup]]) {
+ threadgroup int tint_symbol_2;
+ tint_symbol_inner(local_invocation_index, &(tint_symbol_2));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/workgroup/i32.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/workgroup/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..4b294ee
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/i32.wgsl.expected.spvasm
@@ -0,0 +1,48 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 26
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %local_invocation_index_1
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %local_invocation_index_1 "local_invocation_index_1"
+ OpName %S "S"
+ OpName %func_S "func_S"
+ OpName %main_inner "main_inner"
+ OpName %local_invocation_index "local_invocation_index"
+ OpName %main "main"
+ OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+ %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+ %int = OpTypeInt 32 1
+%_ptr_Workgroup_int = OpTypePointer Workgroup %int
+ %S = OpVariable %_ptr_Workgroup_int Workgroup
+ %7 = OpTypeFunction %int
+ %void = OpTypeVoid
+ %11 = OpTypeFunction %void %uint
+ %16 = OpConstantNull %int
+ %uint_2 = OpConstant %uint 2
+ %uint_264 = OpConstant %uint 264
+ %21 = OpTypeFunction %void
+ %func_S = OpFunction %int None %7
+ %9 = OpLabel
+ %10 = OpLoad %int %S
+ OpReturnValue %10
+ OpFunctionEnd
+ %main_inner = OpFunction %void None %11
+%local_invocation_index = OpFunctionParameter %uint
+ %15 = OpLabel
+ OpStore %S %16
+ OpControlBarrier %uint_2 %uint_2 %uint_264
+ %20 = OpFunctionCall %int %func_S
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %21
+ %23 = OpLabel
+ %25 = OpLoad %uint %local_invocation_index_1
+ %24 = OpFunctionCall %void %main_inner %25
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/workgroup/i32.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/workgroup/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..8c26859d
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/i32.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> S : i32;
+
+fn func(pointer : ptr<workgroup, i32>) -> i32 {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S));
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl b/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl
new file mode 100644
index 0000000..b777a56
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+var<workgroup> S : str;
+
+fn func(pointer : ptr<workgroup, i32>) -> i32 {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S.i);
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8cf40a2
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,28 @@
+struct str {
+ int i;
+};
+
+groupshared str S;
+
+int func_S_i() {
+ return S.i;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ const str tint_symbol_2 = (str)0;
+ S = tint_symbol_2;
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const int r = func_S_i();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8cf40a2
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+struct str {
+ int i;
+};
+
+groupshared str S;
+
+int func_S_i() {
+ return S.i;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ const str tint_symbol_2 = (str)0;
+ S = tint_symbol_2;
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const int r = func_S_i();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..f59ffb0
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl.expected.glsl
@@ -0,0 +1,25 @@
+#version 310 es
+
+struct str {
+ int i;
+};
+
+shared str S;
+int func_S_i() {
+ return S.i;
+}
+
+void tint_symbol(uint local_invocation_index) {
+ {
+ str tint_symbol_1 = str(0);
+ S = tint_symbol_1;
+ }
+ barrier();
+ int r = func_S_i();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol(gl_LocalInvocationIndex);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..514268e
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl.expected.msl
@@ -0,0 +1,26 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct str {
+ int i;
+};
+
+int func(threadgroup int* const pointer) {
+ return *(pointer);
+}
+
+void tint_symbol_inner(uint local_invocation_index, threadgroup str* const tint_symbol_2) {
+ {
+ str const tint_symbol_1 = str{};
+ *(tint_symbol_2) = tint_symbol_1;
+ }
+ threadgroup_barrier(mem_flags::mem_threadgroup);
+ int const r = func(&((*(tint_symbol_2)).i));
+}
+
+kernel void tint_symbol(uint local_invocation_index [[thread_index_in_threadgroup]]) {
+ threadgroup str tint_symbol_3;
+ tint_symbol_inner(local_invocation_index, &(tint_symbol_3));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..9297831
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,55 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 30
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %local_invocation_index_1
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %local_invocation_index_1 "local_invocation_index_1"
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %S "S"
+ OpName %func_S_i "func_S_i"
+ OpName %main_inner "main_inner"
+ OpName %local_invocation_index "local_invocation_index"
+ OpName %main "main"
+ OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+ OpMemberDecorate %str 0 Offset 0
+ %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+ %int = OpTypeInt 32 1
+ %str = OpTypeStruct %int
+%_ptr_Workgroup_str = OpTypePointer Workgroup %str
+ %S = OpVariable %_ptr_Workgroup_str Workgroup
+ %8 = OpTypeFunction %int
+ %uint_0 = OpConstant %uint 0
+%_ptr_Workgroup_int = OpTypePointer Workgroup %int
+ %void = OpTypeVoid
+ %15 = OpTypeFunction %void %uint
+ %20 = OpConstantNull %str
+ %uint_2 = OpConstant %uint 2
+ %uint_264 = OpConstant %uint 264
+ %25 = OpTypeFunction %void
+ %func_S_i = OpFunction %int None %8
+ %10 = OpLabel
+ %13 = OpAccessChain %_ptr_Workgroup_int %S %uint_0
+ %14 = OpLoad %int %13
+ OpReturnValue %14
+ OpFunctionEnd
+ %main_inner = OpFunction %void None %15
+%local_invocation_index = OpFunctionParameter %uint
+ %19 = OpLabel
+ OpStore %S %20
+ OpControlBarrier %uint_2 %uint_2 %uint_264
+ %24 = OpFunctionCall %int %func_S_i
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %25
+ %27 = OpLabel
+ %29 = OpLoad %uint %local_invocation_index_1
+ %28 = OpFunctionCall %void %main_inner %29
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..d335ec2
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/i32_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+var<workgroup> S : str;
+
+fn func(pointer : ptr<workgroup, i32>) -> i32 {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S.i));
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl b/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl
new file mode 100644
index 0000000..638ca03
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+var<workgroup> S : array<str, 4>;
+
+fn func(pointer : ptr<workgroup, str>) -> str {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S[2]);
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..1b5ca94
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl.expected.dxc.hlsl
@@ -0,0 +1,32 @@
+struct str {
+ int i;
+};
+
+groupshared str S[4];
+
+str func_S_X(uint pointer[1]) {
+ return S[pointer[0]];
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+ const uint i_1 = idx;
+ const str tint_symbol_2 = (str)0;
+ S[i_1] = tint_symbol_2;
+ }
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const uint tint_symbol_3[1] = {2u};
+ const str r = func_S_X(tint_symbol_3);
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..1b5ca94
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl.expected.fxc.hlsl
@@ -0,0 +1,32 @@
+struct str {
+ int i;
+};
+
+groupshared str S[4];
+
+str func_S_X(uint pointer[1]) {
+ return S[pointer[0]];
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+ const uint i_1 = idx;
+ const str tint_symbol_2 = (str)0;
+ S[i_1] = tint_symbol_2;
+ }
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const uint tint_symbol_3[1] = {2u};
+ const str r = func_S_X(tint_symbol_3);
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl.expected.glsl
new file mode 100644
index 0000000..2466387
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl.expected.glsl
@@ -0,0 +1,29 @@
+#version 310 es
+
+struct str {
+ int i;
+};
+
+shared str S[4];
+str func_S_X(uint pointer[1]) {
+ return S[pointer[0]];
+}
+
+void tint_symbol(uint local_invocation_index) {
+ {
+ for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+ uint i_1 = idx;
+ str tint_symbol_1 = str(0);
+ S[i_1] = tint_symbol_1;
+ }
+ }
+ barrier();
+ uint tint_symbol_2[1] = uint[1](2u);
+ str r = func_S_X(tint_symbol_2);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol(gl_LocalInvocationIndex);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl.expected.msl b/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl.expected.msl
new file mode 100644
index 0000000..15c963d
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl.expected.msl
@@ -0,0 +1,40 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+struct str {
+ int i;
+};
+
+str func(threadgroup str* const pointer) {
+ return *(pointer);
+}
+
+void tint_symbol_inner(uint local_invocation_index, threadgroup tint_array<str, 4>* const tint_symbol_2) {
+ for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+ uint const i_1 = idx;
+ str const tint_symbol_1 = str{};
+ (*(tint_symbol_2))[i_1] = tint_symbol_1;
+ }
+ threadgroup_barrier(mem_flags::mem_threadgroup);
+ str const r = func(&((*(tint_symbol_2))[2]));
+}
+
+kernel void tint_symbol(uint local_invocation_index [[thread_index_in_threadgroup]]) {
+ threadgroup tint_array<str, 4> tint_symbol_3;
+ tint_symbol_inner(local_invocation_index, &(tint_symbol_3));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl.expected.spvasm
new file mode 100644
index 0000000..b0a6175
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl.expected.spvasm
@@ -0,0 +1,93 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 54
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %local_invocation_index_1
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %local_invocation_index_1 "local_invocation_index_1"
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %S "S"
+ OpName %func_S_X "func_S_X"
+ OpName %pointer "pointer"
+ OpName %main_inner "main_inner"
+ OpName %local_invocation_index "local_invocation_index"
+ OpName %idx "idx"
+ OpName %main "main"
+ OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %_arr_str_uint_4 ArrayStride 4
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+ %int = OpTypeInt 32 1
+ %str = OpTypeStruct %int
+ %uint_4 = OpConstant %uint 4
+%_arr_str_uint_4 = OpTypeArray %str %uint_4
+%_ptr_Workgroup__arr_str_uint_4 = OpTypePointer Workgroup %_arr_str_uint_4
+ %S = OpVariable %_ptr_Workgroup__arr_str_uint_4 Workgroup
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %10 = OpTypeFunction %str %_arr_uint_uint_1
+ %16 = OpConstantNull %int
+%_ptr_Workgroup_str = OpTypePointer Workgroup %str
+ %void = OpTypeVoid
+ %21 = OpTypeFunction %void %uint
+%_ptr_Function_uint = OpTypePointer Function %uint
+ %28 = OpConstantNull %uint
+ %bool = OpTypeBool
+ %41 = OpConstantNull %str
+ %uint_2 = OpConstant %uint 2
+ %uint_264 = OpConstant %uint 264
+ %48 = OpConstantComposite %_arr_uint_uint_1 %uint_2
+ %49 = OpTypeFunction %void
+ %func_S_X = OpFunction %str None %10
+ %pointer = OpFunctionParameter %_arr_uint_uint_1
+ %15 = OpLabel
+ %17 = OpCompositeExtract %uint %pointer 0
+ %19 = OpAccessChain %_ptr_Workgroup_str %S %17
+ %20 = OpLoad %str %19
+ OpReturnValue %20
+ OpFunctionEnd
+ %main_inner = OpFunction %void None %21
+%local_invocation_index = OpFunctionParameter %uint
+ %25 = OpLabel
+ %idx = OpVariable %_ptr_Function_uint Function %28
+ OpStore %idx %local_invocation_index
+ OpBranch %29
+ %29 = OpLabel
+ OpLoopMerge %30 %31 None
+ OpBranch %32
+ %32 = OpLabel
+ %34 = OpLoad %uint %idx
+ %35 = OpULessThan %bool %34 %uint_4
+ %33 = OpLogicalNot %bool %35
+ OpSelectionMerge %37 None
+ OpBranchConditional %33 %38 %37
+ %38 = OpLabel
+ OpBranch %30
+ %37 = OpLabel
+ %39 = OpLoad %uint %idx
+ %40 = OpAccessChain %_ptr_Workgroup_str %S %39
+ OpStore %40 %41
+ OpBranch %31
+ %31 = OpLabel
+ %42 = OpLoad %uint %idx
+ %43 = OpIAdd %uint %42 %uint_1
+ OpStore %idx %43
+ OpBranch %29
+ %30 = OpLabel
+ OpControlBarrier %uint_2 %uint_2 %uint_264
+ %47 = OpFunctionCall %str %func_S_X %48
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %49
+ %51 = OpLabel
+ %53 = OpLoad %uint %local_invocation_index_1
+ %52 = OpFunctionCall %void %main_inner %53
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl.expected.wgsl
new file mode 100644
index 0000000..2a586fb
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/struct_in_array.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+var<workgroup> S : array<str, 4>;
+
+fn func(pointer : ptr<workgroup, str>) -> str {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S[2]));
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl b/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl
new file mode 100644
index 0000000..5d8e9ae
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> S : mat2x2<f32>;
+
+fn func(pointer : ptr<workgroup, vec2<f32>>) -> vec2<f32> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S[1]);
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..9ce5c2e
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl
@@ -0,0 +1,24 @@
+groupshared float2x2 S;
+
+float2 func_S_X(uint pointer[1]) {
+ return S[pointer[0]];
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ S = float2x2((0.0f).xx, (0.0f).xx);
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const uint tint_symbol_2[1] = {1u};
+ const float2 r = func_S_X(tint_symbol_2);
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..9ce5c2e
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl
@@ -0,0 +1,24 @@
+groupshared float2x2 S;
+
+float2 func_S_X(uint pointer[1]) {
+ return S[pointer[0]];
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ S = float2x2((0.0f).xx, (0.0f).xx);
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const uint tint_symbol_2[1] = {1u};
+ const float2 r = func_S_X(tint_symbol_2);
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.glsl
new file mode 100644
index 0000000..6208c08
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.glsl
@@ -0,0 +1,21 @@
+#version 310 es
+
+shared mat2 S;
+vec2 func_S_X(uint pointer[1]) {
+ return S[pointer[0]];
+}
+
+void tint_symbol(uint local_invocation_index) {
+ {
+ S = mat2(vec2(0.0f), vec2(0.0f));
+ }
+ barrier();
+ uint tint_symbol_1[1] = uint[1](1u);
+ vec2 r = func_S_X(tint_symbol_1);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol(gl_LocalInvocationIndex);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.msl b/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.msl
new file mode 100644
index 0000000..77d8114
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.msl
@@ -0,0 +1,25 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_4 {
+ float2x2 S;
+};
+
+float2 func(threadgroup float2* const pointer) {
+ return *(pointer);
+}
+
+void tint_symbol_inner(uint local_invocation_index, threadgroup float2x2* const tint_symbol_1) {
+ {
+ *(tint_symbol_1) = float2x2(float2(0.0f), float2(0.0f));
+ }
+ threadgroup_barrier(mem_flags::mem_threadgroup);
+ float2 const r = func(&((*(tint_symbol_1))[1]));
+}
+
+kernel void tint_symbol(threadgroup tint_symbol_4* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+ threadgroup float2x2* const tint_symbol_2 = &((*(tint_symbol_3)).S);
+ tint_symbol_inner(local_invocation_index, tint_symbol_2);
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.spvasm
new file mode 100644
index 0000000..513a654
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.spvasm
@@ -0,0 +1,61 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 37
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %local_invocation_index_1
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %local_invocation_index_1 "local_invocation_index_1"
+ OpName %S "S"
+ OpName %func_S_X "func_S_X"
+ OpName %pointer "pointer"
+ OpName %main_inner "main_inner"
+ OpName %local_invocation_index "local_invocation_index"
+ OpName %main "main"
+ OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+ %float = OpTypeFloat 32
+ %v2float = OpTypeVector %float 2
+%mat2v2float = OpTypeMatrix %v2float 2
+%_ptr_Workgroup_mat2v2float = OpTypePointer Workgroup %mat2v2float
+ %S = OpVariable %_ptr_Workgroup_mat2v2float Workgroup
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %9 = OpTypeFunction %v2float %_arr_uint_uint_1
+ %int = OpTypeInt 32 1
+ %16 = OpConstantNull %int
+%_ptr_Workgroup_v2float = OpTypePointer Workgroup %v2float
+ %void = OpTypeVoid
+ %21 = OpTypeFunction %void %uint
+ %26 = OpConstantNull %mat2v2float
+ %uint_2 = OpConstant %uint 2
+ %uint_264 = OpConstant %uint 264
+ %31 = OpConstantComposite %_arr_uint_uint_1 %uint_1
+ %32 = OpTypeFunction %void
+ %func_S_X = OpFunction %v2float None %9
+ %pointer = OpFunctionParameter %_arr_uint_uint_1
+ %14 = OpLabel
+ %17 = OpCompositeExtract %uint %pointer 0
+ %19 = OpAccessChain %_ptr_Workgroup_v2float %S %17
+ %20 = OpLoad %v2float %19
+ OpReturnValue %20
+ OpFunctionEnd
+ %main_inner = OpFunction %void None %21
+%local_invocation_index = OpFunctionParameter %uint
+ %25 = OpLabel
+ OpStore %S %26
+ OpControlBarrier %uint_2 %uint_2 %uint_264
+ %30 = OpFunctionCall %v2float %func_S_X %31
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %32
+ %34 = OpLabel
+ %36 = OpLoad %uint %local_invocation_index_1
+ %35 = OpFunctionCall %void %main_inner %36
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.wgsl
new file mode 100644
index 0000000..55afec1
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> S : mat2x2<f32>;
+
+fn func(pointer : ptr<workgroup, vec2<f32>>) -> vec2<f32> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S[1]));
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl b/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl
new file mode 100644
index 0000000..0ccdce7
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> S : vec4<f32>;
+
+fn func(pointer : ptr<workgroup, vec4<f32>>) -> vec4<f32> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S);
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0273faf
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,23 @@
+groupshared float4 S;
+
+float4 func_S() {
+ return S;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ S = (0.0f).xxxx;
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const float4 r = func_S();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..0273faf
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,23 @@
+groupshared float4 S;
+
+float4 func_S() {
+ return S;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ S = (0.0f).xxxx;
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const float4 r = func_S();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..93c3bdd
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+shared vec4 S;
+vec4 func_S() {
+ return S;
+}
+
+void tint_symbol(uint local_invocation_index) {
+ {
+ S = vec4(0.0f);
+ }
+ barrier();
+ vec4 r = func_S();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol(gl_LocalInvocationIndex);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl.expected.msl b/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl.expected.msl
new file mode 100644
index 0000000..3a2d553
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+float4 func(threadgroup float4* const pointer) {
+ return *(pointer);
+}
+
+void tint_symbol_inner(uint local_invocation_index, threadgroup float4* const tint_symbol_1) {
+ {
+ *(tint_symbol_1) = float4(0.0f);
+ }
+ threadgroup_barrier(mem_flags::mem_threadgroup);
+ float4 const r = func(tint_symbol_1);
+}
+
+kernel void tint_symbol(uint local_invocation_index [[thread_index_in_threadgroup]]) {
+ threadgroup float4 tint_symbol_2;
+ tint_symbol_inner(local_invocation_index, &(tint_symbol_2));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..eec223f
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl.expected.spvasm
@@ -0,0 +1,49 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 27
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %local_invocation_index_1
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %local_invocation_index_1 "local_invocation_index_1"
+ OpName %S "S"
+ OpName %func_S "func_S"
+ OpName %main_inner "main_inner"
+ OpName %local_invocation_index "local_invocation_index"
+ OpName %main "main"
+ OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+ %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float
+ %S = OpVariable %_ptr_Workgroup_v4float Workgroup
+ %8 = OpTypeFunction %v4float
+ %void = OpTypeVoid
+ %12 = OpTypeFunction %void %uint
+ %17 = OpConstantNull %v4float
+ %uint_2 = OpConstant %uint 2
+ %uint_264 = OpConstant %uint 264
+ %22 = OpTypeFunction %void
+ %func_S = OpFunction %v4float None %8
+ %10 = OpLabel
+ %11 = OpLoad %v4float %S
+ OpReturnValue %11
+ OpFunctionEnd
+ %main_inner = OpFunction %void None %12
+%local_invocation_index = OpFunctionParameter %uint
+ %16 = OpLabel
+ OpStore %S %17
+ OpControlBarrier %uint_2 %uint_2 %uint_264
+ %21 = OpFunctionCall %v4float %func_S
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %22
+ %24 = OpLabel
+ %26 = OpLoad %uint %local_invocation_index_1
+ %25 = OpFunctionCall %void %main_inner %26
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..3c9ab35
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> S : vec4<f32>;
+
+fn func(pointer : ptr<workgroup, vec4<f32>>) -> vec4<f32> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S));
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl
new file mode 100644
index 0000000..204d6c2
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> S : mat2x4<f32>;
+
+fn func(pointer : ptr<workgroup, vec4<f32>>) -> vec4<f32> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S[1]);
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..4a0f881
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl
@@ -0,0 +1,24 @@
+groupshared float2x4 S;
+
+float4 func_S_X(uint pointer[1]) {
+ return S[pointer[0]];
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ S = float2x4((0.0f).xxxx, (0.0f).xxxx);
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const uint tint_symbol_2[1] = {1u};
+ const float4 r = func_S_X(tint_symbol_2);
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..4a0f881
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl
@@ -0,0 +1,24 @@
+groupshared float2x4 S;
+
+float4 func_S_X(uint pointer[1]) {
+ return S[pointer[0]];
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ S = float2x4((0.0f).xxxx, (0.0f).xxxx);
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const uint tint_symbol_2[1] = {1u};
+ const float4 r = func_S_X(tint_symbol_2);
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.glsl
new file mode 100644
index 0000000..0e1cc3b
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.glsl
@@ -0,0 +1,21 @@
+#version 310 es
+
+shared mat2x4 S;
+vec4 func_S_X(uint pointer[1]) {
+ return S[pointer[0]];
+}
+
+void tint_symbol(uint local_invocation_index) {
+ {
+ S = mat2x4(vec4(0.0f), vec4(0.0f));
+ }
+ barrier();
+ uint tint_symbol_1[1] = uint[1](1u);
+ vec4 r = func_S_X(tint_symbol_1);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol(gl_LocalInvocationIndex);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.msl b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.msl
new file mode 100644
index 0000000..992678f
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.msl
@@ -0,0 +1,25 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_4 {
+ float2x4 S;
+};
+
+float4 func(threadgroup float4* const pointer) {
+ return *(pointer);
+}
+
+void tint_symbol_inner(uint local_invocation_index, threadgroup float2x4* const tint_symbol_1) {
+ {
+ *(tint_symbol_1) = float2x4(float4(0.0f), float4(0.0f));
+ }
+ threadgroup_barrier(mem_flags::mem_threadgroup);
+ float4 const r = func(&((*(tint_symbol_1))[1]));
+}
+
+kernel void tint_symbol(threadgroup tint_symbol_4* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+ threadgroup float2x4* const tint_symbol_2 = &((*(tint_symbol_3)).S);
+ tint_symbol_inner(local_invocation_index, tint_symbol_2);
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.spvasm
new file mode 100644
index 0000000..8725df1
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.spvasm
@@ -0,0 +1,61 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 37
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %local_invocation_index_1
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %local_invocation_index_1 "local_invocation_index_1"
+ OpName %S "S"
+ OpName %func_S_X "func_S_X"
+ OpName %pointer "pointer"
+ OpName %main_inner "main_inner"
+ OpName %local_invocation_index "local_invocation_index"
+ OpName %main "main"
+ OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+%_ptr_Workgroup_mat2v4float = OpTypePointer Workgroup %mat2v4float
+ %S = OpVariable %_ptr_Workgroup_mat2v4float Workgroup
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %9 = OpTypeFunction %v4float %_arr_uint_uint_1
+ %int = OpTypeInt 32 1
+ %16 = OpConstantNull %int
+%_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float
+ %void = OpTypeVoid
+ %21 = OpTypeFunction %void %uint
+ %26 = OpConstantNull %mat2v4float
+ %uint_2 = OpConstant %uint 2
+ %uint_264 = OpConstant %uint 264
+ %31 = OpConstantComposite %_arr_uint_uint_1 %uint_1
+ %32 = OpTypeFunction %void
+ %func_S_X = OpFunction %v4float None %9
+ %pointer = OpFunctionParameter %_arr_uint_uint_1
+ %14 = OpLabel
+ %17 = OpCompositeExtract %uint %pointer 0
+ %19 = OpAccessChain %_ptr_Workgroup_v4float %S %17
+ %20 = OpLoad %v4float %19
+ OpReturnValue %20
+ OpFunctionEnd
+ %main_inner = OpFunction %void None %21
+%local_invocation_index = OpFunctionParameter %uint
+ %25 = OpLabel
+ OpStore %S %26
+ OpControlBarrier %uint_2 %uint_2 %uint_264
+ %30 = OpFunctionCall %v4float %func_S_X %31
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %32
+ %34 = OpLabel
+ %36 = OpLoad %uint %local_invocation_index_1
+ %35 = OpFunctionCall %void %main_inner %36
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.wgsl
new file mode 100644
index 0000000..5f0f9ae
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> S : mat2x4<f32>;
+
+fn func(pointer : ptr<workgroup, vec4<f32>>) -> vec4<f32> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S[1]));
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl
new file mode 100644
index 0000000..5251b66
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<f32>,
+};
+
+var<workgroup> S : str;
+
+fn func(pointer : ptr<workgroup, vec4<f32>>) -> vec4<f32> {
+ return *pointer;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&S.i);
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5c05d92
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,28 @@
+struct str {
+ float4 i;
+};
+
+groupshared str S;
+
+float4 func_S_i() {
+ return S.i;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ const str tint_symbol_2 = (str)0;
+ S = tint_symbol_2;
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const float4 r = func_S_i();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..5c05d92
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+struct str {
+ float4 i;
+};
+
+groupshared str S;
+
+float4 func_S_i() {
+ return S.i;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ const str tint_symbol_2 = (str)0;
+ S = tint_symbol_2;
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const float4 r = func_S_i();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..863db2a
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl.expected.glsl
@@ -0,0 +1,25 @@
+#version 310 es
+
+struct str {
+ vec4 i;
+};
+
+shared str S;
+vec4 func_S_i() {
+ return S.i;
+}
+
+void tint_symbol(uint local_invocation_index) {
+ {
+ str tint_symbol_1 = str(vec4(0.0f));
+ S = tint_symbol_1;
+ }
+ barrier();
+ vec4 r = func_S_i();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol(gl_LocalInvocationIndex);
+ return;
+}
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..b8dd6d8
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl.expected.msl
@@ -0,0 +1,26 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct str {
+ float4 i;
+};
+
+float4 func(threadgroup float4* const pointer) {
+ return *(pointer);
+}
+
+void tint_symbol_inner(uint local_invocation_index, threadgroup str* const tint_symbol_2) {
+ {
+ str const tint_symbol_1 = str{};
+ *(tint_symbol_2) = tint_symbol_1;
+ }
+ threadgroup_barrier(mem_flags::mem_threadgroup);
+ float4 const r = func(&((*(tint_symbol_2)).i));
+}
+
+kernel void tint_symbol(uint local_invocation_index [[thread_index_in_threadgroup]]) {
+ threadgroup str tint_symbol_3;
+ tint_symbol_inner(local_invocation_index, &(tint_symbol_3));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..1323b99
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,56 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 31
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %local_invocation_index_1
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %local_invocation_index_1 "local_invocation_index_1"
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %S "S"
+ OpName %func_S_i "func_S_i"
+ OpName %main_inner "main_inner"
+ OpName %local_invocation_index "local_invocation_index"
+ OpName %main "main"
+ OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+ OpMemberDecorate %str 0 Offset 0
+ %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %str = OpTypeStruct %v4float
+%_ptr_Workgroup_str = OpTypePointer Workgroup %str
+ %S = OpVariable %_ptr_Workgroup_str Workgroup
+ %9 = OpTypeFunction %v4float
+ %uint_0 = OpConstant %uint 0
+%_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float
+ %void = OpTypeVoid
+ %16 = OpTypeFunction %void %uint
+ %21 = OpConstantNull %str
+ %uint_2 = OpConstant %uint 2
+ %uint_264 = OpConstant %uint 264
+ %26 = OpTypeFunction %void
+ %func_S_i = OpFunction %v4float None %9
+ %11 = OpLabel
+ %14 = OpAccessChain %_ptr_Workgroup_v4float %S %uint_0
+ %15 = OpLoad %v4float %14
+ OpReturnValue %15
+ OpFunctionEnd
+ %main_inner = OpFunction %void None %16
+%local_invocation_index = OpFunctionParameter %uint
+ %20 = OpLabel
+ OpStore %S %21
+ OpControlBarrier %uint_2 %uint_2 %uint_264
+ %25 = OpFunctionCall %v4float %func_S_i
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %26
+ %28 = OpLabel
+ %30 = OpLoad %uint %local_invocation_index_1
+ %29 = OpFunctionCall %void %main_inner %30
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..0d3e1d4
--- /dev/null
+++ b/test/tint/ptr_ref/load/param/workgroup/vec4_f32_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<f32>,
+}
+
+var<workgroup> S : str;
+
+fn func(pointer : ptr<workgroup, vec4<f32>>) -> vec4<f32> {
+ return *(pointer);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ let r = func(&(S.i));
+}
diff --git a/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl b/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl
new file mode 100644
index 0000000..c39eca4
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl
@@ -0,0 +1,15 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+};
+
+fn func(pointer : ptr<function, array<i32, 4>>) {
+ *pointer = array<i32, 4>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : str;
+ func(&F.arr);
+}
diff --git a/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ba0930f
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,15 @@
+struct str {
+ int arr[4];
+};
+
+void func(inout int pointer[4]) {
+ const int tint_symbol[4] = (int[4])0;
+ pointer = tint_symbol;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ str F = (str)0;
+ func(F.arr);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ba0930f
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,15 @@
+struct str {
+ int arr[4];
+};
+
+void func(inout int pointer[4]) {
+ const int tint_symbol[4] = (int[4])0;
+ pointer = tint_symbol;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ str F = (str)0;
+ func(F.arr);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..c171f12
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl.expected.glsl
@@ -0,0 +1,21 @@
+#version 310 es
+
+struct str {
+ int arr[4];
+};
+
+void func(inout int pointer[4]) {
+ int tint_symbol_1[4] = int[4](0, 0, 0, 0);
+ pointer = tint_symbol_1;
+}
+
+void tint_symbol() {
+ str F = str(int[4](0, 0, 0, 0));
+ func(F.arr);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..fb8a998
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl.expected.msl
@@ -0,0 +1,31 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+struct str {
+ tint_array<int, 4> arr;
+};
+
+void func(thread tint_array<int, 4>* const pointer) {
+ tint_array<int, 4> const tint_symbol_1 = tint_array<int, 4>{};
+ *(pointer) = tint_symbol_1;
+}
+
+kernel void tint_symbol() {
+ str F = {};
+ func(&(F.arr));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..a39fb3b
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,43 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 24
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %str "str"
+ OpMemberName %str 0 "arr"
+ OpName %func_F_arr "func_F_arr"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpName %F "F"
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %_arr_int_uint_4 ArrayStride 4
+ %void = OpTypeVoid
+ %int = OpTypeInt 32 1
+ %uint = OpTypeInt 32 0
+ %uint_4 = OpConstant %uint 4
+%_arr_int_uint_4 = OpTypeArray %int %uint_4
+ %str = OpTypeStruct %_arr_int_uint_4
+%_ptr_Function_str = OpTypePointer Function %str
+ %1 = OpTypeFunction %void %_ptr_Function_str
+ %uint_0 = OpConstant %uint 0
+%_ptr_Function__arr_int_uint_4 = OpTypePointer Function %_arr_int_uint_4
+ %16 = OpConstantNull %_arr_int_uint_4
+ %17 = OpTypeFunction %void
+ %21 = OpConstantNull %str
+ %func_F_arr = OpFunction %void None %1
+ %pointer = OpFunctionParameter %_ptr_Function_str
+ %11 = OpLabel
+ %15 = OpAccessChain %_ptr_Function__arr_int_uint_4 %pointer %uint_0
+ OpStore %15 %16
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %17
+ %19 = OpLabel
+ %F = OpVariable %_ptr_Function_str Function %21
+ %22 = OpFunctionCall %void %func_F_arr %F
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..f45fcae
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/array_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,15 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+}
+
+fn func(pointer : ptr<function, array<i32, 4>>) {
+ *(pointer) = array<i32, 4>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : str;
+ func(&(F.arr));
+}
diff --git a/test/tint/ptr_ref/store/param/function/i32.wgsl b/test/tint/ptr_ref/store/param/function/i32.wgsl
new file mode 100644
index 0000000..f64f384
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/i32.wgsl
@@ -0,0 +1,9 @@
+fn func(pointer : ptr<function, i32>) {
+ *pointer = 42;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : i32;
+ func(&F);
+}
diff --git a/test/tint/ptr_ref/store/param/function/i32.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/function/i32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..1b5ec00
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/i32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,10 @@
+void func(inout int pointer) {
+ pointer = 42;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ int F = 0;
+ func(F);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/i32.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/function/i32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..1b5ec00
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/i32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,10 @@
+void func(inout int pointer) {
+ pointer = 42;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ int F = 0;
+ func(F);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/i32.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/function/i32.wgsl.expected.glsl
new file mode 100644
index 0000000..88ce758
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/i32.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+void func(inout int pointer) {
+ pointer = 42;
+}
+
+void tint_symbol() {
+ int F = 0;
+ func(F);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/i32.wgsl.expected.msl b/test/tint/ptr_ref/store/param/function/i32.wgsl.expected.msl
new file mode 100644
index 0000000..39497aa
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/i32.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void func(thread int* const pointer) {
+ *(pointer) = 42;
+}
+
+kernel void tint_symbol() {
+ int F = 0;
+ func(&(F));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/function/i32.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/function/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..ed7174b
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/i32.wgsl.expected.spvasm
@@ -0,0 +1,32 @@
+; 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 %func "func"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpName %F "F"
+ %void = OpTypeVoid
+ %int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+ %1 = OpTypeFunction %void %_ptr_Function_int
+ %int_42 = OpConstant %int 42
+ %10 = OpTypeFunction %void
+ %14 = OpConstantNull %int
+ %func = OpFunction %void None %1
+ %pointer = OpFunctionParameter %_ptr_Function_int
+ %7 = OpLabel
+ OpStore %pointer %int_42
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %10
+ %12 = OpLabel
+ %F = OpVariable %_ptr_Function_int Function %14
+ %15 = OpFunctionCall %void %func %F
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/function/i32.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/function/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..de8ec37
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/i32.wgsl.expected.wgsl
@@ -0,0 +1,9 @@
+fn func(pointer : ptr<function, i32>) {
+ *(pointer) = 42;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : i32;
+ func(&(F));
+}
diff --git a/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl b/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl
new file mode 100644
index 0000000..971651c
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl
@@ -0,0 +1,15 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+fn func(pointer : ptr<function, i32>) {
+ *pointer = 42;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : str;
+ func(&F.i);
+}
diff --git a/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..701095e
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,14 @@
+struct str {
+ int i;
+};
+
+void func(inout int pointer) {
+ pointer = 42;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ str F = (str)0;
+ func(F.i);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..701095e
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,14 @@
+struct str {
+ int i;
+};
+
+void func(inout int pointer) {
+ pointer = 42;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ str F = (str)0;
+ func(F.i);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..d06a029
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+struct str {
+ int i;
+};
+
+void func(inout int pointer) {
+ pointer = 42;
+}
+
+void tint_symbol() {
+ str F = str(0);
+ func(F.i);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..e5bc71a
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct str {
+ int i;
+};
+
+void func(thread int* const pointer) {
+ *(pointer) = 42;
+}
+
+kernel void tint_symbol() {
+ str F = {};
+ func(&(F.i));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..3c5bb74
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,40 @@
+; 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 %str "str"
+ OpMemberName %str 0 "i"
+ OpName %func_F_i "func_F_i"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpName %F "F"
+ OpMemberDecorate %str 0 Offset 0
+ %void = OpTypeVoid
+ %int = OpTypeInt 32 1
+ %str = OpTypeStruct %int
+%_ptr_Function_str = OpTypePointer Function %str
+ %1 = OpTypeFunction %void %_ptr_Function_str
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Function_int = OpTypePointer Function %int
+ %int_42 = OpConstant %int 42
+ %15 = OpTypeFunction %void
+ %19 = OpConstantNull %str
+ %func_F_i = OpFunction %void None %1
+ %pointer = OpFunctionParameter %_ptr_Function_str
+ %8 = OpLabel
+ %13 = OpAccessChain %_ptr_Function_int %pointer %uint_0
+ OpStore %13 %int_42
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %15
+ %17 = OpLabel
+ %F = OpVariable %_ptr_Function_str Function %19
+ %20 = OpFunctionCall %void %func_F_i %F
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..3db8678
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/i32_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,15 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+fn func(pointer : ptr<function, i32>) {
+ *(pointer) = 42;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : str;
+ func(&(F.i));
+}
diff --git a/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl b/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl
new file mode 100644
index 0000000..631b70a
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl
@@ -0,0 +1,15 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+fn func(pointer : ptr<function, str>) {
+ *pointer = str();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : array<str, 4>;
+ func(&F[2]);
+}
diff --git a/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..13c0184
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl.expected.dxc.hlsl
@@ -0,0 +1,15 @@
+struct str {
+ int i;
+};
+
+void func(inout str pointer) {
+ const str tint_symbol = (str)0;
+ pointer = tint_symbol;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ str F[4] = (str[4])0;
+ func(F[2]);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..13c0184
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl.expected.fxc.hlsl
@@ -0,0 +1,15 @@
+struct str {
+ int i;
+};
+
+void func(inout str pointer) {
+ const str tint_symbol = (str)0;
+ pointer = tint_symbol;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ str F[4] = (str[4])0;
+ func(F[2]);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl.expected.glsl
new file mode 100644
index 0000000..88406352
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl.expected.glsl
@@ -0,0 +1,21 @@
+#version 310 es
+
+struct str {
+ int i;
+};
+
+void func(inout str pointer) {
+ str tint_symbol_1 = str(0);
+ pointer = tint_symbol_1;
+}
+
+void tint_symbol() {
+ str F[4] = str[4](str(0), str(0), str(0), str(0));
+ func(F[2]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl.expected.msl b/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl.expected.msl
new file mode 100644
index 0000000..1242b36
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl.expected.msl
@@ -0,0 +1,31 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+struct str {
+ int i;
+};
+
+void func(thread str* const pointer) {
+ str const tint_symbol_1 = str{};
+ *(pointer) = tint_symbol_1;
+}
+
+kernel void tint_symbol() {
+ tint_array<str, 4> F = {};
+ func(&(F[2]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl.expected.spvasm
new file mode 100644
index 0000000..11f5024
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl.expected.spvasm
@@ -0,0 +1,51 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 30
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %func_F_X "func_F_X"
+ OpName %pointer_base "pointer_base"
+ OpName %pointer_indices "pointer_indices"
+ OpName %main "main"
+ OpName %F "F"
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %_arr_str_uint_4 ArrayStride 4
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %void = OpTypeVoid
+ %int = OpTypeInt 32 1
+ %str = OpTypeStruct %int
+ %uint = OpTypeInt 32 0
+ %uint_4 = OpConstant %uint 4
+%_arr_str_uint_4 = OpTypeArray %str %uint_4
+%_ptr_Function__arr_str_uint_4 = OpTypePointer Function %_arr_str_uint_4
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %1 = OpTypeFunction %void %_ptr_Function__arr_str_uint_4 %_arr_uint_uint_1
+ %16 = OpConstantNull %int
+%_ptr_Function_str = OpTypePointer Function %str
+ %20 = OpConstantNull %str
+ %21 = OpTypeFunction %void
+ %25 = OpConstantNull %_arr_str_uint_4
+ %uint_2 = OpConstant %uint 2
+ %29 = OpConstantComposite %_arr_uint_uint_1 %uint_2
+ %func_F_X = OpFunction %void None %1
+%pointer_base = OpFunctionParameter %_ptr_Function__arr_str_uint_4
+%pointer_indices = OpFunctionParameter %_arr_uint_uint_1
+ %14 = OpLabel
+ %17 = OpCompositeExtract %uint %pointer_indices 0
+ %19 = OpAccessChain %_ptr_Function_str %pointer_base %17
+ OpStore %19 %20
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %21
+ %23 = OpLabel
+ %F = OpVariable %_ptr_Function__arr_str_uint_4 Function %25
+ %26 = OpFunctionCall %void %func_F_X %F %29
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl.expected.wgsl
new file mode 100644
index 0000000..fe15aa5
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/struct_in_array.wgsl.expected.wgsl
@@ -0,0 +1,15 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+fn func(pointer : ptr<function, str>) {
+ *(pointer) = str();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : array<str, 4>;
+ func(&(F[2]));
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl b/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl
new file mode 100644
index 0000000..3108042
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl
@@ -0,0 +1,11 @@
+enable chromium_experimental_full_ptr_parameters;
+
+fn func(pointer : ptr<function, vec2<f32>>) {
+ *pointer = vec2<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : mat2x2<f32>;
+ func(&F[1]);
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e19db34
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl
@@ -0,0 +1,10 @@
+void func(inout float2 pointer) {
+ pointer = (0.0f).xx;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ float2x2 F = float2x2(0.0f, 0.0f, 0.0f, 0.0f);
+ func(F[1]);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e19db34
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl
@@ -0,0 +1,10 @@
+void func(inout float2 pointer) {
+ pointer = (0.0f).xx;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ float2x2 F = float2x2(0.0f, 0.0f, 0.0f, 0.0f);
+ func(F[1]);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl.expected.glsl
new file mode 100644
index 0000000..947ecd6
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+void func(inout vec2 pointer) {
+ pointer = vec2(0.0f);
+}
+
+void tint_symbol() {
+ mat2 F = mat2(0.0f, 0.0f, 0.0f, 0.0f);
+ func(F[1]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl.expected.msl b/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl.expected.msl
new file mode 100644
index 0000000..f8f7aed
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void func(thread float2* const pointer) {
+ *(pointer) = float2(0.0f);
+}
+
+kernel void tint_symbol() {
+ float2x2 F = float2x2(0.0f);
+ func(&(F[1]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl.expected.spvasm
new file mode 100644
index 0000000..a8de55d
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl.expected.spvasm
@@ -0,0 +1,46 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 29
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %func_F_X "func_F_X"
+ OpName %pointer_base "pointer_base"
+ OpName %pointer_indices "pointer_indices"
+ OpName %main "main"
+ OpName %F "F"
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %void = OpTypeVoid
+ %float = OpTypeFloat 32
+ %v2float = OpTypeVector %float 2
+%mat2v2float = OpTypeMatrix %v2float 2
+%_ptr_Function_mat2v2float = OpTypePointer Function %mat2v2float
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %1 = OpTypeFunction %void %_ptr_Function_mat2v2float %_arr_uint_uint_1
+ %int = OpTypeInt 32 1
+ %16 = OpConstantNull %int
+%_ptr_Function_v2float = OpTypePointer Function %v2float
+ %20 = OpConstantNull %v2float
+ %21 = OpTypeFunction %void
+ %25 = OpConstantNull %mat2v2float
+ %28 = OpConstantComposite %_arr_uint_uint_1 %uint_1
+ %func_F_X = OpFunction %void None %1
+%pointer_base = OpFunctionParameter %_ptr_Function_mat2v2float
+%pointer_indices = OpFunctionParameter %_arr_uint_uint_1
+ %13 = OpLabel
+ %17 = OpCompositeExtract %uint %pointer_indices 0
+ %19 = OpAccessChain %_ptr_Function_v2float %pointer_base %17
+ OpStore %19 %20
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %21
+ %23 = OpLabel
+ %F = OpVariable %_ptr_Function_mat2v2float Function %25
+ %26 = OpFunctionCall %void %func_F_X %F %28
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl.expected.wgsl
new file mode 100644
index 0000000..a8dca7e
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec2_f32_in_mat2x2.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+enable chromium_experimental_full_ptr_parameters;
+
+fn func(pointer : ptr<function, vec2<f32>>) {
+ *(pointer) = vec2<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : mat2x2<f32>;
+ func(&(F[1]));
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl b/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl
new file mode 100644
index 0000000..3055a86
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl
@@ -0,0 +1,9 @@
+fn func(pointer : ptr<function, vec4<f32>>) {
+ *pointer = vec4<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : vec4<f32>;
+ func(&F);
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..74c4735
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,10 @@
+void func(inout float4 pointer) {
+ pointer = (0.0f).xxxx;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ float4 F = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ func(F);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..74c4735
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,10 @@
+void func(inout float4 pointer) {
+ pointer = (0.0f).xxxx;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ float4 F = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ func(F);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..6c2db02
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+void func(inout vec4 pointer) {
+ pointer = vec4(0.0f);
+}
+
+void tint_symbol() {
+ vec4 F = vec4(0.0f, 0.0f, 0.0f, 0.0f);
+ func(F);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl.expected.msl b/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl.expected.msl
new file mode 100644
index 0000000..e90fddf
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void func(thread float4* const pointer) {
+ *(pointer) = float4(0.0f);
+}
+
+kernel void tint_symbol() {
+ float4 F = 0.0f;
+ func(&(F));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..c6e3a08
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl.expected.spvasm
@@ -0,0 +1,32 @@
+; 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 %func "func"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpName %F "F"
+ %void = OpTypeVoid
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+ %1 = OpTypeFunction %void %_ptr_Function_v4float
+ %10 = OpConstantNull %v4float
+ %11 = OpTypeFunction %void
+ %func = OpFunction %void None %1
+ %pointer = OpFunctionParameter %_ptr_Function_v4float
+ %8 = OpLabel
+ OpStore %pointer %10
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %11
+ %13 = OpLabel
+ %F = OpVariable %_ptr_Function_v4float Function %10
+ %15 = OpFunctionCall %void %func %F
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..5e861d0
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32.wgsl.expected.wgsl
@@ -0,0 +1,9 @@
+fn func(pointer : ptr<function, vec4<f32>>) {
+ *(pointer) = vec4<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : vec4<f32>;
+ func(&(F));
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl b/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl
new file mode 100644
index 0000000..b71ee41
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl
@@ -0,0 +1,11 @@
+enable chromium_experimental_full_ptr_parameters;
+
+fn func(pointer : ptr<function, vec4<f32>>) {
+ *pointer = vec4<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : mat2x4<f32>;
+ func(&F[1]);
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c071e39
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl
@@ -0,0 +1,10 @@
+void func(inout float4 pointer) {
+ pointer = (0.0f).xxxx;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ float2x4 F = float2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+ func(F[1]);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c071e39
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl
@@ -0,0 +1,10 @@
+void func(inout float4 pointer) {
+ pointer = (0.0f).xxxx;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ float2x4 F = float2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+ func(F[1]);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl.expected.glsl
new file mode 100644
index 0000000..0f200b2
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+void func(inout vec4 pointer) {
+ pointer = vec4(0.0f);
+}
+
+void tint_symbol() {
+ mat2x4 F = mat2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+ func(F[1]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl.expected.msl b/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl.expected.msl
new file mode 100644
index 0000000..ecd2c7d
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void func(thread float4* const pointer) {
+ *(pointer) = float4(0.0f);
+}
+
+kernel void tint_symbol() {
+ float2x4 F = float2x4(0.0f);
+ func(&(F[1]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl.expected.spvasm
new file mode 100644
index 0000000..9daa630
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl.expected.spvasm
@@ -0,0 +1,46 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 29
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %func_F_X "func_F_X"
+ OpName %pointer_base "pointer_base"
+ OpName %pointer_indices "pointer_indices"
+ OpName %main "main"
+ OpName %F "F"
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %void = OpTypeVoid
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+%_ptr_Function_mat2v4float = OpTypePointer Function %mat2v4float
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %1 = OpTypeFunction %void %_ptr_Function_mat2v4float %_arr_uint_uint_1
+ %int = OpTypeInt 32 1
+ %16 = OpConstantNull %int
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+ %20 = OpConstantNull %v4float
+ %21 = OpTypeFunction %void
+ %25 = OpConstantNull %mat2v4float
+ %28 = OpConstantComposite %_arr_uint_uint_1 %uint_1
+ %func_F_X = OpFunction %void None %1
+%pointer_base = OpFunctionParameter %_ptr_Function_mat2v4float
+%pointer_indices = OpFunctionParameter %_arr_uint_uint_1
+ %13 = OpLabel
+ %17 = OpCompositeExtract %uint %pointer_indices 0
+ %19 = OpAccessChain %_ptr_Function_v4float %pointer_base %17
+ OpStore %19 %20
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %21
+ %23 = OpLabel
+ %F = OpVariable %_ptr_Function_mat2v4float Function %25
+ %26 = OpFunctionCall %void %func_F_X %F %28
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl.expected.wgsl
new file mode 100644
index 0000000..590aa4f
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32_in_mat2x4.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+enable chromium_experimental_full_ptr_parameters;
+
+fn func(pointer : ptr<function, vec4<f32>>) {
+ *(pointer) = vec4<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : mat2x4<f32>;
+ func(&(F[1]));
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl b/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl
new file mode 100644
index 0000000..9351165
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl
@@ -0,0 +1,15 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<f32>,
+};
+
+fn func(pointer : ptr<function, vec4<f32>>) {
+ *pointer = vec4<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : str;
+ func(&F.i);
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0e8b13b
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,14 @@
+struct str {
+ float4 i;
+};
+
+void func(inout float4 pointer) {
+ pointer = (0.0f).xxxx;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ str F = (str)0;
+ func(F.i);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..0e8b13b
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,14 @@
+struct str {
+ float4 i;
+};
+
+void func(inout float4 pointer) {
+ pointer = (0.0f).xxxx;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ str F = (str)0;
+ func(F.i);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..f56072d
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+struct str {
+ vec4 i;
+};
+
+void func(inout vec4 pointer) {
+ pointer = vec4(0.0f);
+}
+
+void tint_symbol() {
+ str F = str(vec4(0.0f, 0.0f, 0.0f, 0.0f));
+ func(F.i);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..b67035e
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct str {
+ float4 i;
+};
+
+void func(thread float4* const pointer) {
+ *(pointer) = float4(0.0f);
+}
+
+kernel void tint_symbol() {
+ str F = {};
+ func(&(F.i));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..19f521c
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,41 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 23
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %func_F_i "func_F_i"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpName %F "F"
+ OpMemberDecorate %str 0 Offset 0
+ %void = OpTypeVoid
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %str = OpTypeStruct %v4float
+%_ptr_Function_str = OpTypePointer Function %str
+ %1 = OpTypeFunction %void %_ptr_Function_str
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+ %15 = OpConstantNull %v4float
+ %16 = OpTypeFunction %void
+ %20 = OpConstantNull %str
+ %func_F_i = OpFunction %void None %1
+ %pointer = OpFunctionParameter %_ptr_Function_str
+ %9 = OpLabel
+ %14 = OpAccessChain %_ptr_Function_v4float %pointer %uint_0
+ OpStore %14 %15
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %16
+ %18 = OpLabel
+ %F = OpVariable %_ptr_Function_str Function %20
+ %21 = OpFunctionCall %void %func_F_i %F
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..cf878a0
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/function/vec4_f32_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,15 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<f32>,
+}
+
+fn func(pointer : ptr<function, vec4<f32>>) {
+ *(pointer) = vec4<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var F : str;
+ func(&(F.i));
+}
diff --git a/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl b/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl
new file mode 100644
index 0000000..0d7c2d8
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+};
+
+fn func(pointer : ptr<private, array<i32, 4>>) {
+ *pointer = array<i32, 4>();
+}
+
+var<private> P : str;
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&P.arr);
+}
diff --git a/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c6c407b
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,16 @@
+struct str {
+ int arr[4];
+};
+
+void func(inout int pointer[4]) {
+ const int tint_symbol[4] = (int[4])0;
+ pointer = tint_symbol;
+}
+
+static str P = (str)0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ func(P.arr);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c6c407b
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,16 @@
+struct str {
+ int arr[4];
+};
+
+void func(inout int pointer[4]) {
+ const int tint_symbol[4] = (int[4])0;
+ pointer = tint_symbol;
+}
+
+static str P = (str)0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ func(P.arr);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..2b10ffb
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl.expected.glsl
@@ -0,0 +1,21 @@
+#version 310 es
+
+struct str {
+ int arr[4];
+};
+
+void func(inout int pointer[4]) {
+ int tint_symbol_1[4] = int[4](0, 0, 0, 0);
+ pointer = tint_symbol_1;
+}
+
+str P = str(int[4](0, 0, 0, 0));
+void tint_symbol() {
+ func(P.arr);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..fbc443b
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl.expected.msl
@@ -0,0 +1,31 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+struct str {
+ tint_array<int, 4> arr;
+};
+
+void func(thread tint_array<int, 4>* const pointer) {
+ tint_array<int, 4> const tint_symbol_1 = tint_array<int, 4>{};
+ *(pointer) = tint_symbol_1;
+}
+
+kernel void tint_symbol() {
+ thread str tint_symbol_2 = {};
+ func(&(tint_symbol_2.arr));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..c2762ee
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,43 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 24
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %str "str"
+ OpMemberName %str 0 "arr"
+ OpName %P "P"
+ OpName %func_F_arr "func_F_arr"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %_arr_int_uint_4 ArrayStride 4
+ %int = OpTypeInt 32 1
+ %uint = OpTypeInt 32 0
+ %uint_4 = OpConstant %uint 4
+%_arr_int_uint_4 = OpTypeArray %int %uint_4
+ %str = OpTypeStruct %_arr_int_uint_4
+%_ptr_Private_str = OpTypePointer Private %str
+ %8 = OpConstantNull %str
+ %P = OpVariable %_ptr_Private_str Private %8
+ %void = OpTypeVoid
+ %9 = OpTypeFunction %void %_ptr_Private_str
+ %uint_0 = OpConstant %uint 0
+%_ptr_Private__arr_int_uint_4 = OpTypePointer Private %_arr_int_uint_4
+ %18 = OpConstantNull %_arr_int_uint_4
+ %19 = OpTypeFunction %void
+ %func_F_arr = OpFunction %void None %9
+ %pointer = OpFunctionParameter %_ptr_Private_str
+ %13 = OpLabel
+ %17 = OpAccessChain %_ptr_Private__arr_int_uint_4 %pointer %uint_0
+ OpStore %17 %18
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %19
+ %21 = OpLabel
+ %22 = OpFunctionCall %void %func_F_arr %P
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..99958c7
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/array_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+}
+
+fn func(pointer : ptr<private, array<i32, 4>>) {
+ *(pointer) = array<i32, 4>();
+}
+
+var<private> P : str;
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(P.arr));
+}
diff --git a/test/tint/ptr_ref/store/param/private/i32.wgsl b/test/tint/ptr_ref/store/param/private/i32.wgsl
new file mode 100644
index 0000000..aad045c
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/i32.wgsl
@@ -0,0 +1,10 @@
+fn func(pointer : ptr<private, i32>) {
+ *pointer = 42;
+}
+
+var<private> P : i32;
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&P);
+}
diff --git a/test/tint/ptr_ref/store/param/private/i32.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/private/i32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..9085c4b
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/i32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,11 @@
+void func(inout int pointer) {
+ pointer = 42;
+}
+
+static int P = 0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ func(P);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/i32.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/private/i32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..9085c4b
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/i32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,11 @@
+void func(inout int pointer) {
+ pointer = 42;
+}
+
+static int P = 0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ func(P);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/i32.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/private/i32.wgsl.expected.glsl
new file mode 100644
index 0000000..2c29881
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/i32.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+void func(inout int pointer) {
+ pointer = 42;
+}
+
+int P = 0;
+void tint_symbol() {
+ func(P);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/i32.wgsl.expected.msl b/test/tint/ptr_ref/store/param/private/i32.wgsl.expected.msl
new file mode 100644
index 0000000..ead132a
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/i32.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void func(thread int* const pointer) {
+ *(pointer) = 42;
+}
+
+kernel void tint_symbol() {
+ thread int tint_symbol_1 = 0;
+ func(&(tint_symbol_1));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/private/i32.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/private/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..867f836
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/i32.wgsl.expected.spvasm
@@ -0,0 +1,32 @@
+; 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 %P "P"
+ OpName %func "func"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ %int = OpTypeInt 32 1
+%_ptr_Private_int = OpTypePointer Private %int
+ %4 = OpConstantNull %int
+ %P = OpVariable %_ptr_Private_int Private %4
+ %void = OpTypeVoid
+ %5 = OpTypeFunction %void %_ptr_Private_int
+ %int_42 = OpConstant %int 42
+ %12 = OpTypeFunction %void
+ %func = OpFunction %void None %5
+ %pointer = OpFunctionParameter %_ptr_Private_int
+ %9 = OpLabel
+ OpStore %pointer %int_42
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %12
+ %14 = OpLabel
+ %15 = OpFunctionCall %void %func %P
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/private/i32.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/private/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..fded040
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/i32.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+fn func(pointer : ptr<private, i32>) {
+ *(pointer) = 42;
+}
+
+var<private> P : i32;
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(P));
+}
diff --git a/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl b/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl
new file mode 100644
index 0000000..2238584
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+fn func(pointer : ptr<private, i32>) {
+ *pointer = 42;
+}
+
+var<private> P : str;
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&P.i);
+}
diff --git a/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..87c1651
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,15 @@
+struct str {
+ int i;
+};
+
+void func(inout int pointer) {
+ pointer = 42;
+}
+
+static str P = (str)0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ func(P.i);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..87c1651
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,15 @@
+struct str {
+ int i;
+};
+
+void func(inout int pointer) {
+ pointer = 42;
+}
+
+static str P = (str)0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ func(P.i);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..0934fe1
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+struct str {
+ int i;
+};
+
+void func(inout int pointer) {
+ pointer = 42;
+}
+
+str P = str(0);
+void tint_symbol() {
+ func(P.i);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..bcc4591
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct str {
+ int i;
+};
+
+void func(thread int* const pointer) {
+ *(pointer) = 42;
+}
+
+kernel void tint_symbol() {
+ thread str tint_symbol_1 = {};
+ func(&(tint_symbol_1.i));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..cc49222
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,40 @@
+; 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 %str "str"
+ OpMemberName %str 0 "i"
+ OpName %P "P"
+ OpName %func_F_i "func_F_i"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpMemberDecorate %str 0 Offset 0
+ %int = OpTypeInt 32 1
+ %str = OpTypeStruct %int
+%_ptr_Private_str = OpTypePointer Private %str
+ %5 = OpConstantNull %str
+ %P = OpVariable %_ptr_Private_str Private %5
+ %void = OpTypeVoid
+ %6 = OpTypeFunction %void %_ptr_Private_str
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Private_int = OpTypePointer Private %int
+ %int_42 = OpConstant %int 42
+ %17 = OpTypeFunction %void
+ %func_F_i = OpFunction %void None %6
+ %pointer = OpFunctionParameter %_ptr_Private_str
+ %10 = OpLabel
+ %15 = OpAccessChain %_ptr_Private_int %pointer %uint_0
+ OpStore %15 %int_42
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %17
+ %19 = OpLabel
+ %20 = OpFunctionCall %void %func_F_i %P
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..7052c23
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/i32_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+fn func(pointer : ptr<private, i32>) {
+ *(pointer) = 42;
+}
+
+var<private> P : str;
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(P.i));
+}
diff --git a/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl b/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl
new file mode 100644
index 0000000..2a9d4cd
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+fn func(pointer : ptr<private, str>) {
+ *pointer = str();
+}
+
+var<private> P : array<str, 4>;
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&P[2]);
+}
diff --git a/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ecc8458
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl.expected.dxc.hlsl
@@ -0,0 +1,16 @@
+struct str {
+ int i;
+};
+
+void func(inout str pointer) {
+ const str tint_symbol = (str)0;
+ pointer = tint_symbol;
+}
+
+static str P[4] = (str[4])0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ func(P[2]);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ecc8458
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl.expected.fxc.hlsl
@@ -0,0 +1,16 @@
+struct str {
+ int i;
+};
+
+void func(inout str pointer) {
+ const str tint_symbol = (str)0;
+ pointer = tint_symbol;
+}
+
+static str P[4] = (str[4])0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ func(P[2]);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl.expected.glsl
new file mode 100644
index 0000000..1791ced
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl.expected.glsl
@@ -0,0 +1,21 @@
+#version 310 es
+
+struct str {
+ int i;
+};
+
+void func(inout str pointer) {
+ str tint_symbol_1 = str(0);
+ pointer = tint_symbol_1;
+}
+
+str P[4] = str[4](str(0), str(0), str(0), str(0));
+void tint_symbol() {
+ func(P[2]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl.expected.msl b/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl.expected.msl
new file mode 100644
index 0000000..d0f273b
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl.expected.msl
@@ -0,0 +1,31 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+struct str {
+ int i;
+};
+
+void func(thread str* const pointer) {
+ str const tint_symbol_1 = str{};
+ *(pointer) = tint_symbol_1;
+}
+
+kernel void tint_symbol() {
+ thread tint_array<str, 4> tint_symbol_2 = {};
+ func(&(tint_symbol_2[2]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl.expected.spvasm
new file mode 100644
index 0000000..c502970
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl.expected.spvasm
@@ -0,0 +1,51 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 30
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %P "P"
+ OpName %func_F_X "func_F_X"
+ OpName %pointer_base "pointer_base"
+ OpName %pointer_indices "pointer_indices"
+ OpName %main "main"
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %_arr_str_uint_4 ArrayStride 4
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %int = OpTypeInt 32 1
+ %str = OpTypeStruct %int
+ %uint = OpTypeInt 32 0
+ %uint_4 = OpConstant %uint 4
+%_arr_str_uint_4 = OpTypeArray %str %uint_4
+%_ptr_Private__arr_str_uint_4 = OpTypePointer Private %_arr_str_uint_4
+ %8 = OpConstantNull %_arr_str_uint_4
+ %P = OpVariable %_ptr_Private__arr_str_uint_4 Private %8
+ %void = OpTypeVoid
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %9 = OpTypeFunction %void %_ptr_Private__arr_str_uint_4 %_arr_uint_uint_1
+ %18 = OpConstantNull %int
+%_ptr_Private_str = OpTypePointer Private %str
+ %22 = OpConstantNull %str
+ %23 = OpTypeFunction %void
+ %uint_2 = OpConstant %uint 2
+ %29 = OpConstantComposite %_arr_uint_uint_1 %uint_2
+ %func_F_X = OpFunction %void None %9
+%pointer_base = OpFunctionParameter %_ptr_Private__arr_str_uint_4
+%pointer_indices = OpFunctionParameter %_arr_uint_uint_1
+ %16 = OpLabel
+ %19 = OpCompositeExtract %uint %pointer_indices 0
+ %21 = OpAccessChain %_ptr_Private_str %pointer_base %19
+ OpStore %21 %22
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %23
+ %25 = OpLabel
+ %26 = OpFunctionCall %void %func_F_X %P %29
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl.expected.wgsl
new file mode 100644
index 0000000..3c97892
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/struct_in_array.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+fn func(pointer : ptr<private, str>) {
+ *(pointer) = str();
+}
+
+var<private> P : array<str, 4>;
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(P[2]));
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl b/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl
new file mode 100644
index 0000000..012a14d
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+fn func(pointer : ptr<private, vec2<f32>>) {
+ *pointer = vec2<f32>();
+}
+
+var<private> P : mat2x2<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&P[1]);
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..6c9b6fc
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl
@@ -0,0 +1,11 @@
+void func(inout float2 pointer) {
+ pointer = (0.0f).xx;
+}
+
+static float2x2 P = float2x2(0.0f, 0.0f, 0.0f, 0.0f);
+
+[numthreads(1, 1, 1)]
+void main() {
+ func(P[1]);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..6c9b6fc
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl
@@ -0,0 +1,11 @@
+void func(inout float2 pointer) {
+ pointer = (0.0f).xx;
+}
+
+static float2x2 P = float2x2(0.0f, 0.0f, 0.0f, 0.0f);
+
+[numthreads(1, 1, 1)]
+void main() {
+ func(P[1]);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl.expected.glsl
new file mode 100644
index 0000000..ea4cba1
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+void func(inout vec2 pointer) {
+ pointer = vec2(0.0f);
+}
+
+mat2 P = mat2(0.0f, 0.0f, 0.0f, 0.0f);
+void tint_symbol() {
+ func(P[1]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl.expected.msl b/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl.expected.msl
new file mode 100644
index 0000000..5ba30955
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void func(thread float2* const pointer) {
+ *(pointer) = float2(0.0f);
+}
+
+kernel void tint_symbol() {
+ thread float2x2 tint_symbol_1 = float2x2(0.0f);
+ func(&(tint_symbol_1[1]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl.expected.spvasm
new file mode 100644
index 0000000..46d241c
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl.expected.spvasm
@@ -0,0 +1,46 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 29
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %P "P"
+ OpName %func_F_X "func_F_X"
+ OpName %pointer_base "pointer_base"
+ OpName %pointer_indices "pointer_indices"
+ OpName %main "main"
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %float = OpTypeFloat 32
+ %v2float = OpTypeVector %float 2
+%mat2v2float = OpTypeMatrix %v2float 2
+%_ptr_Private_mat2v2float = OpTypePointer Private %mat2v2float
+ %6 = OpConstantNull %mat2v2float
+ %P = OpVariable %_ptr_Private_mat2v2float Private %6
+ %void = OpTypeVoid
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %7 = OpTypeFunction %void %_ptr_Private_mat2v2float %_arr_uint_uint_1
+ %int = OpTypeInt 32 1
+ %18 = OpConstantNull %int
+%_ptr_Private_v2float = OpTypePointer Private %v2float
+ %22 = OpConstantNull %v2float
+ %23 = OpTypeFunction %void
+ %28 = OpConstantComposite %_arr_uint_uint_1 %uint_1
+ %func_F_X = OpFunction %void None %7
+%pointer_base = OpFunctionParameter %_ptr_Private_mat2v2float
+%pointer_indices = OpFunctionParameter %_arr_uint_uint_1
+ %15 = OpLabel
+ %19 = OpCompositeExtract %uint %pointer_indices 0
+ %21 = OpAccessChain %_ptr_Private_v2float %pointer_base %19
+ OpStore %21 %22
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %23
+ %25 = OpLabel
+ %26 = OpFunctionCall %void %func_F_X %P %28
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl.expected.wgsl
new file mode 100644
index 0000000..fe087a1
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec2_f32_in_mat2x2.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+fn func(pointer : ptr<private, vec2<f32>>) {
+ *(pointer) = vec2<f32>();
+}
+
+var<private> P : mat2x2<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(P[1]));
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl b/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl
new file mode 100644
index 0000000..5097807
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl
@@ -0,0 +1,10 @@
+fn func(pointer : ptr<private, vec4<f32>>) {
+ *pointer = vec4<f32>();
+}
+
+var<private> P : vec4<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&P);
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..7e68214
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,11 @@
+void func(inout float4 pointer) {
+ pointer = (0.0f).xxxx;
+}
+
+static float4 P = float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+[numthreads(1, 1, 1)]
+void main() {
+ func(P);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7e68214
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,11 @@
+void func(inout float4 pointer) {
+ pointer = (0.0f).xxxx;
+}
+
+static float4 P = float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+[numthreads(1, 1, 1)]
+void main() {
+ func(P);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..a92e4e0
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+void func(inout vec4 pointer) {
+ pointer = vec4(0.0f);
+}
+
+vec4 P = vec4(0.0f, 0.0f, 0.0f, 0.0f);
+void tint_symbol() {
+ func(P);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl.expected.msl b/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl.expected.msl
new file mode 100644
index 0000000..1f3faf7
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void func(thread float4* const pointer) {
+ *(pointer) = float4(0.0f);
+}
+
+kernel void tint_symbol() {
+ thread float4 tint_symbol_1 = 0.0f;
+ func(&(tint_symbol_1));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..334b687
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl.expected.spvasm
@@ -0,0 +1,32 @@
+; 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 %P "P"
+ OpName %func "func"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%_ptr_Private_v4float = OpTypePointer Private %v4float
+ %5 = OpConstantNull %v4float
+ %P = OpVariable %_ptr_Private_v4float Private %5
+ %void = OpTypeVoid
+ %6 = OpTypeFunction %void %_ptr_Private_v4float
+ %12 = OpTypeFunction %void
+ %func = OpFunction %void None %6
+ %pointer = OpFunctionParameter %_ptr_Private_v4float
+ %10 = OpLabel
+ OpStore %pointer %5
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %12
+ %14 = OpLabel
+ %15 = OpFunctionCall %void %func %P
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..328a6b7
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+fn func(pointer : ptr<private, vec4<f32>>) {
+ *(pointer) = vec4<f32>();
+}
+
+var<private> P : vec4<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(P));
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl b/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl
new file mode 100644
index 0000000..14e4bfa
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+fn func(pointer : ptr<private, vec4<f32>>) {
+ *pointer = vec4<f32>();
+}
+
+var<private> P : mat2x4<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&P[1]);
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..dcc5bde
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl
@@ -0,0 +1,11 @@
+void func(inout float4 pointer) {
+ pointer = (0.0f).xxxx;
+}
+
+static float2x4 P = float2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+
+[numthreads(1, 1, 1)]
+void main() {
+ func(P[1]);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..dcc5bde
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl
@@ -0,0 +1,11 @@
+void func(inout float4 pointer) {
+ pointer = (0.0f).xxxx;
+}
+
+static float2x4 P = float2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+
+[numthreads(1, 1, 1)]
+void main() {
+ func(P[1]);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl.expected.glsl
new file mode 100644
index 0000000..e231815
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+void func(inout vec4 pointer) {
+ pointer = vec4(0.0f);
+}
+
+mat2x4 P = mat2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+void tint_symbol() {
+ func(P[1]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl.expected.msl b/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl.expected.msl
new file mode 100644
index 0000000..cbc5a43
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void func(thread float4* const pointer) {
+ *(pointer) = float4(0.0f);
+}
+
+kernel void tint_symbol() {
+ thread float2x4 tint_symbol_1 = float2x4(0.0f);
+ func(&(tint_symbol_1[1]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl.expected.spvasm
new file mode 100644
index 0000000..278d725
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl.expected.spvasm
@@ -0,0 +1,46 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 29
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %P "P"
+ OpName %func_F_X "func_F_X"
+ OpName %pointer_base "pointer_base"
+ OpName %pointer_indices "pointer_indices"
+ OpName %main "main"
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+%_ptr_Private_mat2v4float = OpTypePointer Private %mat2v4float
+ %6 = OpConstantNull %mat2v4float
+ %P = OpVariable %_ptr_Private_mat2v4float Private %6
+ %void = OpTypeVoid
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %7 = OpTypeFunction %void %_ptr_Private_mat2v4float %_arr_uint_uint_1
+ %int = OpTypeInt 32 1
+ %18 = OpConstantNull %int
+%_ptr_Private_v4float = OpTypePointer Private %v4float
+ %22 = OpConstantNull %v4float
+ %23 = OpTypeFunction %void
+ %28 = OpConstantComposite %_arr_uint_uint_1 %uint_1
+ %func_F_X = OpFunction %void None %7
+%pointer_base = OpFunctionParameter %_ptr_Private_mat2v4float
+%pointer_indices = OpFunctionParameter %_arr_uint_uint_1
+ %15 = OpLabel
+ %19 = OpCompositeExtract %uint %pointer_indices 0
+ %21 = OpAccessChain %_ptr_Private_v4float %pointer_base %19
+ OpStore %21 %22
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %23
+ %25 = OpLabel
+ %26 = OpFunctionCall %void %func_F_X %P %28
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl.expected.wgsl
new file mode 100644
index 0000000..3ba72c6
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32_in_mat2x4.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+fn func(pointer : ptr<private, vec4<f32>>) {
+ *(pointer) = vec4<f32>();
+}
+
+var<private> P : mat2x4<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(P[1]));
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl b/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl
new file mode 100644
index 0000000..bdc5cbc
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<f32>,
+};
+
+fn func(pointer : ptr<private, vec4<f32>>) {
+ *pointer = vec4<f32>();
+}
+
+var<private> P : str;
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&P.i);
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..221d08a
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,15 @@
+struct str {
+ float4 i;
+};
+
+void func(inout float4 pointer) {
+ pointer = (0.0f).xxxx;
+}
+
+static str P = (str)0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ func(P.i);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..221d08a
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,15 @@
+struct str {
+ float4 i;
+};
+
+void func(inout float4 pointer) {
+ pointer = (0.0f).xxxx;
+}
+
+static str P = (str)0;
+
+[numthreads(1, 1, 1)]
+void main() {
+ func(P.i);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..afea0f0
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+struct str {
+ vec4 i;
+};
+
+void func(inout vec4 pointer) {
+ pointer = vec4(0.0f);
+}
+
+str P = str(vec4(0.0f, 0.0f, 0.0f, 0.0f));
+void tint_symbol() {
+ func(P.i);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..3185a65
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct str {
+ float4 i;
+};
+
+void func(thread float4* const pointer) {
+ *(pointer) = float4(0.0f);
+}
+
+kernel void tint_symbol() {
+ thread str tint_symbol_1 = {};
+ func(&(tint_symbol_1.i));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..5f41d63
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,41 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 23
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %P "P"
+ OpName %func_F_i "func_F_i"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpMemberDecorate %str 0 Offset 0
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %str = OpTypeStruct %v4float
+%_ptr_Private_str = OpTypePointer Private %str
+ %6 = OpConstantNull %str
+ %P = OpVariable %_ptr_Private_str Private %6
+ %void = OpTypeVoid
+ %7 = OpTypeFunction %void %_ptr_Private_str
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Private_v4float = OpTypePointer Private %v4float
+ %17 = OpConstantNull %v4float
+ %18 = OpTypeFunction %void
+ %func_F_i = OpFunction %void None %7
+ %pointer = OpFunctionParameter %_ptr_Private_str
+ %11 = OpLabel
+ %16 = OpAccessChain %_ptr_Private_v4float %pointer %uint_0
+ OpStore %16 %17
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %18
+ %20 = OpLabel
+ %21 = OpFunctionCall %void %func_F_i %P
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..d4c15e1
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/private/vec4_f32_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<f32>,
+}
+
+fn func(pointer : ptr<private, vec4<f32>>) {
+ *(pointer) = vec4<f32>();
+}
+
+var<private> P : str;
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(P.i));
+}
diff --git a/test/tint/ptr_ref/store/param/ptr.spvasm b/test/tint/ptr_ref/store/param/ptr.spvasm
deleted file mode 100644
index e750538..0000000
--- a/test/tint/ptr_ref/store/param/ptr.spvasm
+++ /dev/null
@@ -1,35 +0,0 @@
-; 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/tint/ptr_ref/store/param/ptr.spvasm.expected.glsl b/test/tint/ptr_ref/store/param/ptr.spvasm.expected.glsl
deleted file mode 100644
index b90efb1..0000000
--- a/test/tint/ptr_ref/store/param/ptr.spvasm.expected.glsl
+++ /dev/null
@@ -1,23 +0,0 @@
-#version 310 es
-
-void func(int value, inout int pointer) {
- pointer = value;
- return;
-}
-
-void main_1() {
- int i = 0;
- i = 123;
- func(123, i);
- return;
-}
-
-void tint_symbol() {
- main_1();
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
- tint_symbol();
- return;
-}
diff --git a/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl b/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl
new file mode 100644
index 0000000..e0e40eb
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+};
+
+@group(0) @binding(0) var<storage, read_write> S : str;
+
+fn func(pointer : ptr<storage, array<i32, 4>, read_write>) {
+ *pointer = array<i32, 4>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&S.arr);
+}
diff --git a/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..30148d5
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,21 @@
+RWByteAddressBuffer S : register(u0, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, int value[4]) {
+ int array[4] = value;
+ {
+ for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+ buffer.Store((offset + (i * 4u)), asuint(array[i]));
+ }
+ }
+}
+
+void func_S_arr() {
+ const int tint_symbol_2[4] = (int[4])0;
+ tint_symbol(S, 0u, tint_symbol_2);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ func_S_arr();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..30148d5
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,21 @@
+RWByteAddressBuffer S : register(u0, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, int value[4]) {
+ int array[4] = value;
+ {
+ for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+ buffer.Store((offset + (i * 4u)), asuint(array[i]));
+ }
+ }
+}
+
+void func_S_arr() {
+ const int tint_symbol_2[4] = (int[4])0;
+ tint_symbol(S, 0u, tint_symbol_2);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ func_S_arr();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..51fb051
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl.expected.glsl
@@ -0,0 +1,24 @@
+#version 310 es
+
+struct str {
+ int arr[4];
+};
+
+layout(binding = 0, std430) buffer S_block_ssbo {
+ str inner;
+} S;
+
+void func_S_arr() {
+ int tint_symbol_1[4] = int[4](0, 0, 0, 0);
+ S.inner.arr = tint_symbol_1;
+}
+
+void tint_symbol() {
+ func_S_arr();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..14a5b86
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl.expected.msl
@@ -0,0 +1,30 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+struct str {
+ /* 0x0000 */ tint_array<int, 4> arr;
+};
+
+void func(device tint_array<int, 4>* const pointer) {
+ tint_array<int, 4> const tint_symbol_1 = tint_array<int, 4>{};
+ *(pointer) = tint_symbol_1;
+}
+
+kernel void tint_symbol(device str* tint_symbol_2 [[buffer(0)]]) {
+ func(&((*(tint_symbol_2)).arr));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..51fda12
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,46 @@
+; SPIR-V
+; Version: 1.3
+; 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 %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %str "str"
+ OpMemberName %str 0 "arr"
+ OpName %S "S"
+ OpName %func_S_arr "func_S_arr"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %_arr_int_uint_4 ArrayStride 4
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ %int = OpTypeInt 32 1
+ %uint = OpTypeInt 32 0
+ %uint_4 = OpConstant %uint 4
+%_arr_int_uint_4 = OpTypeArray %int %uint_4
+ %str = OpTypeStruct %_arr_int_uint_4
+ %S_block = OpTypeStruct %str
+%_ptr_StorageBuffer_S_block = OpTypePointer StorageBuffer %S_block
+ %S = OpVariable %_ptr_StorageBuffer_S_block StorageBuffer
+ %void = OpTypeVoid
+ %9 = OpTypeFunction %void
+ %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_int_uint_4 = OpTypePointer StorageBuffer %_arr_int_uint_4
+ %16 = OpConstantNull %_arr_int_uint_4
+ %func_S_arr = OpFunction %void None %9
+ %12 = OpLabel
+ %15 = OpAccessChain %_ptr_StorageBuffer__arr_int_uint_4 %S %uint_0 %uint_0
+ OpStore %15 %16
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %9
+ %18 = OpLabel
+ %19 = OpFunctionCall %void %func_S_arr
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..5545a0d
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/array_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> S : str;
+
+fn func(pointer : ptr<storage, array<i32, 4>, read_write>) {
+ *(pointer) = array<i32, 4>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(S.arr));
+}
diff --git a/test/tint/ptr_ref/store/param/storage/i32.wgsl b/test/tint/ptr_ref/store/param/storage/i32.wgsl
new file mode 100644
index 0000000..8f1c6e9
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/i32.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage, read_write> S : i32;
+
+fn func(pointer : ptr<storage, i32, read_write>) {
+ *pointer = 42;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&S);
+}
diff --git a/test/tint/ptr_ref/store/param/storage/i32.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/storage/i32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a907f4f
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/i32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,11 @@
+RWByteAddressBuffer S : register(u0, space0);
+
+void func_S() {
+ S.Store(0u, asuint(42));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ func_S();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/i32.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/storage/i32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a907f4f
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/i32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,11 @@
+RWByteAddressBuffer S : register(u0, space0);
+
+void func_S() {
+ S.Store(0u, asuint(42));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ func_S();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/i32.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/storage/i32.wgsl.expected.glsl
new file mode 100644
index 0000000..081c682
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/i32.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer S_block_ssbo {
+ int inner;
+} S;
+
+void func_S() {
+ S.inner = 42;
+}
+
+void tint_symbol() {
+ func_S();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/i32.wgsl.expected.msl b/test/tint/ptr_ref/store/param/storage/i32.wgsl.expected.msl
new file mode 100644
index 0000000..b2a8e0e
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/i32.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void func(device int* const pointer) {
+ *(pointer) = 42;
+}
+
+kernel void tint_symbol(device int* tint_symbol_1 [[buffer(0)]]) {
+ func(tint_symbol_1);
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/storage/i32.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/storage/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..0d849ef
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/i32.wgsl.expected.spvasm
@@ -0,0 +1,39 @@
+; 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 %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %S "S"
+ OpName %func_S "func_S"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ %int = OpTypeInt 32 1
+ %S_block = OpTypeStruct %int
+%_ptr_StorageBuffer_S_block = OpTypePointer StorageBuffer %S_block
+ %S = OpVariable %_ptr_StorageBuffer_S_block StorageBuffer
+ %void = OpTypeVoid
+ %5 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
+ %int_42 = OpConstant %int 42
+ %func_S = OpFunction %void None %5
+ %8 = OpLabel
+ %12 = OpAccessChain %_ptr_StorageBuffer_int %S %uint_0
+ OpStore %12 %int_42
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %5
+ %15 = OpLabel
+ %16 = OpFunctionCall %void %func_S
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/storage/i32.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/storage/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..6ed869b
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/i32.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage, read_write> S : i32;
+
+fn func(pointer : ptr<storage, i32, read_write>) {
+ *(pointer) = 42;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(S));
+}
diff --git a/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl b/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl
new file mode 100644
index 0000000..f68d27c
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+@group(0) @binding(0) var<storage, read_write> S : str;
+
+fn func(pointer : ptr<storage, i32, read_write>) {
+ *pointer = 42;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&S.i);
+}
diff --git a/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..d020bf6
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,11 @@
+RWByteAddressBuffer S : register(u0, space0);
+
+void func_S_i() {
+ S.Store(0u, asuint(42));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ func_S_i();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..d020bf6
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,11 @@
+RWByteAddressBuffer S : register(u0, space0);
+
+void func_S_i() {
+ S.Store(0u, asuint(42));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ func_S_i();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..1552104
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+
+struct str {
+ int i;
+};
+
+layout(binding = 0, std430) buffer S_block_ssbo {
+ str inner;
+} S;
+
+void func_S_i() {
+ S.inner.i = 42;
+}
+
+void tint_symbol() {
+ func_S_i();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..a708f66
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl.expected.msl
@@ -0,0 +1,16 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct str {
+ /* 0x0000 */ int i;
+};
+
+void func(device int* const pointer) {
+ *(pointer) = 42;
+}
+
+kernel void tint_symbol(device str* tint_symbol_1 [[buffer(0)]]) {
+ func(&((*(tint_symbol_1)).i));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..042d5b4
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,43 @@
+; 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_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %S "S"
+ OpName %func_S_i "func_S_i"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ %int = OpTypeInt 32 1
+ %str = OpTypeStruct %int
+ %S_block = OpTypeStruct %str
+%_ptr_StorageBuffer_S_block = OpTypePointer StorageBuffer %S_block
+ %S = OpVariable %_ptr_StorageBuffer_S_block StorageBuffer
+ %void = OpTypeVoid
+ %6 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
+ %int_42 = OpConstant %int 42
+ %func_S_i = OpFunction %void None %6
+ %9 = OpLabel
+ %13 = OpAccessChain %_ptr_StorageBuffer_int %S %uint_0 %uint_0
+ OpStore %13 %int_42
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %6
+ %16 = OpLabel
+ %17 = OpFunctionCall %void %func_S_i
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..6a35569
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/i32_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+@group(0) @binding(0) var<storage, read_write> S : str;
+
+fn func(pointer : ptr<storage, i32, read_write>) {
+ *(pointer) = 42;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(S.i));
+}
diff --git a/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl b/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl
new file mode 100644
index 0000000..f13db83
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+@group(0) @binding(0) var<storage, read_write> S : array<str, 4>;
+
+fn func(pointer : ptr<storage, str, read_write>) {
+ *pointer = str();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&S[2]);
+}
diff --git a/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..b51e632
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl.expected.dxc.hlsl
@@ -0,0 +1,21 @@
+struct str {
+ int i;
+};
+
+RWByteAddressBuffer S : register(u0, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, str value) {
+ buffer.Store((offset + 0u), asuint(value.i));
+}
+
+void func_S_X(uint pointer[1]) {
+ const str tint_symbol_2 = (str)0;
+ tint_symbol(S, (4u * pointer[0]), tint_symbol_2);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const uint tint_symbol_3[1] = {2u};
+ func_S_X(tint_symbol_3);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b51e632
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl.expected.fxc.hlsl
@@ -0,0 +1,21 @@
+struct str {
+ int i;
+};
+
+RWByteAddressBuffer S : register(u0, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, str value) {
+ buffer.Store((offset + 0u), asuint(value.i));
+}
+
+void func_S_X(uint pointer[1]) {
+ const str tint_symbol_2 = (str)0;
+ tint_symbol(S, (4u * pointer[0]), tint_symbol_2);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const uint tint_symbol_3[1] = {2u};
+ func_S_X(tint_symbol_3);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl.expected.glsl
new file mode 100644
index 0000000..55c82f8
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl.expected.glsl
@@ -0,0 +1,25 @@
+#version 310 es
+
+struct str {
+ int i;
+};
+
+layout(binding = 0, std430) buffer S_block_ssbo {
+ str inner[4];
+} S;
+
+void func_S_X(uint pointer[1]) {
+ str tint_symbol_1 = str(0);
+ S.inner[pointer[0]] = tint_symbol_1;
+}
+
+void tint_symbol() {
+ uint tint_symbol_2[1] = uint[1](2u);
+ func_S_X(tint_symbol_2);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl.expected.msl b/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl.expected.msl
new file mode 100644
index 0000000..3119e7a
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl.expected.msl
@@ -0,0 +1,30 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+struct str {
+ /* 0x0000 */ int i;
+};
+
+void func(device str* const pointer) {
+ str const tint_symbol_1 = str{};
+ *(pointer) = tint_symbol_1;
+}
+
+kernel void tint_symbol(device tint_array<str, 4>* tint_symbol_2 [[buffer(0)]]) {
+ func(&((*(tint_symbol_2))[2]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl.expected.spvasm
new file mode 100644
index 0000000..190781a
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl.expected.spvasm
@@ -0,0 +1,56 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 28
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %S "S"
+ OpName %func_S_X "func_S_X"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %_arr_str_uint_4 ArrayStride 4
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %int = OpTypeInt 32 1
+ %str = OpTypeStruct %int
+ %uint = OpTypeInt 32 0
+ %uint_4 = OpConstant %uint 4
+%_arr_str_uint_4 = OpTypeArray %str %uint_4
+ %S_block = OpTypeStruct %_arr_str_uint_4
+%_ptr_StorageBuffer_S_block = OpTypePointer StorageBuffer %S_block
+ %S = OpVariable %_ptr_StorageBuffer_S_block StorageBuffer
+ %void = OpTypeVoid
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %9 = OpTypeFunction %void %_arr_uint_uint_1
+ %uint_0 = OpConstant %uint 0
+ %17 = OpConstantNull %int
+%_ptr_StorageBuffer_str = OpTypePointer StorageBuffer %str
+ %21 = OpConstantNull %str
+ %22 = OpTypeFunction %void
+ %uint_2 = OpConstant %uint 2
+ %27 = OpConstantComposite %_arr_uint_uint_1 %uint_2
+ %func_S_X = OpFunction %void None %9
+ %pointer = OpFunctionParameter %_arr_uint_uint_1
+ %15 = OpLabel
+ %18 = OpCompositeExtract %uint %pointer 0
+ %20 = OpAccessChain %_ptr_StorageBuffer_str %S %uint_0 %18
+ OpStore %20 %21
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %22
+ %24 = OpLabel
+ %25 = OpFunctionCall %void %func_S_X %27
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl.expected.wgsl
new file mode 100644
index 0000000..90db206
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/struct_in_array.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+@group(0) @binding(0) var<storage, read_write> S : array<str, 4>;
+
+fn func(pointer : ptr<storage, str, read_write>) {
+ *(pointer) = str();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(S[2]));
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl b/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl
new file mode 100644
index 0000000..d69899b
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage, read_write> S : mat2x2<f32>;
+
+fn func(pointer : ptr<storage, vec2<f32>, read_write>) {
+ *pointer = vec2<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&S[1]);
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c2a926b
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl
@@ -0,0 +1,12 @@
+RWByteAddressBuffer S : register(u0, space0);
+
+void func_S_X(uint pointer[1]) {
+ S.Store2((8u * pointer[0]), asuint((0.0f).xx));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const uint tint_symbol_1[1] = {1u};
+ func_S_X(tint_symbol_1);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c2a926b
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl
@@ -0,0 +1,12 @@
+RWByteAddressBuffer S : register(u0, space0);
+
+void func_S_X(uint pointer[1]) {
+ S.Store2((8u * pointer[0]), asuint((0.0f).xx));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const uint tint_symbol_1[1] = {1u};
+ func_S_X(tint_symbol_1);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl.expected.glsl
new file mode 100644
index 0000000..ea1f5fc
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer S_block_ssbo {
+ mat2 inner;
+} S;
+
+void func_S_X(uint pointer[1]) {
+ S.inner[pointer[0]] = vec2(0.0f);
+}
+
+void tint_symbol() {
+ uint tint_symbol_1[1] = uint[1](1u);
+ func_S_X(tint_symbol_1);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl.expected.msl b/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl.expected.msl
new file mode 100644
index 0000000..fb8b603
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void func(device float2* const pointer) {
+ *(pointer) = float2(0.0f);
+}
+
+kernel void tint_symbol(device float2x2* tint_symbol_1 [[buffer(0)]]) {
+ func(&((*(tint_symbol_1))[1]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl.expected.spvasm
new file mode 100644
index 0000000..0b294a2
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl.expected.spvasm
@@ -0,0 +1,53 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 27
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %S "S"
+ OpName %func_S_X "func_S_X"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpMemberDecorate %S_block 0 ColMajor
+ OpMemberDecorate %S_block 0 MatrixStride 8
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %float = OpTypeFloat 32
+ %v2float = OpTypeVector %float 2
+%mat2v2float = OpTypeMatrix %v2float 2
+ %S_block = OpTypeStruct %mat2v2float
+%_ptr_StorageBuffer_S_block = OpTypePointer StorageBuffer %S_block
+ %S = OpVariable %_ptr_StorageBuffer_S_block StorageBuffer
+ %void = OpTypeVoid
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %7 = OpTypeFunction %void %_arr_uint_uint_1
+ %uint_0 = OpConstant %uint 0
+ %int = OpTypeInt 32 1
+ %17 = OpConstantNull %int
+%_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
+ %21 = OpConstantNull %v2float
+ %22 = OpTypeFunction %void
+ %26 = OpConstantComposite %_arr_uint_uint_1 %uint_1
+ %func_S_X = OpFunction %void None %7
+ %pointer = OpFunctionParameter %_arr_uint_uint_1
+ %14 = OpLabel
+ %18 = OpCompositeExtract %uint %pointer 0
+ %20 = OpAccessChain %_ptr_StorageBuffer_v2float %S %uint_0 %18
+ OpStore %20 %21
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %22
+ %24 = OpLabel
+ %25 = OpFunctionCall %void %func_S_X %26
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl.expected.wgsl
new file mode 100644
index 0000000..d31440c
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec2_f32_in_mat2x2.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage, read_write> S : mat2x2<f32>;
+
+fn func(pointer : ptr<storage, vec2<f32>, read_write>) {
+ *(pointer) = vec2<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(S[1]));
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl b/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl
new file mode 100644
index 0000000..b76e544
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage, read_write> S : vec4<f32>;
+
+fn func(pointer : ptr<storage, vec4<f32>, read_write>) {
+ *pointer = vec4<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&S);
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..7343fc8
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,11 @@
+RWByteAddressBuffer S : register(u0, space0);
+
+void func_S() {
+ S.Store4(0u, asuint((0.0f).xxxx));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ func_S();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7343fc8
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,11 @@
+RWByteAddressBuffer S : register(u0, space0);
+
+void func_S() {
+ S.Store4(0u, asuint((0.0f).xxxx));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ func_S();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..4a01502
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer S_block_ssbo {
+ vec4 inner;
+} S;
+
+void func_S() {
+ S.inner = vec4(0.0f);
+}
+
+void tint_symbol() {
+ func_S();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl.expected.msl b/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl.expected.msl
new file mode 100644
index 0000000..e727b7c
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void func(device float4* const pointer) {
+ *(pointer) = float4(0.0f);
+}
+
+kernel void tint_symbol(device float4* tint_symbol_1 [[buffer(0)]]) {
+ func(tint_symbol_1);
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..d8bae29
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl.expected.spvasm
@@ -0,0 +1,40 @@
+; 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_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %S "S"
+ OpName %func_S "func_S"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %S_block = OpTypeStruct %v4float
+%_ptr_StorageBuffer_S_block = OpTypePointer StorageBuffer %S_block
+ %S = OpVariable %_ptr_StorageBuffer_S_block StorageBuffer
+ %void = OpTypeVoid
+ %6 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+ %14 = OpConstantNull %v4float
+ %func_S = OpFunction %void None %6
+ %9 = OpLabel
+ %13 = OpAccessChain %_ptr_StorageBuffer_v4float %S %uint_0
+ OpStore %13 %14
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %6
+ %16 = OpLabel
+ %17 = OpFunctionCall %void %func_S
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..3a10bfb
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage, read_write> S : vec4<f32>;
+
+fn func(pointer : ptr<storage, vec4<f32>, read_write>) {
+ *(pointer) = vec4<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(S));
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl
new file mode 100644
index 0000000..82b69e9
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage, read_write> S : mat2x4<f32>;
+
+fn func(pointer : ptr<storage, vec4<f32>, read_write>) {
+ *pointer = vec4<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&S[1]);
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a345b7a
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl
@@ -0,0 +1,12 @@
+RWByteAddressBuffer S : register(u0, space0);
+
+void func_S_X(uint pointer[1]) {
+ S.Store4((16u * pointer[0]), asuint((0.0f).xxxx));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const uint tint_symbol_1[1] = {1u};
+ func_S_X(tint_symbol_1);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a345b7a
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl
@@ -0,0 +1,12 @@
+RWByteAddressBuffer S : register(u0, space0);
+
+void func_S_X(uint pointer[1]) {
+ S.Store4((16u * pointer[0]), asuint((0.0f).xxxx));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const uint tint_symbol_1[1] = {1u};
+ func_S_X(tint_symbol_1);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl.expected.glsl
new file mode 100644
index 0000000..51898ee
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer S_block_ssbo {
+ mat2x4 inner;
+} S;
+
+void func_S_X(uint pointer[1]) {
+ S.inner[pointer[0]] = vec4(0.0f);
+}
+
+void tint_symbol() {
+ uint tint_symbol_1[1] = uint[1](1u);
+ func_S_X(tint_symbol_1);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl.expected.msl b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl.expected.msl
new file mode 100644
index 0000000..51641a3
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void func(device float4* const pointer) {
+ *(pointer) = float4(0.0f);
+}
+
+kernel void tint_symbol(device float2x4* tint_symbol_1 [[buffer(0)]]) {
+ func(&((*(tint_symbol_1))[1]));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl.expected.spvasm
new file mode 100644
index 0000000..db5ca8a
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl.expected.spvasm
@@ -0,0 +1,53 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 27
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %S "S"
+ OpName %func_S_X "func_S_X"
+ OpName %pointer "pointer"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpMemberDecorate %S_block 0 ColMajor
+ OpMemberDecorate %S_block 0 MatrixStride 16
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+ %S_block = OpTypeStruct %mat2v4float
+%_ptr_StorageBuffer_S_block = OpTypePointer StorageBuffer %S_block
+ %S = OpVariable %_ptr_StorageBuffer_S_block StorageBuffer
+ %void = OpTypeVoid
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %7 = OpTypeFunction %void %_arr_uint_uint_1
+ %uint_0 = OpConstant %uint 0
+ %int = OpTypeInt 32 1
+ %17 = OpConstantNull %int
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+ %21 = OpConstantNull %v4float
+ %22 = OpTypeFunction %void
+ %26 = OpConstantComposite %_arr_uint_uint_1 %uint_1
+ %func_S_X = OpFunction %void None %7
+ %pointer = OpFunctionParameter %_arr_uint_uint_1
+ %14 = OpLabel
+ %18 = OpCompositeExtract %uint %pointer 0
+ %20 = OpAccessChain %_ptr_StorageBuffer_v4float %S %uint_0 %18
+ OpStore %20 %21
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %22
+ %24 = OpLabel
+ %25 = OpFunctionCall %void %func_S_X %26
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl.expected.wgsl
new file mode 100644
index 0000000..822fba4
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_mat2x4.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage, read_write> S : mat2x4<f32>;
+
+fn func(pointer : ptr<storage, vec4<f32>, read_write>) {
+ *(pointer) = vec4<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(S[1]));
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl
new file mode 100644
index 0000000..c49e789
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<f32>,
+};
+
+@group(0) @binding(0) var<storage, read_write> S : str;
+
+fn func(pointer : ptr<storage, vec4<f32>, read_write>) {
+ *pointer = vec4<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&S.i);
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..d98c3c6
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,11 @@
+RWByteAddressBuffer S : register(u0, space0);
+
+void func_S_i() {
+ S.Store4(0u, asuint((0.0f).xxxx));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ func_S_i();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..d98c3c6
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,11 @@
+RWByteAddressBuffer S : register(u0, space0);
+
+void func_S_i() {
+ S.Store4(0u, asuint((0.0f).xxxx));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ func_S_i();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..314e7d4
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+
+struct str {
+ vec4 i;
+};
+
+layout(binding = 0, std430) buffer S_block_ssbo {
+ str inner;
+} S;
+
+void func_S_i() {
+ S.inner.i = vec4(0.0f);
+}
+
+void tint_symbol() {
+ func_S_i();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..f4b522f
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl.expected.msl
@@ -0,0 +1,16 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct str {
+ /* 0x0000 */ float4 i;
+};
+
+void func(device float4* const pointer) {
+ *(pointer) = float4(0.0f);
+}
+
+kernel void tint_symbol(device str* tint_symbol_1 [[buffer(0)]]) {
+ func(&((*(tint_symbol_1)).i));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..12a8253
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,44 @@
+; 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 %S_block "S_block"
+ OpMemberName %S_block 0 "inner"
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %S "S"
+ OpName %func_S_i "func_S_i"
+ OpName %main "main"
+ OpDecorate %S_block Block
+ OpMemberDecorate %S_block 0 Offset 0
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %S DescriptorSet 0
+ OpDecorate %S Binding 0
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %str = OpTypeStruct %v4float
+ %S_block = OpTypeStruct %str
+%_ptr_StorageBuffer_S_block = OpTypePointer StorageBuffer %S_block
+ %S = OpVariable %_ptr_StorageBuffer_S_block StorageBuffer
+ %void = OpTypeVoid
+ %7 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+ %15 = OpConstantNull %v4float
+ %func_S_i = OpFunction %void None %7
+ %10 = OpLabel
+ %14 = OpAccessChain %_ptr_StorageBuffer_v4float %S %uint_0 %uint_0
+ OpStore %14 %15
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %7
+ %17 = OpLabel
+ %18 = OpFunctionCall %void %func_S_i
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..89c0bc3
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/storage/vec4_f32_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> S : str;
+
+fn func(pointer : ptr<storage, vec4<f32>, read_write>) {
+ *(pointer) = vec4<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(S.i));
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl b/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl
new file mode 100644
index 0000000..4bf2e36
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+};
+
+var<workgroup> S : str;
+
+fn func(pointer : ptr<workgroup, array<i32, 4>>) {
+ *pointer = array<i32, 4>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&S.arr);
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..7a28ceb
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,31 @@
+struct str {
+ int arr[4];
+};
+
+groupshared str S;
+
+void func_S_arr() {
+ const int tint_symbol_2[4] = (int[4])0;
+ S.arr = tint_symbol_2;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+ const uint i = idx;
+ S.arr[i] = 0;
+ }
+ }
+ GroupMemoryBarrierWithGroupSync();
+ func_S_arr();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7a28ceb
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,31 @@
+struct str {
+ int arr[4];
+};
+
+groupshared str S;
+
+void func_S_arr() {
+ const int tint_symbol_2[4] = (int[4])0;
+ S.arr = tint_symbol_2;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+ const uint i = idx;
+ S.arr[i] = 0;
+ }
+ }
+ GroupMemoryBarrierWithGroupSync();
+ func_S_arr();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..a551b4b
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl.expected.glsl
@@ -0,0 +1,28 @@
+#version 310 es
+
+struct str {
+ int arr[4];
+};
+
+shared str S;
+void func_S_arr() {
+ int tint_symbol_1[4] = int[4](0, 0, 0, 0);
+ S.arr = tint_symbol_1;
+}
+
+void tint_symbol(uint local_invocation_index) {
+ {
+ for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+ uint i = idx;
+ S.arr[i] = 0;
+ }
+ }
+ barrier();
+ func_S_arr();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol(gl_LocalInvocationIndex);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..8652c09
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl.expected.msl
@@ -0,0 +1,40 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+struct str {
+ tint_array<int, 4> arr;
+};
+
+void func(threadgroup tint_array<int, 4>* const pointer) {
+ tint_array<int, 4> const tint_symbol_1 = tint_array<int, 4>{};
+ *(pointer) = tint_symbol_1;
+}
+
+void tint_symbol_inner(uint local_invocation_index, threadgroup str* const tint_symbol_2) {
+ for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+ uint const i = idx;
+ (*(tint_symbol_2)).arr[i] = 0;
+ }
+ threadgroup_barrier(mem_flags::mem_threadgroup);
+ func(&((*(tint_symbol_2)).arr));
+}
+
+kernel void tint_symbol(uint local_invocation_index [[thread_index_in_threadgroup]]) {
+ threadgroup str tint_symbol_3;
+ tint_symbol_inner(local_invocation_index, &(tint_symbol_3));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..d6080c8
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,88 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 50
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %local_invocation_index_1
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %local_invocation_index_1 "local_invocation_index_1"
+ OpName %str "str"
+ OpMemberName %str 0 "arr"
+ OpName %S "S"
+ OpName %func_S_arr "func_S_arr"
+ OpName %main_inner "main_inner"
+ OpName %local_invocation_index "local_invocation_index"
+ OpName %idx "idx"
+ OpName %main "main"
+ OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %_arr_int_uint_4 ArrayStride 4
+ %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+ %int = OpTypeInt 32 1
+ %uint_4 = OpConstant %uint 4
+%_arr_int_uint_4 = OpTypeArray %int %uint_4
+ %str = OpTypeStruct %_arr_int_uint_4
+%_ptr_Workgroup_str = OpTypePointer Workgroup %str
+ %S = OpVariable %_ptr_Workgroup_str Workgroup
+ %void = OpTypeVoid
+ %10 = OpTypeFunction %void
+ %uint_0 = OpConstant %uint 0
+%_ptr_Workgroup__arr_int_uint_4 = OpTypePointer Workgroup %_arr_int_uint_4
+ %17 = OpConstantNull %_arr_int_uint_4
+ %18 = OpTypeFunction %void %uint
+%_ptr_Function_uint = OpTypePointer Function %uint
+ %24 = OpConstantNull %uint
+ %bool = OpTypeBool
+%_ptr_Workgroup_int = OpTypePointer Workgroup %int
+ %38 = OpConstantNull %int
+ %uint_1 = OpConstant %uint 1
+ %uint_2 = OpConstant %uint 2
+ %uint_264 = OpConstant %uint 264
+ %func_S_arr = OpFunction %void None %10
+ %13 = OpLabel
+ %16 = OpAccessChain %_ptr_Workgroup__arr_int_uint_4 %S %uint_0
+ OpStore %16 %17
+ OpReturn
+ OpFunctionEnd
+ %main_inner = OpFunction %void None %18
+%local_invocation_index = OpFunctionParameter %uint
+ %21 = OpLabel
+ %idx = OpVariable %_ptr_Function_uint Function %24
+ OpStore %idx %local_invocation_index
+ OpBranch %25
+ %25 = OpLabel
+ OpLoopMerge %26 %27 None
+ OpBranch %28
+ %28 = OpLabel
+ %30 = OpLoad %uint %idx
+ %31 = OpULessThan %bool %30 %uint_4
+ %29 = OpLogicalNot %bool %31
+ OpSelectionMerge %33 None
+ OpBranchConditional %29 %34 %33
+ %34 = OpLabel
+ OpBranch %26
+ %33 = OpLabel
+ %35 = OpLoad %uint %idx
+ %37 = OpAccessChain %_ptr_Workgroup_int %S %uint_0 %35
+ OpStore %37 %38
+ OpBranch %27
+ %27 = OpLabel
+ %39 = OpLoad %uint %idx
+ %41 = OpIAdd %uint %39 %uint_1
+ OpStore %idx %41
+ OpBranch %25
+ %26 = OpLabel
+ OpControlBarrier %uint_2 %uint_2 %uint_264
+ %45 = OpFunctionCall %void %func_S_arr
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %10
+ %47 = OpLabel
+ %49 = OpLoad %uint %local_invocation_index_1
+ %48 = OpFunctionCall %void %main_inner %49
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..b6f7aeb
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/array_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ arr : array<i32, 4>,
+}
+
+var<workgroup> S : str;
+
+fn func(pointer : ptr<workgroup, array<i32, 4>>) {
+ *(pointer) = array<i32, 4>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(S.arr));
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/i32.wgsl b/test/tint/ptr_ref/store/param/workgroup/i32.wgsl
new file mode 100644
index 0000000..9d7d66a
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/i32.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> S : i32;
+
+fn func(pointer : ptr<workgroup, i32>) {
+ *pointer = 42;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&S);
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/i32.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/workgroup/i32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8ed52c4
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/i32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,23 @@
+groupshared int S;
+
+void func_S() {
+ S = 42;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ S = 0;
+ }
+ GroupMemoryBarrierWithGroupSync();
+ func_S();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/i32.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/workgroup/i32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8ed52c4
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/i32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,23 @@
+groupshared int S;
+
+void func_S() {
+ S = 42;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ S = 0;
+ }
+ GroupMemoryBarrierWithGroupSync();
+ func_S();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/i32.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/workgroup/i32.wgsl.expected.glsl
new file mode 100644
index 0000000..3b35642
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/i32.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+shared int S;
+void func_S() {
+ S = 42;
+}
+
+void tint_symbol(uint local_invocation_index) {
+ {
+ S = 0;
+ }
+ barrier();
+ func_S();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol(gl_LocalInvocationIndex);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/i32.wgsl.expected.msl b/test/tint/ptr_ref/store/param/workgroup/i32.wgsl.expected.msl
new file mode 100644
index 0000000..f6a36ce
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/i32.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void func(threadgroup int* const pointer) {
+ *(pointer) = 42;
+}
+
+void tint_symbol_inner(uint local_invocation_index, threadgroup int* const tint_symbol_1) {
+ {
+ *(tint_symbol_1) = 0;
+ }
+ threadgroup_barrier(mem_flags::mem_threadgroup);
+ func(tint_symbol_1);
+}
+
+kernel void tint_symbol(uint local_invocation_index [[thread_index_in_threadgroup]]) {
+ threadgroup int tint_symbol_2;
+ tint_symbol_inner(local_invocation_index, &(tint_symbol_2));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/workgroup/i32.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/workgroup/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..a471fe4
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/i32.wgsl.expected.spvasm
@@ -0,0 +1,48 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 25
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %local_invocation_index_1
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %local_invocation_index_1 "local_invocation_index_1"
+ OpName %S "S"
+ OpName %func_S "func_S"
+ OpName %main_inner "main_inner"
+ OpName %local_invocation_index "local_invocation_index"
+ OpName %main "main"
+ OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+ %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+ %int = OpTypeInt 32 1
+%_ptr_Workgroup_int = OpTypePointer Workgroup %int
+ %S = OpVariable %_ptr_Workgroup_int Workgroup
+ %void = OpTypeVoid
+ %7 = OpTypeFunction %void
+ %int_42 = OpConstant %int 42
+ %12 = OpTypeFunction %void %uint
+ %16 = OpConstantNull %int
+ %uint_2 = OpConstant %uint 2
+ %uint_264 = OpConstant %uint 264
+ %func_S = OpFunction %void None %7
+ %10 = OpLabel
+ OpStore %S %int_42
+ OpReturn
+ OpFunctionEnd
+ %main_inner = OpFunction %void None %12
+%local_invocation_index = OpFunctionParameter %uint
+ %15 = OpLabel
+ OpStore %S %16
+ OpControlBarrier %uint_2 %uint_2 %uint_264
+ %20 = OpFunctionCall %void %func_S
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %7
+ %22 = OpLabel
+ %24 = OpLoad %uint %local_invocation_index_1
+ %23 = OpFunctionCall %void %main_inner %24
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/workgroup/i32.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/workgroup/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..3bb4d84
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/i32.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> S : i32;
+
+fn func(pointer : ptr<workgroup, i32>) {
+ *(pointer) = 42;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(S));
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl b/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl
new file mode 100644
index 0000000..3c3209f
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+var<workgroup> S : str;
+
+fn func(pointer : ptr<workgroup, i32>) {
+ *pointer = 42;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&S.i);
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a8ddec6
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,28 @@
+struct str {
+ int i;
+};
+
+groupshared str S;
+
+void func_S_i() {
+ S.i = 42;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ const str tint_symbol_2 = (str)0;
+ S = tint_symbol_2;
+ }
+ GroupMemoryBarrierWithGroupSync();
+ func_S_i();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a8ddec6
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+struct str {
+ int i;
+};
+
+groupshared str S;
+
+void func_S_i() {
+ S.i = 42;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ const str tint_symbol_2 = (str)0;
+ S = tint_symbol_2;
+ }
+ GroupMemoryBarrierWithGroupSync();
+ func_S_i();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..dc3ac54
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl.expected.glsl
@@ -0,0 +1,25 @@
+#version 310 es
+
+struct str {
+ int i;
+};
+
+shared str S;
+void func_S_i() {
+ S.i = 42;
+}
+
+void tint_symbol(uint local_invocation_index) {
+ {
+ str tint_symbol_1 = str(0);
+ S = tint_symbol_1;
+ }
+ barrier();
+ func_S_i();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol(gl_LocalInvocationIndex);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..419a502
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl.expected.msl
@@ -0,0 +1,26 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct str {
+ int i;
+};
+
+void func(threadgroup int* const pointer) {
+ *(pointer) = 42;
+}
+
+void tint_symbol_inner(uint local_invocation_index, threadgroup str* const tint_symbol_2) {
+ {
+ str const tint_symbol_1 = str{};
+ *(tint_symbol_2) = tint_symbol_1;
+ }
+ threadgroup_barrier(mem_flags::mem_threadgroup);
+ func(&((*(tint_symbol_2)).i));
+}
+
+kernel void tint_symbol(uint local_invocation_index [[thread_index_in_threadgroup]]) {
+ threadgroup str tint_symbol_3;
+ tint_symbol_inner(local_invocation_index, &(tint_symbol_3));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..5a4b764
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,55 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 29
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %local_invocation_index_1
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %local_invocation_index_1 "local_invocation_index_1"
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %S "S"
+ OpName %func_S_i "func_S_i"
+ OpName %main_inner "main_inner"
+ OpName %local_invocation_index "local_invocation_index"
+ OpName %main "main"
+ OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+ OpMemberDecorate %str 0 Offset 0
+ %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+ %int = OpTypeInt 32 1
+ %str = OpTypeStruct %int
+%_ptr_Workgroup_str = OpTypePointer Workgroup %str
+ %S = OpVariable %_ptr_Workgroup_str Workgroup
+ %void = OpTypeVoid
+ %8 = OpTypeFunction %void
+ %uint_0 = OpConstant %uint 0
+%_ptr_Workgroup_int = OpTypePointer Workgroup %int
+ %int_42 = OpConstant %int 42
+ %16 = OpTypeFunction %void %uint
+ %20 = OpConstantNull %str
+ %uint_2 = OpConstant %uint 2
+ %uint_264 = OpConstant %uint 264
+ %func_S_i = OpFunction %void None %8
+ %11 = OpLabel
+ %14 = OpAccessChain %_ptr_Workgroup_int %S %uint_0
+ OpStore %14 %int_42
+ OpReturn
+ OpFunctionEnd
+ %main_inner = OpFunction %void None %16
+%local_invocation_index = OpFunctionParameter %uint
+ %19 = OpLabel
+ OpStore %S %20
+ OpControlBarrier %uint_2 %uint_2 %uint_264
+ %24 = OpFunctionCall %void %func_S_i
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %8
+ %26 = OpLabel
+ %28 = OpLoad %uint %local_invocation_index_1
+ %27 = OpFunctionCall %void %main_inner %28
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..642e2a5
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/i32_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+var<workgroup> S : str;
+
+fn func(pointer : ptr<workgroup, i32>) {
+ *(pointer) = 42;
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(S.i));
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl b/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl
new file mode 100644
index 0000000..5fbef20
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+};
+
+var<workgroup> S : array<str, 4>;
+
+fn func(pointer : ptr<workgroup, str>) {
+ *pointer = str();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&S[2]);
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..b3b8183
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl.expected.dxc.hlsl
@@ -0,0 +1,33 @@
+struct str {
+ int i;
+};
+
+groupshared str S[4];
+
+void func_S_X(uint pointer[1]) {
+ const str tint_symbol_2 = (str)0;
+ S[pointer[0]] = tint_symbol_2;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+ const uint i_1 = idx;
+ const str tint_symbol_3 = (str)0;
+ S[i_1] = tint_symbol_3;
+ }
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const uint tint_symbol_4[1] = {2u};
+ func_S_X(tint_symbol_4);
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b3b8183
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl.expected.fxc.hlsl
@@ -0,0 +1,33 @@
+struct str {
+ int i;
+};
+
+groupshared str S[4];
+
+void func_S_X(uint pointer[1]) {
+ const str tint_symbol_2 = (str)0;
+ S[pointer[0]] = tint_symbol_2;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+ const uint i_1 = idx;
+ const str tint_symbol_3 = (str)0;
+ S[i_1] = tint_symbol_3;
+ }
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const uint tint_symbol_4[1] = {2u};
+ func_S_X(tint_symbol_4);
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl.expected.glsl
new file mode 100644
index 0000000..76b2e7d
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl.expected.glsl
@@ -0,0 +1,30 @@
+#version 310 es
+
+struct str {
+ int i;
+};
+
+shared str S[4];
+void func_S_X(uint pointer[1]) {
+ str tint_symbol_1 = str(0);
+ S[pointer[0]] = tint_symbol_1;
+}
+
+void tint_symbol(uint local_invocation_index) {
+ {
+ for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+ uint i_1 = idx;
+ str tint_symbol_2 = str(0);
+ S[i_1] = tint_symbol_2;
+ }
+ }
+ barrier();
+ uint tint_symbol_3[1] = uint[1](2u);
+ func_S_X(tint_symbol_3);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol(gl_LocalInvocationIndex);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl.expected.msl b/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl.expected.msl
new file mode 100644
index 0000000..7520035
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl.expected.msl
@@ -0,0 +1,41 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
+
+struct str {
+ int i;
+};
+
+void func(threadgroup str* const pointer) {
+ str const tint_symbol_1 = str{};
+ *(pointer) = tint_symbol_1;
+}
+
+void tint_symbol_inner(uint local_invocation_index, threadgroup tint_array<str, 4>* const tint_symbol_3) {
+ for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+ uint const i_1 = idx;
+ str const tint_symbol_2 = str{};
+ (*(tint_symbol_3))[i_1] = tint_symbol_2;
+ }
+ threadgroup_barrier(mem_flags::mem_threadgroup);
+ func(&((*(tint_symbol_3))[2]));
+}
+
+kernel void tint_symbol(uint local_invocation_index [[thread_index_in_threadgroup]]) {
+ threadgroup tint_array<str, 4> tint_symbol_4;
+ tint_symbol_inner(local_invocation_index, &(tint_symbol_4));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl.expected.spvasm
new file mode 100644
index 0000000..61ef214
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl.expected.spvasm
@@ -0,0 +1,93 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 53
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %local_invocation_index_1
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %local_invocation_index_1 "local_invocation_index_1"
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %S "S"
+ OpName %func_S_X "func_S_X"
+ OpName %pointer "pointer"
+ OpName %main_inner "main_inner"
+ OpName %local_invocation_index "local_invocation_index"
+ OpName %idx "idx"
+ OpName %main "main"
+ OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+ OpMemberDecorate %str 0 Offset 0
+ OpDecorate %_arr_str_uint_4 ArrayStride 4
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+ %int = OpTypeInt 32 1
+ %str = OpTypeStruct %int
+ %uint_4 = OpConstant %uint 4
+%_arr_str_uint_4 = OpTypeArray %str %uint_4
+%_ptr_Workgroup__arr_str_uint_4 = OpTypePointer Workgroup %_arr_str_uint_4
+ %S = OpVariable %_ptr_Workgroup__arr_str_uint_4 Workgroup
+ %void = OpTypeVoid
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %10 = OpTypeFunction %void %_arr_uint_uint_1
+ %17 = OpConstantNull %int
+%_ptr_Workgroup_str = OpTypePointer Workgroup %str
+ %21 = OpConstantNull %str
+ %22 = OpTypeFunction %void %uint
+%_ptr_Function_uint = OpTypePointer Function %uint
+ %28 = OpConstantNull %uint
+ %bool = OpTypeBool
+ %uint_2 = OpConstant %uint 2
+ %uint_264 = OpConstant %uint 264
+ %47 = OpConstantComposite %_arr_uint_uint_1 %uint_2
+ %48 = OpTypeFunction %void
+ %func_S_X = OpFunction %void None %10
+ %pointer = OpFunctionParameter %_arr_uint_uint_1
+ %16 = OpLabel
+ %18 = OpCompositeExtract %uint %pointer 0
+ %20 = OpAccessChain %_ptr_Workgroup_str %S %18
+ OpStore %20 %21
+ OpReturn
+ OpFunctionEnd
+ %main_inner = OpFunction %void None %22
+%local_invocation_index = OpFunctionParameter %uint
+ %25 = OpLabel
+ %idx = OpVariable %_ptr_Function_uint Function %28
+ OpStore %idx %local_invocation_index
+ OpBranch %29
+ %29 = OpLabel
+ OpLoopMerge %30 %31 None
+ OpBranch %32
+ %32 = OpLabel
+ %34 = OpLoad %uint %idx
+ %35 = OpULessThan %bool %34 %uint_4
+ %33 = OpLogicalNot %bool %35
+ OpSelectionMerge %37 None
+ OpBranchConditional %33 %38 %37
+ %38 = OpLabel
+ OpBranch %30
+ %37 = OpLabel
+ %39 = OpLoad %uint %idx
+ %40 = OpAccessChain %_ptr_Workgroup_str %S %39
+ OpStore %40 %21
+ OpBranch %31
+ %31 = OpLabel
+ %41 = OpLoad %uint %idx
+ %42 = OpIAdd %uint %41 %uint_1
+ OpStore %idx %42
+ OpBranch %29
+ %30 = OpLabel
+ OpControlBarrier %uint_2 %uint_2 %uint_264
+ %46 = OpFunctionCall %void %func_S_X %47
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %48
+ %50 = OpLabel
+ %52 = OpLoad %uint %local_invocation_index_1
+ %51 = OpFunctionCall %void %main_inner %52
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl.expected.wgsl
new file mode 100644
index 0000000..8177527
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/struct_in_array.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : i32,
+}
+
+var<workgroup> S : array<str, 4>;
+
+fn func(pointer : ptr<workgroup, str>) {
+ *(pointer) = str();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(S[2]));
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl b/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl
new file mode 100644
index 0000000..2c25bbf
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> S : mat2x2<f32>;
+
+fn func(pointer : ptr<workgroup, vec2<f32>>) {
+ *pointer = vec2<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&S[1]);
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..642e72c
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.dxc.hlsl
@@ -0,0 +1,31 @@
+void set_vector_float2x2(inout float2x2 mat, int col, float2 val) {
+ switch (col) {
+ case 0: mat[0] = val; break;
+ case 1: mat[1] = val; break;
+ }
+}
+
+groupshared float2x2 S;
+
+void func_S_X(uint pointer[1]) {
+ set_vector_float2x2(S, pointer[0], (0.0f).xx);
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ S = float2x2((0.0f).xx, (0.0f).xx);
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const uint tint_symbol_2[1] = {1u};
+ func_S_X(tint_symbol_2);
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..642e72c
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.fxc.hlsl
@@ -0,0 +1,31 @@
+void set_vector_float2x2(inout float2x2 mat, int col, float2 val) {
+ switch (col) {
+ case 0: mat[0] = val; break;
+ case 1: mat[1] = val; break;
+ }
+}
+
+groupshared float2x2 S;
+
+void func_S_X(uint pointer[1]) {
+ set_vector_float2x2(S, pointer[0], (0.0f).xx);
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ S = float2x2((0.0f).xx, (0.0f).xx);
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const uint tint_symbol_2[1] = {1u};
+ func_S_X(tint_symbol_2);
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.glsl
new file mode 100644
index 0000000..6d63b6a
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.glsl
@@ -0,0 +1,21 @@
+#version 310 es
+
+shared mat2 S;
+void func_S_X(uint pointer[1]) {
+ S[pointer[0]] = vec2(0.0f);
+}
+
+void tint_symbol(uint local_invocation_index) {
+ {
+ S = mat2(vec2(0.0f), vec2(0.0f));
+ }
+ barrier();
+ uint tint_symbol_1[1] = uint[1](1u);
+ func_S_X(tint_symbol_1);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol(gl_LocalInvocationIndex);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.msl b/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.msl
new file mode 100644
index 0000000..9e04a33
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.msl
@@ -0,0 +1,25 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_4 {
+ float2x2 S;
+};
+
+void func(threadgroup float2* const pointer) {
+ *(pointer) = float2(0.0f);
+}
+
+void tint_symbol_inner(uint local_invocation_index, threadgroup float2x2* const tint_symbol_1) {
+ {
+ *(tint_symbol_1) = float2x2(float2(0.0f), float2(0.0f));
+ }
+ threadgroup_barrier(mem_flags::mem_threadgroup);
+ func(&((*(tint_symbol_1))[1]));
+}
+
+kernel void tint_symbol(threadgroup tint_symbol_4* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+ threadgroup float2x2* const tint_symbol_2 = &((*(tint_symbol_3)).S);
+ tint_symbol_inner(local_invocation_index, tint_symbol_2);
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.spvasm
new file mode 100644
index 0000000..8246c4a
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.spvasm
@@ -0,0 +1,62 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 37
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %local_invocation_index_1
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %local_invocation_index_1 "local_invocation_index_1"
+ OpName %S "S"
+ OpName %func_S_X "func_S_X"
+ OpName %pointer "pointer"
+ OpName %main_inner "main_inner"
+ OpName %local_invocation_index "local_invocation_index"
+ OpName %main "main"
+ OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+ %float = OpTypeFloat 32
+ %v2float = OpTypeVector %float 2
+%mat2v2float = OpTypeMatrix %v2float 2
+%_ptr_Workgroup_mat2v2float = OpTypePointer Workgroup %mat2v2float
+ %S = OpVariable %_ptr_Workgroup_mat2v2float Workgroup
+ %void = OpTypeVoid
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %9 = OpTypeFunction %void %_arr_uint_uint_1
+ %int = OpTypeInt 32 1
+ %17 = OpConstantNull %int
+%_ptr_Workgroup_v2float = OpTypePointer Workgroup %v2float
+ %21 = OpConstantNull %v2float
+ %22 = OpTypeFunction %void %uint
+ %26 = OpConstantNull %mat2v2float
+ %uint_2 = OpConstant %uint 2
+ %uint_264 = OpConstant %uint 264
+ %31 = OpConstantComposite %_arr_uint_uint_1 %uint_1
+ %32 = OpTypeFunction %void
+ %func_S_X = OpFunction %void None %9
+ %pointer = OpFunctionParameter %_arr_uint_uint_1
+ %15 = OpLabel
+ %18 = OpCompositeExtract %uint %pointer 0
+ %20 = OpAccessChain %_ptr_Workgroup_v2float %S %18
+ OpStore %20 %21
+ OpReturn
+ OpFunctionEnd
+ %main_inner = OpFunction %void None %22
+%local_invocation_index = OpFunctionParameter %uint
+ %25 = OpLabel
+ OpStore %S %26
+ OpControlBarrier %uint_2 %uint_2 %uint_264
+ %30 = OpFunctionCall %void %func_S_X %31
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %32
+ %34 = OpLabel
+ %36 = OpLoad %uint %local_invocation_index_1
+ %35 = OpFunctionCall %void %main_inner %36
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.wgsl
new file mode 100644
index 0000000..7f66524
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec2_f32_in_mat2x2.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> S : mat2x2<f32>;
+
+fn func(pointer : ptr<workgroup, vec2<f32>>) {
+ *(pointer) = vec2<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(S[1]));
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl b/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl
new file mode 100644
index 0000000..382f211
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> S : vec4<f32>;
+
+fn func(pointer : ptr<workgroup, vec4<f32>>) {
+ *pointer = vec4<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&S);
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..abc201b
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,23 @@
+groupshared float4 S;
+
+void func_S() {
+ S = (0.0f).xxxx;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ S = (0.0f).xxxx;
+ }
+ GroupMemoryBarrierWithGroupSync();
+ func_S();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..abc201b
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,23 @@
+groupshared float4 S;
+
+void func_S() {
+ S = (0.0f).xxxx;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ S = (0.0f).xxxx;
+ }
+ GroupMemoryBarrierWithGroupSync();
+ func_S();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..f542b63
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+shared vec4 S;
+void func_S() {
+ S = vec4(0.0f);
+}
+
+void tint_symbol(uint local_invocation_index) {
+ {
+ S = vec4(0.0f);
+ }
+ barrier();
+ func_S();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol(gl_LocalInvocationIndex);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl.expected.msl b/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl.expected.msl
new file mode 100644
index 0000000..8489e3f
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void func(threadgroup float4* const pointer) {
+ *(pointer) = float4(0.0f);
+}
+
+void tint_symbol_inner(uint local_invocation_index, threadgroup float4* const tint_symbol_1) {
+ {
+ *(tint_symbol_1) = float4(0.0f);
+ }
+ threadgroup_barrier(mem_flags::mem_threadgroup);
+ func(tint_symbol_1);
+}
+
+kernel void tint_symbol(uint local_invocation_index [[thread_index_in_threadgroup]]) {
+ threadgroup float4 tint_symbol_2;
+ tint_symbol_inner(local_invocation_index, &(tint_symbol_2));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..d657955
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl.expected.spvasm
@@ -0,0 +1,48 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 25
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %local_invocation_index_1
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %local_invocation_index_1 "local_invocation_index_1"
+ OpName %S "S"
+ OpName %func_S "func_S"
+ OpName %main_inner "main_inner"
+ OpName %local_invocation_index "local_invocation_index"
+ OpName %main "main"
+ OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+ %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float
+ %S = OpVariable %_ptr_Workgroup_v4float Workgroup
+ %void = OpTypeVoid
+ %8 = OpTypeFunction %void
+ %12 = OpConstantNull %v4float
+ %13 = OpTypeFunction %void %uint
+ %uint_2 = OpConstant %uint 2
+ %uint_264 = OpConstant %uint 264
+ %func_S = OpFunction %void None %8
+ %11 = OpLabel
+ OpStore %S %12
+ OpReturn
+ OpFunctionEnd
+ %main_inner = OpFunction %void None %13
+%local_invocation_index = OpFunctionParameter %uint
+ %16 = OpLabel
+ OpStore %S %12
+ OpControlBarrier %uint_2 %uint_2 %uint_264
+ %20 = OpFunctionCall %void %func_S
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %8
+ %22 = OpLabel
+ %24 = OpLoad %uint %local_invocation_index_1
+ %23 = OpFunctionCall %void %main_inner %24
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..1244c4a
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> S : vec4<f32>;
+
+fn func(pointer : ptr<workgroup, vec4<f32>>) {
+ *(pointer) = vec4<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(S));
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl
new file mode 100644
index 0000000..8143ef6
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> S : mat2x4<f32>;
+
+fn func(pointer : ptr<workgroup, vec4<f32>>) {
+ *pointer = vec4<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&S[1]);
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..bceda5e
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.dxc.hlsl
@@ -0,0 +1,31 @@
+void set_vector_float2x4(inout float2x4 mat, int col, float4 val) {
+ switch (col) {
+ case 0: mat[0] = val; break;
+ case 1: mat[1] = val; break;
+ }
+}
+
+groupshared float2x4 S;
+
+void func_S_X(uint pointer[1]) {
+ set_vector_float2x4(S, pointer[0], (0.0f).xxxx);
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ S = float2x4((0.0f).xxxx, (0.0f).xxxx);
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const uint tint_symbol_2[1] = {1u};
+ func_S_X(tint_symbol_2);
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..bceda5e
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.fxc.hlsl
@@ -0,0 +1,31 @@
+void set_vector_float2x4(inout float2x4 mat, int col, float4 val) {
+ switch (col) {
+ case 0: mat[0] = val; break;
+ case 1: mat[1] = val; break;
+ }
+}
+
+groupshared float2x4 S;
+
+void func_S_X(uint pointer[1]) {
+ set_vector_float2x4(S, pointer[0], (0.0f).xxxx);
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ S = float2x4((0.0f).xxxx, (0.0f).xxxx);
+ }
+ GroupMemoryBarrierWithGroupSync();
+ const uint tint_symbol_2[1] = {1u};
+ func_S_X(tint_symbol_2);
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.glsl
new file mode 100644
index 0000000..76afcaf
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.glsl
@@ -0,0 +1,21 @@
+#version 310 es
+
+shared mat2x4 S;
+void func_S_X(uint pointer[1]) {
+ S[pointer[0]] = vec4(0.0f);
+}
+
+void tint_symbol(uint local_invocation_index) {
+ {
+ S = mat2x4(vec4(0.0f), vec4(0.0f));
+ }
+ barrier();
+ uint tint_symbol_1[1] = uint[1](1u);
+ func_S_X(tint_symbol_1);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol(gl_LocalInvocationIndex);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.msl b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.msl
new file mode 100644
index 0000000..0f5241d
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.msl
@@ -0,0 +1,25 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_4 {
+ float2x4 S;
+};
+
+void func(threadgroup float4* const pointer) {
+ *(pointer) = float4(0.0f);
+}
+
+void tint_symbol_inner(uint local_invocation_index, threadgroup float2x4* const tint_symbol_1) {
+ {
+ *(tint_symbol_1) = float2x4(float4(0.0f), float4(0.0f));
+ }
+ threadgroup_barrier(mem_flags::mem_threadgroup);
+ func(&((*(tint_symbol_1))[1]));
+}
+
+kernel void tint_symbol(threadgroup tint_symbol_4* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+ threadgroup float2x4* const tint_symbol_2 = &((*(tint_symbol_3)).S);
+ tint_symbol_inner(local_invocation_index, tint_symbol_2);
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.spvasm
new file mode 100644
index 0000000..a007c93
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.spvasm
@@ -0,0 +1,62 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 37
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %local_invocation_index_1
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %local_invocation_index_1 "local_invocation_index_1"
+ OpName %S "S"
+ OpName %func_S_X "func_S_X"
+ OpName %pointer "pointer"
+ OpName %main_inner "main_inner"
+ OpName %local_invocation_index "local_invocation_index"
+ OpName %main "main"
+ OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+ OpDecorate %_arr_uint_uint_1 ArrayStride 4
+ %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+%_ptr_Workgroup_mat2v4float = OpTypePointer Workgroup %mat2v4float
+ %S = OpVariable %_ptr_Workgroup_mat2v4float Workgroup
+ %void = OpTypeVoid
+ %uint_1 = OpConstant %uint 1
+%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
+ %9 = OpTypeFunction %void %_arr_uint_uint_1
+ %int = OpTypeInt 32 1
+ %17 = OpConstantNull %int
+%_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float
+ %21 = OpConstantNull %v4float
+ %22 = OpTypeFunction %void %uint
+ %26 = OpConstantNull %mat2v4float
+ %uint_2 = OpConstant %uint 2
+ %uint_264 = OpConstant %uint 264
+ %31 = OpConstantComposite %_arr_uint_uint_1 %uint_1
+ %32 = OpTypeFunction %void
+ %func_S_X = OpFunction %void None %9
+ %pointer = OpFunctionParameter %_arr_uint_uint_1
+ %15 = OpLabel
+ %18 = OpCompositeExtract %uint %pointer 0
+ %20 = OpAccessChain %_ptr_Workgroup_v4float %S %18
+ OpStore %20 %21
+ OpReturn
+ OpFunctionEnd
+ %main_inner = OpFunction %void None %22
+%local_invocation_index = OpFunctionParameter %uint
+ %25 = OpLabel
+ OpStore %S %26
+ OpControlBarrier %uint_2 %uint_2 %uint_264
+ %30 = OpFunctionCall %void %func_S_X %31
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %32
+ %34 = OpLabel
+ %36 = OpLoad %uint %local_invocation_index_1
+ %35 = OpFunctionCall %void %main_inner %36
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.wgsl
new file mode 100644
index 0000000..b58576d
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_mat2x4.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+enable chromium_experimental_full_ptr_parameters;
+
+var<workgroup> S : mat2x4<f32>;
+
+fn func(pointer : ptr<workgroup, vec4<f32>>) {
+ *(pointer) = vec4<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(S[1]));
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl
new file mode 100644
index 0000000..f21f9bf
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<f32>,
+};
+
+var<workgroup> S : str;
+
+fn func(pointer : ptr<workgroup, vec4<f32>>) {
+ *pointer = vec4<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&S.i);
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl.expected.dxc.hlsl b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e9f5ab4
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,28 @@
+struct str {
+ float4 i;
+};
+
+groupshared str S;
+
+void func_S_i() {
+ S.i = (0.0f).xxxx;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ const str tint_symbol_2 = (str)0;
+ S = tint_symbol_2;
+ }
+ GroupMemoryBarrierWithGroupSync();
+ func_S_i();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl.expected.fxc.hlsl b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e9f5ab4
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+struct str {
+ float4 i;
+};
+
+groupshared str S;
+
+void func_S_i() {
+ S.i = (0.0f).xxxx;
+}
+
+struct tint_symbol_1 {
+ uint local_invocation_index : SV_GroupIndex;
+};
+
+void main_inner(uint local_invocation_index) {
+ {
+ const str tint_symbol_2 = (str)0;
+ S = tint_symbol_2;
+ }
+ GroupMemoryBarrierWithGroupSync();
+ func_S_i();
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.local_invocation_index);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl.expected.glsl b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..4852cef
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl.expected.glsl
@@ -0,0 +1,25 @@
+#version 310 es
+
+struct str {
+ vec4 i;
+};
+
+shared str S;
+void func_S_i() {
+ S.i = vec4(0.0f);
+}
+
+void tint_symbol(uint local_invocation_index) {
+ {
+ str tint_symbol_1 = str(vec4(0.0f));
+ S = tint_symbol_1;
+ }
+ barrier();
+ func_S_i();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol(gl_LocalInvocationIndex);
+ return;
+}
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl.expected.msl b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl.expected.msl
new file mode 100644
index 0000000..d0437f0
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl.expected.msl
@@ -0,0 +1,26 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct str {
+ float4 i;
+};
+
+void func(threadgroup float4* const pointer) {
+ *(pointer) = float4(0.0f);
+}
+
+void tint_symbol_inner(uint local_invocation_index, threadgroup str* const tint_symbol_2) {
+ {
+ str const tint_symbol_1 = str{};
+ *(tint_symbol_2) = tint_symbol_1;
+ }
+ threadgroup_barrier(mem_flags::mem_threadgroup);
+ func(&((*(tint_symbol_2)).i));
+}
+
+kernel void tint_symbol(uint local_invocation_index [[thread_index_in_threadgroup]]) {
+ threadgroup str tint_symbol_3;
+ tint_symbol_inner(local_invocation_index, &(tint_symbol_3));
+ return;
+}
+
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl.expected.spvasm b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..c21aeae
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl.expected.spvasm
@@ -0,0 +1,56 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 30
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main" %local_invocation_index_1
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %local_invocation_index_1 "local_invocation_index_1"
+ OpName %str "str"
+ OpMemberName %str 0 "i"
+ OpName %S "S"
+ OpName %func_S_i "func_S_i"
+ OpName %main_inner "main_inner"
+ OpName %local_invocation_index "local_invocation_index"
+ OpName %main "main"
+ OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+ OpMemberDecorate %str 0 Offset 0
+ %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %str = OpTypeStruct %v4float
+%_ptr_Workgroup_str = OpTypePointer Workgroup %str
+ %S = OpVariable %_ptr_Workgroup_str Workgroup
+ %void = OpTypeVoid
+ %9 = OpTypeFunction %void
+ %uint_0 = OpConstant %uint 0
+%_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float
+ %16 = OpConstantNull %v4float
+ %17 = OpTypeFunction %void %uint
+ %21 = OpConstantNull %str
+ %uint_2 = OpConstant %uint 2
+ %uint_264 = OpConstant %uint 264
+ %func_S_i = OpFunction %void None %9
+ %12 = OpLabel
+ %15 = OpAccessChain %_ptr_Workgroup_v4float %S %uint_0
+ OpStore %15 %16
+ OpReturn
+ OpFunctionEnd
+ %main_inner = OpFunction %void None %17
+%local_invocation_index = OpFunctionParameter %uint
+ %20 = OpLabel
+ OpStore %S %21
+ OpControlBarrier %uint_2 %uint_2 %uint_264
+ %25 = OpFunctionCall %void %func_S_i
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %9
+ %27 = OpLabel
+ %29 = OpLoad %uint %local_invocation_index_1
+ %28 = OpFunctionCall %void %main_inner %29
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl.expected.wgsl b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..d6841c1
--- /dev/null
+++ b/test/tint/ptr_ref/store/param/workgroup/vec4_f32_in_struct.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+enable chromium_experimental_full_ptr_parameters;
+
+struct str {
+ i : vec4<f32>,
+}
+
+var<workgroup> S : str;
+
+fn func(pointer : ptr<workgroup, vec4<f32>>) {
+ *(pointer) = vec4<f32>();
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ func(&(S.i));
+}