2
0
Эх сурвалжийг харах

[spirv] Handle Sparse Images in GatherRGBA (#872)

Ehsan 7 жил өмнө
parent
commit
b0713a6b50

+ 4 - 3
tools/clang/include/clang/SPIRV/ModuleBuilder.h

@@ -198,14 +198,15 @@ public:
 
   /// \brief Creates SPIR-V instructions for gathering the given image.
   ///
-  /// If compareVal is given a non-zero value, OpImageDrefGather will be
-  /// generated; otherwise, OpImageGather will be generated.
+  /// If compareVal is given a non-zero value, OpImageDrefGather or
+  /// OpImageSparseDrefGather will be generated; otherwise, OpImageGather or
+  /// OpImageSparseGather will be generated.
   uint32_t createImageGather(uint32_t texelType, uint32_t imageType,
                              uint32_t image, uint32_t sampler,
                              uint32_t coordinate, uint32_t component,
                              uint32_t compareVal, uint32_t constOffset,
                              uint32_t varOffset, uint32_t constOffsets,
-                             uint32_t sample);
+                             uint32_t sample, bool isSparse);
 
   /// \brief Creates a select operation with the given values for true and false
   /// cases and returns the <result-id> for the result.

+ 20 - 6
tools/clang/lib/SPIRV/ModuleBuilder.cpp

