Implement textureLoad()

Bug: tint:140
Bug: tint:143
Bug: tint:144
Bug: tint:145
Bug: tint:146
Bug: tint:147
Change-Id: I8f41abac2e355c121e8868aa708ae51d0db87665
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/34960
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index 2ca5d04..6e11dae 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -431,10 +431,10 @@
     "src/validator/validator_impl.h",
     "src/validator/validator_test_helper.cc",
     "src/validator/validator_test_helper.h",
+    "src/writer/append_vector.cc",
+    "src/writer/append_vector.h",
     "src/writer/float_to_string.cc",
     "src/writer/float_to_string.h",
-    "src/writer/pack_coord_arrayidx.cc",
-    "src/writer/pack_coord_arrayidx.h",
     "src/writer/text.cc",
     "src/writer/text.h",
     "src/writer/text_generator.cc",
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 1f23742..d9636d8 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -252,10 +252,10 @@
   validator/validator_impl.h
   validator/validator_test_helper.cc
   validator/validator_test_helper.h
+  writer/append_vector.cc
+  writer/append_vector.h
   writer/float_to_string.cc
   writer/float_to_string.h
-  writer/pack_coord_arrayidx.cc
-  writer/pack_coord_arrayidx.h
   writer/text.cc
   writer/text.h
   writer/text_generator.cc
diff --git a/src/ast/intrinsic.h b/src/ast/intrinsic.h
index ddad395..37edca5 100644
--- a/src/ast/intrinsic.h
+++ b/src/ast/intrinsic.h
@@ -139,6 +139,8 @@
       size_t offset = kNotUsed;
       /// `sampler` parameter index.
       size_t sampler = kNotUsed;
+      /// `sample_index` parameter index.
+      size_t sample_index = kNotUsed;
       /// `texture` parameter index.
       size_t texture = kNotUsed;
     };
diff --git a/src/ast/intrinsic_texture_helper_test.cc b/src/ast/intrinsic_texture_helper_test.cc
index 9fce78f..e492e0d 100644
--- a/src/ast/intrinsic_texture_helper_test.cc
+++ b/src/ast/intrinsic_texture_helper_test.cc
@@ -14,6 +14,11 @@
 
 #include "src/ast/intrinsic_texture_helper_test.h"
 
+#include "src/ast/builder.h"
+#include "src/ast/type/depth_texture_type.h"
+#include "src/ast/type/multisampled_texture_type.h"
+#include "src/ast/type/sampled_texture_type.h"
+#include "src/ast/type/storage_texture_type.h"
 #include "src/ast/type_constructor_expression.h"
 
 namespace tint {
@@ -21,1096 +26,1957 @@
 namespace intrinsic {
 namespace test {
 
-TextureOverloadCase::TextureOverloadCase() = default;
+using u32 = ast::Builder::u32;
+using i32 = ast::Builder::i32;
+using f32 = ast::Builder::f32;
+
+TextureOverloadCase::TextureOverloadCase(
+    ValidTextureOverload o,
+    const char* desc,
+    TextureKind tk,
+    type::SamplerKind sk,
+    type::TextureDimension dims,
+    TextureDataType datatype,
+    const char* f,
+    std::function<ExpressionList(Builder*)> a)
+    : overload(o),
+      description(desc),
+      texture_kind(tk),
+      sampler_kind(sk),
+      texture_dimension(dims),
+      texture_data_type(datatype),
+      function(f),
+      args(std::move(a)) {}
+TextureOverloadCase::TextureOverloadCase(
+    ValidTextureOverload o,
+    const char* desc,
+    TextureKind tk,
+    type::TextureDimension dims,
+    TextureDataType datatype,
+    const char* f,
+    std::function<ExpressionList(Builder*)> a)
+    : overload(o),
+      description(desc),
+      texture_kind(tk),
+      texture_dimension(dims),
+      texture_data_type(datatype),
+      function(f),
+      args(std::move(a)) {}
 TextureOverloadCase::TextureOverloadCase(
     ValidTextureOverload o,
     const char* d,
-    TextureKind tk,
-    type::SamplerKind sk,
-    type::TextureDimension td,
-    TextureDataType tdt,
+    AccessControl access,
+    type::ImageFormat i,
+    type::TextureDimension dims,
+    TextureDataType datatype,
     const char* f,
     std::function<ExpressionList(Builder*)> a)
     : overload(o),
       description(d),
-      texture_kind(tk),
-      sampler_kind(sk),
-      texture_dimension(td),
-      texture_data_type(tdt),
+      texture_kind(TextureKind::kStorage),
+      access_control(access),
+      image_format(i),
+      texture_dimension(dims),
+      texture_data_type(datatype),
       function(f),
       args(std::move(a)) {}
 TextureOverloadCase::TextureOverloadCase(const TextureOverloadCase&) = default;
 TextureOverloadCase::~TextureOverloadCase() = default;
 
+std::ostream& operator<<(std::ostream& out, const TextureKind& kind) {
+  switch (kind) {
+    case TextureKind::kRegular:
+      out << "regular";
+      break;
+    case TextureKind::kDepth:
+      out << "depth";
+      break;
+    case TextureKind::kMultisampled:
+      out << "multisampled";
+      break;
+    case TextureKind::kStorage:
+      out << "storage";
+      break;
+  }
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const TextureDataType& ty) {
+  switch (ty) {
+    case TextureDataType::kF32:
+      out << "f32";
+      break;
+    case TextureDataType::kU32:
+      out << "u32";
+      break;
+    case TextureDataType::kI32:
+      out << "i32";
+      break;
+  }
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const TextureOverloadCase& data) {
+  out << "TextureOverloadCase " << static_cast<int>(data.overload) << "\n";
+  out << data.description << "\n";
+  out << "texture_kind:      " << data.texture_kind << "\n";
+  out << "sampler_kind:      ";
+  if (data.texture_kind != TextureKind::kStorage) {
+    out << data.sampler_kind;
+  } else {
+    out << "<unused>";
+  }
+  out << "\n";
+  out << "access_control:    " << data.access_control << "\n";
+  out << "image_format:      " << data.image_format << "\n";
+  out << "texture_dimension: " << data.texture_dimension << "\n";
+  out << "texture_data_type: " << data.texture_data_type << "\n";
+  return out;
+}
+
+ast::type::Type* TextureOverloadCase::resultVectorComponentType(
+    ast::Builder* b) const {
+  switch (texture_data_type) {
+    case ast::intrinsic::test::TextureDataType::kF32:
+      return b->ty.f32;
+    case ast::intrinsic::test::TextureDataType::kU32:
+      return b->ty.u32;
+    case ast::intrinsic::test::TextureDataType::kI32:
+      return b->ty.i32;
+  }
+
+  assert(false /* unreachable */);
+  return nullptr;
+}
+
+ast::Variable* TextureOverloadCase::buildTextureVariable(
+    ast::Builder* b) const {
+  auto* datatype = resultVectorComponentType(b);
+
+  switch (texture_kind) {
+    case ast::intrinsic::test::TextureKind::kRegular:
+      return b->Var(
+          "texture", ast::StorageClass::kNone,
+          b->create<ast::type::SampledTexture>(texture_dimension, datatype));
+
+    case ast::intrinsic::test::TextureKind::kDepth:
+      return b->Var("texture", ast::StorageClass::kNone,
+                    b->create<ast::type::DepthTexture>(texture_dimension));
+
+    case ast::intrinsic::test::TextureKind::kMultisampled:
+      return b->Var("texture", ast::StorageClass::kNone,
+                    b->create<ast::type::MultisampledTexture>(texture_dimension,
+                                                              datatype));
+
+    case ast::intrinsic::test::TextureKind::kStorage:
+      return b->Var("texture", ast::StorageClass::kNone,
+                    b->create<ast::type::StorageTexture>(
+                        texture_dimension, access_control, image_format));
+  }
+
+  assert(false /* unreachable */);
+  return nullptr;
+}
+
+ast::Variable* TextureOverloadCase::buildSamplerVariable(
+    ast::Builder* b) const {
+  return b->Var("sampler", ast::StorageClass::kNone,
+                b->create<ast::type::Sampler>(sampler_kind));
+}
+
 std::vector<TextureOverloadCase> TextureOverloadCase::ValidCases() {
-  return {{
-              ValidTextureOverload::kSample1dF32,
-              "textureSample(t : texture_1d<f32>,\n"
-              "              s : sampler,\n"
-              "              coords : f32) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k1d,
-              TextureDataType::kF32,
-              "textureSample",
-              [](Builder* b) {
-                return b->ExprList("texture",  // t
-                                   "sampler",  // s
-                                   1.0f);      // coords
-              },
+  return {
+      {
+          ValidTextureOverload::kSample1dF32,
+          "textureSample(t      : texture_1d<f32>,\n"
+          "              s      : sampler,\n"
+          "              coords : f32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k1d,
+          TextureDataType::kF32,
+          "textureSample",
+          [](Builder* b) {
+            return b->ExprList("texture",  // t
+                               "sampler",  // s
+                               1.0f);      // coords
           },
-          {
-              ValidTextureOverload::kSample1dArrayF32,
-              "textureSample(t : texture_1d_array<f32>,\n"
-              "              s : sampler,\n"
-              "              coords : f32,\n"
-              "              array_index : u32) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k1dArray,
-              TextureDataType::kF32,
-              "textureSample",
-              [](Builder* b) {
-                return b->ExprList("texture",  // t
-                                   "sampler",  // s
-                                   1.0f,       // coords
-                                   2);         // array_index
-              },
+      },
+      {
+          ValidTextureOverload::kSample1dArrayF32,
+          "textureSample(t           : texture_1d_array<f32>,\n"
+          "              s           : sampler,\n"
+          "              coords      : f32,\n"
+          "              array_index : i32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k1dArray,
+          TextureDataType::kF32,
+          "textureSample",
+          [](Builder* b) {
+            return b->ExprList("texture",  // t
+                               "sampler",  // s
+                               1.0f,       // coords
+                               2);         // array_index
           },
-          {
-              ValidTextureOverload::kSample2dF32,
-              "textureSample(t : texture_2d<f32>,\n"
-              "              s : sampler,\n"
-              "              coords : vec2<f32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2d,
-              TextureDataType::kF32,
-              "textureSample",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                // t
-                                   "sampler",                // s
-                                   b->vec2<f32>(1.f, 2.f));  // coords
-              },
+      },
+      {
+          ValidTextureOverload::kSample2dF32,
+          "textureSample(t      : texture_2d<f32>,\n"
+          "              s      : sampler,\n"
+          "              coords : vec2<f32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureSample",
+          [](Builder* b) {
+            return b->ExprList("texture",                // t
+                               "sampler",                // s
+                               b->vec2<f32>(1.f, 2.f));  // coords
           },
-          {
-              ValidTextureOverload::kSample2dOffsetF32,
-              "textureSample(t : texture_2d<f32>,\n"
-              "              s : sampler,\n"
-              "              coords : vec2<f32>\n"
-              "              offset : vec2<i32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2d,
-              TextureDataType::kF32,
-              "textureSample",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                using i32 = Builder::i32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   b->vec2<i32>(3, 4));     // offset
-              },
+      },
+      {
+          ValidTextureOverload::kSample2dOffsetF32,
+          "textureSample(t      : texture_2d<f32>,\n"
+          "              s      : sampler,\n"
+          "              coords : vec2<f32>\n"
+          "              offset : vec2<i32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureSample",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               b->vec2<i32>(3, 4));     // offset
           },
-          {
-              ValidTextureOverload::kSample2dArrayF32,
-              "textureSample(t : texture_2d_array<f32>,\n"
-              "              s : sampler,\n"
-              "              coords : vec2<f32>,\n"
-              "              array_index : u32) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2dArray,
-              TextureDataType::kF32,
-              "textureSample",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   3);                      // array_index
-              },
+      },
+      {
+          ValidTextureOverload::kSample2dArrayF32,
+          "textureSample(t           : texture_2d_array<f32>,\n"
+          "              s           : sampler,\n"
+          "              coords      : vec2<f32>,\n"
+          "              array_index : i32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureSample",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               3);                      // array_index
           },
-          {
-              ValidTextureOverload::kSample2dArrayOffsetF32,
-              "textureSample(t : texture_2d_array<f32>,\n"
-              "              s : sampler,\n"
-              "              coords : vec2<f32>,\n"
-              "              array_index : u32\n"
-              "              offset : vec2<i32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2dArray,
-              TextureDataType::kF32,
-              "textureSample",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                using i32 = Builder::i32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   3,                       // array_index
-                                   b->vec2<i32>(4, 5));     // offset
-              },
+      },
+      {
+          ValidTextureOverload::kSample2dArrayOffsetF32,
+          "textureSample(t           : texture_2d_array<f32>,\n"
+          "              s           : sampler,\n"
+          "              coords      : vec2<f32>,\n"
+          "              array_index : i32\n"
+          "              offset      : vec2<i32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureSample",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               3,                       // array_index
+                               b->vec2<i32>(4, 5));     // offset
           },
-          {
-              ValidTextureOverload::kSample3dF32,
-              "textureSample(t : texture_3d<f32>,\n"
-              "              s : sampler,\n"
-              "              coords : vec3<f32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k3d,
-              TextureDataType::kF32,
-              "textureSample",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                     // t
-                                   "sampler",                     // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f));  // coords
-              },
+      },
+      {
+          ValidTextureOverload::kSample3dF32,
+          "textureSample(t      : texture_3d<f32>,\n"
+          "              s      : sampler,\n"
+          "              coords : vec3<f32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k3d,
+          TextureDataType::kF32,
+          "textureSample",
+          [](Builder* b) {
+            return b->ExprList("texture",                     // t
+                               "sampler",                     // s
+                               b->vec3<f32>(1.f, 2.f, 3.f));  // coords
           },
-          {
-              ValidTextureOverload::kSample3dOffsetF32,
-              "textureSample(t : texture_3d<f32>,\n"
-              "              s : sampler,\n"
-              "              coords : vec3<f32>\n"
-              "              offset : vec3<i32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k3d,
-              TextureDataType::kF32,
-              "textureSample",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                using i32 = Builder::i32;
-                return b->ExprList("texture",                    // t
-                                   "sampler",                    // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                                   b->vec3<i32>(4, 5, 6));       // offset
-              },
+      },
+      {
+          ValidTextureOverload::kSample3dOffsetF32,
+          "textureSample(t      : texture_3d<f32>,\n"
+          "              s      : sampler,\n"
+          "              coords : vec3<f32>\n"
+          "              offset : vec3<i32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k3d,
+          TextureDataType::kF32,
+          "textureSample",
+          [](Builder* b) {
+            return b->ExprList("texture",                    // t
+                               "sampler",                    // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                               b->vec3<i32>(4, 5, 6));       // offset
           },
-          {
-              ValidTextureOverload::kSampleCubeF32,
-              "textureSample(t : texture_cube<f32>,\n"
-              "              s : sampler,\n"
-              "              coords : vec3<f32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::kCube,
-              TextureDataType::kF32,
-              "textureSample",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                     // t
-                                   "sampler",                     // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f));  // coords
-              },
+      },
+      {
+          ValidTextureOverload::kSampleCubeF32,
+          "textureSample(t      : texture_cube<f32>,\n"
+          "              s      : sampler,\n"
+          "              coords : vec3<f32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCube,
+          TextureDataType::kF32,
+          "textureSample",
+          [](Builder* b) {
+            return b->ExprList("texture",                     // t
+                               "sampler",                     // s
+                               b->vec3<f32>(1.f, 2.f, 3.f));  // coords
           },
-          {
-              ValidTextureOverload::kSampleCubeArrayF32,
-              "textureSample(t : texture_cube_array<f32>,\n"
-              "              s : sampler,\n"
-              "              coords : vec3<f32>,\n"
-              "              array_index : u32) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::kCubeArray,
-              TextureDataType::kF32,
-              "textureSample",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                    // t
-                                   "sampler",                    // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                                   4);                           // array_index
-              },
+      },
+      {
+          ValidTextureOverload::kSampleCubeArrayF32,
+          "textureSample(t           : texture_cube_array<f32>,\n"
+          "              s           : sampler,\n"
+          "              coords      : vec3<f32>,\n"
+          "              array_index : i32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCubeArray,
+          TextureDataType::kF32,
+          "textureSample",
+          [](Builder* b) {
+            return b->ExprList("texture",                    // t
+                               "sampler",                    // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                               4);                           // array_index
           },
-          {
-              ValidTextureOverload::kSampleDepth2dF32,
-              "textureSample(t : texture_depth_2d,\n"
-              "              s : sampler,\n"
-              "              coords : vec2<f32>) -> f32",
-              TextureKind::kDepth,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2d,
-              TextureDataType::kF32,
-              "textureSample",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                // t
-                                   "sampler",                // s
-                                   b->vec2<f32>(1.f, 2.f));  // coords
-              },
+      },
+      {
+          ValidTextureOverload::kSampleDepth2dF32,
+          "textureSample(t      : texture_depth_2d,\n"
+          "              s      : sampler,\n"
+          "              coords : vec2<f32>) -> f32",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureSample",
+          [](Builder* b) {
+            return b->ExprList("texture",                // t
+                               "sampler",                // s
+                               b->vec2<f32>(1.f, 2.f));  // coords
           },
-          {
-              ValidTextureOverload::kSampleDepth2dOffsetF32,
-              "textureSample(t : texture_depth_2d,\n"
-              "              s : sampler,\n"
-              "              coords : vec2<f32>\n"
-              "              offset : vec2<i32>) -> f32",
-              TextureKind::kDepth,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2d,
-              TextureDataType::kF32,
-              "textureSample",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                using i32 = Builder::i32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   b->vec2<i32>(3, 4));     // offset
-              },
+      },
+      {
+          ValidTextureOverload::kSampleDepth2dOffsetF32,
+          "textureSample(t      : texture_depth_2d,\n"
+          "              s      : sampler,\n"
+          "              coords : vec2<f32>\n"
+          "              offset : vec2<i32>) -> f32",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureSample",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               b->vec2<i32>(3, 4));     // offset
           },
-          {
-              ValidTextureOverload::kSampleDepth2dArrayF32,
-              "textureSample(t : texture_depth_2d_array,\n"
-              "              s : sampler,\n"
-              "              coords : vec2<f32>,\n"
-              "              array_index : u32) -> f32",
-              TextureKind::kDepth,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2dArray,
-              TextureDataType::kF32,
-              "textureSample",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   3);                      // array_index
-              },
+      },
+      {
+          ValidTextureOverload::kSampleDepth2dArrayF32,
+          "textureSample(t           : texture_depth_2d_array,\n"
+          "              s           : sampler,\n"
+          "              coords      : vec2<f32>,\n"
+          "              array_index : i32) -> f32",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureSample",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               3);                      // array_index
           },
-          {
-              ValidTextureOverload::kSampleDepth2dArrayOffsetF32,
-              "textureSample(t : texture_depth_2d_array,\n"
-              "              s : sampler,\n"
-              "              coords : vec2<f32>,\n"
-              "              array_index : u32\n"
-              "              offset : vec2<i32>) -> f32",
-              TextureKind::kDepth,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2dArray,
-              TextureDataType::kF32,
-              "textureSample",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                using i32 = Builder::i32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   3,                       // array_index
-                                   b->vec2<i32>(4, 5));     // offset
-              },
+      },
+      {
+          ValidTextureOverload::kSampleDepth2dArrayOffsetF32,
+          "textureSample(t           : texture_depth_2d_array,\n"
+          "              s           : sampler,\n"
+          "              coords      : vec2<f32>,\n"
+          "              array_index : i32\n"
+          "              offset      : vec2<i32>) -> f32",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureSample",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               3,                       // array_index
+                               b->vec2<i32>(4, 5));     // offset
           },
-          {
-              ValidTextureOverload::kSampleDepthCubeF32,
-              "textureSample(t : texture_depth_cube,\n"
-              "              s : sampler,\n"
-              "              coords : vec3<f32>) -> f32",
-              TextureKind::kDepth,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::kCube,
-              TextureDataType::kF32,
-              "textureSample",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                     // t
-                                   "sampler",                     // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f));  // coords
-              },
+      },
+      {
+          ValidTextureOverload::kSampleDepthCubeF32,
+          "textureSample(t      : texture_depth_cube,\n"
+          "              s      : sampler,\n"
+          "              coords : vec3<f32>) -> f32",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCube,
+          TextureDataType::kF32,
+          "textureSample",
+          [](Builder* b) {
+            return b->ExprList("texture",                     // t
+                               "sampler",                     // s
+                               b->vec3<f32>(1.f, 2.f, 3.f));  // coords
           },
-          {
-              ValidTextureOverload::kSampleDepthCubeArrayF32,
-              "textureSample(t : texture_depth_cube_array,\n"
-              "              s : sampler,\n"
-              "              coords : vec3<f32>,\n"
-              "              array_index : u32) -> f32",
-              TextureKind::kDepth,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::kCubeArray,
-              TextureDataType::kF32,
-              "textureSample",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                    // t
-                                   "sampler",                    // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                                   4);                           // array_index
-              },
+      },
+      {
+          ValidTextureOverload::kSampleDepthCubeArrayF32,
+          "textureSample(t           : texture_depth_cube_array,\n"
+          "              s           : sampler,\n"
+          "              coords      : vec3<f32>,\n"
+          "              array_index : i32) -> f32",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCubeArray,
+          TextureDataType::kF32,
+          "textureSample",
+          [](Builder* b) {
+            return b->ExprList("texture",                    // t
+                               "sampler",                    // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                               4);                           // array_index
           },
-          {
-              ValidTextureOverload::kSampleBias2dF32,
-              "textureSampleBias(t : texture_2d<f32>,\n"
-              "                  s : sampler,\n"
-              "                  coords : vec2<f32>,\n"
-              "                  bias : f32) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2d,
-              TextureDataType::kF32,
-              "textureSampleBias",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   3.f);                    // bias
-              },
+      },
+      {
+          ValidTextureOverload::kSampleBias2dF32,
+          "textureSampleBias(t      : texture_2d<f32>,\n"
+          "                  s      : sampler,\n"
+          "                  coords : vec2<f32>,\n"
+          "                  bias   : f32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureSampleBias",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               3.f);                    // bias
           },
