spirv-reader: support OpImageQuerySamples

Bug: tint:109
Change-Id: I1a7677c9322f5f2f01d6bf436222b58ab9bdbf95
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/39721
Commit-Queue: David Neto <dneto@google.com>
Auto-Submit: David Neto <dneto@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index b47dcca..fa4300d 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -4408,9 +4408,13 @@
       return Fail() << "WGSL does not support querying the level of detail of "
                        "an image: "
                     << inst.PrettyPrint();
-    case SpvOpImageQueryLevels: {
+    case SpvOpImageQueryLevels:
+    case SpvOpImageQuerySamples: {
+      const auto* name = (opcode == SpvOpImageQueryLevels)
+                             ? "textureNumLevels"
+                             : "textureNumSamples";
       auto* levels_ident = create<ast::IdentifierExpression>(
-          Source{}, builder_.Symbols().Register("textureNumLevels"));
+          Source{}, builder_.Symbols().Register(name));
       ast::Expression* ast_expr = create<ast::CallExpression>(
           Source{}, levels_ident,
           ast::ExpressionList{GetImageExpression(inst)});
@@ -4424,7 +4428,6 @@
       TypedExpression expr{result_type, ast_expr};
       return EmitConstDefOrWriteToHoistedVar(inst, expr);
     }
-    case SpvOpImageQuerySamples:  // TODO(dneto)
     default:
       break;
   }
diff --git a/src/reader/spirv/parser_impl_handle_test.cc b/src/reader/spirv/parser_impl_handle_test.cc
index 6c5a7ec..0bb9024 100644
--- a/src/reader/spirv/parser_impl_handle_test.cc
+++ b/src/reader/spirv/parser_impl_handle_test.cc
@@ -4693,6 +4693,129 @@
       }
     })"}}));
 
+INSTANTIATE_TEST_SUITE_P(
+    ImageQuerySamples_SignedResult,
+    SpvParserTest_SampledImageAccessTest,
+    ::testing::ValuesIn(std::vector<ImageAccessCase>{
+        // Multsample 2D
+        {"%float 2D 0 0 1 1 Unknown", "%99 = OpImageQuerySamples %int %im\n",
+         R"(Variable{
+    Decorations{
+      GroupDecoration{2}
+      BindingDecoration{1}
+    }
+    x_20
+    uniform_constant
+    __multisampled_texture_2d__f32
+  })",
+         R"(VariableDeclStatement{
+      VariableConst{
+        x_99
+        none
+        __i32
+        {
+          Call[not set]{
+            Identifier[not set]{textureNumSamples}
+            (
+              Identifier[not set]{x_20}
+            )
+          }
+        }
+      }
+    })"},
+
+        // Multisample 2D array
+        {"%float 2D 0 1 1 1 Unknown", "%99 = OpImageQuerySamples %int %im\n",
+         R"(Variable{
+    Decorations{
+      GroupDecoration{2}
+      BindingDecoration{1}
+    }
+    x_20
+    uniform_constant
+    __multisampled_texture_2d_array__f32
+  })",
+         R"(VariableDeclStatement{
+      VariableConst{
+        x_99
+        none
+        __i32
+        {
+          Call[not set]{
+            Identifier[not set]{textureNumSamples}
+            (
+              Identifier[not set]{x_20}
+            )
+          }
+        }
+      }
+    })"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+    // Translation must inject a type coersion from signed to unsigned.
+    ImageQuerySamples_UnsignedResult,
+    SpvParserTest_SampledImageAccessTest,
+    ::testing::ValuesIn(std::vector<ImageAccessCase>{
+        // Multsample 2D
+        {"%float 2D 0 0 1 1 Unknown", "%99 = OpImageQuerySamples %uint %im\n",
+         R"(Variable{
+    Decorations{
+      GroupDecoration{2}
+      BindingDecoration{1}
+    }
+    x_20
+    uniform_constant
+    __multisampled_texture_2d__f32
+  })",
+         R"(VariableDeclStatement{
+      VariableConst{
+        x_99
+        none
+        __u32
+        {
+          TypeConstructor[not set]{
+            __u32
+            Call[not set]{
+              Identifier[not set]{textureNumSamples}
+              (
+                Identifier[not set]{x_20}
+              )
+            }
+          }
+        }
+      }
+    })"},
+
+        // Multisample 2D array
+        {"%float 2D 0 1 1 1 Unknown", "%99 = OpImageQuerySamples %uint %im\n",
+         R"(Variable{
+    Decorations{
+      GroupDecoration{2}
+      BindingDecoration{1}
+    }
+    x_20
+    uniform_constant
+    __multisampled_texture_2d_array__f32
+  })",
+         R"(VariableDeclStatement{
+      VariableConst{
+        x_99
+        none
+        __u32
+        {
+          TypeConstructor[not set]{
+            __u32
+            Call[not set]{
+              Identifier[not set]{textureNumSamples}
+              (
+                Identifier[not set]{x_20}
+              )
+            }
+          }
+        }
+      }
+    })"}}));
+
 struct ImageCoordsCase {
   // SPIR-V image type, excluding result ID and opcode
   std::string spirv_image_type_details;