@@ -438,9 +438,12 @@ uint32_t ModuleBuilder::createImageGather(
     uint32_t texelType, uint32_t imageType, uint32_t image, uint32_t sampler,
     uint32_t coordinate, uint32_t component, uint32_t compareVal,
     uint32_t constOffset, uint32_t varOffset, uint32_t constOffsets,
-    uint32_t sample) {
+    uint32_t sample, bool isSparse) {
   assert(insertPoint && "null insert point");
 
+  if (isSparse)
+    requireCapability(spv::Capability::SparseResidency);
+
   // An OpSampledImage is required to do the image sampling.
   const uint32_t sampledImgId = theContext.takeNextId();
   const uint32_t sampledImgTy = getSampledImageType(imageType);
@@ -456,12 +459,23 @@ uint32_t ModuleBuilder::createImageGather(
   const uint32_t texelId = theContext.takeNextId();
 
   if (compareVal) {
-    // Note: OpImageDrefGather does not take the component parameter.
-    instBuilder.opImageDrefGather(texelType, texelId, sampledImgId, coordinate,
-                                  compareVal, mask);
+    if (isSparse) {
+      // Note: OpImageSparseDrefGather does not take the component parameter.
+      instBuilder.opImageSparseDrefGather(texelType, texelId, sampledImgId,
+                                          coordinate, compareVal, mask);
+    } else {
+      // Note: OpImageDrefGather does not take the component parameter.
+      instBuilder.opImageDrefGather(texelType, texelId, sampledImgId,
+                                    coordinate, compareVal, mask);
+    }
   } else {
-    instBuilder.opImageGather(texelType, texelId, sampledImgId, coordinate,
-                              component, mask);
+    if (isSparse) {
+      instBuilder.opImageSparseGather(texelType, texelId, sampledImgId,
+                                      coordinate, component, mask);
+    } else {
+      instBuilder.opImageGather(texelType, texelId, sampledImgId, coordinate,
+                                component, mask);
+    }
   }
 
   for (const auto param : params)

+ 71 - 28
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -2151,42 +2151,51 @@ uint32_t SPIRVEmitter::processTextureGatherRGBACmpRGBA(
   // * SamplerState s, float2 location, int2 offset0, int2 offset1,
   //   int offset2, int2 offset3
   //
-  // An additional out uint status parameter can appear in both of the above,
-  // which we does not support yet.
+  // An additional 'out uint status' parameter can appear in both of the above.
   //
   // Parameters for .GatherCmp{Red|Green|Blue|Alpha}() are one of the following
   // two sets:
-  // * SamplerState s, float2 location, int2 offset
-  // * SamplerState s, float2 location, int2 offset0, int2 offset1,
-  //   int offset2, int2 offset3
+  // * SamplerState s, float2 location, float compare_value, int2 offset
+  // * SamplerState s, float2 location, float compare_value, int2 offset1,
+  //   int2 offset2, int2 offset3, int2 offset4
+  //
+  // An additional 'out uint status' parameter can appear in both of the above.
   //
-  // An additional out uint status parameter can appear in both of the above,
-  // which we does not support yet.
+  // TextureCube's signature is somewhat different from the rest.
+  // Parameters for .Gather{Red|Green|Blue|Alpha}() for TextureCube are:
+  // * SamplerState s, float2 location, out uint status
+  // Parameters for .GatherCmp{Red|Green|Blue|Alpha}() for TextureCube are:
+  // * SamplerState s, float2 location, float compare_value, out uint status
   //
   // Return type is always a 4-component vector.
   const FunctionDecl *callee = expr->getDirectCallee();
   const auto numArgs = expr->getNumArgs();
+  const auto *imageExpr = expr->getImplicitObjectArgument();
+  const QualType imageType = imageExpr->getType();
+  const auto imageTypeId = typeTranslator.translateType(imageType);
+  const auto retTypeId = typeTranslator.translateType(callee->getReturnType());
 
-  if (numArgs != 3 + isCmp && numArgs != 6 + isCmp) {
-    emitError("unsupported '%0' method call with status parameter",
-              expr->getExprLoc())
-        << callee->getName() << expr->getSourceRange();
-    return 0;
-  }
+  // If the last arg is an unsigned integer, it must be the status.
+  const bool hasStatusArg =
+      expr->getArg(numArgs - 1)->getType()->isUnsignedIntegerType();
 
-  const auto *imageExpr = expr->getImplicitObjectArgument();
+  // Subtract 1 for status arg (if it exists), subtract 1 for compare_value (if
+  // it exists), and subtract 2 for SamplerState and location.
+  const auto numOffsetArgs = numArgs - hasStatusArg - isCmp - 2;
+  // No offset args for TextureCube, 1 or 4 offset args for the rest.
+  assert(numOffsetArgs == 0 || numOffsetArgs == 1 || numOffsetArgs == 4);
 
   const uint32_t image = loadIfGLValue(imageExpr);
   const uint32_t sampler = doExpr(expr->getArg(0));
   const uint32_t coordinate = doExpr(expr->getArg(1));
   const uint32_t compareVal = isCmp ? doExpr(expr->getArg(2)) : 0;
 
+  // Handle offsets (if any).
   uint32_t constOffset = 0, varOffset = 0, constOffsets = 0;
-  if (numArgs == 3 + isCmp) {
-    // One offset parameter
-    handleOptionalOffsetInMethodCall(expr, 2 + isCmp, &constOffset, &varOffset);
-  } else {
-    // Four offset parameters
+  if (numOffsetArgs == 1) {
+    // The offset arg is not optional.
+    handleOffsetInMethodCall(expr, 2 + isCmp, &constOffset, &varOffset);
+  } else if(numOffsetArgs == 4) {
     const auto offset0 = tryToEvaluateAsConst(expr->getArg(2 + isCmp));
     const auto offset1 = tryToEvaluateAsConst(expr->getArg(3 + isCmp));
     const auto offset2 = tryToEvaluateAsConst(expr->getArg(4 + isCmp));
@@ -2206,13 +2215,31 @@ uint32_t SPIRVEmitter::processTextureGatherRGBACmpRGBA(
         offsetType, {offset0, offset1, offset2, offset3});
   }
 
-  const auto retType = typeTranslator.translateType(callee->getReturnType());
-  const auto imageType = typeTranslator.translateType(imageExpr->getType());
+  if (!hasStatusArg)
+    return theBuilder.createImageGather(
+        retTypeId, imageTypeId, image, sampler, coordinate,
+        theBuilder.getConstantInt32(component), compareVal, constOffset,
+        varOffset, constOffsets, /*sampleNumber*/ 0, /*isSparse*/ false);
 
-  return theBuilder.createImageGather(
-      retType, imageType, image, sampler, coordinate,
+  // If the Status parameter is present, OpImageSparseGather should be used.
+  // The result type of this SPIR-V instruction is a struct in which the first
+  // member is an integer that holds the Residency Code.
+  const auto uintType = theBuilder.getUint32Type();
+  const auto sparseRetType =
+      theBuilder.getStructType({uintType, retTypeId}, "SparseResidencyStruct",
+                               {"Residency.Code", "Result.Type"});
+
+  // Perform ImageSparseGather
+  const auto sparseGather = theBuilder.createImageGather(
+      sparseRetType, imageTypeId, image, sampler, coordinate,
       theBuilder.getConstantInt32(component), compareVal, constOffset,
-      varOffset, constOffsets, /*sampleNumber*/ 0);
+      varOffset, constOffsets, /*sampleNumber*/ 0, /*isSparse*/ true);
+  // Write the Residency Code
+  const auto status =
+      theBuilder.createCompositeExtract(uintType, sparseGather, {0});
+  theBuilder.createStore(doExpr(expr->getArg(numArgs - 1)), status);
+  // Return the results
+  return theBuilder.createCompositeExtract(retTypeId, sparseGather, {1});
 }
 
 uint32_t SPIRVEmitter::processTextureGatherCmp(const CXXMemberCallExpr *expr) {
@@ -2246,10 +2273,11 @@ uint32_t SPIRVEmitter::processTextureGatherCmp(const CXXMemberCallExpr *expr) {
   const auto retType = typeTranslator.translateType(callee->getReturnType());
   const auto imageType = typeTranslator.translateType(imageExpr->getType());
 
+  // TODO: Update this function to include sparse cases.
   return theBuilder.createImageGather(
       retType, imageType, image, sampler, coordinate,
       /*component*/ 0, comparator, constOffset, varOffset, /*constOffsets*/ 0,
-      /*sampleNumber*/ 0);
+      /*sampleNumber*/ 0, /*isSparse*/ false);
 }
 
 SpirvEvalInfo SPIRVEmitter::processBufferTextureLoad(const Expr *object,
@@ -2534,6 +2562,21 @@ SpirvEvalInfo SPIRVEmitter::doCXXMemberCallExpr(const CXXMemberCallExpr *expr) {
 
   return processCall(expr);
 }
+
+void SPIRVEmitter::handleOffsetInMethodCall(const CXXMemberCallExpr *expr,
+                                            uint32_t index,
+                                            uint32_t *constOffset,
+                                            uint32_t *varOffset) {
+  // Ensure the given arg index is not out-of-range.
+  assert(index < expr->getNumArgs());
+
+  *constOffset = *varOffset = 0; // Initialize both first
+  if (*constOffset = tryToEvaluateAsConst(expr->getArg(index)))
+    return; // Constant offset
+  else
+    *varOffset = doExpr(expr->getArg(index));
+};
+
 void SPIRVEmitter::handleOptionalOffsetInMethodCall(
     const CXXMemberCallExpr *expr, uint32_t index, uint32_t *constOffset,
     uint32_t *varOffset) {
@@ -2680,7 +2723,6 @@ uint32_t SPIRVEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr,
   //                                [, int2 Offset]);
 
   const auto *imageExpr = expr->getImplicitObjectArgument();
-
   const uint32_t imageType = typeTranslator.translateType(imageExpr->getType());
 
   const uint32_t image = loadIfGLValue(imageExpr);
@@ -2699,11 +2741,12 @@ uint32_t SPIRVEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr,
         /*bias*/ 0, /*lod*/ 0, std::make_pair(0, 0), constOffset, varOffset,
         /*constOffsets*/ 0, /*sampleNumber*/ 0);
   } else {
+    // TODO: update this function to handle sparse cases.
     return theBuilder.createImageGather(
         retType, imageType, image, sampler, coordinate,
         // .Gather() doc says we return four components of red data.
         theBuilder.getConstantInt32(0), /*compareVal*/ 0, constOffset,
-        varOffset, /*constOffsets*/ 0, /*sampleNumber*/ 0);
+        varOffset, /*constOffsets*/ 0, /*sampleNumber*/ 0, /*isSparse*/ false);
   }
 }
 
@@ -2816,7 +2859,7 @@ SpirvEvalInfo
 SPIRVEmitter::processBufferTextureLoad(const CXXMemberCallExpr *expr) {
   // Signature:
   // ret Object.Load(int Location
-  //                 [, int SampleIndex,]
+  //                 [, int SampleIndex]
   //                 [, int Offset]);
 
   const auto *object = expr->getImplicitObjectArgument();

+ 7 - 0
tools/clang/lib/SPIRV/SPIRVEmitter.h

@@ -581,6 +581,13 @@ private:
                                         uint32_t index, uint32_t *constOffset,
                                         uint32_t *varOffset);
 
+  /// Handles the offset argument in the given method call at the given argument
+  /// index. Panics if the argument at the given index does not exist. Writes
+  /// the <result-id> to either *constOffset or *varOffset, depending on the
+  /// constantness of the offset.
+  void handleOffsetInMethodCall(const CXXMemberCallExpr *expr, uint32_t index,
+                                uint32_t *constOffset, uint32_t *varOffset);
+
   /// \brief Processes .Load() method call for Buffer/RWBuffer and texture
   /// objects.
   SpirvEvalInfo processBufferTextureLoad(const CXXMemberCallExpr *);

+ 46 - 8
tools/clang/test/CodeGenSPIRV/texture.array.gather-alpha.hlsl

@@ -2,16 +2,21 @@
 
 SamplerState gSampler : register(s5);
 
-Texture2DArray<float4> t2f4 : register(t1);
-Texture2DArray<uint4>  t2u4 : register(t2);
+Texture2DArray<float4>  t2f4       : register(t1);
+Texture2DArray<uint4>   t2u4       : register(t2);
+TextureCubeArray<uint4> tCubeArray : register(t3);
 // .GatherAlpha() does not support Texture1DArray.
-// .GatherAlpha() for TextureCubeArray only has one signature that takes the status parameter.
 
-// CHECK: [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
-// CHECK: [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
-// CHECK: [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
-// CHECK: [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
-// CHECK: [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: OpCapability SparseResidency
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4uint
+
+// CHECK:      [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
+// CHECK:      [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
+// CHECK:      [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
+// CHECK:      [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
+// CHECK:    [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: [[cv4f_1_5:%\d+]] = OpConstantComposite %v4float %float_1_5 %float_1_5 %float_1_5 %float_1_5
 
 float4 main(float3 location: A) : SV_Target {
 // CHECK:            [[t2f4:%\d+]] = OpLoad %type_2d_image_array %t2f4
@@ -44,5 +49,38 @@ float4 main(float3 location: A) : SV_Target {
 // CHECK-NEXT:                       OpStore %d [[res]]
     uint4 d = t2u4.GatherAlpha(gSampler, location, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8));
 
+    uint status;
+// CHECK:              [[t2u4:%\d+]] = OpLoad %type_2d_image_array_0 %t2u4
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:          [[loc:%\d+]] = OpLoad %v3float %location
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2u4]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct [[sampledImg]] [[loc]] %int_3 ConstOffset [[c12]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:                         OpStore %e [[result]]
+    uint4 e = t2u4.GatherAlpha(gSampler, location, int2(1, 2), status);
+
+// CHECK:              [[t2u4:%\d+]] = OpLoad %type_2d_image_array_0 %t2u4
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:          [[loc:%\d+]] = OpLoad %v3float %location
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2u4]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct [[sampledImg]] [[loc]] %int_3 ConstOffsets [[c1to8]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:                         OpStore %f [[result]]
+    uint4 f = t2u4.GatherAlpha(gSampler, location, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8), status);
+
+// CHECK:        [[tCubeArray:%\d+]] = OpLoad %type_cube_image_array %tCubeArray
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[tCubeArray]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct [[sampledImg]] [[cv4f_1_5]] %int_3 None
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:                         OpStore %g [[result]]
+    uint4 g = tCubeArray.GatherAlpha(gSampler, /*location*/ float4(1.5, 1.5, 1.5, 1.5), status);
+
     return 1.0;
 }