-          {
-              ValidTextureOverload::kSampleBias2dOffsetF32,
-              "textureSampleBias(t : texture_2d<f32>,\n"
-              "                  s : sampler,\n"
-              "                  coords : vec2<f32>,\n"
-              "                  bias : f32,\n"
-              "                  offset : vec2<i32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2d,
-              TextureDataType::kF32,
-              "textureSampleBias",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                using i32 = Builder::i32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   3.f,                     // bias
-                                   b->vec2<i32>(4, 5));     // offset
-              },
+      },
+      {
+          ValidTextureOverload::kSampleBias2dOffsetF32,
+          "textureSampleBias(t      : texture_2d<f32>,\n"
+          "                  s      : sampler,\n"
+          "                  coords : vec2<f32>,\n"
+          "                  bias   : f32,\n"
+          "                  offset : vec2<i32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureSampleBias",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               3.f,                     // bias
+                               b->vec2<i32>(4, 5));     // offset
           },
-          {
-              ValidTextureOverload::kSampleBias2dArrayF32,
-              "textureSampleBias(t : texture_2d_array<f32>,\n"
-              "                  s : sampler,\n"
-              "                  coords : vec2<f32>,\n"
-              "                  array_index : u32,\n"
-              "                  bias : f32) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2dArray,
-              TextureDataType::kF32,
-              "textureSampleBias",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   4,                       // array_index
-                                   3.f);                    // bias
-              },
+      },
+      {
+          ValidTextureOverload::kSampleBias2dArrayF32,
+          "textureSampleBias(t           : texture_2d_array<f32>,\n"
+          "                  s           : sampler,\n"
+          "                  coords      : vec2<f32>,\n"
+          "                  array_index : i32,\n"
+          "                  bias        : f32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureSampleBias",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               4,                       // array_index
+                               3.f);                    // bias
           },
-          {
-              ValidTextureOverload::kSampleBias2dArrayOffsetF32,
-              "textureSampleBias(t : texture_2d_array<f32>,\n"
-              "                  s : sampler,\n"
-              "                  coords : vec2<f32>,\n"
-              "                  array_index : u32,\n"
-              "                  bias : f32,\n"
-              "                  offset : vec2<i32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2dArray,
-              TextureDataType::kF32,
-              "textureSampleBias",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                using i32 = Builder::i32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   3,                       // array_index
-                                   4.f,                     // bias
-                                   b->vec2<i32>(5, 6));     // offset
-              },
+      },
+      {
+          ValidTextureOverload::kSampleBias2dArrayOffsetF32,
+          "textureSampleBias(t           : texture_2d_array<f32>,\n"
+          "                  s           : sampler,\n"
+          "                  coords      : vec2<f32>,\n"
+          "                  array_index : i32,\n"
+          "                  bias        : f32,\n"
+          "                  offset      : vec2<i32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureSampleBias",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               3,                       // array_index
+                               4.f,                     // bias
+                               b->vec2<i32>(5, 6));     // offset
           },
-          {
-              ValidTextureOverload::kSampleBias3dF32,
-              "textureSampleBias(t : texture_3d<f32>,\n"
-              "                  s : sampler,\n"
-              "                  coords : vec3<f32>,\n"
-              "                  bias : f32) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k3d,
-              TextureDataType::kF32,
-              "textureSampleBias",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                    // t
-                                   "sampler",                    // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                                   4.f);                         // bias
-              },
+      },
+      {
+          ValidTextureOverload::kSampleBias3dF32,
+          "textureSampleBias(t      : texture_3d<f32>,\n"
+          "                  s      : sampler,\n"
+          "                  coords : vec3<f32>,\n"
+          "                  bias   : f32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k3d,
+          TextureDataType::kF32,
+          "textureSampleBias",
+          [](Builder* b) {
+            return b->ExprList("texture",                    // t
+                               "sampler",                    // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                               4.f);                         // bias
           },
-          {
-              ValidTextureOverload::kSampleBias3dOffsetF32,
-              "textureSampleBias(t : texture_3d<f32>,\n"
-              "                  s : sampler,\n"
-              "                  coords : vec3<f32>,\n"
-              "                  bias : f32,\n"
-              "                  offset : vec3<i32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k3d,
-              TextureDataType::kF32,
-              "textureSampleBias",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                using i32 = Builder::i32;
-                return b->ExprList("texture",                    // t
-                                   "sampler",                    // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                                   4.f,                          // bias
-                                   b->vec3<i32>(5, 6, 7));       // offset
-              },
+      },
+      {
+          ValidTextureOverload::kSampleBias3dOffsetF32,
+          "textureSampleBias(t      : texture_3d<f32>,\n"
+          "                  s      : sampler,\n"
+          "                  coords : vec3<f32>,\n"
+          "                  bias   : f32,\n"
+          "                  offset : vec3<i32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k3d,
+          TextureDataType::kF32,
+          "textureSampleBias",
+          [](Builder* b) {
+            return b->ExprList("texture",                    // t
+                               "sampler",                    // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                               4.f,                          // bias
+                               b->vec3<i32>(5, 6, 7));       // offset
           },
-          {
-              ValidTextureOverload::kSampleBiasCubeF32,
-              "textureSampleBias(t : texture_cube<f32>,\n"
-              "                  s : sampler,\n"
-              "                  coords : vec3<f32>,\n"
-              "                  bias : f32) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::kCube,
-              TextureDataType::kF32,
-              "textureSampleBias",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                    // t
-                                   "sampler",                    // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                                   4.f);                         // bias
-              },
+      },
+      {
+          ValidTextureOverload::kSampleBiasCubeF32,
+          "textureSampleBias(t      : texture_cube<f32>,\n"
+          "                  s      : sampler,\n"
+          "                  coords : vec3<f32>,\n"
+          "                  bias   : f32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCube,
+          TextureDataType::kF32,
+          "textureSampleBias",
+          [](Builder* b) {
+            return b->ExprList("texture",                    // t
+                               "sampler",                    // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                               4.f);                         // bias
           },
-          {
-              ValidTextureOverload::kSampleBiasCubeArrayF32,
-              "textureSampleBias(t : texture_cube_array<f32>,\n"
-              "                  s : sampler,\n"
-              "                  coords : vec3<f32>,\n"
-              "                  array_index : u32,\n"
-              "                  bias : f32) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::kCubeArray,
-              TextureDataType::kF32,
-              "textureSampleBias",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                    // t
-                                   "sampler",                    // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                                   3,                            // array_index
-                                   4.f);                         // bias
-              },
+      },
+      {
+          ValidTextureOverload::kSampleBiasCubeArrayF32,
+          "textureSampleBias(t           : texture_cube_array<f32>,\n"
+          "                  s           : sampler,\n"
+          "                  coords      : vec3<f32>,\n"
+          "                  array_index : i32,\n"
+          "                  bias        : f32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCubeArray,
+          TextureDataType::kF32,
+          "textureSampleBias",
+          [](Builder* b) {
+            return b->ExprList("texture",                    // t
+                               "sampler",                    // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                               3,                            // array_index
+                               4.f);                         // bias
           },
-          {
-              ValidTextureOverload::kSampleLevel2dF32,
-              "textureSampleLevel(t : texture_2d<f32>,\n"
-              "                   s : sampler,\n"
-              "                   coords : vec2<f32>,\n"
-              "                   level : f32) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2d,
-              TextureDataType::kF32,
-              "textureSampleLevel",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   3.f);                    // level
-              },
+      },
+      {
+          ValidTextureOverload::kSampleLevel2dF32,
+          "textureSampleLevel(t      : texture_2d<f32>,\n"
+          "                   s      : sampler,\n"
+          "                   coords : vec2<f32>,\n"
+          "                   level  : f32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureSampleLevel",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               3.f);                    // level
           },
-          {
-              ValidTextureOverload::kSampleLevel2dOffsetF32,
-              "textureSampleLevel(t : texture_2d<f32>,\n"
-              "                   s : sampler,\n"
-              "                   coords : vec2<f32>,\n"
-              "                   level : f32,\n"
-              "                   offset : vec2<i32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2d,
-              TextureDataType::kF32,
-              "textureSampleLevel",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                using i32 = Builder::i32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   3.f,                     // level
-                                   b->vec2<i32>(4, 5));     // offset
-              },
+      },
+      {
+          ValidTextureOverload::kSampleLevel2dOffsetF32,
+          "textureSampleLevel(t      : texture_2d<f32>,\n"
+          "                   s      : sampler,\n"
+          "                   coords : vec2<f32>,\n"
+          "                   level  : f32,\n"
+          "                   offset : vec2<i32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureSampleLevel",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               3.f,                     // level
+                               b->vec2<i32>(4, 5));     // offset
           },
-          {
-              ValidTextureOverload::kSampleLevel2dArrayF32,
-              "textureSampleLevel(t : texture_2d_array<f32>,\n"
-              "                   s : sampler,\n"
-              "                   coords : vec2<f32>,\n"
-              "                   array_index : u32,\n"
-              "                   level : f32) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2dArray,
-              TextureDataType::kF32,
-              "textureSampleLevel",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   3,                       // array_index
-                                   4.f);                    // level
-              },
+      },
+      {
+          ValidTextureOverload::kSampleLevel2dArrayF32,
+          "textureSampleLevel(t           : texture_2d_array<f32>,\n"
+          "                   s           : sampler,\n"
+          "                   coords      : vec2<f32>,\n"
+          "                   array_index : i32,\n"
+          "                   level       : f32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureSampleLevel",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               3,                       // array_index
+                               4.f);                    // level
           },
-          {
-              ValidTextureOverload::kSampleLevel2dArrayOffsetF32,
-              "textureSampleLevel(t : texture_2d_array<f32>,\n"
-              "                   s : sampler,\n"
-              "                   coords : vec2<f32>,\n"
-              "                   array_index : u32,\n"
-              "                   level : f32,\n"
-              "                   offset : vec2<i32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2dArray,
-              TextureDataType::kF32,
-              "textureSampleLevel",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                using i32 = Builder::i32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   3,                       // array_index
-                                   4.f,                     // level
-                                   b->vec2<i32>(5, 6));     // offset
-              },
+      },
+      {
+          ValidTextureOverload::kSampleLevel2dArrayOffsetF32,
+          "textureSampleLevel(t           : texture_2d_array<f32>,\n"
+          "                   s           : sampler,\n"
+          "                   coords      : vec2<f32>,\n"
+          "                   array_index : i32,\n"
+          "                   level       : f32,\n"
+          "                   offset      : vec2<i32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureSampleLevel",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               3,                       // array_index
+                               4.f,                     // level
+                               b->vec2<i32>(5, 6));     // offset
           },
-          {
-              ValidTextureOverload::kSampleLevel3dF32,
-              "textureSampleLevel(t : texture_3d<f32>,\n"
-              "                   s : sampler,\n"
-              "                   coords : vec3<f32>,\n"
-              "                   level : f32) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k3d,
-              TextureDataType::kF32,
-              "textureSampleLevel",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                    // t
-                                   "sampler",                    // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                                   4.f);                         // level
-              },
+      },
+      {
+          ValidTextureOverload::kSampleLevel3dF32,
+          "textureSampleLevel(t      : texture_3d<f32>,\n"
+          "                   s      : sampler,\n"
+          "                   coords : vec3<f32>,\n"
+          "                   level  : f32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k3d,
+          TextureDataType::kF32,
+          "textureSampleLevel",
+          [](Builder* b) {
+            return b->ExprList("texture",                    // t
+                               "sampler",                    // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                               4.f);                         // level
           },
-          {
-              ValidTextureOverload::kSampleLevel3dOffsetF32,
-              "textureSampleLevel(t : texture_3d<f32>,\n"
-              "                   s : sampler,\n"
-              "                   coords : vec3<f32>,\n"
-              "                   level : f32,\n"
-              "                   offset : vec3<i32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k3d,
-              TextureDataType::kF32,
-              "textureSampleLevel",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                using i32 = Builder::i32;
-                return b->ExprList("texture",                    // t
-                                   "sampler",                    // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                                   4.f,                          // level
-                                   b->vec3<i32>(5, 6, 7));       // offset
-              },
+      },
+      {
+          ValidTextureOverload::kSampleLevel3dOffsetF32,
+          "textureSampleLevel(t      : texture_3d<f32>,\n"
+          "                   s      : sampler,\n"
+          "                   coords : vec3<f32>,\n"
+          "                   level  : f32,\n"
+          "                   offset : vec3<i32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k3d,
+          TextureDataType::kF32,
+          "textureSampleLevel",
+          [](Builder* b) {
+            return b->ExprList("texture",                    // t
+                               "sampler",                    // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                               4.f,                          // level
+                               b->vec3<i32>(5, 6, 7));       // offset
           },
-          {
-              ValidTextureOverload::kSampleLevelCubeF32,
-              "textureSampleLevel(t : texture_cube<f32>,\n"
-              "                   s : sampler,\n"
-              "                   coords : vec3<f32>,\n"
-              "                   level : f32) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::kCube,
-              TextureDataType::kF32,
-              "textureSampleLevel",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                    // t
-                                   "sampler",                    // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                                   4.f);                         // level
-              },
+      },
+      {
+          ValidTextureOverload::kSampleLevelCubeF32,
+          "textureSampleLevel(t      : texture_cube<f32>,\n"
+          "                   s      : sampler,\n"
+          "                   coords : vec3<f32>,\n"
+          "                   level  : f32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCube,
+          TextureDataType::kF32,
+          "textureSampleLevel",
+          [](Builder* b) {
+            return b->ExprList("texture",                    // t
+                               "sampler",                    // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                               4.f);                         // level
           },
-          {
-              ValidTextureOverload::kSampleLevelCubeArrayF32,
-              "textureSampleLevel(t : texture_cube_array<f32>,\n"
-              "                   s : sampler,\n"
-              "                   coords : vec3<f32>,\n"
-              "                   array_index : u32,\n"
-              "                   level : f32) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::kCubeArray,
-              TextureDataType::kF32,
-              "textureSampleLevel",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                    // t
-                                   "sampler",                    // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                                   4,                            // array_index
-                                   5.f);                         // level
-              },
+      },
+      {
+          ValidTextureOverload::kSampleLevelCubeArrayF32,
+          "textureSampleLevel(t           : texture_cube_array<f32>,\n"
+          "                   s           : sampler,\n"
+          "                   coords      : vec3<f32>,\n"
+          "                   array_index : i32,\n"
+          "                   level       : f32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCubeArray,
+          TextureDataType::kF32,
+          "textureSampleLevel",
+          [](Builder* b) {
+            return b->ExprList("texture",                    // t
+                               "sampler",                    // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                               4,                            // array_index
+                               5.f);                         // level
           },
-          {
-              ValidTextureOverload::kSampleLevelDepth2dF32,
-              "textureSampleLevel(t : texture_depth_2d,\n"
-              "                   s : sampler,\n"
-              "                   coords : vec2<f32>,\n"
-              "                   level : u32) -> f32",
-              TextureKind::kDepth,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2d,
-              TextureDataType::kF32,
-              "textureSampleLevel",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   3);                      // level
-              },
+      },
+      {
+          ValidTextureOverload::kSampleLevelDepth2dF32,
+          "textureSampleLevel(t      : texture_depth_2d,\n"
+          "                   s      : sampler,\n"
+          "                   coords : vec2<f32>,\n"
+          "                   level  : i32) -> f32",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureSampleLevel",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               3);                      // level
           },
-          {
-              ValidTextureOverload::kSampleLevelDepth2dOffsetF32,
-              "textureSampleLevel(t : texture_depth_2d,\n"
-              "                   s : sampler,\n"
-              "                   coords : vec2<f32>,\n"
-              "                   level : u32,\n"
-              "                   offset : vec2<i32>) -> f32",
-              TextureKind::kDepth,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2d,
-              TextureDataType::kF32,
-              "textureSampleLevel",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                using i32 = Builder::i32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   3,                       // level
-                                   b->vec2<i32>(4, 5));     // offset
-              },
+      },
+      {
+          ValidTextureOverload::kSampleLevelDepth2dOffsetF32,
+          "textureSampleLevel(t      : texture_depth_2d,\n"
+          "                   s      : sampler,\n"
+          "                   coords : vec2<f32>,\n"
+          "                   level  : i32,\n"
+          "                   offset : vec2<i32>) -> f32",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureSampleLevel",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               3,                       // level
+                               b->vec2<i32>(4, 5));     // offset
           },
-          {
-              ValidTextureOverload::kSampleLevelDepth2dArrayF32,
-              "textureSampleLevel(t : texture_depth_2d_array,\n"
-              "                   s : sampler,\n"
-              "                   coords : vec2<f32>,\n"
-              "                   array_index : u32,\n"
-              "                   level : u32) -> f32",
-              TextureKind::kDepth,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2dArray,
-              TextureDataType::kF32,
-              "textureSampleLevel",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   3,                       // array_index
-                                   4);                      // level
-              },
+      },
+      {
+          ValidTextureOverload::kSampleLevelDepth2dArrayF32,
+          "textureSampleLevel(t           : texture_depth_2d_array,\n"
+          "                   s           : sampler,\n"
+          "                   coords      : vec2<f32>,\n"
+          "                   array_index : i32,\n"
+          "                   level       : i32) -> f32",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureSampleLevel",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               3,                       // array_index
+                               4);                      // level
           },
-          {
-              ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32,
-              "textureSampleLevel(t : texture_depth_2d_array,\n"
-              "                   s : sampler,\n"
-              "                   coords : vec2<f32>,\n"
-              "                   array_index : u32,\n"
-              "                   level : u32,\n"
-              "                   offset : vec2<i32>) -> f32",
-              TextureKind::kDepth,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2dArray,
-              TextureDataType::kF32,
-              "textureSampleLevel",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                using i32 = Builder::i32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   3,                       // array_index
-                                   4,                       // level
-                                   b->vec2<i32>(5, 6));     // offset
-              },
+      },
+      {
+          ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32,
+          "textureSampleLevel(t           : texture_depth_2d_array,\n"
+          "                   s           : sampler,\n"
+          "                   coords      : vec2<f32>,\n"
+          "                   array_index : i32,\n"
+          "                   level       : i32,\n"
+          "                   offset      : vec2<i32>) -> f32",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureSampleLevel",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               3,                       // array_index
+                               4,                       // level
+                               b->vec2<i32>(5, 6));     // offset
           },
-          {
-              ValidTextureOverload::kSampleLevelDepthCubeF32,
-              "textureSampleLevel(t : texture_depth_cube,\n"
-              "                   s : sampler,\n"
-              "                   coords : vec3<f32>,\n"
-              "                   level : u32) -> f32",
-              TextureKind::kDepth,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::kCube,
-              TextureDataType::kF32,
-              "textureSampleLevel",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                    // t
-                                   "sampler",                    // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                                   4);                           // level
-              },
+      },
+      {
+          ValidTextureOverload::kSampleLevelDepthCubeF32,
+          "textureSampleLevel(t      : texture_depth_cube,\n"
+          "                   s      : sampler,\n"
+          "                   coords : vec3<f32>,\n"
+          "                   level  : i32) -> f32",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCube,
+          TextureDataType::kF32,
+          "textureSampleLevel",
+          [](Builder* b) {
+            return b->ExprList("texture",                    // t
+                               "sampler",                    // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                               4);                           // level
           },
-          {
-              ValidTextureOverload::kSampleLevelDepthCubeArrayF32,
-              "textureSampleLevel(t : texture_depth_cube_array,\n"
-              "                   s : sampler,\n"
-              "                   coords : vec3<f32>,\n"
-              "                   array_index : u32,\n"
-              "                   level : u32) -> f32",
-              TextureKind::kDepth,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::kCubeArray,
-              TextureDataType::kF32,
-              "textureSampleLevel",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                    // t
-                                   "sampler",                    // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                                   4,                            // array_index
-                                   5);                           // level
-              },
+      },
+      {
+          ValidTextureOverload::kSampleLevelDepthCubeArrayF32,
+          "textureSampleLevel(t           : texture_depth_cube_array,\n"
+          "                   s           : sampler,\n"
+          "                   coords      : vec3<f32>,\n"
+          "                   array_index : i32,\n"
+          "                   level       : i32) -> f32",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCubeArray,
+          TextureDataType::kF32,
+          "textureSampleLevel",
+          [](Builder* b) {
+            return b->ExprList("texture",                    // t
+                               "sampler",                    // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                               4,                            // array_index
+                               5);                           // level
           },
-          {
-              ValidTextureOverload::kSampleGrad2dF32,
-              "textureSampleGrad(t : texture_2d<f32>,\n"
-              "                  s : sampler,\n"
-              "                  coords : vec2<f32>\n"
-              "                  ddx : vec2<f32>,\n"
-              "                  ddy : vec2<f32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2d,
-              TextureDataType::kF32,
-              "textureSampleGrad",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                  // t
-                                   "sampler",                  // s
-                                   b->vec2<f32>(1.0f, 2.0f),   // coords
-                                   b->vec2<f32>(3.0f, 4.0f),   // ddx
-                                   b->vec2<f32>(5.0f, 6.0f));  // ddy
-              },
+      },
+      {
+          ValidTextureOverload::kSampleGrad2dF32,
+          "textureSampleGrad(t      : texture_2d<f32>,\n"
+          "                  s      : sampler,\n"
+          "                  coords : vec2<f32>\n"
+          "                  ddx    : vec2<f32>,\n"
+          "                  ddy    : vec2<f32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureSampleGrad",
+          [](Builder* b) {
+            return b->ExprList("texture",                  // t
+                               "sampler",                  // s
+                               b->vec2<f32>(1.0f, 2.0f),   // coords
+                               b->vec2<f32>(3.0f, 4.0f),   // ddx
+                               b->vec2<f32>(5.0f, 6.0f));  // ddy
           },
-          {
-              ValidTextureOverload::kSampleGrad2dOffsetF32,
-              "textureSampleGrad(t : texture_2d<f32>,\n"
-              "                  s : sampler,\n"
-              "                  coords : vec2<f32>,\n"
-              "                  ddx : vec2<f32>,\n"
-              "                  ddy : vec2<f32>,\n"
-              "                  offset : vec2<i32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2d,
-              TextureDataType::kF32,
-              "textureSampleGrad",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                using i32 = Builder::i32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   b->vec2<f32>(3.f, 4.f),  // ddx
-                                   b->vec2<f32>(5.f, 6.f),  // ddy
-                                   b->vec2<i32>(7, 8));     // offset
-              },
+      },
+      {
+          ValidTextureOverload::kSampleGrad2dOffsetF32,
+          "textureSampleGrad(t      : texture_2d<f32>,\n"
+          "                  s      : sampler,\n"
+          "                  coords : vec2<f32>,\n"
+          "                  ddx    : vec2<f32>,\n"
+          "                  ddy    : vec2<f32>,\n"
+          "                  offset : vec2<i32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureSampleGrad",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               b->vec2<f32>(3.f, 4.f),  // ddx
+                               b->vec2<f32>(5.f, 6.f),  // ddy
+                               b->vec2<i32>(7, 8));     // offset
           },
