Implement textureSample builtins

Handle wsgl parsing and spirv writing of:
  textureSample(), textureSampleBias(), textureSampleLevel(),
  textureSampleGrad(), textureSampleCompare()

Handle the different signature for array texture types.
Includes offset overloads.

Change-Id: I6802d97cd9a7083f12439b32725b9a4b666b8c63
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/32985
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: David Neto <dneto@google.com>
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/ast/identifier_expression.h b/src/ast/identifier_expression.h
index af08b69..4c6ac31 100644
--- a/src/ast/identifier_expression.h
+++ b/src/ast/identifier_expression.h
@@ -15,7 +15,9 @@
 #ifndef SRC_AST_IDENTIFIER_EXPRESSION_H_
 #define SRC_AST_IDENTIFIER_EXPRESSION_H_
 
+#include <memory>
 #include <string>
+#include <utility>
 
 #include "src/ast/expression.h"
 #include "src/ast/intrinsic.h"
@@ -45,6 +47,17 @@
   void set_intrinsic(Intrinsic i) { intrinsic_ = i; }
   /// @returns the intrinsic this identifier represents
   Intrinsic intrinsic() const { return intrinsic_; }
+
+  /// Sets the intrinsic signature
+  /// @param s the intrinsic signature to set
+  void set_intrinsic_signature(std::unique_ptr<intrinsic::Signature> s) {
+    intrinsic_sig_ = std::move(s);
+  }
+  /// @returns the intrinsic signature for this identifier.
+  const intrinsic::Signature* intrinsic_signature() const {
+    return intrinsic_sig_.get();
+  }
+
   /// @returns true if this identifier is for an intrinsic
   bool IsIntrinsic() const { return intrinsic_ != Intrinsic::kNone; }
 
@@ -63,6 +76,7 @@
   IdentifierExpression(const IdentifierExpression&) = delete;
 
   Intrinsic intrinsic_ = Intrinsic::kNone;
+  std::unique_ptr<intrinsic::Signature> intrinsic_sig_;
   std::string name_;
 };
 
diff --git a/src/ast/intrinsic.cc b/src/ast/intrinsic.cc
index 14fdeef..dc6c60a 100644
--- a/src/ast/intrinsic.cc
+++ b/src/ast/intrinsic.cc
@@ -216,6 +216,9 @@
     case Intrinsic::kTextureSampleCompare:
       out << "textureSampleCompare";
       break;
+    case Intrinsic::kTextureSampleGrad:
+      out << "textureSampleGrad";
+      break;
     case Intrinsic::kTextureSampleLevel:
       out << "textureSampleLevel";
       break;
@@ -231,6 +234,12 @@
 
 namespace intrinsic {
 
+Signature::~Signature() = default;
+TextureSignature::~TextureSignature() = default;
+
+TextureSignature::Parameters::Index::Index() = default;
+TextureSignature::Parameters::Index::Index(const Index&) = default;
+
 bool IsCoarseDerivative(ast::Intrinsic i) {
   return i == Intrinsic::kDpdxCoarse || i == Intrinsic::kDpdyCoarse ||
          i == Intrinsic::kFwidthCoarse;
@@ -256,7 +265,8 @@
   return i == Intrinsic::kTextureLoad || i == Intrinsic::kTextureSample ||
          i == Intrinsic::kTextureSampleLevel ||
          i == Intrinsic::kTextureSampleBias ||
-         i == Intrinsic::kTextureSampleCompare;
+         i == Intrinsic::kTextureSampleCompare ||
+         i == Intrinsic::kTextureSampleGrad;
 }
 
 }  // namespace intrinsic
diff --git a/src/ast/intrinsic.h b/src/ast/intrinsic.h
index 9eb1600..a122ad3 100644
--- a/src/ast/intrinsic.h
+++ b/src/ast/intrinsic.h
@@ -89,6 +89,7 @@
   kTextureSample,
   kTextureSampleBias,
   kTextureSampleCompare,
+  kTextureSampleGrad,
   kTextureSampleLevel,
   kTrunc
 };