+ 47 - 8
tools/clang/test/CodeGenSPIRV/texture.array.gather-blue.hlsl

@@ -2,16 +2,22 @@
 
 SamplerState gSampler : register(s5);
 
-Texture2DArray<float4> t2f4 : register(t1);
-Texture2DArray<int3>   t2i3 : register(t2);
+Texture2DArray<float4>  t2f4       : register(t1);
+Texture2DArray<int3>    t2i3       : register(t2);
+TextureCubeArray<uint4> tCubeArray : register(t3);
 // .GatherBlue() does not support Texture1DArray.
-// .GatherBlue() for TextureCubeArray only has one signature that takes the status parameter.
 
-// CHECK: [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
-// CHECK: [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
-// CHECK: [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
-// CHECK: [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
-// CHECK: [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: OpCapability SparseResidency
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4int
+// CHECK: %SparseResidencyStruct_0 = OpTypeStruct %uint %v4uint
+
+// CHECK:      [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
+// CHECK:      [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
+// CHECK:      [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
+// CHECK:      [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
+// CHECK:    [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: [[cv4f_1_5:%\d+]] = OpConstantComposite %v4float %float_1_5 %float_1_5 %float_1_5 %float_1_5
 
 float4 main(float3 location: A) : SV_Target {
 // CHECK:            [[t2f4:%\d+]] = OpLoad %type_2d_image_array %t2f4
@@ -44,5 +50,38 @@ float4 main(float3 location: A) : SV_Target {
 // CHECK-NEXT:                       OpStore %d [[res]]
     int4 d = t2i3.GatherBlue(gSampler, location, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8));
 
+    uint status;
+// CHECK:              [[t2i3:%\d+]] = OpLoad %type_2d_image_array_0 %t2i3
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:          [[loc:%\d+]] = OpLoad %v3float %location
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2i3]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct [[sampledImg]] [[loc]] %int_2 ConstOffset [[c12]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4int [[structResult]] 1
+// CHECK-NEXT:                         OpStore %e [[result]]
+    int4 e = t2i3.GatherBlue(gSampler, location, int2(1, 2), status);
+
+// CHECK:              [[t2i3:%\d+]] = OpLoad %type_2d_image_array_0 %t2i3
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:          [[loc:%\d+]] = OpLoad %v3float %location
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2i3]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct [[sampledImg]] [[loc]] %int_2 ConstOffsets [[c1to8]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4int [[structResult]] 1
+// CHECK-NEXT:                         OpStore %f [[result]]
+    int4 f = t2i3.GatherBlue(gSampler, location, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8), status);
+
+// CHECK:        [[tCubeArray:%\d+]] = OpLoad %type_cube_image_array %tCubeArray
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[tCubeArray]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct_0 [[sampledImg]] [[cv4f_1_5]] %int_2 None
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:                         OpStore %g [[result]]
+    uint4 g = tCubeArray.GatherBlue(gSampler, /*location*/ float4(1.5, 1.5, 1.5, 1.5), status);
+
     return 1.0;
 }