-          {
-              ValidTextureOverload::kSampleGrad2dArrayF32,
-              "textureSampleGrad(t : texture_2d_array<f32>,\n"
-              "                  s : sampler,\n"
-              "                  coords : vec2<f32>,\n"
-              "                  array_index : u32,\n"
-              "                  ddx : vec2<f32>,\n"
-              "                  ddy : vec2<f32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2dArray,
-              TextureDataType::kF32,
-              "textureSampleGrad",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                // t
-                                   "sampler",                // s
-                                   b->vec2<f32>(1.f, 2.f),   // coords
-                                   3,                        // array_index
-                                   b->vec2<f32>(4.f, 5.f),   // ddx
-                                   b->vec2<f32>(6.f, 7.f));  // ddy
-              },
+      },
+      {
+          ValidTextureOverload::kSampleGrad2dArrayF32,
+          "textureSampleGrad(t           : texture_2d_array<f32>,\n"
+          "                  s           : sampler,\n"
+          "                  coords      : vec2<f32>,\n"
+          "                  array_index : i32,\n"
+          "                  ddx         : vec2<f32>,\n"
+          "                  ddy         : vec2<f32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureSampleGrad",
+          [](Builder* b) {
+            return b->ExprList("texture",                // t
+                               "sampler",                // s
+                               b->vec2<f32>(1.f, 2.f),   // coords
+                               3,                        // array_index
+                               b->vec2<f32>(4.f, 5.f),   // ddx
+                               b->vec2<f32>(6.f, 7.f));  // ddy
           },
-          {
-              ValidTextureOverload::kSampleGrad2dArrayOffsetF32,
-              "textureSampleGrad(t : texture_2d_array<f32>,\n"
-              "                  s : sampler,\n"
-              "                  coords : vec2<f32>,\n"
-              "                  array_index : u32,\n"
-              "                  ddx : vec2<f32>,\n"
-              "                  ddy : vec2<f32>,\n"
-              "                  offset : vec2<i32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k2dArray,
-              TextureDataType::kF32,
-              "textureSampleGrad",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                using i32 = Builder::i32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   3,                       // array_index
-                                   b->vec2<f32>(4.f, 5.f),  // ddx
-                                   b->vec2<f32>(6.f, 7.f),  // ddy
-                                   b->vec2<i32>(8, 9));     // offset
-              },
+      },
+      {
+          ValidTextureOverload::kSampleGrad2dArrayOffsetF32,
+          "textureSampleGrad(t           : texture_2d_array<f32>,\n"
+          "                  s           : sampler,\n"
+          "                  coords      : vec2<f32>,\n"
+          "                  array_index : i32,\n"
+          "                  ddx         : vec2<f32>,\n"
+          "                  ddy         : vec2<f32>,\n"
+          "                  offset      : vec2<i32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureSampleGrad",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               3,                       // array_index
+                               b->vec2<f32>(4.f, 5.f),  // ddx
+                               b->vec2<f32>(6.f, 7.f),  // ddy
+                               b->vec2<i32>(8, 9));     // offset
           },
-          {
-              ValidTextureOverload::kSampleGrad3dF32,
-              "textureSampleGrad(t : texture_3d<f32>,\n"
-              "                  s : sampler,\n"
-              "                  coords : vec3<f32>,\n"
-              "                  ddx : vec3<f32>,\n"
-              "                  ddy : vec3<f32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k3d,
-              TextureDataType::kF32,
-              "textureSampleGrad",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                     // t
-                                   "sampler",                     // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),   // coords
-                                   b->vec3<f32>(4.f, 5.f, 6.f),   // ddx
-                                   b->vec3<f32>(7.f, 8.f, 9.f));  // ddy
-              },
+      },
+      {
+          ValidTextureOverload::kSampleGrad3dF32,
+          "textureSampleGrad(t      : texture_3d<f32>,\n"
+          "                  s      : sampler,\n"
+          "                  coords : vec3<f32>,\n"
+          "                  ddx    : vec3<f32>,\n"
+          "                  ddy    : vec3<f32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k3d,
+          TextureDataType::kF32,
+          "textureSampleGrad",
+          [](Builder* b) {
+            return b->ExprList("texture",                     // t
+                               "sampler",                     // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),   // coords
+                               b->vec3<f32>(4.f, 5.f, 6.f),   // ddx
+                               b->vec3<f32>(7.f, 8.f, 9.f));  // ddy
           },
-          {
-              ValidTextureOverload::kSampleGrad3dOffsetF32,
-              "textureSampleGrad(t : texture_3d<f32>,\n"
-              "                  s : sampler,\n"
-              "                  coords : vec3<f32>,\n"
-              "                  ddx : vec3<f32>,\n"
-              "                  ddy : vec3<f32>,\n"
-              "                  offset : vec3<i32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::k3d,
-              TextureDataType::kF32,
-              "textureSampleGrad",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                using i32 = Builder::i32;
-                return b->ExprList("texture",                    // t
-                                   "sampler",                    // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                                   b->vec3<f32>(4.f, 5.f, 6.f),  // ddx
-                                   b->vec3<f32>(7.f, 8.f, 9.f),  // ddy
-                                   b->vec3<i32>(10, 11, 12));    // offset
-              },
+      },
+      {
+          ValidTextureOverload::kSampleGrad3dOffsetF32,
+          "textureSampleGrad(t      : texture_3d<f32>,\n"
+          "                  s      : sampler,\n"
+          "                  coords : vec3<f32>,\n"
+          "                  ddx    : vec3<f32>,\n"
+          "                  ddy    : vec3<f32>,\n"
+          "                  offset : vec3<i32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k3d,
+          TextureDataType::kF32,
+          "textureSampleGrad",
+          [](Builder* b) {
+            return b->ExprList("texture",                    // t
+                               "sampler",                    // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                               b->vec3<f32>(4.f, 5.f, 6.f),  // ddx
+                               b->vec3<f32>(7.f, 8.f, 9.f),  // ddy
+                               b->vec3<i32>(10, 11, 12));    // offset
           },
-          {
-              ValidTextureOverload::kSampleGradCubeF32,
-              "textureSampleGrad(t : texture_cube<f32>,\n"
-              "                  s : sampler,\n"
-              "                  coords : vec3<f32>,\n"
-              "                  ddx : vec3<f32>,\n"
-              "                  ddy : vec3<f32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::kCube,
-              TextureDataType::kF32,
-              "textureSampleGrad",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                     // t
-                                   "sampler",                     // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),   // coords
-                                   b->vec3<f32>(4.f, 5.f, 6.f),   // ddx
-                                   b->vec3<f32>(7.f, 8.f, 9.f));  // ddy
-              },
+      },
+      {
+          ValidTextureOverload::kSampleGradCubeF32,
+          "textureSampleGrad(t      : texture_cube<f32>,\n"
+          "                  s      : sampler,\n"
+          "                  coords : vec3<f32>,\n"
+          "                  ddx    : vec3<f32>,\n"
+          "                  ddy    : vec3<f32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCube,
+          TextureDataType::kF32,
+          "textureSampleGrad",
+          [](Builder* b) {
+            return b->ExprList("texture",                     // t
+                               "sampler",                     // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),   // coords
+                               b->vec3<f32>(4.f, 5.f, 6.f),   // ddx
+                               b->vec3<f32>(7.f, 8.f, 9.f));  // ddy
           },
-          {
-              ValidTextureOverload::kSampleGradCubeArrayF32,
-              "textureSampleGrad(t : texture_cube_array<f32>,\n"
-              "                  s : sampler,\n"
-              "                  coords : vec3<f32>,\n"
-              "                  array_index : u32,\n"
-              "                  ddx : vec3<f32>,\n"
-              "                  ddy : vec3<f32>) -> vec4<f32>",
-              TextureKind::kRegular,
-              type::SamplerKind::kSampler,
-              type::TextureDimension::kCubeArray,
-              TextureDataType::kF32,
-              "textureSampleGrad",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                    // t
-                                   "sampler",                    // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                                   4,                            // array_index
-                                   b->vec3<f32>(5.f, 6.f, 7.f),  // ddx
-                                   b->vec3<f32>(8.f, 9.f, 10.f));  // ddy
-              },
+      },
+      {
+          ValidTextureOverload::kSampleGradCubeArrayF32,
+          "textureSampleGrad(t           : texture_cube_array<f32>,\n"
+          "                  s           : sampler,\n"
+          "                  coords      : vec3<f32>,\n"
+          "                  array_index : i32,\n"
+          "                  ddx         : vec3<f32>,\n"
+          "                  ddy         : vec3<f32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCubeArray,
+          TextureDataType::kF32,
+          "textureSampleGrad",
+          [](Builder* b) {
+            return b->ExprList("texture",                      // t
+                               "sampler",                      // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),    // coords
+                               4,                              // array_index
+                               b->vec3<f32>(5.f, 6.f, 7.f),    // ddx
+                               b->vec3<f32>(8.f, 9.f, 10.f));  // ddy
           },
-          {
-              ValidTextureOverload::kSampleGradDepth2dF32,
-              "textureSampleCompare(t : texture_depth_2d,\n"
-              "                     s : sampler_comparison,\n"
-              "                     coords : vec2<f32>,\n"
-              "                     depth_ref : f32) -> f32",
-              TextureKind::kDepth,
-              type::SamplerKind::kComparisonSampler,
-              type::TextureDimension::k2d,
-              TextureDataType::kF32,
-              "textureSampleCompare",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   3.f);                    // depth_ref
-              },
+      },
+      {
+          ValidTextureOverload::kSampleGradDepth2dF32,
+          "textureSampleCompare(t         : texture_depth_2d,\n"
+          "                     s         : sampler_comparison,\n"
+          "                     coords    : vec2<f32>,\n"
+          "                     depth_ref : f32) -> f32",
+          TextureKind::kDepth,
+          type::SamplerKind::kComparisonSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureSampleCompare",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               3.f);                    // depth_ref
           },
-          {
-              ValidTextureOverload::kSampleGradDepth2dOffsetF32,
-              "textureSampleCompare(t : texture_depth_2d,\n"
-              "                     s : sampler_comparison,\n"
-              "                     coords : vec2<f32>,\n"
-              "                     depth_ref : f32,\n"
-              "                     offset : vec2<i32>) -> f32",
-              TextureKind::kDepth,
-              type::SamplerKind::kComparisonSampler,
-              type::TextureDimension::k2d,
-              TextureDataType::kF32,
-              "textureSampleCompare",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                using i32 = Builder::i32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   3.f,                     // depth_ref
-                                   b->vec2<i32>(4, 5));     // offset
-              },
+      },
+      {
+          ValidTextureOverload::kSampleGradDepth2dOffsetF32,
+          "textureSampleCompare(t         : texture_depth_2d,\n"
+          "                     s         : sampler_comparison,\n"
+          "                     coords    : vec2<f32>,\n"
+          "                     depth_ref : f32,\n"
+          "                     offset    : vec2<i32>) -> f32",
+          TextureKind::kDepth,
+          type::SamplerKind::kComparisonSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureSampleCompare",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               3.f,                     // depth_ref
+                               b->vec2<i32>(4, 5));     // offset
           },
-          {
-              ValidTextureOverload::kSampleGradDepth2dArrayF32,
-              "textureSampleCompare(t : texture_depth_2d_array,\n"
-              "                     s : sampler_comparison,\n"
-              "                     coords : vec2<f32>,\n"
-              "                     array_index : u32,\n"
-              "                     depth_ref : f32) -> f32",
-              TextureKind::kDepth,
-              type::SamplerKind::kComparisonSampler,
-              type::TextureDimension::k2dArray,
-              TextureDataType::kF32,
-              "textureSampleCompare",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   4,                       // array_index
-                                   3.f);                    // depth_ref
-              },
+      },
+      {
+          ValidTextureOverload::kSampleGradDepth2dArrayF32,
+          "textureSampleCompare(t           : texture_depth_2d_array,\n"
+          "                     s           : sampler_comparison,\n"
+          "                     coords      : vec2<f32>,\n"
+          "                     array_index : i32,\n"
+          "                     depth_ref   : f32) -> f32",
+          TextureKind::kDepth,
+          type::SamplerKind::kComparisonSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureSampleCompare",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               4,                       // array_index
+                               3.f);                    // depth_ref
           },
-          {
-              ValidTextureOverload::kSampleGradDepth2dArrayOffsetF32,
-              "textureSampleCompare(t : texture_depth_2d_array,\n"
-              "                     s : sampler_comparison,\n"
-              "                     coords : vec2<f32>,\n"
-              "                     array_index : u32,\n"
-              "                     depth_ref : f32,\n"
-              "                     offset : vec2<i32>) -> f32",
-              TextureKind::kDepth,
-              type::SamplerKind::kComparisonSampler,
-              type::TextureDimension::k2dArray,
-              TextureDataType::kF32,
-              "textureSampleCompare",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                using i32 = Builder::i32;
-                return b->ExprList("texture",               // t
-                                   "sampler",               // s
-                                   b->vec2<f32>(1.f, 2.f),  // coords
-                                   4,                       // array_index
-                                   3.f,                     // depth_ref
-                                   b->vec2<i32>(5, 6));     // offset
-              },
+      },
+      {
+          ValidTextureOverload::kSampleGradDepth2dArrayOffsetF32,
+          "textureSampleCompare(t           : texture_depth_2d_array,\n"
+          "                     s           : sampler_comparison,\n"
+          "                     coords      : vec2<f32>,\n"
+          "                     array_index : i32,\n"
+          "                     depth_ref   : f32,\n"
+          "                     offset      : vec2<i32>) -> f32",
+          TextureKind::kDepth,
+          type::SamplerKind::kComparisonSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureSampleCompare",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               "sampler",               // s
+                               b->vec2<f32>(1.f, 2.f),  // coords
+                               4,                       // array_index
+                               3.f,                     // depth_ref
+                               b->vec2<i32>(5, 6));     // offset
           },