@@ -99,6 +100,64 @@
 
 namespace intrinsic {
 
+/// Signature is the base struct for all intrinsic signature types.
+/// Signatures are used to identify the particular overload for intrinsics that
+/// have different signatures with the same function name.
+struct Signature {
+  virtual ~Signature();
+};
+
+/// TextureSignature describes the signature of a texture intrinsic function.
+struct TextureSignature : public Signature {
+  /// Parameters describes the parameters for the texture function.
+  struct Parameters {
+    /// kNotUsed is the constant that indicates the given parameter is not part
+    /// of the texture function signature.
+    static constexpr const size_t kNotUsed = ~static_cast<size_t>(0u);
+    /// Index holds each of the possible parameter indices. If a parameter index
+    /// is equal to `kNotUsed` then this parameter is not used by the function.
+    struct Index {
+      /// Constructor
+      Index();
+      /// Copy constructor
+      Index(const Index&);
+      /// `array_index` parameter index.
+      size_t array_index = kNotUsed;
+      /// `bias` parameter index.
+      size_t bias = kNotUsed;
+      /// `coords` parameter index.
+      size_t coords = kNotUsed;
+      /// `depth_ref` parameter index.
+      size_t depth_ref = kNotUsed;
+      /// `ddx` parameter index.
+      size_t ddx = kNotUsed;
+      /// `ddy` parameter index.
+      size_t ddy = kNotUsed;
+      /// `level` parameter index.
+      size_t level = kNotUsed;
+      /// `offset` parameter index.
+      size_t offset = kNotUsed;
+      /// `sampler` parameter index.
+      size_t sampler = kNotUsed;
+      /// `texture` parameter index.
+      size_t texture = kNotUsed;
+    };
+    /// The indices of all possible parameters.
+    Index idx;
+    /// Total number of parameters.
+    size_t count = 0;
+  };
+
+  /// Construct an immutable `TextureSignature`.
+  /// @param p the texture intrinsic parameter signature.
+  explicit TextureSignature(const Parameters& p) : params(p) {}
+
+  ~TextureSignature() override;
+
+  /// The texture intrinsic parameter signature.
+  const Parameters params;
+};
+
 /// Determines if the given |name| is a coarse derivative
 /// @param i the intrinsic
 /// @returns true if the given derivative is coarse.
diff --git a/src/ast/intrinsic_texture_helper_test.cc b/src/ast/intrinsic_texture_helper_test.cc
new file mode 100644
index 0000000..5e1587c
--- /dev/null
+++ b/src/ast/intrinsic_texture_helper_test.cc
@@ -0,0 +1,1119 @@
+// 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.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/ast/intrinsic_texture_helper_test.h"
+
+#include "src/ast/type_constructor_expression.h"
+
+namespace tint {
+namespace ast {
+namespace intrinsic {
+namespace test {
+
+TextureOverloadCase::TextureOverloadCase() = default;
+TextureOverloadCase::TextureOverloadCase(
+    ValidTextureOverload o,
+    const char* d,
+    TextureKind tk,
+    ast::type::SamplerKind sk,
+    ast::type::TextureDimension td,
+    TextureDataType tdt,
+    const char* f,
+    std::function<ast::ExpressionList(ast::Builder*)> a)
+    : overload(o),
+      description(d),
+      texture_kind(tk),
+      sampler_kind(sk),
+      texture_dimension(td),
+      texture_data_type(tdt),
+      function(f),
+      args(std::move(a)) {}
+TextureOverloadCase::TextureOverloadCase(const TextureOverloadCase&) = default;
+TextureOverloadCase::~TextureOverloadCase() = default;
+
+std::vector<TextureOverloadCase> TextureOverloadCase::ValidCases() {
+  return {{
+              ValidTextureOverload::kSample1dF32,
+              "textureSample(t : texture_1d<f32>,\n"
+              "              s : sampler,\n"
+              "              coords : f32) -> vec4<f32>",
+              TextureKind::kRegular,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k1d,
+              TextureDataType::kF32,
+              "textureSample",
+              [](ast::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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k1dArray,
+              TextureDataType::kF32,
+              "textureSample",
+              [](ast::Builder* b) {
+                return b->ExprList("texture",  // t
+                                   "sampler",  // s
+                                   1.0f,       // coords
+                                   2u);        // array_index
+              },
+          },
+          {
+              ValidTextureOverload::kSample2dF32,
+              "textureSample(t : texture_2d<f32>,\n"
+              "              s : sampler,\n"
+              "              coords : vec2<f32>) -> vec4<f32>",
+              TextureKind::kRegular,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2d,
+              TextureDataType::kF32,
+              "textureSample",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2d,
+              TextureDataType::kF32,
+              "textureSample",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                using i32 = ast::Builder::i32;
+                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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2dArray,
+              TextureDataType::kF32,
+              "textureSample",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3u);                     // 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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2dArray,
+              TextureDataType::kF32,
+              "textureSample",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                using i32 = ast::Builder::i32;
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3u,                      // 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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k3d,
+              TextureDataType::kF32,
+              "textureSample",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k3d,
+              TextureDataType::kF32,
+              "textureSample",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                using i32 = ast::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::kSampleCubeF32,
+              "textureSample(t : texture_cube<f32>,\n"
+              "              s : sampler,\n"
+              "              coords : vec3<f32>) -> vec4<f32>",
+              TextureKind::kRegular,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::kCube,
+              TextureDataType::kF32,
+              "textureSample",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::kCubeArray,
+              TextureDataType::kF32,
+              "textureSample",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4u);                          // array_index
+              },
+          },
+          {
+              ValidTextureOverload::kSampleDepth2dF32,
+              "textureSample(t : texture_depth_2d,\n"
+              "              s : sampler,\n"
+              "              coords : vec2<f32>) -> f32",
+              TextureKind::kDepth,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2d,
+              TextureDataType::kF32,
+              "textureSample",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2d,
+              TextureDataType::kF32,
+              "textureSample",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                using i32 = ast::Builder::i32;
+                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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2dArray,
+              TextureDataType::kF32,
+              "textureSample",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3u);                     // 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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2dArray,
+              TextureDataType::kF32,
+              "textureSample",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                using i32 = ast::Builder::i32;
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3u,                      // 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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::kCube,
+              TextureDataType::kF32,
+              "textureSample",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                return b->ExprList("texture",                     // t
+                                   "sampler",                     // s
+                                   b->vec2<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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::kCubeArray,
+              TextureDataType::kF32,
+              "textureSample",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec2<f32>(1.f, 2.f, 3.f),  // coords
+                                   4u);                          // array_index
+              },
+          },
+          {
+              ValidTextureOverload::kSampleBias2dF32,
+              "textureSampleBias(t : texture_2d<f32>,\n"
+              "                  s : sampler,\n"
+              "                  coords : vec2<f32>,\n"
+              "                  bias : f32) -> vec4<f32>",
+              TextureKind::kRegular,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2d,
+              TextureDataType::kF32,
+              "textureSampleBias",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2d,
+              TextureDataType::kF32,
+              "textureSampleBias",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                using i32 = ast::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::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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2dArray,
+              TextureDataType::kF32,
+              "textureSampleBias",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   4u,                      // 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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2dArray,
+              TextureDataType::kF32,
+              "textureSampleBias",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                using i32 = ast::Builder::i32;
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3u,                      // 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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k3d,
+              TextureDataType::kF32,
+              "textureSampleBias",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k3d,
+              TextureDataType::kF32,
+              "textureSampleBias",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                using i32 = ast::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::kSampleBiasCubeF32,
+              "textureSampleBias(t : texture_cube<f32>,\n"
+              "                  s : sampler,\n"
+              "                  coords : vec3<f32>,\n"
+              "                  bias : f32) -> vec4<f32>",
+              TextureKind::kRegular,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::kCube,
+              TextureDataType::kF32,
+              "textureSampleBias",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::kCubeArray,
+              TextureDataType::kF32,
+              "textureSampleBias",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   3u,                           // 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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2d,
+              TextureDataType::kF32,
+              "textureSampleLevel",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2d,
+              TextureDataType::kF32,
+              "textureSampleLevel",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                using i32 = ast::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::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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2dArray,
+              TextureDataType::kF32,
+              "textureSampleLevel",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3u,                      // 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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2dArray,
+              TextureDataType::kF32,
+              "textureSampleLevel",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                using i32 = ast::Builder::i32;
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3u,                      // 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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k3d,
+              TextureDataType::kF32,
+              "textureSampleLevel",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k3d,
+              TextureDataType::kF32,
+              "textureSampleLevel",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                using i32 = ast::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::kSampleLevelCubeF32,
+              "textureSampleLevel(t : texture_cube<f32>,\n"
+              "                   s : sampler,\n"
+              "                   coords : vec3<f32>,\n"
+              "                   level : f32) -> vec4<f32>",
+              TextureKind::kRegular,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::kCube,
+              TextureDataType::kF32,
+              "textureSampleLevel",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::kCubeArray,
+              TextureDataType::kF32,
+              "textureSampleLevel",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4u,                           // 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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2d,
+              TextureDataType::kF32,
+              "textureSampleLevel",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3u);                     // 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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2d,
+              TextureDataType::kF32,
+              "textureSampleLevel",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                using i32 = ast::Builder::i32;
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3u,                      // 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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2dArray,
+              TextureDataType::kF32,
+              "textureSampleLevel",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3u,                      // array_index
+                                   4u);                     // 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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2dArray,
+              TextureDataType::kF32,
+              "textureSampleLevel",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                using i32 = ast::Builder::i32;
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3u,                      // array_index
+                                   4u,                      // 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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::kCube,
+              TextureDataType::kF32,
+              "textureSampleLevel",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4u);                          // 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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::kCubeArray,
+              TextureDataType::kF32,
+              "textureSampleLevel",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4u,                           // array_index
+                                   5u);                          // 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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2d,
+              TextureDataType::kF32,
+              "textureSampleGrad",
+              [](ast::Builder* b) {
+                using f32 = ast::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::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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2d,
+              TextureDataType::kF32,
+              "textureSampleGrad",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                using i32 = ast::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::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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2dArray,
+              TextureDataType::kF32,
+              "textureSampleGrad",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   3u,                       // 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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k2dArray,
+              TextureDataType::kF32,
+              "textureSampleGrad",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                using i32 = ast::Builder::i32;
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3u,                      // 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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k3d,
+              TextureDataType::kF32,
+              "textureSampleGrad",
+              [](ast::Builder* b) {
+                using f32 = ast::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::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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::k3d,
+              TextureDataType::kF32,
+              "textureSampleGrad",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                using i32 = ast::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::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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::kCube,
+              TextureDataType::kF32,
+              "textureSampleGrad",
+              [](ast::Builder* b) {
+                using f32 = ast::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::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,
+              ast::type::SamplerKind::kSampler,
+              ast::type::TextureDimension::kCubeArray,
+              TextureDataType::kF32,
+              "textureSampleGrad",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4u,                           // 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,
+              ast::type::SamplerKind::kComparisonSampler,
+              ast::type::TextureDimension::k2d,
+              TextureDataType::kF32,
+              "textureSampleCompare",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                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,
+              ast::type::SamplerKind::kComparisonSampler,
+              ast::type::TextureDimension::k2d,
+              TextureDataType::kF32,
+              "textureSampleCompare",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                using i32 = ast::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::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,
+              ast::type::SamplerKind::kComparisonSampler,
+              ast::type::TextureDimension::k2dArray,
+              TextureDataType::kF32,
+              "textureSampleCompare",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   4u,                      // 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,
+              ast::type::SamplerKind::kComparisonSampler,
+              ast::type::TextureDimension::k2dArray,
+              TextureDataType::kF32,
+              "textureSampleCompare",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                using i32 = ast::Builder::i32;
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   4u,                      // 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,
+              ast::type::SamplerKind::kComparisonSampler,
+              ast::type::TextureDimension::kCube,
+              TextureDataType::kF32,
+              "textureSampleCompare",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                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,
+              ast::type::SamplerKind::kComparisonSampler,
+              ast::type::TextureDimension::kCubeArray,
+              TextureDataType::kF32,
+              "textureSampleCompare",
+              [](ast::Builder* b) {
+                using f32 = ast::Builder::f32;
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4u,                           // array_index
+                                   5.f);                         // depth_ref
+              },
+          }};
+}
+
+}  // namespace test
+}  // namespace intrinsic
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/intrinsic_texture_helper_test.h b/src/ast/intrinsic_texture_helper_test.h
new file mode 100644
index 0000000..5e7da8a
--- /dev/null
+++ b/src/ast/intrinsic_texture_helper_test.h
@@ -0,0 +1,171 @@
+// 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.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_AST_INTRINSIC_TEXTURE_HELPER_TEST_H_
+#define SRC_AST_INTRINSIC_TEXTURE_HELPER_TEST_H_
+
+#include <functional>
+#include <vector>
+
+#include "src/ast/builder.h"
+#include "src/ast/type/sampler_type.h"
+#include "src/ast/type/texture_type.h"
+
+namespace tint {
+namespace ast {
+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 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;
+}
+
+enum class ValidTextureOverload {
+  kSample1dF32,
+  kSample1dArrayF32,
+  kSample2dF32,
+  kSample2dOffsetF32,
+  kSample2dArrayF32,
+  kSample2dArrayOffsetF32,
+  kSample3dF32,
+  kSample3dOffsetF32,
+  kSampleCubeF32,
+  kSampleCubeArrayF32,
+  kSampleDepth2dF32,
+  kSampleDepth2dOffsetF32,
+  kSampleDepth2dArrayF32,
+  kSampleDepth2dArrayOffsetF32,
+  kSampleDepthCubeF32,
+  kSampleDepthCubeArrayF32,
+  kSampleBias2dF32,
+  kSampleBias2dOffsetF32,
+  kSampleBias2dArrayF32,
+  kSampleBias2dArrayOffsetF32,
+  kSampleBias3dF32,
+  kSampleBias3dOffsetF32,
+  kSampleBiasCubeF32,
+  kSampleBiasCubeArrayF32,
+  kSampleLevel2dF32,
+  kSampleLevel2dOffsetF32,
+  kSampleLevel2dArrayF32,
+  kSampleLevel2dArrayOffsetF32,
+  kSampleLevel3dF32,
+  kSampleLevel3dOffsetF32,
+  kSampleLevelCubeF32,
+  kSampleLevelCubeArrayF32,
+  kSampleLevelDepth2dF32,
+  kSampleLevelDepth2dOffsetF32,
+  kSampleLevelDepth2dArrayF32,
+  kSampleLevelDepth2dArrayOffsetF32,
+  kSampleLevelDepthCubeF32,
+  kSampleLevelDepthCubeArrayF32,
+  kSampleGrad2dF32,
+  kSampleGrad2dOffsetF32,
+  kSampleGrad2dArrayF32,
+  kSampleGrad2dArrayOffsetF32,
+  kSampleGrad3dF32,
+  kSampleGrad3dOffsetF32,
+  kSampleGradCubeF32,
+  kSampleGradCubeArrayF32,
+  kSampleGradDepth2dF32,
+  kSampleGradDepth2dOffsetF32,
+  kSampleGradDepth2dArrayF32,
+  kSampleGradDepth2dArrayOffsetF32,
+  kSampleGradDepthCubeF32,
+  kSampleGradDepthCubeArrayF32,
+};
+
+/// Describes a texture intrinsic overload
+struct TextureOverloadCase {
+  /// Constructor
+  TextureOverloadCase();
+  /// Constructor
+  TextureOverloadCase(ValidTextureOverload,
+                      const char*,
+                      TextureKind,
+                      ast::type::SamplerKind,
+                      ast::type::TextureDimension,
+                      TextureDataType,
+                      const char*,
+                      std::function<ast::ExpressionList(ast::Builder*)>);
+  /// Copy constructor
+  TextureOverloadCase(const TextureOverloadCase&);
+  /// Destructor
+  ~TextureOverloadCase();
+
+  /// @return a vector containing a large number of valid texture overloads
+  static std::vector<TextureOverloadCase> ValidCases();
+
+  /// The enumerator for this overload
+  ValidTextureOverload overload;
+  /// A human readable description of the overload
+  const char* description;
+  /// The texture kind for the texture parameter
+  TextureKind texture_kind;
+  /// The sampler kind for the sampler parameter
+  ast::type::SamplerKind sampler_kind;
+  /// The dimensions of the texture parameter
+  ast::type::TextureDimension texture_dimension;
+  /// The data type of the texture parameter
+  TextureDataType texture_data_type;
+  /// Name of the function. e.g. `textureSample`, `textureSampleGrad`, etc
+  const char* function;
+  /// A function that builds the AST arguments for the overload
+  std::function<ast::ExpressionList(ast::Builder*)> 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;
+}
+
+}  // namespace test
+}  // namespace intrinsic
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_INTRINSIC_TEXTURE_HELPER_TEST_H_