+ 49 - 8
tools/clang/test/CodeGenSPIRV/texture.array.gather-cmp-red.hlsl

@@ -2,16 +2,22 @@
 
 SamplerComparisonState gSampler : register(s5);
 
-Texture2DArray<float4> t2f4 : register(t1);
-Texture2DArray<uint>   t2u1 : register(t2);
+Texture2DArray<float4> t2f4       : register(t1);
+Texture2DArray<uint>   t2u1       : register(t2);
+TextureCubeArray<int4> tCubeArray : register(t3);
 // .GatherCmpRed() does not support Texture1DArray.
-// .GatherCmpRed() for TextureCubeArray only has one signature that takes the status parameter.
 
-// CHECK: [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
-// CHECK: [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
-// CHECK: [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
-// CHECK: [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
-// CHECK: [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: OpCapability SparseResidency
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4uint
+// CHECK: %SparseResidencyStruct_0 = OpTypeStruct %uint %v4int
+
+// CHECK:      [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
+// CHECK:      [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
+// CHECK:      [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
+// CHECK:      [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
+// CHECK:    [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: [[cv4f_1_5:%\d+]] = OpConstantComposite %v4float %float_1_5 %float_1_5 %float_1_5 %float_1_5
 
 float4 main(float3 location: A, float comparator: B) : SV_Target {
 // CHECK:            [[t2f4:%\d+]] = OpLoad %type_2d_image_array %t2f4
@@ -48,5 +54,40 @@ float4 main(float3 location: A, float comparator: B) : SV_Target {
 // CHECK-NEXT:                       OpStore %d [[res]]
     uint4 d = t2u1.GatherCmpRed(gSampler, location, comparator, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8));
 
+    uint status;
+// CHECK:             [[t2u1:%\d+]] = OpLoad %type_2d_image_array_0 %t2u1
+// CHECK-NEXT:    [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:         [[loc:%\d+]] = OpLoad %v3float %location
+// CHECK-NEXT:  [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT:  [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2u1]] [[gSampler]]
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseDrefGather %SparseResidencyStruct [[sampledImg]] [[loc]] [[comparator]] ConstOffset [[c12]]
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:      [[result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:                        OpStore %e [[result]]
+    uint4 e = t2u1.GatherCmpRed(gSampler, location, comparator, int2(1, 2), status);
+
+// CHECK:              [[t2u1:%\d+]] = OpLoad %type_2d_image_array_0 %t2u1
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:          [[loc:%\d+]] = OpLoad %v3float %location
+// CHECK-NEXT:   [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2u1]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseDrefGather %SparseResidencyStruct [[sampledImg]] [[loc]] [[comparator]] ConstOffsets [[c1to8]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:                         OpStore %f [[result]]
+    uint4 f = t2u1.GatherCmpRed(gSampler, location, comparator, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8), status);
+
+// CHECK:        [[tCubeArray:%\d+]] = OpLoad %type_cube_image_array %tCubeArray
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[tCubeArray]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseDrefGather %SparseResidencyStruct_0 [[sampledImg]] [[cv4f_1_5]] %float_2_5 None
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4int [[structResult]] 1
+// CHECK-NEXT:                         OpStore %g [[result]]
+    int4 g = tCubeArray.GatherCmpRed(gSampler, /*location*/ float4(1.5, 1.5, 1.5, 1.5), /*compare_value*/ 2.5, status);
+
     return 1.0;
 }

+ 48 - 8
tools/clang/test/CodeGenSPIRV/texture.array.gather-green.hlsl

@@ -2,16 +2,22 @@
 
 SamplerState gSampler : register(s5);
 
-Texture2DArray<float4> t2f4 : register(t1);
-Texture2DArray<uint2>  t2u2 : register(t2);
+Texture2DArray<float4> t2f4       : register(t1);
+Texture2DArray<uint2>  t2u2       : register(t2);
+TextureCubeArray<int4> tCubeArray : register(t3);
 // .GatherGreen() does not support Texture1DArray.
-// .GatherGreen() for TextureCubeArray only has one signature that takes the status parameter.
 
-// CHECK: [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
-// CHECK: [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
-// CHECK: [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
-// CHECK: [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
-// CHECK: [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: OpCapability SparseResidency
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4uint
+// CHECK: %SparseResidencyStruct_0 = OpTypeStruct %uint %v4int
+
+// CHECK:      [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
+// CHECK:      [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
+// CHECK:      [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
+// CHECK:      [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
+// CHECK:    [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: [[cv4f_1_5:%\d+]] = OpConstantComposite %v4float %float_1_5 %float_1_5 %float_1_5 %float_1_5
 
 float4 main(float3 location: A) : SV_Target {
 // CHECK:            [[t2f4:%\d+]] = OpLoad %type_2d_image_array %t2f4
@@ -44,5 +50,39 @@ float4 main(float3 location: A) : SV_Target {
 // CHECK-NEXT:                       OpStore %d [[res]]
     uint4 d = t2u2.GatherGreen(gSampler, location, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8));
 
+    uint status;
+
+// CHECK:              [[t2u2:%\d+]] = OpLoad %type_2d_image_array_0 %t2u2
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:          [[loc:%\d+]] = OpLoad %v3float %location
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2u2]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct [[sampledImg]] [[loc]] %int_1 ConstOffset [[c12]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:                         OpStore %e [[result]]
+    uint4 e = t2u2.GatherGreen(gSampler, location, int2(1, 2), status);
+
+// CHECK:              [[t2u2:%\d+]] = OpLoad %type_2d_image_array_0 %t2u2
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:          [[loc:%\d+]] = OpLoad %v3float %location
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2u2]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct [[sampledImg]] [[loc]] %int_1 ConstOffsets [[c1to8]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:                         OpStore %f [[result]]
+    uint4 f = t2u2.GatherGreen(gSampler, location, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8), status);
+
+// CHECK:        [[tCubeArray:%\d+]] = OpLoad %type_cube_image_array %tCubeArray
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[tCubeArray]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct_0 [[sampledImg]] [[cv4f_1_5]] %int_1 None
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4int [[structResult]] 1
+// CHECK-NEXT:                         OpStore %g [[result]]
+    int4 g = tCubeArray.GatherGreen(gSampler, /*location*/ float4(1.5, 1.5, 1.5, 1.5), status);
+
     return 1.0;
 }