-          {
-              ValidTextureOverload::kSampleGradDepthCubeF32,
-              "textureSampleCompare(t : texture_depth_cube,\n"
-              "                     s : sampler_comparison,\n"
-              "                     coords : vec3<f32>,\n"
-              "                     depth_ref : f32) -> f32",
-              TextureKind::kDepth,
-              type::SamplerKind::kComparisonSampler,
-              type::TextureDimension::kCube,
-              TextureDataType::kF32,
-              "textureSampleCompare",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                    // t
-                                   "sampler",                    // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                                   4.f);                         // depth_ref
-              },
+      },
+      {
+          ValidTextureOverload::kSampleGradDepthCubeF32,
+          "textureSampleCompare(t         : texture_depth_cube,\n"
+          "                     s         : sampler_comparison,\n"
+          "                     coords    : vec3<f32>,\n"
+          "                     depth_ref : f32) -> f32",
+          TextureKind::kDepth,
+          type::SamplerKind::kComparisonSampler,
+          type::TextureDimension::kCube,
+          TextureDataType::kF32,
+          "textureSampleCompare",
+          [](Builder* b) {
+            return b->ExprList("texture",                    // t
+                               "sampler",                    // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                               4.f);                         // depth_ref
           },
-          {
-              ValidTextureOverload::kSampleGradDepthCubeArrayF32,
-              "textureSampleCompare(t : texture_depth_cube_array,\n"
-              "                     s : sampler_comparison,\n"
-              "                     coords : vec3<f32>,\n"
-              "                     array_index : u32,\n"
-              "                     depth_ref : f32) -> f32",
-              TextureKind::kDepth,
-              type::SamplerKind::kComparisonSampler,
-              type::TextureDimension::kCubeArray,
-              TextureDataType::kF32,
-              "textureSampleCompare",
-              [](Builder* b) {
-                using f32 = Builder::f32;
-                return b->ExprList("texture",                    // t
-                                   "sampler",                    // s
-                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                                   4,                            // array_index
-                                   5.f);                         // depth_ref
-              },
-          }};
+      },
+      {
+          ValidTextureOverload::kSampleGradDepthCubeArrayF32,
+          "textureSampleCompare(t           : texture_depth_cube_array,\n"
+          "                     s           : sampler_comparison,\n"
+          "                     coords      : vec3<f32>,\n"
+          "                     array_index : i32,\n"
+          "                     depth_ref   : f32) -> f32",
+          TextureKind::kDepth,
+          type::SamplerKind::kComparisonSampler,
+          type::TextureDimension::kCubeArray,
+          TextureDataType::kF32,
+          "textureSampleCompare",
+          [](Builder* b) {
+            return b->ExprList("texture",                    // t
+                               "sampler",                    // s
+                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                               4,                            // array_index
+                               5.f);                         // depth_ref
+          },
+      },
+      {
+          ValidTextureOverload::kLoad1dF32,
+          "textureLoad(t      : texture_1d<f32>,\n"
+          "            coords : i32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k1d,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",  // t
+                               1);         // coords
+          },
+      },
+      {
+          ValidTextureOverload::kLoad1dU32,
+          "textureLoad(t      : texture_1d<u32>,\n"
+          "            coords : i32) -> vec4<u32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k1d,
+          TextureDataType::kU32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",  // t
+                               1);         // coords
+          },
+      },
+      {
+          ValidTextureOverload::kLoad1dI32,
+          "textureLoad(t      : texture_1d<i32>,\n"
+          "            coords : i32) -> vec4<i32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k1d,
+          TextureDataType::kI32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",  // t
+                               1);         // coords
+          },
+      },
+      {
+          ValidTextureOverload::kLoad1dArrayF32,
+          "textureLoad(t           : texture_1d_array<f32>,\n"
+          "            coords      : i32,\n"
+          "            array_index : i32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k1dArray,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",  // t
+                               1,          // coords
+                               2);         // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoad1dArrayU32,
+          "textureLoad(t           : texture_1d_array<u32>,\n"
+          "            coords      : i32,\n"
+          "            array_index : i32) -> vec4<u32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k1dArray,
+          TextureDataType::kU32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",  // t
+                               1,          // coords
+                               2);         // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoad1dArrayI32,
+          "textureLoad(t           : texture_1d_array<i32>,\n"
+          "            coords      : i32,\n"
+          "            array_index : i32) -> vec4<i32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k1dArray,
+          TextureDataType::kI32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",  // t
+                               1,          // coords
+                               2);         // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoad2dF32,
+          "textureLoad(t      : texture_2d<f32>,\n"
+          "            coords : vec2<i32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // coords
+          },
+      },
+      {
+          ValidTextureOverload::kLoad2dU32,
+          "textureLoad(t      : texture_2d<u32>,\n"
+          "            coords : vec2<i32>) -> vec4<u32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k2d,
+          TextureDataType::kU32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // coords
+          },
+      },
+      {
+          ValidTextureOverload::kLoad2dI32,
+          "textureLoad(t      : texture_2d<i32>,\n"
+          "            coords : vec2<i32>) -> vec4<i32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k2d,
+          TextureDataType::kI32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // coords
+          },
+      },
+      {
+          ValidTextureOverload::kLoad2dLevelF32,
+          "textureLoad(t      : texture_2d<f32>,\n"
+          "            coords : vec2<i32>,\n"
+          "            level  : i32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3);                  // level
+          },
+      },
+      {
+          ValidTextureOverload::kLoad2dLevelU32,
+          "textureLoad(t      : texture_2d<u32>,\n"
+          "            coords : vec2<i32>,\n"
+          "            level  : i32) -> vec4<u32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k2d,
+          TextureDataType::kU32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3);                  // level
+          },
+      },
+      {
+          ValidTextureOverload::kLoad2dLevelI32,
+          "textureLoad(t      : texture_2d<i32>,\n"
+          "            coords : vec2<i32>,\n"
+          "            level  : i32) -> vec4<i32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k2d,
+          TextureDataType::kI32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3);                  // level
+          },
+      },
+      {
+          ValidTextureOverload::kLoad2dArrayF32,
+          "textureLoad(t           : texture_2d_array<f32>,\n"
+          "            coords      : vec2<i32>,\n"
+          "            array_index : i32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3);                  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoad2dArrayU32,
+          "textureLoad(t           : texture_2d_array<u32>,\n"
+          "            coords      : vec2<i32>,\n"
+          "            array_index : i32) -> vec4<u32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kU32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3);                  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoad2dArrayI32,
+          "textureLoad(t           : texture_2d_array<i32>,\n"
+          "            coords      : vec2<i32>,\n"
+          "            array_index : i32) -> vec4<i32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kI32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3);                  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoad2dArrayLevelF32,
+          "textureLoad(t           : texture_2d_array<f32>,\n"
+          "            coords      : vec2<i32>,\n"
+          "            array_index : i32,\n"
+          "            level       : i32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3,                   // array_index
+                               4);                  // level
+          },
+      },
+      {
+          ValidTextureOverload::kLoad2dArrayLevelU32,
+          "textureLoad(t           : texture_2d_array<u32>,\n"
+          "            coords      : vec2<i32>,\n"
+          "            array_index : i32,\n"
+          "            level       : i32) -> vec4<u32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kU32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3,                   // array_index
+                               4);                  // level
+          },
+      },
+      {
+          ValidTextureOverload::kLoad2dArrayLevelI32,
+          "textureLoad(t           : texture_2d_array<i32>,\n"
+          "            coords      : vec2<i32>,\n"
+          "            array_index : i32,\n"
+          "            level       : i32) -> vec4<i32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kI32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3,                   // array_index
+                               4);                  // level
+          },
+      },
+      {
+          ValidTextureOverload::kLoad3dF32,
+          "textureLoad(t      : texture_3d<f32>,\n"
+          "            coords : vec3<i32>) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k3d,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               b->vec3<i32>(1, 2, 3));  // coords
+          },
+      },
+      {
+          ValidTextureOverload::kLoad3dU32,
+          "textureLoad(t      : texture_3d<u32>,\n"
+          "            coords : vec3<i32>) -> vec4<u32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k3d,
+          TextureDataType::kU32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               b->vec3<i32>(1, 2, 3));  // coords
+          },
+      },
+      {
+          ValidTextureOverload::kLoad3dI32,
+          "textureLoad(t      : texture_3d<i32>,\n"
+          "            coords : vec3<i32>) -> vec4<i32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k3d,
+          TextureDataType::kI32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               b->vec3<i32>(1, 2, 3));  // coords
+          },
+      },
+      {
+          ValidTextureOverload::kLoad3dLevelF32,
+          "textureLoad(t      : texture_3d<f32>,\n"
+          "            coords : vec3<i32>,\n"
+          "            level  : i32) -> vec4<f32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k3d,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",              // t
+                               b->vec3<i32>(1, 2, 3),  // coords
+                               4);                     // level
+          },
+      },
+      {
+          ValidTextureOverload::kLoad3dLevelU32,
+          "textureLoad(t      : texture_3d<u32>,\n"
+          "            coords : vec3<i32>,\n"
+          "            level  : i32) -> vec4<u32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k3d,
+          TextureDataType::kU32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",              // t
+                               b->vec3<i32>(1, 2, 3),  // coords
+                               4);                     // level
+          },
+      },
+      {
+          ValidTextureOverload::kLoad3dLevelI32,
+          "textureLoad(t      : texture_3d<i32>,\n"
+          "            coords : vec3<i32>,\n"
+          "            level  : i32) -> vec4<i32>",
+          TextureKind::kRegular,
+          type::TextureDimension::k3d,
+          TextureDataType::kI32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",              // t
+                               b->vec3<i32>(1, 2, 3),  // coords
+                               4);                     // level
+          },
+      },
+      {
+          ValidTextureOverload::kLoadMultisampled2dF32,
+          "textureLoad(t            : texture_multisampled_2d<f32>,\n"
+          "            coords       : vec2<i32>,\n"
+          "            sample_index : i32) -> vec4<f32>",
+          TextureKind::kMultisampled,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3);                  // sample_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadMultisampled2dU32,
+          "textureLoad(t            : texture_multisampled_2d<u32>,\n"
+          "            coords       : vec2<i32>,\n"
+          "            sample_index : i32) -> vec4<u32>",
+          TextureKind::kMultisampled,
+          type::TextureDimension::k2d,
+          TextureDataType::kU32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3);                  // sample_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadMultisampled2dI32,
+          "textureLoad(t            : texture_multisampled_2d<i32>,\n"
+          "            coords       : vec2<i32>,\n"
+          "            sample_index : i32) -> vec4<i32>",
+          TextureKind::kMultisampled,
+          type::TextureDimension::k2d,
+          TextureDataType::kI32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3);                  // sample_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadMultisampled2dArrayF32,
+          "textureLoad(t            : texture_multisampled_2d_array<f32>,\n"
+          "            coords       : vec2<i32>,\n"
+          "            array_index  : i32,\n"
+          "            sample_index : i32) -> vec4<f32>",
+          TextureKind::kMultisampled,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3,                   // array_index
+                               4);                  // sample_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadMultisampled2dArrayU32,
+          "textureLoad(t            : texture_multisampled_2d_array<u32>,\n"
+          "            coords       : vec2<i32>,\n"
+          "            array_index  : i32,\n"
+          "            sample_index : i32) -> vec4<u32>",
+          TextureKind::kMultisampled,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kU32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3,                   // array_index
+                               4);                  // sample_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadMultisampled2dArrayI32,
+          "textureLoad(t            : texture_multisampled_2d_array<i32>,\n"
+          "            coords       : vec2<i32>,\n"
+          "            array_index  : i32,\n"
+          "            sample_index : i32) -> vec4<i32>",
+          TextureKind::kMultisampled,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kI32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3,                   // array_index
+                               4);                  // sample_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadDepth2dF32,
+          "textureLoad(t      : texture_depth_2d,\n"
+          "            coords : vec2<i32>) -> f32",
+          TextureKind::kDepth,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // coords
+          },
+      },
+      {
+          ValidTextureOverload::kLoadDepth2dLevelF32,
+          "textureLoad(t      : texture_depth_2d,\n"
+          "            coords : vec2<i32>,\n"
+          "            level  : i32) -> f32",
+          TextureKind::kDepth,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3);                  // level
+          },
+      },
+      {
+          ValidTextureOverload::kLoadDepth2dArrayF32,
+          "textureLoad(t           : texture_depth_2d_array,\n"
+          "            coords      : vec2<i32>,\n"
+          "            array_index : i32) -> f32",
+          TextureKind::kDepth,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3);                  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadDepth2dArrayLevelF32,
+          "textureLoad(t           : texture_depth_2d_array,\n"
+          "            coords      : vec2<i32>,\n"
+          "            array_index : i32,\n"
+          "            level       : i32) -> f32",
+          TextureKind::kDepth,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3,                   // array_index
+                               4);                  // level
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO1dRgba32float,
+          "textureLoad(t      : texture_storage_ro_1d<rgba32float>,\n"
+          "            coords : i32) -> vec4<f32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba32Float,
+          type::TextureDimension::k1d,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",  // t
+                               1);         // coords
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO1dArrayRgba32float,
+          "textureLoad(t           : "
+          "texture_storage_ro_1d_array<rgba32float>,\n"
+          "            coords      : i32,\n"
+          "            array_index : i32) -> vec4<f32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba32Float,
+          type::TextureDimension::k1dArray,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",  // t
+                               1,          // coords
+                               2);         // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO2dRgba8unorm,
+          "textureLoad(t           : texture_storage_ro_2d<rgba8unorm>,\n"
+          "            coords      : vec2<i32>) -> vec4<f32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba8Unorm,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO2dRgba8snorm,
+          "textureLoad(t           : texture_storage_ro_2d<rgba8snorm>,\n"
+          "            coords      : vec2<i32>) -> vec4<f32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba8Snorm,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO2dRgba8uint,
+          "textureLoad(t           : texture_storage_ro_2d<rgba8uint>,\n"
+          "            coords      : vec2<i32>) -> vec4<u32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba8Uint,
+          type::TextureDimension::k2d,
+          TextureDataType::kU32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO2dRgba8sint,
+          "textureLoad(t           : texture_storage_ro_2d<rgba8sint>,\n"
+          "            coords      : vec2<i32>) -> vec4<i32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba8Sint,
+          type::TextureDimension::k2d,
+          TextureDataType::kI32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO2dRgba16uint,
+          "textureLoad(t           : texture_storage_ro_2d<rgba16uint>,\n"
+          "            coords      : vec2<i32>) -> vec4<u32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba16Uint,
+          type::TextureDimension::k2d,
+          TextureDataType::kU32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO2dRgba16sint,
+          "textureLoad(t           : texture_storage_ro_2d<rgba16sint>,\n"
+          "            coords      : vec2<i32>) -> vec4<i32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba16Sint,
+          type::TextureDimension::k2d,
+          TextureDataType::kI32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO2dRgba16float,
+          "textureLoad(t           : texture_storage_ro_2d<rgba16float>,\n"
+          "            coords      : vec2<i32>) -> vec4<f32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba16Float,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO2dR32uint,
+          "textureLoad(t           : texture_storage_ro_2d<r32uint>,\n"
+          "            coords      : vec2<i32>) -> vec4<u32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kR32Uint,
+          type::TextureDimension::k2d,
+          TextureDataType::kU32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO2dR32sint,
+          "textureLoad(t           : texture_storage_ro_2d<r32sint>,\n"
+          "            coords      : vec2<i32>) -> vec4<i32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kR32Sint,
+          type::TextureDimension::k2d,
+          TextureDataType::kI32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO2dR32float,
+          "textureLoad(t           : texture_storage_ro_2d<r32float>,\n"
+          "            coords      : vec2<i32>) -> vec4<f32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kR32Float,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO2dRg32uint,
+          "textureLoad(t           : texture_storage_ro_2d<rg32uint>,\n"
+          "            coords      : vec2<i32>) -> vec4<u32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRg32Uint,
+          type::TextureDimension::k2d,
+          TextureDataType::kU32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO2dRg32sint,
+          "textureLoad(t           : texture_storage_ro_2d<rg32sint>,\n"
+          "            coords      : vec2<i32>) -> vec4<i32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRg32Sint,
+          type::TextureDimension::k2d,
+          TextureDataType::kI32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO2dRg32float,
+          "textureLoad(t           : texture_storage_ro_2d<rg32float>,\n"
+          "            coords      : vec2<i32>) -> vec4<f32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRg32Float,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO2dRgba32uint,
+          "textureLoad(t           : texture_storage_ro_2d<rgba32uint>,\n"
+          "            coords      : vec2<i32>) -> vec4<u32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba32Uint,
+          type::TextureDimension::k2d,
+          TextureDataType::kU32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO2dRgba32sint,
+          "textureLoad(t           : texture_storage_ro_2d<rgba32sint>,\n"
+          "            coords      : vec2<i32>) -> vec4<i32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba32Sint,
+          type::TextureDimension::k2d,
+          TextureDataType::kI32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO2dRgba32float,
+          "textureLoad(t           : texture_storage_ro_2d<rgba32float>,\n"
+          "            coords      : vec2<i32>) -> vec4<f32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba32Float,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",            // t
+                               b->vec2<i32>(1, 2));  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO2dArrayRgba32float,
+          "textureLoad(t           : "
+          "texture_storage_ro_2d_array<rgba32float>,\n"
+          "            coords      : vec2<i32>,\n"
+          "            array_index : i32) -> vec4<f32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba32Float,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",           // t
+                               b->vec2<i32>(1, 2),  // coords
+                               3);                  // array_index
+          },
+      },
+      {
+          ValidTextureOverload::kLoadStorageRO3dRgba32float,
+          "textureLoad(t      : texture_storage_ro_3d<rgba32float>,\n"
+          "            coords : vec3<i32>) -> vec4<f32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba32Float,
+          type::TextureDimension::k3d,
+          TextureDataType::kF32,
+          "textureLoad",
+          [](Builder* b) {
+            return b->ExprList("texture",               // t
+                               b->vec3<i32>(1, 2, 3));  // coords
+          },
+      },
+  };
 }
 
 }  // namespace test
diff --git a/src/ast/intrinsic_texture_helper_test.h b/src/ast/intrinsic_texture_helper_test.h
index 88bac80..cb42568 100644
--- a/src/ast/intrinsic_texture_helper_test.h
+++ b/src/ast/intrinsic_texture_helper_test.h
@@ -20,6 +20,7 @@
 
 #include "src/ast/builder.h"
 #include "src/ast/type/sampler_type.h"
+#include "src/ast/type/storage_texture_type.h"
 #include "src/ast/type/texture_type.h"
 
 namespace tint {
@@ -27,37 +28,13 @@
 namespace intrinsic {
 namespace test {
 
-enum class TextureKind { kRegular, kDepth };
-
-inline std::ostream& operator<<(std::ostream& out, const TextureKind& kind) {
-  switch (kind) {
-    case TextureKind::kRegular:
-      out << "regular";
-      break;
-    case TextureKind::kDepth:
-      out << "depth";
-      break;
-  }
-  return out;
-}
-
+enum class TextureKind { kRegular, kDepth, kMultisampled, kStorage };
 enum class TextureDataType { kF32, kU32, kI32 };
 
-inline std::ostream& operator<<(std::ostream& out, const TextureDataType& ty) {
-  switch (ty) {
-    case TextureDataType::kF32:
-      out << "f32";
-      break;
-    case TextureDataType::kU32:
-      out << "u32";
-      break;
-    case TextureDataType::kI32:
-      out << "i32";
-      break;
-  }
-  return out;
-}
+std::ostream& operator<<(std::ostream& out, const TextureKind& kind);
+std::ostream& operator<<(std::ostream& out, const TextureDataType& ty);
 
+/// Non-exhaustive list of valid texture overloads
 enum class ValidTextureOverload {
   kSample1dF32,
   kSample1dArrayF32,
@@ -111,13 +88,65 @@
   kSampleGradDepth2dArrayOffsetF32,
   kSampleGradDepthCubeF32,
   kSampleGradDepthCubeArrayF32,
+  kLoad1dF32,
+  kLoad1dU32,
+  kLoad1dI32,
+  kLoad1dArrayF32,
+  kLoad1dArrayU32,
+  kLoad1dArrayI32,
+  kLoad2dF32,
+  kLoad2dU32,
+  kLoad2dI32,
+  kLoad2dLevelF32,
+  kLoad2dLevelU32,
+  kLoad2dLevelI32,
+  kLoad2dArrayF32,
+  kLoad2dArrayU32,
+  kLoad2dArrayI32,
+  kLoad2dArrayLevelF32,
+  kLoad2dArrayLevelU32,
+  kLoad2dArrayLevelI32,
+  kLoad3dF32,
+  kLoad3dU32,
+  kLoad3dI32,
+  kLoad3dLevelF32,
+  kLoad3dLevelU32,
+  kLoad3dLevelI32,
+  kLoadMultisampled2dF32,
+  kLoadMultisampled2dU32,
+  kLoadMultisampled2dI32,
+  kLoadMultisampled2dArrayF32,
+  kLoadMultisampled2dArrayU32,
+  kLoadMultisampled2dArrayI32,
+  kLoadDepth2dF32,
+  kLoadDepth2dLevelF32,
+  kLoadDepth2dArrayF32,
+  kLoadDepth2dArrayLevelF32,
+  kLoadStorageRO1dRgba32float,       // Not permutated for all texel formats
+  kLoadStorageRO1dArrayRgba32float,  // Not permutated for all texel formats
+  kLoadStorageRO2dRgba8unorm,
+  kLoadStorageRO2dRgba8snorm,
+  kLoadStorageRO2dRgba8uint,
+  kLoadStorageRO2dRgba8sint,
+  kLoadStorageRO2dRgba16uint,
+  kLoadStorageRO2dRgba16sint,
+  kLoadStorageRO2dRgba16float,
+  kLoadStorageRO2dR32uint,
+  kLoadStorageRO2dR32sint,
+  kLoadStorageRO2dR32float,
+  kLoadStorageRO2dRg32uint,
+  kLoadStorageRO2dRg32sint,
+  kLoadStorageRO2dRg32float,
+  kLoadStorageRO2dRgba32uint,
+  kLoadStorageRO2dRgba32sint,
+  kLoadStorageRO2dRgba32float,
+  kLoadStorageRO2dArrayRgba32float,  // Not permutated for all texel formats
+  kLoadStorageRO3dRgba32float,       // Not permutated for all texel formats
 };
 
 /// Describes a texture intrinsic overload
 struct TextureOverloadCase {
-  /// Constructor
-  TextureOverloadCase();
-  /// Constructor
+  /// Constructor for textureSample...() functions
   TextureOverloadCase(ValidTextureOverload,
                       const char*,
                       TextureKind,
@@ -126,42 +155,68 @@
                       TextureDataType,
                       const char*,
                       std::function<ExpressionList(Builder*)>);
+  /// Constructor for textureLoad() functions with non-storage textures
+  TextureOverloadCase(ValidTextureOverload,
+                      const char*,
+                      TextureKind,
+                      type::TextureDimension,
+                      TextureDataType,
+                      const char*,
+                      std::function<ExpressionList(Builder*)>);
+  /// Constructor for textureLoad() with storage textures
+  TextureOverloadCase(ValidTextureOverload,
+                      const char*,
+                      AccessControl,
+                      type::ImageFormat,
+                      type::TextureDimension,
+                      TextureDataType,
+                      const char*,
+                      std::function<ExpressionList(Builder*)>);
   /// Copy constructor
   TextureOverloadCase(const TextureOverloadCase&);
   /// Destructor
   ~TextureOverloadCase();
 
-  /// @return a vector containing a large number of valid texture overloads
+  /// @return a vector containing a large number (non-exhaustive) of valid
+  /// texture overloads.
   static std::vector<TextureOverloadCase> ValidCases();
 
+  /// @param builder the AST builder used for the test
+  /// @returns the vector component type of the texture function return value
+  ast::type::Type* resultVectorComponentType(ast::Builder* builder) const;
+  /// @param builder the AST builder used for the test
+  /// @returns a Variable holding the test texture
+  ast::Variable* buildTextureVariable(ast::Builder* builder) const;
+  /// @param builder the AST builder used for the test
+  /// @returns a Variable holding the test sampler
+  ast::Variable* buildSamplerVariable(ast::Builder* builder) const;
+
   /// The enumerator for this overload
-  ValidTextureOverload overload;
+  ValidTextureOverload const overload;
   /// A human readable description of the overload
-  const char* description;
+  const char* const description;
   /// The texture kind for the texture parameter
-  TextureKind texture_kind;
+  TextureKind const texture_kind;
   /// The sampler kind for the sampler parameter
-  type::SamplerKind sampler_kind;
+  /// Used only when texture_kind is not kStorage
+  type::SamplerKind const sampler_kind = type::SamplerKind::kSampler;
+  /// The access control for the storage texture
+  /// Used only when texture_kind is kStorage
+  AccessControl const access_control = AccessControl::kReadWrite;
+  /// The image format for the storage texture
+  /// Used only when texture_kind is kStorage
+  type::ImageFormat const image_format = type::ImageFormat::kNone;
   /// The dimensions of the texture parameter
-  type::TextureDimension texture_dimension;
+  type::TextureDimension const texture_dimension;
   /// The data type of the texture parameter
-  TextureDataType texture_data_type;
+  TextureDataType const texture_data_type;
   /// Name of the function. e.g. `textureSample`, `textureSampleGrad`, etc
-  const char* function;
+  const char* const function;
   /// A function that builds the AST arguments for the overload
-  std::function<ExpressionList(Builder*)> args;
+  std::function<ExpressionList(Builder*)> const args;
 };
 
-inline std::ostream& operator<<(std::ostream& out,
-                                const TextureOverloadCase& data) {
-  out << "TextureOverloadCase" << static_cast<int>(data.overload) << "\n";
-  out << data.description << "\n";
-  out << "texture_kind:      " << data.texture_kind << "\n";
-  out << "sampler_kind:      " << data.sampler_kind << "\n";
-  out << "texture_dimension: " << data.texture_dimension << "\n";
-  out << "texture_data_type: " << data.texture_data_type << "\n";
-  return out;
-}
+std::ostream& operator<<(std::ostream& out, const TextureOverloadCase& data);
 
 }  // namespace test
 }  // namespace intrinsic
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 61d35ec..607dc39 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -408,7 +408,7 @@
       return "trunc";
 
     default:
-    // TODO(dneto). The following are not implemented.
+    // TODO(dneto) - The following are not implemented.
     // They are grouped semantically, as in GLSL.std.450.h.
     case GLSLstd450RoundEven:
     case GLSLstd450SAbs:
diff --git a/src/reader/spirv/parser_impl.h b/src/reader/spirv/parser_impl.h
index f5b9689..4d3b22a 100644
--- a/src/reader/spirv/parser_impl.h
+++ b/src/reader/spirv/parser_impl.h
@@ -235,10 +235,10 @@
   /// @returns true if parser is still successful.
   bool RegisterExtendedInstructionImports();
 
-  // Returns true when the given instruction is an extended instruction
-  // for GLSL.std.450.
-  // @param inst a SPIR-V instruction
-  // @returns true if its an SpvOpExtInst for GLSL.std.450
+  /// Returns true when the given instruction is an extended instruction
+  /// for GLSL.std.450.
+  /// @param inst a SPIR-V instruction
+  /// @returns true if its an SpvOpExtInst for GLSL.std.450
   bool IsGlslExtendedInstruction(const spvtools::opt::Instruction& inst) const;
 
   /// Registers user names for SPIR-V objects, from OpName, and OpMemberName.
diff --git a/src/transform/first_index_offset.h b/src/transform/first_index_offset.h
index ae28629..163bfbb 100644
--- a/src/transform/first_index_offset.h
+++ b/src/transform/first_index_offset.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Tint Authors.
+// Copyright 2020 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.
diff --git a/src/type_determiner.cc b/src/type_determiner.cc
index ab4d34c..b341777 100644
--- a/src/type_determiner.cc
+++ b/src/type_determiner.cc
@@ -555,6 +555,7 @@
                                       ->As<ast::type::Texture>();
 
     bool is_array = false;
+    bool is_multisampled = texture->Is<ast::type::MultisampledTexture>();
     switch (texture->dim()) {
       case ast::type::TextureDimension::k1dArray:
       case ast::type::TextureDimension::k2dArray:
@@ -571,13 +572,13 @@
         if (is_array) {
           param.idx.array_index = param.count++;
         }
-
-        // TODO(dsinclair): Remove the LOD param from textureLoad on storage
-        // textures when https://github.com/gpuweb/gpuweb/pull/1032 gets merged.
         if (expr->params().size() > param.count) {
-          param.idx.level = param.count++;
+          if (is_multisampled) {
+            param.idx.sample_index = param.count++;
+          } else {
+            param.idx.level = param.count++;
+          }
         }
-
         break;
       case ast::Intrinsic::kTextureSample:
         param.idx.texture = param.count++;
@@ -659,21 +660,21 @@
 
     if (texture->Is<ast::type::DepthTexture>()) {
       expr->func()->set_result_type(mod_->create<ast::type::F32>());
-      return true;
-    }
-
-    ast::type::Type* type = nullptr;
-    if (auto* storage = texture->As<ast::type::StorageTexture>()) {
-      type = storage->type();
-    } else if (auto* sampled = texture->As<ast::type::SampledTexture>()) {
-      type = sampled->type();
-    } else if (auto* msampled = texture->As<ast::type::MultisampledTexture>()) {
-      type = msampled->type();
     } else {
-      set_error(expr->source(), "unknown texture type for texture sampling");
-      return false;
+      ast::type::Type* type = nullptr;
+      if (auto* storage = texture->As<ast::type::StorageTexture>()) {
+        type = storage->type();
+      } else if (auto* sampled = texture->As<ast::type::SampledTexture>()) {
+        type = sampled->type();
+      } else if (auto* msampled =
+                     texture->As<ast::type::MultisampledTexture>()) {
+        type = msampled->type();
+      } else {
+        set_error(expr->source(), "unknown texture type for texture sampling");
+        return false;
+      }
+      expr->func()->set_result_type(mod_->create<ast::type::Vector>(type, 4));
     }
-    expr->func()->set_result_type(mod_->create<ast::type::Vector>(type, 4));
     return true;
   }
   if (ident->intrinsic() == ast::Intrinsic::kDot) {
diff --git a/src/type_determiner_test.cc b/src/type_determiner_test.cc
index 0b217a4..678141e 100644
--- a/src/type_determiner_test.cc
+++ b/src/type_determiner_test.cc
@@ -54,6 +54,7 @@
 #include "src/ast/type/f32_type.h"
 #include "src/ast/type/i32_type.h"
 #include "src/ast/type/matrix_type.h"
+#include "src/ast/type/multisampled_texture_type.h"
 #include "src/ast/type/pointer_type.h"
 #include "src/ast/type/sampled_texture_type.h"
 #include "src/ast/type/sampler_type.h"
@@ -4510,6 +4511,7 @@
   maybe_add_param(sig->params.idx.level, "level");
   maybe_add_param(sig->params.idx.offset, "offset");
   maybe_add_param(sig->params.idx.sampler, "sampler");
+  maybe_add_param(sig->params.idx.sample_index, "sample_index");
   maybe_add_param(sig->params.idx.texture, "texture");
   std::sort(
       params.begin(), params.end(),
@@ -4534,126 +4536,202 @@
   using ValidTextureOverload = ast::intrinsic::test::ValidTextureOverload;
   switch (overload) {
     case ValidTextureOverload::kSample1dF32:
-      return "textureSample(texture, sampler, coords)";
+      return R"(textureSample(texture, sampler, coords))";
     case ValidTextureOverload::kSample1dArrayF32:
-      return "textureSample(texture, sampler, coords, array_index)";
+      return R"(textureSample(texture, sampler, coords, array_index))";
     case ValidTextureOverload::kSample2dF32:
-      return "textureSample(texture, sampler, coords)";
+      return R"(textureSample(texture, sampler, coords))";
     case ValidTextureOverload::kSample2dOffsetF32:
-      return "textureSample(texture, sampler, coords, offset)";
+      return R"(textureSample(texture, sampler, coords, offset))";
     case ValidTextureOverload::kSample2dArrayF32:
-      return "textureSample(texture, sampler, coords, array_index)";
+      return R"(textureSample(texture, sampler, coords, array_index))";
     case ValidTextureOverload::kSample2dArrayOffsetF32:
-      return "textureSample(texture, sampler, coords, array_index, offset)";
+      return R"(textureSample(texture, sampler, coords, array_index, offset))";
     case ValidTextureOverload::kSample3dF32:
-      return "textureSample(texture, sampler, coords)";
+      return R"(textureSample(texture, sampler, coords))";
     case ValidTextureOverload::kSample3dOffsetF32:
-      return "textureSample(texture, sampler, coords, offset)";
+      return R"(textureSample(texture, sampler, coords, offset))";
     case ValidTextureOverload::kSampleCubeF32:
-      return "textureSample(texture, sampler, coords)";
+      return R"(textureSample(texture, sampler, coords))";
     case ValidTextureOverload::kSampleCubeArrayF32:
-      return "textureSample(texture, sampler, coords, array_index)";
+      return R"(textureSample(texture, sampler, coords, array_index))";
     case ValidTextureOverload::kSampleDepth2dF32:
-      return "textureSample(texture, sampler, coords)";
+      return R"(textureSample(texture, sampler, coords))";
     case ValidTextureOverload::kSampleDepth2dOffsetF32:
-      return "textureSample(texture, sampler, coords, offset)";
+      return R"(textureSample(texture, sampler, coords, offset))";
     case ValidTextureOverload::kSampleDepth2dArrayF32:
-      return "textureSample(texture, sampler, coords, array_index)";
+      return R"(textureSample(texture, sampler, coords, array_index))";
     case ValidTextureOverload::kSampleDepth2dArrayOffsetF32:
-      return "textureSample(texture, sampler, coords, array_index, offset)";
+      return R"(textureSample(texture, sampler, coords, array_index, offset))";
     case ValidTextureOverload::kSampleDepthCubeF32:
-      return "textureSample(texture, sampler, coords)";
+      return R"(textureSample(texture, sampler, coords))";
     case ValidTextureOverload::kSampleDepthCubeArrayF32:
-      return "textureSample(texture, sampler, coords, array_index)";
+      return R"(textureSample(texture, sampler, coords, array_index))";
     case ValidTextureOverload::kSampleBias2dF32:
-      return "textureSampleBias(texture, sampler, coords, bias)";
+      return R"(textureSampleBias(texture, sampler, coords, bias))";
     case ValidTextureOverload::kSampleBias2dOffsetF32:
-      return "textureSampleBias(texture, sampler, coords, bias, offset)";
+      return R"(textureSampleBias(texture, sampler, coords, bias, offset))";
     case ValidTextureOverload::kSampleBias2dArrayF32:
-      return "textureSampleBias(texture, sampler, coords, array_index, "
-             "bias)";
+      return R"(textureSampleBias(texture, sampler, coords, array_index, bias))";
     case ValidTextureOverload::kSampleBias2dArrayOffsetF32:
-      return "textureSampleBias(texture, sampler, coords, array_index, "
-             "bias, offset)";
+      return R"(textureSampleBias(texture, sampler, coords, array_index, bias, offset))";
     case ValidTextureOverload::kSampleBias3dF32:
-      return "textureSampleBias(texture, sampler, coords, bias)";
+      return R"(textureSampleBias(texture, sampler, coords, bias))";
     case ValidTextureOverload::kSampleBias3dOffsetF32:
-      return "textureSampleBias(texture, sampler, coords, bias, offset)";
+      return R"(textureSampleBias(texture, sampler, coords, bias, offset))";
     case ValidTextureOverload::kSampleBiasCubeF32:
-      return "textureSampleBias(texture, sampler, coords, bias)";
+      return R"(textureSampleBias(texture, sampler, coords, bias))";
     case ValidTextureOverload::kSampleBiasCubeArrayF32:
-      return "textureSampleBias(texture, sampler, coords, array_index, "
-             "bias)";
+      return R"(textureSampleBias(texture, sampler, coords, array_index, bias))";
     case ValidTextureOverload::kSampleLevel2dF32:
-      return "textureSampleLevel(texture, sampler, coords, level)";
+      return R"(textureSampleLevel(texture, sampler, coords, level))";
     case ValidTextureOverload::kSampleLevel2dOffsetF32:
-      return "textureSampleLevel(texture, sampler, coords, level, offset)";
+      return R"(textureSampleLevel(texture, sampler, coords, level, offset))";
     case ValidTextureOverload::kSampleLevel2dArrayF32:
-      return "textureSampleLevel(texture, sampler, coords, array_index, "
-             "level)";
+      return R"(textureSampleLevel(texture, sampler, coords, array_index, level))";
     case ValidTextureOverload::kSampleLevel2dArrayOffsetF32:
-      return "textureSampleLevel(texture, sampler, coords, array_index, "
-             "level, offset)";
+      return R"(textureSampleLevel(texture, sampler, coords, array_index, level, offset))";
     case ValidTextureOverload::kSampleLevel3dF32:
-      return "textureSampleLevel(texture, sampler, coords, level)";
+      return R"(textureSampleLevel(texture, sampler, coords, level))";
     case ValidTextureOverload::kSampleLevel3dOffsetF32:
-      return "textureSampleLevel(texture, sampler, coords, level, offset)";
+      return R"(textureSampleLevel(texture, sampler, coords, level, offset))";
     case ValidTextureOverload::kSampleLevelCubeF32:
-      return "textureSampleLevel(texture, sampler, coords, level)";
+      return R"(textureSampleLevel(texture, sampler, coords, level))";
     case ValidTextureOverload::kSampleLevelCubeArrayF32:
-      return "textureSampleLevel(texture, sampler, coords, array_index, "
-             "level)";
+      return R"(textureSampleLevel(texture, sampler, coords, array_index, level))";
     case ValidTextureOverload::kSampleLevelDepth2dF32:
-      return "textureSampleLevel(texture, sampler, coords, level)";
+      return R"(textureSampleLevel(texture, sampler, coords, level))";
     case ValidTextureOverload::kSampleLevelDepth2dOffsetF32:
-      return "textureSampleLevel(texture, sampler, coords, level, offset)";
+      return R"(textureSampleLevel(texture, sampler, coords, level, offset))";
     case ValidTextureOverload::kSampleLevelDepth2dArrayF32:
-      return "textureSampleLevel(texture, sampler, coords, array_index, level)";
+      return R"(textureSampleLevel(texture, sampler, coords, array_index, level))";
     case ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32:
-      return "textureSampleLevel(texture, sampler, coords, array_index, level, "
-             "offset)";
+      return R"(textureSampleLevel(texture, sampler, coords, array_index, level, offset))";
     case ValidTextureOverload::kSampleLevelDepthCubeF32:
-      return "textureSampleLevel(texture, sampler, coords, level)";
+      return R"(textureSampleLevel(texture, sampler, coords, level))";
     case ValidTextureOverload::kSampleLevelDepthCubeArrayF32:
-      return "textureSampleLevel(texture, sampler, coords, array_index, "
-             "level)";
+      return R"(textureSampleLevel(texture, sampler, coords, array_index, level))";
     case ValidTextureOverload::kSampleGrad2dF32:
-      return "textureSampleGrad(texture, sampler, coords, ddx, ddy)";
+      return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy))";
     case ValidTextureOverload::kSampleGrad2dOffsetF32:
-      return "textureSampleGrad(texture, sampler, coords, ddx, ddy, "
-             "offset)";
+      return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy, offset))";
     case ValidTextureOverload::kSampleGrad2dArrayF32:
-      return "textureSampleGrad(texture, sampler, coords, array_index, ddx, "
-             "ddy)";
+      return R"(textureSampleGrad(texture, sampler, coords, array_index, ddx, ddy))";
     case ValidTextureOverload::kSampleGrad2dArrayOffsetF32:
-      return "textureSampleGrad(texture, sampler, coords, array_index, ddx, "
-             "ddy, offset)";
+      return R"(textureSampleGrad(texture, sampler, coords, array_index, ddx, ddy, offset))";
     case ValidTextureOverload::kSampleGrad3dF32:
-      return "textureSampleGrad(texture, sampler, coords, ddx, ddy)";
+      return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy))";
     case ValidTextureOverload::kSampleGrad3dOffsetF32:
-      return "textureSampleGrad(texture, sampler, coords, ddx, ddy, "
-             "offset)";
+      return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy, offset))";
     case ValidTextureOverload::kSampleGradCubeF32:
-      return "textureSampleGrad(texture, sampler, coords, ddx, ddy)";
+      return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy))";
     case ValidTextureOverload::kSampleGradCubeArrayF32:
-      return "textureSampleGrad(texture, sampler, coords, array_index, ddx, "
-             "ddy)";
+      return R"(textureSampleGrad(texture, sampler, coords, array_index, ddx, ddy))";
     case ValidTextureOverload::kSampleGradDepth2dF32:
-      return "textureSampleCompare(texture, sampler, coords, depth_ref)";
+      return R"(textureSampleCompare(texture, sampler, coords, depth_ref))";
     case ValidTextureOverload::kSampleGradDepth2dOffsetF32:
-      return "textureSampleCompare(texture, sampler, coords, depth_ref, "
-             "offset)";
+      return R"(textureSampleCompare(texture, sampler, coords, depth_ref, offset))";
     case ValidTextureOverload::kSampleGradDepth2dArrayF32:
-      return "textureSampleCompare(texture, sampler, coords, array_index, "
-             "depth_ref)";
+      return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref))";
     case ValidTextureOverload::kSampleGradDepth2dArrayOffsetF32:
-      return "textureSampleCompare(texture, sampler, coords, array_index, "
-             "depth_ref, offset)";
+      return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref, offset))";
     case ValidTextureOverload::kSampleGradDepthCubeF32:
-      return "textureSampleCompare(texture, sampler, coords, depth_ref)";
+      return R"(textureSampleCompare(texture, sampler, coords, depth_ref))";
     case ValidTextureOverload::kSampleGradDepthCubeArrayF32:
-      return "textureSampleCompare(texture, sampler, coords, array_index, "
-             "depth_ref)";
+      return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref))";
+    case ValidTextureOverload::kLoad1dF32:
+      return R"(textureLoad(texture, coords))";
+    case ValidTextureOverload::kLoad1dU32:
+      return R"(textureLoad(texture, coords))";
+    case ValidTextureOverload::kLoad1dI32:
+      return R"(textureLoad(texture, coords))";
+    case ValidTextureOverload::kLoad1dArrayF32:
+      return R"(textureLoad(texture, coords, array_index))";
+    case ValidTextureOverload::kLoad1dArrayU32:
+      return R"(textureLoad(texture, coords, array_index))";
+    case ValidTextureOverload::kLoad1dArrayI32:
+      return R"(textureLoad(texture, coords, array_index))";
+    case ValidTextureOverload::kLoad2dF32:
+      return R"(textureLoad(texture, coords))";
+    case ValidTextureOverload::kLoad2dU32:
+      return R"(textureLoad(texture, coords))";
+    case ValidTextureOverload::kLoad2dI32:
+      return R"(textureLoad(texture, coords))";
+    case ValidTextureOverload::kLoad2dLevelF32:
+      return R"(textureLoad(texture, coords, level))";
+    case ValidTextureOverload::kLoad2dLevelU32:
+      return R"(textureLoad(texture, coords, level))";
+    case ValidTextureOverload::kLoad2dLevelI32:
+      return R"(textureLoad(texture, coords, level))";
+    case ValidTextureOverload::kLoad2dArrayF32:
+      return R"(textureLoad(texture, coords, array_index))";
+    case ValidTextureOverload::kLoad2dArrayU32:
+      return R"(textureLoad(texture, coords, array_index))";
+    case ValidTextureOverload::kLoad2dArrayI32:
+      return R"(textureLoad(texture, coords, array_index))";
+    case ValidTextureOverload::kLoad2dArrayLevelF32:
+      return R"(textureLoad(texture, coords, array_index, level))";
+    case ValidTextureOverload::kLoad2dArrayLevelU32:
+      return R"(textureLoad(texture, coords, array_index, level))";
+    case ValidTextureOverload::kLoad2dArrayLevelI32:
+      return R"(textureLoad(texture, coords, array_index, level))";
+    case ValidTextureOverload::kLoad3dF32:
+      return R"(textureLoad(texture, coords))";
+    case ValidTextureOverload::kLoad3dU32:
+      return R"(textureLoad(texture, coords))";
+    case ValidTextureOverload::kLoad3dI32:
+      return R"(textureLoad(texture, coords))";
+    case ValidTextureOverload::kLoad3dLevelF32:
+      return R"(textureLoad(texture, coords, level))";
+    case ValidTextureOverload::kLoad3dLevelU32:
+      return R"(textureLoad(texture, coords, level))";
+    case ValidTextureOverload::kLoad3dLevelI32:
+      return R"(textureLoad(texture, coords, level))";
+    case ValidTextureOverload::kLoadMultisampled2dF32:
+      return R"(textureLoad(texture, coords, sample_index))";
+    case ValidTextureOverload::kLoadMultisampled2dU32:
+      return R"(textureLoad(texture, coords, sample_index))";
+    case ValidTextureOverload::kLoadMultisampled2dI32:
+      return R"(textureLoad(texture, coords, sample_index))";
+    case ValidTextureOverload::kLoadMultisampled2dArrayF32:
+      return R"(textureLoad(texture, coords, array_index, sample_index))";
+    case ValidTextureOverload::kLoadMultisampled2dArrayU32:
+      return R"(textureLoad(texture, coords, array_index, sample_index))";
+    case ValidTextureOverload::kLoadMultisampled2dArrayI32:
+      return R"(textureLoad(texture, coords, array_index, sample_index))";
+    case ValidTextureOverload::kLoadDepth2dF32:
+      return R"(textureLoad(texture, coords))";
+    case ValidTextureOverload::kLoadDepth2dLevelF32:
+      return R"(textureLoad(texture, coords, level))";
+    case ValidTextureOverload::kLoadDepth2dArrayF32:
+      return R"(textureLoad(texture, coords, array_index))";
+    case ValidTextureOverload::kLoadDepth2dArrayLevelF32:
+      return R"(textureLoad(texture, coords, array_index, level))";
+    case ValidTextureOverload::kLoadStorageRO1dRgba32float:
+      return R"(textureLoad(texture, coords))";
+    case ValidTextureOverload::kLoadStorageRO1dArrayRgba32float:
+      return R"(textureLoad(texture, coords, array_index))";
+    case ValidTextureOverload::kLoadStorageRO2dRgba8unorm:
+    case ValidTextureOverload::kLoadStorageRO2dRgba8snorm:
+    case ValidTextureOverload::kLoadStorageRO2dRgba8uint:
+    case ValidTextureOverload::kLoadStorageRO2dRgba8sint:
+    case ValidTextureOverload::kLoadStorageRO2dRgba16uint:
+    case ValidTextureOverload::kLoadStorageRO2dRgba16sint:
+    case ValidTextureOverload::kLoadStorageRO2dRgba16float:
+    case ValidTextureOverload::kLoadStorageRO2dR32uint:
+    case ValidTextureOverload::kLoadStorageRO2dR32sint:
+    case ValidTextureOverload::kLoadStorageRO2dR32float:
+    case ValidTextureOverload::kLoadStorageRO2dRg32uint:
+    case ValidTextureOverload::kLoadStorageRO2dRg32sint:
+    case ValidTextureOverload::kLoadStorageRO2dRg32float:
+    case ValidTextureOverload::kLoadStorageRO2dRgba32uint:
+    case ValidTextureOverload::kLoadStorageRO2dRgba32sint:
+    case ValidTextureOverload::kLoadStorageRO2dRgba32float:
+      return R"(textureLoad(texture, coords))";
+    case ValidTextureOverload::kLoadStorageRO2dArrayRgba32float:
+      return R"(textureLoad(texture, coords, array_index))";
+    case ValidTextureOverload::kLoadStorageRO3dRgba32float:
+      return R"(textureLoad(texture, coords))";
   }
   return "<unmatched texture overload>";
 }
@@ -4661,56 +4739,37 @@
 TEST_P(TypeDeterminerTextureIntrinsicTest, Call) {
   auto param = GetParam();
 
-  ast::type::Type* datatype = nullptr;
-  switch (param.texture_data_type) {
-    case ast::intrinsic::test::TextureDataType::kF32:
-      datatype = ty.f32;
-      break;
-    case ast::intrinsic::test::TextureDataType::kU32:
-      datatype = ty.u32;
-      break;
-    case ast::intrinsic::test::TextureDataType::kI32:
-      datatype = ty.i32;
-      break;
-  }
-
-  ast::type::Sampler sampler_type{param.sampler_kind};
-  switch (param.texture_kind) {
-    case ast::intrinsic::test::TextureKind::kRegular:
-      Var("texture", ast::StorageClass::kNone,
-          mod->create<ast::type::SampledTexture>(param.texture_dimension,
-                                                 datatype));
-      break;
-
-    case ast::intrinsic::test::TextureKind::kDepth:
-      Var("texture", ast::StorageClass::kNone,
-          mod->create<ast::type::DepthTexture>(param.texture_dimension));
-      break;
-  }
-
-  Var("sampler", ast::StorageClass::kNone, &sampler_type);
+  param.buildTextureVariable(this);
+  param.buildSamplerVariable(this);
 
   auto* ident = Expr(param.function);
   ast::CallExpression call{ident, param.args(this)};
 
-  EXPECT_TRUE(td()->DetermineResultType(&call)) << td()->error();
+  ASSERT_TRUE(td()->Determine()) << td()->error();
+  ASSERT_TRUE(td()->DetermineResultType(&call)) << td()->error();
 
   switch (param.texture_kind) {
     case ast::intrinsic::test::TextureKind::kRegular:
+    case ast::intrinsic::test::TextureKind::kMultisampled:
+    case ast::intrinsic::test::TextureKind::kStorage: {
+      auto* datatype = param.resultVectorComponentType(this);
       ASSERT_TRUE(call.result_type()->Is<ast::type::Vector>());
       EXPECT_EQ(call.result_type()->As<ast::type::Vector>()->type(), datatype);
       break;
-
-    case ast::intrinsic::test::TextureKind::kDepth:
+    }
+    case ast::intrinsic::test::TextureKind::kDepth: {
       EXPECT_EQ(call.result_type(), ty.f32);
       break;
+    }
   }
 
   auto* sig = static_cast<const ast::intrinsic::TextureSignature*>(
       ident->intrinsic_signature());
+  ASSERT_NE(sig, nullptr);
 
+  auto got = to_str(param.function, sig);
   auto* expected = expected_texture_overload(param.overload);
-  EXPECT_EQ(to_str(param.function, sig), expected);
+  EXPECT_EQ(got, expected);
 }
 
 }  // namespace