+ 45 - 6
tools/clang/test/CodeGenSPIRV/texture.array.gather-red.hlsl

@@ -4,14 +4,20 @@ SamplerState gSampler : register(s5);
 
 Texture2DArray<float4> t2f4 : register(t1);
 Texture2DArray<uint>   t2u1 : register(t2);
+TextureCubeArray<int4> tCubeArray : register(t3);
 // .GatherRed() does not support Texture1DArray.
-// .GatherRed() for TextureCubeArray only has one signature that takes the status parameter.
 
-// CHECK: [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
-// CHECK: [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
-// CHECK: [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
-// CHECK: [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
-// CHECK: [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: OpCapability SparseResidency
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4uint
+// CHECK: %SparseResidencyStruct_0 = OpTypeStruct %uint %v4int
+
+// CHECK:      [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
+// CHECK:      [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
+// CHECK:      [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
+// CHECK:      [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
+// CHECK:    [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: [[cv4f_1_5:%\d+]] = OpConstantComposite %v4float %float_1_5 %float_1_5 %float_1_5 %float_1_5
 
 float4 main(float3 location: A) : SV_Target {
 // CHECK:            [[t2f4:%\d+]] = OpLoad %type_2d_image_array %t2f4
@@ -44,5 +50,38 @@ float4 main(float3 location: A) : SV_Target {
 // CHECK-NEXT:                       OpStore %d [[res]]
     uint4 d = t2u1.GatherRed(gSampler, location, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8));
 
+    uint status;
+// CHECK:              [[t2u1:%\d+]] = OpLoad %type_2d_image_array_0 %t2u1
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:          [[loc:%\d+]] = OpLoad %v3float %location
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2u1]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct [[sampledImg]] [[loc]] %int_0 ConstOffset [[c12]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:                         OpStore %e [[result]]
+    uint4 e = t2u1.GatherRed(gSampler, location, int2(1, 2), status);
+
+// CHECK:              [[t2u1:%\d+]] = OpLoad %type_2d_image_array_0 %t2u1
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:          [[loc:%\d+]] = OpLoad %v3float %location
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2u1]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct [[sampledImg]] [[loc]] %int_0 ConstOffsets [[c1to8]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:                         OpStore %f [[result]]
+    uint4 f = t2u1.GatherRed(gSampler, location, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8), status);
+
+// CHECK:        [[tCubeArray:%\d+]] = OpLoad %type_cube_image_array %tCubeArray
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[tCubeArray]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct_0 [[sampledImg]] [[cv4f_1_5]] %int_0 None
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4int [[structResult]] 1
+// CHECK-NEXT:                         OpStore %g [[result]]
+    int4 g = tCubeArray.GatherRed(gSampler, /*location*/ float4(1.5, 1.5, 1.5, 1.5), status);
+
     return 1.0;
 }

+ 47 - 8
tools/clang/test/CodeGenSPIRV/texture.gather-alpha.hlsl

@@ -2,16 +2,22 @@
 
 SamplerState gSampler : register(s5);
 
-Texture2D<float4> t2f4 : register(t1);
-Texture2D<int4>   t2i4 : register(t2);
+Texture2D<float4>  t2f4 : register(t1);
+Texture2D<int4>    t2i4 : register(t2);
+TextureCube<uint4> tCube : register(t3);
 // .GatherAlpha() does not support Texture1D and Texture3D.
-// .GatherAlpha() for TextureCube only has one signature that takes the status parameter.
 
-// CHECK: [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
-// CHECK: [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
-// CHECK: [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
-// CHECK: [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
-// CHECK: [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: OpCapability SparseResidency
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4int
+// CHECK: %SparseResidencyStruct_0 = OpTypeStruct %uint %v4uint
+
+// CHECK:      [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
+// CHECK:      [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
+// CHECK:      [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
+// CHECK:      [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
+// CHECK:    [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: [[cv3f_1_5:%\d+]] = OpConstantComposite %v3float %float_1_5 %float_1_5 %float_1_5
 
 float4 main(float2 location: A) : SV_Target {
 // CHECK:            [[t2f4:%\d+]] = OpLoad %type_2d_image %t2f4
@@ -44,6 +50,39 @@ float4 main(float2 location: A) : SV_Target {
 // CHECK-NEXT:                       OpStore %d [[res]]
     int4 d = t2i4.GatherAlpha(gSampler, location, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8));
 
+    uint status;
+// CHECK:             [[t2i4:%\d+]] = OpLoad %type_2d_image_0 %t2i4
+// CHECK-NEXT:    [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:         [[loc:%\d+]] = OpLoad %v2float %location
+// CHECK-NEXT:  [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2i4]] [[gSampler]]
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct [[sampledImg]] [[loc]] %int_3 ConstOffset [[c12]]
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:      [[result:%\d+]] = OpCompositeExtract %v4int [[structResult]] 1
+// CHECK-NEXT:                        OpStore %e [[result]]
+    int4 e = t2i4.GatherAlpha(gSampler, location, int2(1, 2), status);
+
+// CHECK:             [[t2i4:%\d+]] = OpLoad %type_2d_image_0 %t2i4
+// CHECK-NEXT:    [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:         [[loc:%\d+]] = OpLoad %v2float %location
+// CHECK-NEXT:  [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2i4]] [[gSampler]]
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct [[sampledImg]] [[loc]] %int_3 ConstOffsets [[c1to8]]
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:      [[result:%\d+]] = OpCompositeExtract %v4int [[structResult]] 1
+// CHECK-NEXT:                        OpStore %f [[result]]
+    int4 f = t2i4.GatherAlpha(gSampler, location, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8), status);
+
+// CHECK:            [[tCube:%\d+]] = OpLoad %type_cube_image %tCube
+// CHECK-NEXT:    [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:  [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[tCube]] [[gSampler]]
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct_0 [[sampledImg]] [[cv3f_1_5]] %int_3 None
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:      [[result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:                        OpStore %g [[result]]
+    uint4 g = tCube.GatherAlpha(gSampler, /*location*/ float3(1.5, 1.5, 1.5), status);
+
     return 1.0;
 }
 

+ 47 - 8
tools/clang/test/CodeGenSPIRV/texture.gather-blue.hlsl

@@ -2,16 +2,22 @@
 
 SamplerState gSampler : register(s5);
 
-Texture2D<float4> t2f4 : register(t1);
-Texture2D<uint3>  t2u3 : register(t2);
+Texture2D<float4> t2f4  : register(t1);
+Texture2D<uint3>  t2u3  : register(t2);
+TextureCube<int4> tCube : register(t3);
 // .GatherBlue() does not support Texture1D and Texture3D.
-// .GatherBlue() for TextureCube only has one signature that takes the status parameter.
 
-// CHECK: [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
-// CHECK: [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
-// CHECK: [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
-// CHECK: [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
-// CHECK: [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: OpCapability SparseResidency
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4uint
+// CHECK: %SparseResidencyStruct_0 = OpTypeStruct %uint %v4int
+
+// CHECK:      [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
+// CHECK:      [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
+// CHECK:      [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
+// CHECK:      [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
+// CHECK:    [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: [[cv3f_1_5:%\d+]] = OpConstantComposite %v3float %float_1_5 %float_1_5 %float_1_5
 
 float4 main(float2 location: A) : SV_Target {
 // CHECK:            [[t2f4:%\d+]] = OpLoad %type_2d_image %t2f4
@@ -44,6 +50,39 @@ float4 main(float2 location: A) : SV_Target {
 // CHECK-NEXT:                       OpStore %d [[res]]
     uint4 d = t2u3.GatherBlue(gSampler, location, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8));
 
+    uint status;
+// CHECK:             [[t2u3:%\d+]] = OpLoad %type_2d_image_0 %t2u3
+// CHECK-NEXT:    [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:         [[loc:%\d+]] = OpLoad %v2float %location
+// CHECK-NEXT:  [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2u3]] [[gSampler]]
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct [[sampledImg]] [[loc]] %int_2 ConstOffset [[c12]]
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:      [[result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:                        OpStore %e [[result]]
+    uint4 e = t2u3.GatherBlue(gSampler, location, int2(1, 2), status);
+
+// CHECK:             [[t2u3:%\d+]] = OpLoad %type_2d_image_0 %t2u3
+// CHECK-NEXT:    [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:         [[loc:%\d+]] = OpLoad %v2float %location
+// CHECK-NEXT:  [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2u3]] [[gSampler]]
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct [[sampledImg]] [[loc]] %int_2 ConstOffsets [[c1to8]]
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:      [[result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:                        OpStore %f [[result]]
+    uint4 f = t2u3.GatherBlue(gSampler, location, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8), status);
+
+// CHECK:            [[tCube:%\d+]] = OpLoad %type_cube_image %tCube
+// CHECK-NEXT:    [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:  [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[tCube]] [[gSampler]]
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct_0 [[sampledImg]] [[cv3f_1_5]] %int_2 None
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:      [[result:%\d+]] = OpCompositeExtract %v4int [[structResult]] 1
+// CHECK-NEXT:                        OpStore %g [[result]]
+    int4 g = tCube.GatherBlue(gSampler, /*location*/ float3(1.5, 1.5, 1.5), status);
+
     return 1.0;
 }
 

+ 46 - 8
tools/clang/test/CodeGenSPIRV/texture.gather-cmp-red.hlsl

@@ -2,16 +2,19 @@
 
 SamplerComparisonState gSampler : register(s5);
 
-Texture2D<float4> t2f4 : register(t1);
-Texture2D<uint>   t2u1 : register(t2);
+Texture2D<float4> t2f4  : register(t1);
+Texture2D<uint>   t2u1  : register(t2);
+TextureCube<int>  tCube : register(t3);
 // .GatherCmpRed() does not support Texture1D and Texture3D.
-// .GatherCmpRed() for TextureCube only has one signature that takes the status parameter.
 
-// CHECK: [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
-// CHECK: [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
-// CHECK: [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
-// CHECK: [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
-// CHECK: [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: OpCapability SparseResidency
+
+// CHECK:      [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
+// CHECK:      [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
+// CHECK:      [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
+// CHECK:      [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
+// CHECK:    [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: [[cv3f_1_5:%\d+]] = OpConstantComposite %v3float %float_1_5 %float_1_5 %float_1_5
 
 float4 main(float2 location: A, float comparator: B) : SV_Target {
 // CHECK:            [[t2f4:%\d+]] = OpLoad %type_2d_image %t2f4
@@ -48,5 +51,40 @@ float4 main(float2 location: A, float comparator: B) : SV_Target {
 // CHECK-NEXT:                       OpStore %d [[res]]
     uint4 d = t2u1.GatherCmpRed(gSampler, location, comparator, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8));
 
+    uint status;
+// CHECK:             [[t2u1:%\d+]] = OpLoad %type_2d_image_0 %t2u1
+// CHECK-NEXT:    [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:         [[loc:%\d+]] = OpLoad %v2float %location
+// CHECK-NEXT:  [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT:  [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2u1]] [[gSampler]]
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseDrefGather %SparseResidencyStruct [[sampledImg]] [[loc]] [[comparator]] ConstOffset [[c12]]
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:      [[result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:                        OpStore %e [[result]]
+    uint4 e = t2u1.GatherCmpRed(gSampler, location, comparator, int2(1, 2), status);
+
+// CHECK:             [[t2u1:%\d+]] = OpLoad %type_2d_image_0 %t2u1
+// CHECK-NEXT:    [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:         [[loc:%\d+]] = OpLoad %v2float %location
+// CHECK-NEXT:  [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT:  [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2u1]] [[gSampler]]
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseDrefGather %SparseResidencyStruct [[sampledImg]] [[loc]] [[comparator]] ConstOffsets [[c1to8]]
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:      [[result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:                        OpStore %f [[result]]
+    uint4 f = t2u1.GatherCmpRed(gSampler, location, comparator, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8), status);
+
+// CHECK:            [[tCube:%\d+]] = OpLoad %type_cube_image %tCube
+// CHECK-NEXT:    [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:  [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[tCube]] [[gSampler]]
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseDrefGather %SparseResidencyStruct_0 [[sampledImg]] [[cv3f_1_5]] %float_2_5 None
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:      [[result:%\d+]] = OpCompositeExtract %v4int [[structResult]] 1
+// CHECK-NEXT:                        OpStore %g [[result]]
+    int4 g = tCube.GatherCmpRed(gSampler, /*location*/ float3(1.5, 1.5, 1.5), /*compare_value*/ 2.5, status);
+
     return 1.0;
 }

+ 48 - 9
tools/clang/test/CodeGenSPIRV/texture.gather-green.hlsl

@@ -2,16 +2,22 @@
 
 SamplerState gSampler : register(s5);
 
-Texture2D<float4> t2f4 : register(t1);
-Texture2D<uint2>  t2u2 : register(t2);
+Texture2D<float4> t2f4  : register(t1);
+Texture2D<uint2>  t2u2  : register(t2);
+TextureCube<int4> tCube : register(t3);
 // .GatherGreen() does not support Texture1D and Texture3D.
-// .GatherGreen() for TextureCube only has one signature that takes the status parameter.
 
-// CHECK: [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
-// CHECK: [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
-// CHECK: [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
-// CHECK: [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
-// CHECK: [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: OpCapability SparseResidency
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4float
+// CHECK: %SparseResidencyStruct_0 = OpTypeStruct %uint %v4int
+
+// CHECK:      [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
+// CHECK:      [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
+// CHECK:      [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
+// CHECK:      [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
+// CHECK:    [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: [[cv3f_1_5:%\d+]] = OpConstantComposite %v3float %float_1_5 %float_1_5 %float_1_5
 
 float4 main(float2 location: A) : SV_Target {
 // CHECK:            [[t2f4:%\d+]] = OpLoad %type_2d_image %t2f4
@@ -44,6 +50,39 @@ float4 main(float2 location: A) : SV_Target {
 // CHECK-NEXT:                       OpStore %d [[res]]
     uint4 d = t2u2.GatherGreen(gSampler, location, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8));
 
+    uint status;
+
+// CHECK:             [[t2f4:%\d+]] = OpLoad %type_2d_image %t2f4
+// CHECK-NEXT:    [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:         [[loc:%\d+]] = OpLoad %v2float %location
+// CHECK-NEXT:  [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t2f4]] [[gSampler]]
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct [[sampledImg]] [[loc]] %int_1 ConstOffset [[c12]]
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:      [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                        OpStore %e [[result]]
+    float4 e = t2f4.GatherGreen(gSampler, location, int2(1, 2), status);
+
+// CHECK:             [[t2f4:%\d+]] = OpLoad %type_2d_image %t2f4
+// CHECK-NEXT:    [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:         [[loc:%\d+]] = OpLoad %v2float %location
+// CHECK-NEXT:  [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t2f4]] [[gSampler]]
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct [[sampledImg]] [[loc]] %int_1 ConstOffsets [[c1to8]]
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:      [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                        OpStore %f [[result]]
+    float4 f = t2f4.GatherGreen(gSampler, location, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8), status);
+
+// CHECK:            [[tCube:%\d+]] = OpLoad %type_cube_image %tCube
+// CHECK-NEXT:    [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:  [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[tCube]] [[gSampler]]
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct_0 [[sampledImg]] [[cv3f_1_5]] %int_1 None
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:      [[result:%\d+]] = OpCompositeExtract %v4int [[structResult]] 1
+// CHECK-NEXT:                        OpStore %g [[result]]
+    int4 g = tCube.GatherGreen(gSampler, /*location*/ float3(1.5, 1.5, 1.5), status);
+
     return 1.0;
 }
-

+ 47 - 8
tools/clang/test/CodeGenSPIRV/texture.gather-red.hlsl

@@ -2,16 +2,22 @@
 
 SamplerState gSampler : register(s5);
 
-Texture2D<float4> t2f4 : register(t1);
-Texture2D<uint>   t2u1 : register(t2);
+Texture2D<float4> t2f4  : register(t1);
+Texture2D<uint>   t2u1  : register(t2);
+TextureCube<int4> tCube : register(t3);
 // .GatherRed() does not support Texture1D and Texture3D.
-// .GatherRed() for TextureCube only has one signature that takes the status parameter.
 
-// CHECK: [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
-// CHECK: [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
-// CHECK: [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
-// CHECK: [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
-// CHECK: [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: OpCapability SparseResidency
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4uint
+// CHECK: %SparseResidencyStruct_0 = OpTypeStruct %uint %v4int
+
+// CHECK:      [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
+// CHECK:      [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
+// CHECK:      [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
+// CHECK:      [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
+// CHECK:    [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+// CHECK: [[cv3f_1_5:%\d+]] = OpConstantComposite %v3float %float_1_5 %float_1_5 %float_1_5
 
 float4 main(float2 location: A) : SV_Target {
 // CHECK:            [[t2f4:%\d+]] = OpLoad %type_2d_image %t2f4
@@ -44,5 +50,38 @@ float4 main(float2 location: A) : SV_Target {
 // CHECK-NEXT:                       OpStore %d [[res]]
     uint4 d = t2u1.GatherRed(gSampler, location, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8));
 
+    uint status;
+// CHECK:             [[t2u1:%\d+]] = OpLoad %type_2d_image_0 %t2u1
+// CHECK-NEXT:    [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:         [[loc:%\d+]] = OpLoad %v2float %location
+// CHECK-NEXT:  [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2u1]] [[gSampler]]
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct [[sampledImg]] [[loc]] %int_0 ConstOffset [[c12]]
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:      [[result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:                        OpStore %e [[result]]
+    uint4 e = t2u1.GatherRed(gSampler, location, int2(1, 2), status);
+
+// CHECK:             [[t2u1:%\d+]] = OpLoad %type_2d_image_0 %t2u1
+// CHECK-NEXT:    [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:         [[loc:%\d+]] = OpLoad %v2float %location
+// CHECK-NEXT:  [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2u1]] [[gSampler]]
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct [[sampledImg]] [[loc]] %int_0 ConstOffsets [[c1to8]]
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:      [[result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:                        OpStore %f [[result]]
+    uint4 f = t2u1.GatherRed(gSampler, location, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8), status);
+
+// CHECK:            [[tCube:%\d+]] = OpLoad %type_cube_image %tCube
+// CHECK-NEXT:    [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:  [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[tCube]] [[gSampler]]
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseGather %SparseResidencyStruct_0 [[sampledImg]] [[cv3f_1_5]] %int_0 None
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:      [[result:%\d+]] = OpCompositeExtract %v4int [[structResult]] 1
+// CHECK-NEXT:                        OpStore %g [[result]]
+    int4 g = tCube.GatherRed(gSampler, /*location*/ float3(1.5, 1.5, 1.5), status);
+
     return 1.0;
 }