diff --git a/src/writer/pack_coord_arrayidx.cc b/src/writer/append_vector.cc
similarity index 74%
rename from src/writer/pack_coord_arrayidx.cc
rename to src/writer/append_vector.cc
index 4421099..0436c6f 100644
--- a/src/writer/pack_coord_arrayidx.cc
+++ b/src/writer/append_vector.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/writer/pack_coord_arrayidx.h"
+#include "src/writer/append_vector.h"
 
 #include <utility>
 
@@ -36,41 +36,46 @@
 
 }  // namespace
 
-bool PackCoordAndArrayIndex(
-    ast::Expression* coords,
-    ast::Expression* array_idx,
+bool AppendVector(
+    ast::Expression* vector,
+    ast::Expression* scalar,
     std::function<bool(ast::TypeConstructorExpression*)> callback) {
   uint32_t packed_size;
   ast::type::Type* packed_el_ty;  // Currently must be f32.
-  if (auto* vec = coords->result_type()->As<ast::type::Vector>()) {
+  if (auto* vec = vector->result_type()->As<ast::type::Vector>()) {
     packed_size = vec->size() + 1;
     packed_el_ty = vec->type();
   } else {
     packed_size = 2;
-    packed_el_ty = coords->result_type();
+    packed_el_ty = vector->result_type();
   }
 
   if (!packed_el_ty) {
     return false;  // missing type info
   }
 
-  // Cast array_idx to the vector element type
-  ast::TypeConstructorExpression array_index_cast(packed_el_ty, {array_idx});
-  array_index_cast.set_result_type(packed_el_ty);
+  // Cast scalar to the vector element type
+  ast::TypeConstructorExpression scalar_cast(packed_el_ty, {scalar});
+  scalar_cast.set_result_type(packed_el_ty);
 
   ast::type::Vector packed_ty(packed_el_ty, packed_size);
 
   // If the coordinates are already passed in a vector constructor, extract
   // the elements into the new vector instead of nesting a vector-in-vector.
   ast::ExpressionList packed;
-  if (auto* vc = AsVectorConstructor(coords)) {
+  if (auto* vc = AsVectorConstructor(vector)) {
     packed = vc->values();
   } else {
-    packed.emplace_back(coords);
+    packed.emplace_back(vector);
   }
-  packed.emplace_back(&array_index_cast);
+  if (packed_el_ty != scalar->result_type()) {
+    packed.emplace_back(&scalar_cast);
+  } else {
+    packed.emplace_back(scalar);
+  }
 
   ast::TypeConstructorExpression constructor{&packed_ty, std::move(packed)};
+  constructor.set_result_type(&packed_ty);
 
   return callback(&constructor);
 }
diff --git a/src/writer/pack_coord_arrayidx.h b/src/writer/append_vector.h
similarity index 60%
rename from src/writer/pack_coord_arrayidx.h
rename to src/writer/append_vector.h
index 742ee0a..d431336 100644
--- a/src/writer/pack_coord_arrayidx.h
+++ b/src/writer/append_vector.h
@@ -12,8 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_WRITER_PACK_COORD_ARRAYIDX_H_
-#define SRC_WRITER_PACK_COORD_ARRAYIDX_H_
+#ifndef SRC_WRITER_APPEND_VECTOR_H_
+#define SRC_WRITER_APPEND_VECTOR_H_
 
 #include <functional>
 
@@ -28,25 +28,26 @@
 
 namespace writer {
 
-/// A helper function use to generate texture intrinsic function calls for
-/// backends that expect the texture coordinate and array index to be packed
-/// together into a single 'coordinate' parameter.
-/// PackCoordAndArrayIndex() calls the `callback` function with a vector
-/// expression containing the elements of `coords` followed by the single
-/// element of `array_idx` cast to the `coords` element type.
+/// A helper function used to append a vector with an additional scalar.
+/// AppendVector is used to generate texture intrinsic function calls for
+/// backends that expect the texture coordinates to be packed with an additional
+/// mip-level or array-index parameter.
+/// AppendVector() calls the `callback` function with a vector
+/// expression containing the elements of `vector` followed by the single
+/// element of `scalar` cast to the `vector` element type.
 /// All types must have been assigned to the expressions and their child nodes
 /// before calling.
-/// @param coords the texture coordinates. May be a scalar, `vec2` or `vec3`.
-/// @param array_idx the texture array index. Must be a scalar.
+/// @param vector the vector to be appended. May be a scalar, `vec2` or `vec3`.
+/// @param scalar the scalar to append to the vector. Must be a scalar.
 /// @param callback the function called with the packed result. Note that the
 /// pointer argument is only valid for the duration of the call.
 /// @returns the value returned by `callback` to indicate success
-bool PackCoordAndArrayIndex(
-    ast::Expression* coords,
-    ast::Expression* array_idx,
+bool AppendVector(
+    ast::Expression* vector,
+    ast::Expression* scalar,
     std::function<bool(ast::TypeConstructorExpression*)> callback);
 
 }  // namespace writer
 }  // namespace tint
 
-#endif  // SRC_WRITER_PACK_COORD_ARRAYIDX_H_
+#endif  // SRC_WRITER_APPEND_VECTOR_H_
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index 3bde2da..03d86ce 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -57,8 +57,8 @@
 #include "src/ast/uint_literal.h"
 #include "src/ast/unary_op_expression.h"
 #include "src/ast/variable_decl_statement.h"
+#include "src/writer/append_vector.h"
 #include "src/writer/float_to_string.h"
-#include "src/writer/pack_coord_arrayidx.h"
 
 namespace tint {
 namespace writer {
@@ -729,9 +729,14 @@
   auto& pidx = signature->params.idx;
   auto const kNotUsed = ast::intrinsic::TextureSignature::Parameters::kNotUsed;
 
-  if (!EmitExpression(pre, out, params[pidx.texture]))
+  auto* texture = params[pidx.texture];
+  auto* texture_type = texture->result_type()->UnwrapPtrIfNeeded();
+
+  if (!EmitExpression(pre, out, texture))
     return false;
 
+  bool pack_mip_in_coords = false;
+
   switch (ident->intrinsic()) {
     case ast::Intrinsic::kTextureSample:
       out << ".Sample(";
@@ -748,35 +753,61 @@
     case ast::Intrinsic::kTextureSampleCompare:
       out << ".SampleCmp(";
       break;
+    case ast::Intrinsic::kTextureLoad:
+      out << ".Load(";
+      if (!texture_type->Is<ast::type::StorageTexture>()) {
+        pack_mip_in_coords = true;
+      }
+      break;
     default:
       error_ = "Internal compiler error: Unhandled texture intrinsic '" +
                ident->name() + "'";
-      break;
+      return false;
   }
 
-  if (!EmitExpression(pre, out, params[pidx.sampler]))
-    return false;
+  if (pidx.sampler != kNotUsed) {
+    if (!EmitExpression(pre, out, params[pidx.sampler]))
+      return false;
+    out << ", ";
+  }
 
-  out << ", ";
+  auto* param_coords = params[pidx.coords];
+
+  auto emit_vector_appended_with_i32_zero = [&](tint::ast::Expression* vector) {
+    auto* i32 = module_->create<ast::type::I32>();
+    ast::SintLiteral zero_lit(i32, 0);
+    ast::ScalarConstructorExpression zero(&zero_lit);
+    zero.set_result_type(i32);
+    return AppendVector(vector, &zero,
+                        [&](ast::TypeConstructorExpression* packed) {
+                          return EmitExpression(pre, out, packed);
+                        });
+  };
 
   if (pidx.array_index != kNotUsed) {
     // Array index needs to be appended to the coordinates.
-    auto* param_coords = params[pidx.coords];
     auto* param_array_index = params[pidx.array_index];
-    if (!PackCoordAndArrayIndex(param_coords, param_array_index,
-                                [&](ast::TypeConstructorExpression* packed) {
-                                  return EmitExpression(pre, out, packed);
-                                })) {
+    if (!AppendVector(param_coords, param_array_index,
+                      [&](ast::TypeConstructorExpression* packed) {
+                        if (pack_mip_in_coords) {
+                          return emit_vector_appended_with_i32_zero(packed);
+                        } else {
+                          return EmitExpression(pre, out, packed);
+                        }
+                      })) {
       return false;
     }
-
+  } else if (pack_mip_in_coords) {
+    // Mip level needs to be appended to the coordinates, but is always zero.
+    if (!emit_vector_appended_with_i32_zero(param_coords))
+      return false;
   } else {
-    if (!EmitExpression(pre, out, params[pidx.coords]))
+    if (!EmitExpression(pre, out, param_coords))
       return false;
   }
 
   for (auto idx : {pidx.depth_ref, pidx.bias, pidx.level, pidx.ddx, pidx.ddy,
-                   pidx.offset}) {
+                   pidx.sample_index, pidx.offset}) {
     if (idx != kNotUsed) {
       out << ", ";
       if (!EmitExpression(pre, out, params[idx]))
diff --git a/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc b/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc
index 47f702d..db1f2cd 100644
--- a/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc
+++ b/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc
@@ -18,6 +18,7 @@
 #include "src/ast/builder.h"
 #include "src/ast/intrinsic_texture_helper_test.h"
 #include "src/ast/type/depth_texture_type.h"
+#include "src/ast/type/multisampled_texture_type.h"
 #include "src/ast/type/sampled_texture_type.h"
 #include "src/type_determiner.h"
 #include "src/writer/hlsl/generator_impl.h"
@@ -135,9 +136,102 @@
       return R"(texture_tint_0.SampleCmp(sampler_tint_0, float3(1.0f, 2.0f, 3.0f), 4.0f))";
     case ValidTextureOverload::kSampleGradDepthCubeArrayF32:
       return R"(texture_tint_0.SampleCmp(sampler_tint_0, float4(1.0f, 2.0f, 3.0f, float(4)), 5.0f))";
+    case ValidTextureOverload::kLoad1dF32:
+      return R"(texture_tint_0.Load(int2(1, 0)))";
+    case ValidTextureOverload::kLoad1dU32:
+      return R"(texture_tint_0.Load(int2(1, 0)))";
+    case ValidTextureOverload::kLoad1dI32:
+      return R"(texture_tint_0.Load(int2(1, 0)))";
+    case ValidTextureOverload::kLoad1dArrayF32:
+      return R"(texture_tint_0.Load(int3(1, 2, 0)))";
+    case ValidTextureOverload::kLoad1dArrayU32:
+      return R"(texture_tint_0.Load(int3(1, 2, 0)))";
+    case ValidTextureOverload::kLoad1dArrayI32:
+      return R"(texture_tint_0.Load(int3(1, 2, 0)))";
+    case ValidTextureOverload::kLoad2dF32:
+      return R"(texture_tint_0.Load(int3(1, 2, 0)))";
+    case ValidTextureOverload::kLoad2dU32:
+      return R"(texture_tint_0.Load(int3(1, 2, 0)))";
+    case ValidTextureOverload::kLoad2dI32:
+      return R"(texture_tint_0.Load(int3(1, 2, 0)))";
+    case ValidTextureOverload::kLoad2dLevelF32:
+      return R"(texture_tint_0.Load(int3(1, 2, 0), 3))";
+    case ValidTextureOverload::kLoad2dLevelU32:
+      return R"(texture_tint_0.Load(int3(1, 2, 0), 3))";
+    case ValidTextureOverload::kLoad2dLevelI32:
+      return R"(texture_tint_0.Load(int3(1, 2, 0), 3))";
+    case ValidTextureOverload::kLoad2dArrayF32:
+      return R"(texture_tint_0.Load(int4(1, 2, 3, 0)))";
+    case ValidTextureOverload::kLoad2dArrayU32:
+      return R"(texture_tint_0.Load(int4(1, 2, 3, 0)))";
+    case ValidTextureOverload::kLoad2dArrayI32:
+      return R"(texture_tint_0.Load(int4(1, 2, 3, 0)))";
+    case ValidTextureOverload::kLoad2dArrayLevelF32:
+      return R"(texture_tint_0.Load(int4(1, 2, 3, 0), 4))";
+    case ValidTextureOverload::kLoad2dArrayLevelU32:
+      return R"(texture_tint_0.Load(int4(1, 2, 3, 0), 4))";
+    case ValidTextureOverload::kLoad2dArrayLevelI32:
+      return R"(texture_tint_0.Load(int4(1, 2, 3, 0), 4))";
+    case ValidTextureOverload::kLoad3dF32:
+      return R"(texture_tint_0.Load(int4(1, 2, 3, 0)))";
+    case ValidTextureOverload::kLoad3dU32:
+      return R"(texture_tint_0.Load(int4(1, 2, 3, 0)))";
+    case ValidTextureOverload::kLoad3dI32:
+      return R"(texture_tint_0.Load(int4(1, 2, 3, 0)))";
+    case ValidTextureOverload::kLoad3dLevelF32:
+      return R"(texture_tint_0.Load(int4(1, 2, 3, 0), 4))";
+    case ValidTextureOverload::kLoad3dLevelU32:
+      return R"(texture_tint_0.Load(int4(1, 2, 3, 0), 4))";
+    case ValidTextureOverload::kLoad3dLevelI32:
+      return R"(texture_tint_0.Load(int4(1, 2, 3, 0), 4))";
+    case ValidTextureOverload::kLoadMultisampled2dF32:
+      return R"(texture_tint_0.Load(int3(1, 2, 0), 3))";
+    case ValidTextureOverload::kLoadMultisampled2dU32:
+      return R"(texture_tint_0.Load(int3(1, 2, 0), 3))";
+    case ValidTextureOverload::kLoadMultisampled2dI32:
+      return R"(texture_tint_0.Load(int3(1, 2, 0), 3))";
+    case ValidTextureOverload::kLoadMultisampled2dArrayF32:
+      return R"(texture_tint_0.Load(int4(1, 2, 3, 0), 4))";
+    case ValidTextureOverload::kLoadMultisampled2dArrayU32:
+      return R"(texture_tint_0.Load(int4(1, 2, 3, 0), 4))";
+    case ValidTextureOverload::kLoadMultisampled2dArrayI32:
+      return R"(texture_tint_0.Load(int4(1, 2, 3, 0), 4))";
+    case ValidTextureOverload::kLoadDepth2dF32:
+      return R"(texture_tint_0.Load(int3(1, 2, 0)))";
+    case ValidTextureOverload::kLoadDepth2dLevelF32:
+      return R"(texture_tint_0.Load(int3(1, 2, 0), 3))";
+    case ValidTextureOverload::kLoadDepth2dArrayF32:
+      return R"(texture_tint_0.Load(int4(1, 2, 3, 0)))";
+    case ValidTextureOverload::kLoadDepth2dArrayLevelF32:
+      return R"(texture_tint_0.Load(int4(1, 2, 3, 0), 4))";
+    case ValidTextureOverload::kLoadStorageRO1dRgba32float:
+      return R"(texture_tint_0.Load(1))";
+    case ValidTextureOverload::kLoadStorageRO1dArrayRgba32float:
+      return R"(texture_tint_0.Load(int2(1, 2)))";
+    case ValidTextureOverload::kLoadStorageRO2dRgba8unorm:
+    case ValidTextureOverload::kLoadStorageRO2dRgba8snorm:
+    case ValidTextureOverload::kLoadStorageRO2dRgba8uint:
+    case ValidTextureOverload::kLoadStorageRO2dRgba8sint:
+    case ValidTextureOverload::kLoadStorageRO2dRgba16uint:
+    case ValidTextureOverload::kLoadStorageRO2dRgba16sint:
+    case ValidTextureOverload::kLoadStorageRO2dRgba16float:
+    case ValidTextureOverload::kLoadStorageRO2dR32uint:
+    case ValidTextureOverload::kLoadStorageRO2dR32sint:
+    case ValidTextureOverload::kLoadStorageRO2dR32float:
+    case ValidTextureOverload::kLoadStorageRO2dRg32uint:
+    case ValidTextureOverload::kLoadStorageRO2dRg32sint:
+    case ValidTextureOverload::kLoadStorageRO2dRg32float:
+    case ValidTextureOverload::kLoadStorageRO2dRgba32uint:
+    case ValidTextureOverload::kLoadStorageRO2dRgba32sint:
+    case ValidTextureOverload::kLoadStorageRO2dRgba32float:
+      return R"(texture_tint_0.Load(int2(1, 2)))";
+    case ValidTextureOverload::kLoadStorageRO2dArrayRgba32float:
+      return R"(texture_tint_0.Load(int3(1, 2, 3)))";
+    case ValidTextureOverload::kLoadStorageRO3dRgba32float:
+      return R"(texture_tint_0.Load(int3(1, 2, 3)))";
   }
   return "<unmatched texture overload>";
-}  // LINT - Ignore the length of this function
+}  // NOLINT - Ignore the length of this function
 
 class HlslGeneratorIntrinsicTextureTest
     : public ast::BuilderWithModule,
@@ -165,38 +259,13 @@
 TEST_P(HlslGeneratorIntrinsicTextureTest, Call) {
   auto param = GetParam();
 
-  ast::type::Type* datatype = nullptr;
-  switch (param.texture_data_type) {
-    case ast::intrinsic::test::TextureDataType::kF32:
-      datatype = ty.f32;
-      break;
-    case ast::intrinsic::test::TextureDataType::kU32:
-      datatype = ty.u32;
-      break;
-    case ast::intrinsic::test::TextureDataType::kI32:
-      datatype = ty.i32;
-      break;
-  }
-
-  ast::type::Sampler sampler_type{param.sampler_kind};
-  switch (param.texture_kind) {
-    case ast::intrinsic::test::TextureKind::kRegular:
-      Var("texture", ast::StorageClass::kNone,
-          mod->create<ast::type::SampledTexture>(param.texture_dimension,
-                                                 datatype));
-      break;
-
-    case ast::intrinsic::test::TextureKind::kDepth:
-      Var("texture", ast::StorageClass::kNone,
-          mod->create<ast::type::DepthTexture>(param.texture_dimension));
-      break;
-  }
-
-  Var("sampler", ast::StorageClass::kNone, &sampler_type);
+  param.buildTextureVariable(this);
+  param.buildSamplerVariable(this);
 
   ast::CallExpression call{Expr(param.function), param.args(this)};
 
-  EXPECT_TRUE(td.DetermineResultType(&call)) << td.error();
+  ASSERT_TRUE(td.Determine()) << td.error();
+  ASSERT_TRUE(td.DetermineResultType(&call)) << td.error();
 
   ASSERT_TRUE(gen.EmitExpression(pre, out, &call)) << gen.error();
 
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index 003401f..127a8a3 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -663,6 +663,8 @@
   if (!EmitExpression(params[pidx.texture]))
     return false;
 
+  bool lod_param_is_named = true;
+
   switch (ident->intrinsic()) {
     case ast::Intrinsic::kTextureSample:
     case ast::Intrinsic::kTextureSampleBias:
@@ -673,37 +675,59 @@
     case ast::Intrinsic::kTextureSampleCompare:
       out_ << ".sample_compare(";
       break;
+    case ast::Intrinsic::kTextureLoad:
+      out_ << ".read(";
+      lod_param_is_named = false;
+      break;
     default:
       error_ = "Internal compiler error: Unhandled texture intrinsic '" +
                ident->name() + "'";
-      break;
+      return false;
   }
 
-  if (!EmitExpression(params[pidx.sampler])) {
-    return false;
-  }
-
-  for (auto idx : {pidx.coords, pidx.array_index, pidx.depth_ref}) {
-    if (idx != kNotUsed) {
+  bool first_arg = true;
+  auto maybe_write_comma = [&] {
+    if (!first_arg) {
       out_ << ", ";
+    }
+    first_arg = false;
+  };
+
+  if (pidx.sampler != kNotUsed) {
+    if (!EmitExpression(params[pidx.sampler])) {
+      return false;
+    }
+    first_arg = false;
+  }
+
+  for (auto idx :
+       {pidx.coords, pidx.array_index, pidx.depth_ref, pidx.sample_index}) {
+    if (idx != kNotUsed) {
+      maybe_write_comma();
       if (!EmitExpression(params[idx]))
         return false;
     }
   }
 
   if (pidx.bias != kNotUsed) {
-    out_ << ", bias(";
+    maybe_write_comma();
+    out_ << "bias(";
     if (!EmitExpression(params[pidx.bias])) {
       return false;
     }
     out_ << ")";
   }
   if (pidx.level != kNotUsed) {
-    out_ << ", level(";
+    maybe_write_comma();
+    if (lod_param_is_named) {
+      out_ << "level(";
+    }
     if (!EmitExpression(params[pidx.level])) {
       return false;
     }
-    out_ << ")";
+    if (lod_param_is_named) {
+      out_ << ")";
+    }
   }
   if (pidx.ddx != kNotUsed) {
     auto dim = params[pidx.texture]
@@ -714,14 +738,17 @@
     switch (dim) {
       case ast::type::TextureDimension::k2d:
       case ast::type::TextureDimension::k2dArray:
-        out_ << ", gradient2d(";
+        maybe_write_comma();
+        out_ << "gradient2d(";
         break;
       case ast::type::TextureDimension::k3d:
-        out_ << ", gradient3d(";
+        maybe_write_comma();
+        out_ << "gradient3d(";
         break;
       case ast::type::TextureDimension::kCube:
       case ast::type::TextureDimension::kCubeArray:
-        out_ << ", gradientcube(";
+        maybe_write_comma();
+        out_ << "gradientcube(";
         break;
       default: {
         std::stringstream err;
@@ -741,7 +768,7 @@
   }
 
   if (pidx.offset != kNotUsed) {
-    out_ << ", ";
+    maybe_write_comma();
     if (!EmitExpression(params[pidx.offset])) {
       return false;
     }
diff --git a/src/writer/msl/generator_impl_intrinsic_texture_test.cc b/src/writer/msl/generator_impl_intrinsic_texture_test.cc
index e3305ed..ee27a3e 100644
--- a/src/writer/msl/generator_impl_intrinsic_texture_test.cc
+++ b/src/writer/msl/generator_impl_intrinsic_texture_test.cc
@@ -18,6 +18,7 @@
 #include "src/ast/builder.h"
 #include "src/ast/intrinsic_texture_helper_test.h"
 #include "src/ast/type/depth_texture_type.h"
+#include "src/ast/type/multisampled_texture_type.h"
 #include "src/ast/type/sampled_texture_type.h"
 #include "src/type_determiner.h"
 #include "src/writer/msl/generator_impl.h"
@@ -135,9 +136,102 @@
       return R"(texture_tint_0.sample_compare(sampler_tint_0, float3(1.0f, 2.0f, 3.0f), 4.0f))";
     case ValidTextureOverload::kSampleGradDepthCubeArrayF32:
       return R"(texture_tint_0.sample_compare(sampler_tint_0, float3(1.0f, 2.0f, 3.0f), 4, 5.0f))";
+    case ValidTextureOverload::kLoad1dF32:
+      return R"(texture_tint_0.read(1))";
+    case ValidTextureOverload::kLoad1dU32:
+      return R"(texture_tint_0.read(1))";
+    case ValidTextureOverload::kLoad1dI32:
+      return R"(texture_tint_0.read(1))";
+    case ValidTextureOverload::kLoad1dArrayF32:
+      return R"(texture_tint_0.read(1, 2))";
+    case ValidTextureOverload::kLoad1dArrayU32:
+      return R"(texture_tint_0.read(1, 2))";
+    case ValidTextureOverload::kLoad1dArrayI32:
+      return R"(texture_tint_0.read(1, 2))";
+    case ValidTextureOverload::kLoad2dF32:
+      return R"(texture_tint_0.read(int2(1, 2)))";
+    case ValidTextureOverload::kLoad2dU32:
+      return R"(texture_tint_0.read(int2(1, 2)))";
+    case ValidTextureOverload::kLoad2dI32:
+      return R"(texture_tint_0.read(int2(1, 2)))";
+    case ValidTextureOverload::kLoad2dLevelF32:
+      return R"(texture_tint_0.read(int2(1, 2), 3))";
+    case ValidTextureOverload::kLoad2dLevelU32:
+      return R"(texture_tint_0.read(int2(1, 2), 3))";
+    case ValidTextureOverload::kLoad2dLevelI32:
+      return R"(texture_tint_0.read(int2(1, 2), 3))";
+    case ValidTextureOverload::kLoad2dArrayF32:
+      return R"(texture_tint_0.read(int2(1, 2), 3))";
+    case ValidTextureOverload::kLoad2dArrayU32:
+      return R"(texture_tint_0.read(int2(1, 2), 3))";
+    case ValidTextureOverload::kLoad2dArrayI32:
+      return R"(texture_tint_0.read(int2(1, 2), 3))";
+    case ValidTextureOverload::kLoad2dArrayLevelF32:
+      return R"(texture_tint_0.read(int2(1, 2), 3, 4))";
+    case ValidTextureOverload::kLoad2dArrayLevelU32:
+      return R"(texture_tint_0.read(int2(1, 2), 3, 4))";
+    case ValidTextureOverload::kLoad2dArrayLevelI32:
+      return R"(texture_tint_0.read(int2(1, 2), 3, 4))";
+    case ValidTextureOverload::kLoad3dF32:
+      return R"(texture_tint_0.read(int3(1, 2, 3)))";
+    case ValidTextureOverload::kLoad3dU32:
+      return R"(texture_tint_0.read(int3(1, 2, 3)))";
+    case ValidTextureOverload::kLoad3dI32:
+      return R"(texture_tint_0.read(int3(1, 2, 3)))";
+    case ValidTextureOverload::kLoad3dLevelF32:
+      return R"(texture_tint_0.read(int3(1, 2, 3), 4))";
+    case ValidTextureOverload::kLoad3dLevelU32:
+      return R"(texture_tint_0.read(int3(1, 2, 3), 4))";
+    case ValidTextureOverload::kLoad3dLevelI32:
+      return R"(texture_tint_0.read(int3(1, 2, 3), 4))";
+    case ValidTextureOverload::kLoadMultisampled2dF32:
+      return R"(texture_tint_0.read(int2(1, 2), 3))";
+    case ValidTextureOverload::kLoadMultisampled2dU32:
+      return R"(texture_tint_0.read(int2(1, 2), 3))";
+    case ValidTextureOverload::kLoadMultisampled2dI32:
+      return R"(texture_tint_0.read(int2(1, 2), 3))";
+    case ValidTextureOverload::kLoadMultisampled2dArrayF32:
+      return R"(texture_tint_0.read(int2(1, 2), 3, 4))";
+    case ValidTextureOverload::kLoadMultisampled2dArrayU32:
+      return R"(texture_tint_0.read(int2(1, 2), 3, 4))";
+    case ValidTextureOverload::kLoadMultisampled2dArrayI32:
+      return R"(texture_tint_0.read(int2(1, 2), 3, 4))";
+    case ValidTextureOverload::kLoadDepth2dF32:
+      return R"(texture_tint_0.read(int2(1, 2)))";
+    case ValidTextureOverload::kLoadDepth2dLevelF32:
+      return R"(texture_tint_0.read(int2(1, 2), 3))";
+    case ValidTextureOverload::kLoadDepth2dArrayF32:
+      return R"(texture_tint_0.read(int2(1, 2), 3))";
+    case ValidTextureOverload::kLoadDepth2dArrayLevelF32:
+      return R"(texture_tint_0.read(int2(1, 2), 3, 4))";
+    case ValidTextureOverload::kLoadStorageRO1dRgba32float:
+      return R"(texture_tint_0.read(1))";
+    case ValidTextureOverload::kLoadStorageRO1dArrayRgba32float:
+      return R"(texture_tint_0.read(1, 2))";
+    case ValidTextureOverload::kLoadStorageRO2dRgba8unorm:
+    case ValidTextureOverload::kLoadStorageRO2dRgba8snorm:
+    case ValidTextureOverload::kLoadStorageRO2dRgba8uint:
+    case ValidTextureOverload::kLoadStorageRO2dRgba8sint:
+    case ValidTextureOverload::kLoadStorageRO2dRgba16uint:
+    case ValidTextureOverload::kLoadStorageRO2dRgba16sint:
+    case ValidTextureOverload::kLoadStorageRO2dRgba16float:
+    case ValidTextureOverload::kLoadStorageRO2dR32uint:
+    case ValidTextureOverload::kLoadStorageRO2dR32sint:
+    case ValidTextureOverload::kLoadStorageRO2dR32float:
+    case ValidTextureOverload::kLoadStorageRO2dRg32uint:
+    case ValidTextureOverload::kLoadStorageRO2dRg32sint:
+    case ValidTextureOverload::kLoadStorageRO2dRg32float:
+    case ValidTextureOverload::kLoadStorageRO2dRgba32uint:
+    case ValidTextureOverload::kLoadStorageRO2dRgba32sint:
+    case ValidTextureOverload::kLoadStorageRO2dRgba32float:
+      return R"(texture_tint_0.read(int2(1, 2)))";
+    case ValidTextureOverload::kLoadStorageRO2dArrayRgba32float:
+      return R"(texture_tint_0.read(int2(1, 2), 3))";
+    case ValidTextureOverload::kLoadStorageRO3dRgba32float:
+      return R"(texture_tint_0.read(int3(1, 2, 3)))";
   }
   return "<unmatched texture overload>";
-}  // LINT - Ignore the length of this function
+}  // NOLINT - Ignore the length of this function
 
 class MslGeneratorIntrinsicTextureTest
     : public ast::BuilderWithModule,
@@ -156,38 +250,13 @@
 TEST_P(MslGeneratorIntrinsicTextureTest, Call) {
   auto param = GetParam();
 
-  ast::type::Type* datatype = nullptr;
-  switch (param.texture_data_type) {
-    case ast::intrinsic::test::TextureDataType::kF32:
-      datatype = ty.f32;
-      break;
-    case ast::intrinsic::test::TextureDataType::kU32:
-      datatype = ty.u32;
-      break;
-    case ast::intrinsic::test::TextureDataType::kI32:
-      datatype = ty.i32;
-      break;
-  }
-
-  ast::type::Sampler sampler_type{param.sampler_kind};
-  switch (param.texture_kind) {
-    case ast::intrinsic::test::TextureKind::kRegular:
-      Var("texture", ast::StorageClass::kNone,
-          mod->create<ast::type::SampledTexture>(param.texture_dimension,
-                                                 datatype));
-      break;
-
-    case ast::intrinsic::test::TextureKind::kDepth:
-      Var("texture", ast::StorageClass::kNone,
-          mod->create<ast::type::DepthTexture>(param.texture_dimension));
-      break;
-  }
-
-  Var("sampler", ast::StorageClass::kNone, &sampler_type);
+  param.buildTextureVariable(this);
+  param.buildSamplerVariable(this);
 
   ast::CallExpression call{Expr(param.function), param.args(this)};
 
-  EXPECT_TRUE(td.DetermineResultType(&call)) << td.error();
+  ASSERT_TRUE(td.Determine()) << td.error();
+  ASSERT_TRUE(td.DetermineResultType(&call)) << td.error();
 
   ASSERT_TRUE(gen.EmitExpression(&call)) << gen.error();
 
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index 7a565bf..20a03fb 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -13,6 +13,7 @@
 
 #include "src/writer/spirv/builder.h"
 
+#include <algorithm>
 #include <iostream>
 #include <limits>
 #include <sstream>
@@ -72,7 +73,7 @@
 #include "src/ast/uint_literal.h"
 #include "src/ast/unary_op_expression.h"
 #include "src/ast/variable_decl_statement.h"
-#include "src/writer/pack_coord_arrayidx.h"
+#include "src/writer/append_vector.h"
 
 namespace tint {
 namespace writer {
@@ -1946,25 +1947,50 @@
   spirv_params.emplace_back(std::move(result_id));    // result id
 
   // Extra image operands, appended to spirv_params.
-  uint32_t spirv_operand_mask = 0;
-  OperandList spirv_operands;
-  spirv_operands.reserve(4);  // Enough to fit most parameter lists
+  struct ImageOperand {
+    SpvImageOperandsMask mask;
+    tint::writer::spirv::Operand operand;
+  };
+  std::vector<ImageOperand> image_operands;
+  image_operands.reserve(4);  // Enough to fit most parameter lists
+
+  auto append_coords_to_spirv_params = [&] {
+    if (pidx.array_index != kNotUsed) {
+      // Array index needs to be appended to the coordinates.
+      auto* param_coords = call->params()[pidx.coords];
+      auto* param_array_index = call->params()[pidx.array_index];
+
+      if (!AppendVector(param_coords, param_array_index,
+                        [&](ast::TypeConstructorExpression* packed) {
+                          auto param =
+                              GenerateTypeConstructorExpression(packed, false);
+                          if (param == 0) {
+                            return false;
+                          }
+                          spirv_params.emplace_back(Operand::Int(param));
+                          return true;
+                        })) {
+        return;
+      }
+    } else {
+      spirv_params.emplace_back(gen_param(pidx.coords));  // coordinates
+    }
+  };
 
   if (ident->intrinsic() == ast::Intrinsic::kTextureLoad) {
     op = texture_type->Is<ast::type::StorageTexture>() ? spv::Op::OpImageRead
                                                        : spv::Op::OpImageFetch;
     spirv_params.emplace_back(gen_param(pidx.texture));
-    spirv_params.emplace_back(gen_param(pidx.coords));
+    append_coords_to_spirv_params();
 
-    // TODO(dsinclair): Remove the LOD param from textureLoad on storage
-    // textures when https://github.com/gpuweb/gpuweb/pull/1032 gets merged.
     if (pidx.level != kNotUsed) {
-      if (texture_type->Is<ast::type::MultisampledTexture>()) {
-        spirv_operand_mask |= SpvImageOperandsSampleMask;
-      } else {
-        spirv_operand_mask |= SpvImageOperandsLodMask;
-      }
-      spirv_operands.emplace_back(gen_param(pidx.level));
+      image_operands.emplace_back(
+          ImageOperand{SpvImageOperandsLodMask, gen_param(pidx.level)});
+    }
+
+    if (pidx.sample_index != kNotUsed) {
+      image_operands.emplace_back(ImageOperand{SpvImageOperandsSampleMask,
+                                               gen_param(pidx.sample_index)});
     }
   } else {
     assert(pidx.sampler != kNotUsed);
@@ -1976,27 +2002,7 @@
 
     // Populate the spirv_params with the common parameters
     spirv_params.emplace_back(Operand::Int(sampled_image));  // sampled image
-
-    if (pidx.array_index != kNotUsed) {
-      // Array index needs to be appended to the coordinates.
-      auto* param_coords = call->params()[pidx.coords];
-      auto* param_array_index = call->params()[pidx.array_index];
-
-      if (!PackCoordAndArrayIndex(
-              param_coords, param_array_index,
-              [&](ast::TypeConstructorExpression* packed) {
-                auto param = GenerateTypeConstructorExpression(packed, false);
-                if (param == 0) {
-                  return false;
-                }
-                spirv_params.emplace_back(Operand::Int(param));
-                return true;
-              })) {
-        return;
-      }
-    } else {
-      spirv_params.emplace_back(gen_param(pidx.coords));  // coordinates
-    }
+    append_coords_to_spirv_params();
 
     switch (ident->intrinsic()) {
       case ast::Intrinsic::kTextureSample: {
@@ -2006,24 +2012,25 @@
       case ast::Intrinsic::kTextureSampleBias: {
         op = spv::Op::OpImageSampleImplicitLod;
         assert(pidx.bias != kNotUsed);
-        spirv_operand_mask |= SpvImageOperandsBiasMask;
-        spirv_operands.emplace_back(gen_param(pidx.bias));
+        image_operands.emplace_back(
+            ImageOperand{SpvImageOperandsBiasMask, gen_param(pidx.bias)});
         break;
       }
       case ast::Intrinsic::kTextureSampleLevel: {
         op = spv::Op::OpImageSampleExplicitLod;
         assert(pidx.level != kNotUsed);
-        spirv_operand_mask |= SpvImageOperandsLodMask;
-        spirv_operands.emplace_back(gen_param(pidx.level));
+        image_operands.emplace_back(
+            ImageOperand{SpvImageOperandsLodMask, gen_param(pidx.level)});
         break;
       }
       case ast::Intrinsic::kTextureSampleGrad: {
         op = spv::Op::OpImageSampleExplicitLod;
         assert(pidx.ddx != kNotUsed);
         assert(pidx.ddy != kNotUsed);
-        spirv_operand_mask |= SpvImageOperandsGradMask;
-        spirv_operands.emplace_back(gen_param(pidx.ddx));
-        spirv_operands.emplace_back(gen_param(pidx.ddy));
+        image_operands.emplace_back(
+            ImageOperand{SpvImageOperandsGradMask, gen_param(pidx.ddx)});
+        image_operands.emplace_back(
+            ImageOperand{SpvImageOperandsGradMask, gen_param(pidx.ddy)});
         break;
       }
       case ast::Intrinsic::kTextureSampleCompare: {
@@ -2031,11 +2038,11 @@
         assert(pidx.depth_ref != kNotUsed);
         spirv_params.emplace_back(gen_param(pidx.depth_ref));
 
-        spirv_operand_mask |= SpvImageOperandsLodMask;
         ast::type::F32 f32;
         ast::FloatLiteral float_0(&f32, 0.0);
-        spirv_operands.emplace_back(
-            Operand::Int(GenerateLiteralIfNeeded(nullptr, &float_0)));
+        image_operands.emplace_back(ImageOperand{
+            SpvImageOperandsLodMask,
+            Operand::Int(GenerateLiteralIfNeeded(nullptr, &float_0))});
         break;
       }
       default:
@@ -2044,16 +2051,21 @@
   }
 
   if (pidx.offset != kNotUsed) {
-    spirv_operand_mask |= SpvImageOperandsOffsetMask;
-    spirv_operands.emplace_back(gen_param(pidx.offset));
+    image_operands.emplace_back(
+        ImageOperand{SpvImageOperandsOffsetMask, gen_param(pidx.offset)});
   }
 
-  if (spirv_operand_mask != 0) {
-    // Note: Order of operands is based on SpvImageXXXOperands value -
-    // smaller-numbered SpvImageXXXOperands bits appear first.
-    spirv_params.emplace_back(Operand::Int(spirv_operand_mask));
-    spirv_params.insert(std::end(spirv_params), std::begin(spirv_operands),
-                        std::end(spirv_operands));
+  if (!image_operands.empty()) {
+    std::sort(image_operands.begin(), image_operands.end(),
+              [](auto& a, auto& b) { return a.mask < b.mask; });
+    uint32_t mask = 0;
+    for (auto& image_operand : image_operands) {
+      mask |= image_operand.mask;
+    }
+    spirv_params.emplace_back(Operand::Int(mask));
+    for (auto& image_operand : image_operands) {
+      spirv_params.emplace_back(image_operand.operand);
+    }
   }
 
   if (op == spv::Op::OpNop) {
@@ -2143,8 +2155,8 @@
   auto true_block = result_op();
   auto true_block_id = true_block.to_i();
 
-  // if there are no more else statements we branch on false to the merge block
-  // otherwise we branch to the false block
+  // if there are no more else statements we branch on false to the merge
+  // block otherwise we branch to the false block
   auto false_block_id =
       cur_else_idx < else_stmts.size() ? next_id() : merge_block_id;
 
@@ -2644,12 +2656,12 @@
     }
 
     // We're attaching the access control to the members of the struct instead
-    // of to the variable. The reason we do this is that WGSL models the access
-    // as part of the type. If we attach to the variable, it's no longer part
-    // of the type in the SPIR-V backend, but part of the variable. This differs
-    // from the modeling and other backends. Attaching to the struct members
-    // means the access control stays part of the type where it logically makes
-    // the most sense.
+    // of to the variable. The reason we do this is that WGSL models the
+    // access as part of the type. If we attach to the variable, it's no
+    // longer part of the type in the SPIR-V backend, but part of the
+    // variable. This differs from the modeling and other backends. Attaching
+    // to the struct members means the access control stays part of the type
+    // where it logically makes the most sense.
     if (access_control == ast::AccessControl::kReadOnly) {
       push_annot(spv::Op::OpMemberDecorate,
                  {Operand::Int(struct_id), Operand::Int(i),
diff --git a/src/writer/spirv/builder_intrinsic_test.cc b/src/writer/spirv/builder_intrinsic_test.cc
index 48be756..f8f6984 100644
--- a/src/writer/spirv/builder_intrinsic_test.cc
+++ b/src/writer/spirv/builder_intrinsic_test.cc
@@ -413,173 +413,6 @@
 )");
 }
 
-TEST_F(IntrinsicBuilderTest, Call_TextureLoad_Storage_RO_1d) {
-  ast::type::StorageTexture s(ast::type::TextureDimension::k1d,
-                              ast::AccessControl::kReadOnly,
-                              ast::type::ImageFormat::kR16Float);
-
-  ASSERT_TRUE(td.DetermineStorageTextureSubtype(&s)) << td.error();
-
-  b.push_function(Function{});
-
-  auto* tex = Var("texture", ast::StorageClass::kNone, &s);
-  ASSERT_TRUE(b.GenerateGlobalVariable(tex)) << b.error();
-
-  auto expr = Call("textureLoad", "texture", 1.0f, 2);
-
-  EXPECT_TRUE(td.DetermineResultType(&expr)) << td.error();
-  EXPECT_EQ(b.GenerateExpression(&expr), 5u) << b.error();
-
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%4 = OpTypeFloat 32
-%3 = OpTypeImage %4 1D 0 0 0 2 R16f
-%2 = OpTypePointer Private %3
-%1 = OpVariable %2 Private
-%6 = OpTypeVector %4 4
-%8 = OpConstant %4 1
-%9 = OpTypeInt 32 1
-%10 = OpConstant %9 2
-)");
-
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%7 = OpLoad %3 %1
-%5 = OpImageRead %6 %7 %8 Lod %10
-)");
-}
-
-TEST_F(IntrinsicBuilderTest, Call_TextureLoad_Storage_RO_2d) {
-  ast::type::StorageTexture s(ast::type::TextureDimension::k2d,
-                              ast::AccessControl::kReadOnly,
-                              ast::type::ImageFormat::kR16Float);
-
-  ASSERT_TRUE(td.DetermineStorageTextureSubtype(&s)) << td.error();
-
-  b.push_function(Function{});
-
-  auto* tex = Var("texture", ast::StorageClass::kNone, &s);
-  ASSERT_TRUE(b.GenerateGlobalVariable(tex)) << b.error();
-
-  auto expr = Call("textureLoad", "texture", vec2<f32>(1.0f, 2.0f), 2);
-
-  EXPECT_TRUE(td.DetermineResultType(&expr)) << td.error();
-  EXPECT_EQ(b.GenerateExpression(&expr), 5u) << b.error();
-
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%4 = OpTypeFloat 32
-%3 = OpTypeImage %4 2D 0 0 0 2 R16f
-%2 = OpTypePointer Private %3
-%1 = OpVariable %2 Private
-%6 = OpTypeVector %4 4
-%8 = OpTypeVector %4 2
-%9 = OpConstant %4 1
-%10 = OpConstant %4 2
-%11 = OpConstantComposite %8 %9 %10
-%12 = OpTypeInt 32 1
-%13 = OpConstant %12 2
-)");
-
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%7 = OpLoad %3 %1
-%5 = OpImageRead %6 %7 %11 Lod %13
-)");
-}
-
-TEST_F(IntrinsicBuilderTest, Call_TextureLoad_Sampled_1d) {
-  ast::type::SampledTexture s(ast::type::TextureDimension::k1d, ty.f32);
-
-  b.push_function(Function{});
-
-  auto* tex = Var("texture", ast::StorageClass::kNone, &s);
-  ASSERT_TRUE(b.GenerateGlobalVariable(tex)) << b.error();
-
-  auto expr = Call("textureLoad", "texture", 1.0f, 2);
-
-  EXPECT_TRUE(td.DetermineResultType(&expr)) << td.error();
-  EXPECT_EQ(b.GenerateExpression(&expr), 5u) << b.error();
-
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%4 = OpTypeFloat 32
-%3 = OpTypeImage %4 1D 0 0 0 1 Unknown
-%2 = OpTypePointer Private %3
-%1 = OpVariable %2 Private
-%6 = OpTypeVector %4 4
-%8 = OpConstant %4 1
-%9 = OpTypeInt 32 1
-%10 = OpConstant %9 2
-)");
-
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%7 = OpLoad %3 %1
-%5 = OpImageFetch %6 %7 %8 Lod %10
-)");
-}
-
-TEST_F(IntrinsicBuilderTest, Call_TextureLoad_Sampled_2d) {
-  ast::type::SampledTexture s(ast::type::TextureDimension::k2d, ty.f32);
-
-  b.push_function(Function{});
-
-  auto* tex = Var("texture", ast::StorageClass::kNone, &s);
-  ASSERT_TRUE(b.GenerateGlobalVariable(tex)) << b.error();
-
-  auto expr = Call("textureLoad", "texture", vec2<f32>(1.0f, 2.0f), 2);
-
-  EXPECT_TRUE(td.DetermineResultType(&expr)) << td.error();
-  EXPECT_EQ(b.GenerateExpression(&expr), 5u) << b.error();
-
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%4 = OpTypeFloat 32
-%3 = OpTypeImage %4 2D 0 0 0 1 Unknown
-%2 = OpTypePointer Private %3
-%1 = OpVariable %2 Private
-%6 = OpTypeVector %4 4
-%8 = OpTypeVector %4 2
-%9 = OpConstant %4 1
-%10 = OpConstant %4 2
-%11 = OpConstantComposite %8 %9 %10
-%12 = OpTypeInt 32 1
-%13 = OpConstant %12 2
-)");
-
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%7 = OpLoad %3 %1
-%5 = OpImageFetch %6 %7 %11 Lod %13
-)");
-}
-
-TEST_F(IntrinsicBuilderTest, Call_TextureLoad_Multisampled_2d) {
-  ast::type::MultisampledTexture s(ast::type::TextureDimension::k2d, ty.f32);
-
-  b.push_function(Function{});
-
-  auto* tex = Var("texture", ast::StorageClass::kNone, &s);
-  ASSERT_TRUE(b.GenerateGlobalVariable(tex)) << b.error();
-
-  auto expr = Call("textureLoad", "texture", vec2<f32>(1.0f, 2.0f), 2);
-
-  ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
-  EXPECT_EQ(b.GenerateExpression(&expr), 5u) << b.error();
-
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%4 = OpTypeFloat 32
-%3 = OpTypeImage %4 2D 0 0 1 1 Unknown
-%2 = OpTypePointer Private %3
-%1 = OpVariable %2 Private
-%6 = OpTypeVector %4 4
-%8 = OpTypeVector %4 2
-%9 = OpConstant %4 1
-%10 = OpConstant %4 2
-%11 = OpConstantComposite %8 %9 %10
-%12 = OpTypeInt 32 1
-%13 = OpConstant %12 2
-)");
-
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%7 = OpLoad %3 %1
-%5 = OpImageFetch %6 %7 %11 Sample %13
-)");
-}
-
 // This tests that we do not push OpTypeSampledImage and float_0 type twice.
 TEST_F(IntrinsicBuilderTest, Call_TextureSampleCompare_Twice) {
   ast::type::Sampler s(ast::type::SamplerKind::kComparisonSampler);
diff --git a/src/writer/spirv/builder_intrinsic_texture_test.cc b/src/writer/spirv/builder_intrinsic_texture_test.cc
index 3d5bdd5..106b17e 100644
--- a/src/writer/spirv/builder_intrinsic_texture_test.cc
+++ b/src/writer/spirv/builder_intrinsic_texture_test.cc
@@ -18,6 +18,7 @@
 #include "src/ast/builder.h"
 #include "src/ast/intrinsic_texture_helper_test.h"
 #include "src/ast/type/depth_texture_type.h"
+#include "src/ast/type/multisampled_texture_type.h"
 #include "src/ast/type/sampled_texture_type.h"
 #include "src/type_determiner.h"
 #include "src/writer/spirv/builder.h"
@@ -1477,6 +1478,1092 @@
 %20 = OpCompositeConstruct %13 %14 %15 %16 %17
 %8 = OpImageSampleDrefExplicitLod %4 %12 %20 %21 Lod %22
 )"};
+    case ValidTextureOverload::kLoad1dF32:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 1D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%11 = OpTypeInt 32 1
+%12 = OpConstant %11 1
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %12
+)"};
+    case ValidTextureOverload::kLoad1dU32:
+      return {R"(
+%4 = OpTypeInt 32 0
+%3 = OpTypeImage %4 1D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%11 = OpTypeInt 32 1
+%12 = OpConstant %11 1
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %12
+)"};
+    case ValidTextureOverload::kLoad1dI32:
+      return {R"(
+%4 = OpTypeInt 32 1
+%3 = OpTypeImage %4 1D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%11 = OpConstant %4 1
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %11
+)"};
+    case ValidTextureOverload::kLoad1dArrayF32:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 1D 0 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %15
+)"};
+    case ValidTextureOverload::kLoad1dArrayU32:
+      return {R"(
+%4 = OpTypeInt 32 0
+%3 = OpTypeImage %4 1D 0 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %15
+)"};
+    case ValidTextureOverload::kLoad1dArrayI32:
+      return {R"(
+%4 = OpTypeInt 32 1
+%3 = OpTypeImage %4 1D 0 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%11 = OpTypeVector %4 2
+%12 = OpConstant %4 1
+%13 = OpConstant %4 2
+%14 = OpConstantComposite %11 %12 %13
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %14
+)"};
+    case ValidTextureOverload::kLoad2dF32:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %15
+)"};
+    case ValidTextureOverload::kLoad2dU32:
+      return {R"(
+%4 = OpTypeInt 32 0
+%3 = OpTypeImage %4 2D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %15
+)"};
+    case ValidTextureOverload::kLoad2dI32:
+      return {R"(
+%4 = OpTypeInt 32 1
+%3 = OpTypeImage %4 2D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%11 = OpTypeVector %4 2
+%12 = OpConstant %4 1
+%13 = OpConstant %4 2
+%14 = OpConstantComposite %11 %12 %13
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %14
+)"};
+    case ValidTextureOverload::kLoad2dLevelF32:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+%16 = OpConstant %12 3
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %15 Lod %16
+)"};
+    case ValidTextureOverload::kLoad2dLevelU32:
+      return {R"(
+%4 = OpTypeInt 32 0
+%3 = OpTypeImage %4 2D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+%16 = OpConstant %12 3
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %15 Lod %16
+)"};
+    case ValidTextureOverload::kLoad2dLevelI32:
+      return {R"(
+%4 = OpTypeInt 32 1
+%3 = OpTypeImage %4 2D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%11 = OpTypeVector %4 2
+%12 = OpConstant %4 1
+%13 = OpConstant %4 2
+%14 = OpConstantComposite %11 %12 %13
+%15 = OpConstant %4 3
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %14 Lod %15
+)"};
+    case ValidTextureOverload::kLoad2dArrayF32:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 3
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstant %12 3
+%16 = OpConstantComposite %11 %13 %14 %15
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %16
+)"};
+    case ValidTextureOverload::kLoad2dArrayU32:
+      return {R"(
+%4 = OpTypeInt 32 0
+%3 = OpTypeImage %4 2D 0 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 3
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstant %12 3
+%16 = OpConstantComposite %11 %13 %14 %15
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %16
+)"};
+    case ValidTextureOverload::kLoad2dArrayI32:
+      return {R"(
+%4 = OpTypeInt 32 1
+%3 = OpTypeImage %4 2D 0 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%11 = OpTypeVector %4 3
+%12 = OpConstant %4 1
+%13 = OpConstant %4 2
+%14 = OpConstant %4 3
+%15 = OpConstantComposite %11 %12 %13 %14
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %15
+)"};
+    case ValidTextureOverload::kLoad2dArrayLevelF32:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 3
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstant %12 3
+%16 = OpConstantComposite %11 %13 %14 %15
+%17 = OpConstant %12 4
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %16 Lod %17
+)"};
+    case ValidTextureOverload::kLoad2dArrayLevelU32:
+      return {R"(
+%4 = OpTypeInt 32 0
+%3 = OpTypeImage %4 2D 0 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 3
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstant %12 3
+%16 = OpConstantComposite %11 %13 %14 %15
+%17 = OpConstant %12 4
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %16 Lod %17
+)"};
+    case ValidTextureOverload::kLoad2dArrayLevelI32:
+      return {R"(
+%4 = OpTypeInt 32 1
+%3 = OpTypeImage %4 2D 0 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%11 = OpTypeVector %4 3
+%12 = OpConstant %4 1
+%13 = OpConstant %4 2
+%14 = OpConstant %4 3
+%15 = OpConstantComposite %11 %12 %13 %14
+%16 = OpConstant %4 4
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %15 Lod %16
+)"};
+    case ValidTextureOverload::kLoad3dF32:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 3D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 3
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstant %12 3
+%16 = OpConstantComposite %11 %13 %14 %15
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %16
+)"};
+    case ValidTextureOverload::kLoad3dU32:
+      return {R"(
+%4 = OpTypeInt 32 0
+%3 = OpTypeImage %4 3D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 3
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstant %12 3
+%16 = OpConstantComposite %11 %13 %14 %15
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %16
+)"};
+    case ValidTextureOverload::kLoad3dI32:
+      return {R"(
+%4 = OpTypeInt 32 1
+%3 = OpTypeImage %4 3D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%11 = OpTypeVector %4 3
+%12 = OpConstant %4 1
+%13 = OpConstant %4 2
+%14 = OpConstant %4 3
+%15 = OpConstantComposite %11 %12 %13 %14
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %15
+)"};
+    case ValidTextureOverload::kLoad3dLevelF32:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 3D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 3
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstant %12 3
+%16 = OpConstantComposite %11 %13 %14 %15
+%17 = OpConstant %12 4
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %16 Lod %17
+)"};
+    case ValidTextureOverload::kLoad3dLevelU32:
+      return {R"(
+%4 = OpTypeInt 32 0
+%3 = OpTypeImage %4 3D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 3
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstant %12 3
+%16 = OpConstantComposite %11 %13 %14 %15
+%17 = OpConstant %12 4
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %16 Lod %17
+)"};
+    case ValidTextureOverload::kLoad3dLevelI32:
+      return {R"(
+%4 = OpTypeInt 32 1
+%3 = OpTypeImage %4 3D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%11 = OpTypeVector %4 3
+%12 = OpConstant %4 1
+%13 = OpConstant %4 2
+%14 = OpConstant %4 3
+%15 = OpConstantComposite %11 %12 %13 %14
+%16 = OpConstant %4 4
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %15 Lod %16
+)"};
+    case ValidTextureOverload::kLoadMultisampled2dF32:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 0 1 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+%16 = OpConstant %12 3
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %15 Sample %16
+)"};
+    case ValidTextureOverload::kLoadMultisampled2dU32:
+      return {R"(
+%4 = OpTypeInt 32 0
+%3 = OpTypeImage %4 2D 0 0 1 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+%16 = OpConstant %12 3
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %15 Sample %16
+)"};
+    case ValidTextureOverload::kLoadMultisampled2dI32:
+      return {R"(
+%4 = OpTypeInt 32 1
+%3 = OpTypeImage %4 2D 0 0 1 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%11 = OpTypeVector %4 2
+%12 = OpConstant %4 1
+%13 = OpConstant %4 2
+%14 = OpConstantComposite %11 %12 %13
+%15 = OpConstant %4 3
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %14 Sample %15
+)"};
+    case ValidTextureOverload::kLoadMultisampled2dArrayF32:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 1 1 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 3
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstant %12 3
+%16 = OpConstantComposite %11 %13 %14 %15
+%17 = OpConstant %12 4
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %16 Sample %17
+)"};
+    case ValidTextureOverload::kLoadMultisampled2dArrayU32:
+      return {R"(
+%4 = OpTypeInt 32 0
+%3 = OpTypeImage %4 2D 0 1 1 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 3
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstant %12 3
+%16 = OpConstantComposite %11 %13 %14 %15
+%17 = OpConstant %12 4
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %16 Sample %17
+)"};
+    case ValidTextureOverload::kLoadMultisampled2dArrayI32:
+      return {R"(
+%4 = OpTypeInt 32 1
+%3 = OpTypeImage %4 2D 0 1 1 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%11 = OpTypeVector %4 3
+%12 = OpConstant %4 1
+%13 = OpConstant %4 2
+%14 = OpConstant %4 3
+%15 = OpConstantComposite %11 %12 %13 %14
+%16 = OpConstant %4 4
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageFetch %9 %10 %15 Sample %16
+)"};
+    case ValidTextureOverload::kLoadDepth2dF32:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 1 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%11 = OpTypeInt 32 1
+%10 = OpTypeVector %11 2
+%12 = OpConstant %11 1
+%13 = OpConstant %11 2
+%14 = OpConstantComposite %10 %12 %13
+)",
+              R"(
+%9 = OpLoad %3 %1
+%8 = OpImageFetch %4 %9 %14
+)"};
+    case ValidTextureOverload::kLoadDepth2dLevelF32:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 1 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%11 = OpTypeInt 32 1
+%10 = OpTypeVector %11 2
+%12 = OpConstant %11 1
+%13 = OpConstant %11 2
+%14 = OpConstantComposite %10 %12 %13
+%15 = OpConstant %11 3
+)",
+              R"(
+%9 = OpLoad %3 %1
+%8 = OpImageFetch %4 %9 %14 Lod %15
+)"};
+    case ValidTextureOverload::kLoadDepth2dArrayF32:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 1 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%11 = OpTypeInt 32 1
+%10 = OpTypeVector %11 3
+%12 = OpConstant %11 1
+%13 = OpConstant %11 2
+%14 = OpConstant %11 3
+%15 = OpConstantComposite %10 %12 %13 %14
+)",
+              R"(
+%9 = OpLoad %3 %1
+%8 = OpImageFetch %4 %9 %15
+)"};
+    case ValidTextureOverload::kLoadDepth2dArrayLevelF32:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 1 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%11 = OpTypeInt 32 1
+%10 = OpTypeVector %11 3
+%12 = OpConstant %11 1
+%13 = OpConstant %11 2
+%14 = OpConstant %11 3
+%15 = OpConstantComposite %10 %12 %13 %14
+%16 = OpConstant %11 4
+)",
+              R"(
+%9 = OpLoad %3 %1
+%8 = OpImageFetch %4 %9 %15 Lod %16
+)"};
+    case ValidTextureOverload::kLoadStorageRO1dRgba32float:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 1D 0 0 0 2 Rgba32f
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%11 = OpTypeInt 32 1
+%12 = OpConstant %11 1
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %12
+)"};
+    case ValidTextureOverload::kLoadStorageRO1dArrayRgba32float:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 1D 0 1 0 2 Rgba32f
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %15
+)"};
+    case ValidTextureOverload::kLoadStorageRO2dRgba8unorm:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 0 0 2 Rgba8
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %15
+)"};
+    case ValidTextureOverload::kLoadStorageRO2dRgba8snorm:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 0 0 2 Rgba8Snorm
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %15
+)"};
+    case ValidTextureOverload::kLoadStorageRO2dRgba8uint:
+      return {R"(
+%4 = OpTypeInt 32 0
+%3 = OpTypeImage %4 2D 0 0 0 2 Rgba8ui
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %15
+)"};
+    case ValidTextureOverload::kLoadStorageRO2dRgba8sint:
+      return {R"(
+%4 = OpTypeInt 32 1
+%3 = OpTypeImage %4 2D 0 0 0 2 Rgba8i
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%11 = OpTypeVector %4 2
+%12 = OpConstant %4 1
+%13 = OpConstant %4 2
+%14 = OpConstantComposite %11 %12 %13
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %14
+)"};
+    case ValidTextureOverload::kLoadStorageRO2dRgba16uint:
+      return {R"(
+%4 = OpTypeInt 32 0
+%3 = OpTypeImage %4 2D 0 0 0 2 Rgba16ui
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %15
+)"};
+    case ValidTextureOverload::kLoadStorageRO2dRgba16sint:
+      return {R"(
+%4 = OpTypeInt 32 1
+%3 = OpTypeImage %4 2D 0 0 0 2 Rgba16i
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%11 = OpTypeVector %4 2
+%12 = OpConstant %4 1
+%13 = OpConstant %4 2
+%14 = OpConstantComposite %11 %12 %13
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %14
+)"};
+    case ValidTextureOverload::kLoadStorageRO2dRgba16float:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 0 0 2 Rgba16f
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %15
+)"};
+    case ValidTextureOverload::kLoadStorageRO2dR32uint:
+      return {R"(
+%4 = OpTypeInt 32 0
+%3 = OpTypeImage %4 2D 0 0 0 2 R32ui
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %15
+)"};
+    case ValidTextureOverload::kLoadStorageRO2dR32sint:
+      return {R"(
+%4 = OpTypeInt 32 1
+%3 = OpTypeImage %4 2D 0 0 0 2 R32i
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%11 = OpTypeVector %4 2
+%12 = OpConstant %4 1
+%13 = OpConstant %4 2
+%14 = OpConstantComposite %11 %12 %13
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %14
+)"};
+    case ValidTextureOverload::kLoadStorageRO2dR32float:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 0 0 2 R32f
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %15
+)"};
+    case ValidTextureOverload::kLoadStorageRO2dRg32uint:
+      return {R"(
+%4 = OpTypeInt 32 0
+%3 = OpTypeImage %4 2D 0 0 0 2 Rg32ui
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %15
+)"};
+    case ValidTextureOverload::kLoadStorageRO2dRg32sint:
+      return {R"(
+%4 = OpTypeInt 32 1
+%3 = OpTypeImage %4 2D 0 0 0 2 Rg32i
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%11 = OpTypeVector %4 2
+%12 = OpConstant %4 1
+%13 = OpConstant %4 2
+%14 = OpConstantComposite %11 %12 %13
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %14
+)"};
+    case ValidTextureOverload::kLoadStorageRO2dRg32float:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 0 0 2 Rg32f
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %15
+)"};
+    case ValidTextureOverload::kLoadStorageRO2dRgba32uint:
+      return {R"(
+%4 = OpTypeInt 32 0
+%3 = OpTypeImage %4 2D 0 0 0 2 Rgba32ui
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %15
+)"};
+    case ValidTextureOverload::kLoadStorageRO2dRgba32sint:
+      return {R"(
+%4 = OpTypeInt 32 1
+%3 = OpTypeImage %4 2D 0 0 0 2 Rgba32i
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%11 = OpTypeVector %4 2
+%12 = OpConstant %4 1
+%13 = OpConstant %4 2
+%14 = OpConstantComposite %11 %12 %13
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %14
+)"};
+    case ValidTextureOverload::kLoadStorageRO2dRgba32float:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 0 0 2 Rgba32f
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 2
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstantComposite %11 %13 %14
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %15
+)"};
+    case ValidTextureOverload::kLoadStorageRO2dArrayRgba32float:
+
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 1 0 2 Rgba32f
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 3
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstant %12 3
+%16 = OpConstantComposite %11 %13 %14 %15
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %16
+)"};
+    case ValidTextureOverload::kLoadStorageRO3dRgba32float:
+      return {R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 3D 0 0 0 2 Rgba32f
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeVector %4 4
+%12 = OpTypeInt 32 1
+%11 = OpTypeVector %12 3
+%13 = OpConstant %12 1
+%14 = OpConstant %12 2
+%15 = OpConstant %12 3
+%16 = OpConstantComposite %11 %13 %14 %15
+)",
+              R"(
+%10 = OpLoad %3 %1
+%8 = OpImageRead %9 %10 %16
+)"};
   }
   return {"<unmatched texture overload>", "<unmatched texture overload>"};
 }  // NOLINT - Ignore the length of this function
@@ -1503,42 +2590,17 @@
 
   b.push_function(Function{});
 
-  ast::type::Type* datatype = nullptr;
-  switch (param.texture_data_type) {
-    case ast::intrinsic::test::TextureDataType::kF32:
-      datatype = ty.f32;
-      break;
-    case ast::intrinsic::test::TextureDataType::kU32:
-      datatype = ty.u32;
-      break;
-    case ast::intrinsic::test::TextureDataType::kI32:
-      datatype = ty.i32;
-      break;
-  }
-
-  ast::type::Sampler sampler_type{param.sampler_kind};
-  ast::Variable* tex = nullptr;
-  switch (param.texture_kind) {
-    case ast::intrinsic::test::TextureKind::kRegular:
-      tex = Var("texture", ast::StorageClass::kNone,
-                mod->create<ast::type::SampledTexture>(param.texture_dimension,
-                                                       datatype));
-      break;
-
-    case ast::intrinsic::test::TextureKind::kDepth:
-      tex = Var("texture", ast::StorageClass::kNone,
-                mod->create<ast::type::DepthTexture>(param.texture_dimension));
-      break;
-  }
-
-  auto* sampler = Var("sampler", ast::StorageClass::kNone, &sampler_type);
-
-  ASSERT_TRUE(b.GenerateGlobalVariable(tex)) << b.error();
-  ASSERT_TRUE(b.GenerateGlobalVariable(sampler)) << b.error();
+  auto* texture = param.buildTextureVariable(this);
+  auto* sampler = param.buildSamplerVariable(this);
 
   ast::CallExpression call{Expr(param.function), param.args(this)};
 
+  EXPECT_TRUE(td.Determine()) << td.error();
   EXPECT_TRUE(td.DetermineResultType(&call)) << td.error();
+
+  ASSERT_TRUE(b.GenerateGlobalVariable(texture)) << b.error();
+  ASSERT_TRUE(b.GenerateGlobalVariable(sampler)) << b.error();
+
   EXPECT_EQ(b.GenerateExpression(&call), 8u) << b.error();
 
   auto expected = expected_texture_overload(param.overload);