Explorar o código

[spirv] Support Status arg in Sample methods. (#889)

Ehsan %!s(int64=7) %!d(string=hai) anos
pai
achega
8e2f970460

+ 7 - 0
tools/clang/include/clang/SPIRV/InstBuilder.h

@@ -858,6 +858,13 @@ public:
   InstBuilder &opConstant(uint32_t result_type, uint32_t result_id,
                           uint32_t value);
 
+  // All-in-one method for creating different types of OpImageSample*.
+  InstBuilder &
+  opImageSample(uint32_t result_type, uint32_t result_id,
+                uint32_t sampled_image, uint32_t coordinate, uint32_t dref,
+                llvm::Optional<spv::ImageOperandsMask> image_operands,
+                bool isExplicit, bool isSparse);
+
   // Methods for supplying additional parameters.
   InstBuilder &fPFastMathMode(spv::FPFastMathModeMask);
   InstBuilder &fPRoundingMode(spv::FPRoundingMode);

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

@@ -171,9 +171,13 @@ public:
   /// OpImageSample* will be generated; otherwise, *ImplicitLod variant will
   /// be generated.
   ///
-  /// If bias, lod, or grad is given a non-zero value, an additional image
-  /// operands, Bias, Lod, or Grad, will be attached to the current instruction,
-  /// respectively.
+  /// If bias, lod, grad, or minLod is given a non-zero value, an additional
+  /// image operands, Bias, Lod, Grad, or minLod will be attached to the current
+  /// instruction, respectively. Panics if both lod and minLod are non-zero.
+  ///
+  /// If residencyCodeId is not zero, the sparse version of the instructions
+  /// will be used, and the SPIR-V instruction for storing the resulting
+  /// residency code will also be emitted.
   uint32_t createImageSample(uint32_t texelType, uint32_t imageType,
                              uint32_t image, uint32_t sampler,
                              uint32_t coordinate, uint32_t bias,
@@ -181,7 +185,7 @@ public:
                              std::pair<uint32_t, uint32_t> grad,
                              uint32_t constOffset, uint32_t varOffset,
                              uint32_t constOffsets, uint32_t sample,
-                             uint32_t minLod);
+                             uint32_t minLod, uint32_t residencyCodeId);
 
   /// \brief Creates SPIR-V instructions for reading a texel from an image. If
   /// doImageFetch is true, OpImageFetch is used. OpImageRead is used otherwise.

+ 32 - 0
tools/clang/lib/SPIRV/InstBuilderManual.cpp

@@ -80,6 +80,38 @@ InstBuilder &InstBuilder::opConstant(uint32_t resultType, uint32_t resultId,
   return *this;
 }
 
+InstBuilder &InstBuilder::opImageSample(
+    uint32_t result_type, uint32_t result_id, uint32_t sampled_image,
+    uint32_t coordinate, uint32_t dref,
+    llvm::Optional<spv::ImageOperandsMask> image_operands, bool isExplicit,
+    bool isSparse) {
+  spv::Op op = spv::Op::Max;
+  if (dref) {
+    op = isExplicit ? (isSparse ? spv::Op::OpImageSparseSampleDrefExplicitLod
+                                : spv::Op::OpImageSampleDrefExplicitLod)
+                    : (isSparse ? spv::Op::OpImageSparseSampleDrefImplicitLod
+                                : spv::Op::OpImageSampleDrefImplicitLod);
+  } else {
+    op = isExplicit ? (isSparse ? spv::Op::OpImageSparseSampleExplicitLod
+                                : spv::Op::OpImageSampleExplicitLod)
+                    : (isSparse ? spv::Op::OpImageSparseSampleImplicitLod
+                                : spv::Op::OpImageSampleImplicitLod);
+  }
+
+  TheInst.emplace_back(static_cast<uint32_t>(op));
+  TheInst.emplace_back(result_type);
+  TheInst.emplace_back(result_id);
+  TheInst.emplace_back(sampled_image);
+  TheInst.emplace_back(coordinate);
+  if(dref)
+    TheInst.emplace_back(dref);
+  if (image_operands.hasValue()) {
+    const auto &val = image_operands.getValue();
+    encodeImageOperands(val);
+  }
+  return *this;
+}
+
 void InstBuilder::encodeString(std::string value) {
   const auto &words = string::encodeSPIRVString(value);
   TheInst.insert(TheInst.end(), words.begin(), words.end());

+ 21 - 24
tools/clang/lib/SPIRV/ModuleBuilder.cpp

@@ -355,57 +355,54 @@ uint32_t ModuleBuilder::createImageSample(
     uint32_t texelType, uint32_t imageType, uint32_t image, uint32_t sampler,
     uint32_t coordinate, uint32_t compareVal, uint32_t bias, uint32_t lod,
     std::pair<uint32_t, uint32_t> grad, uint32_t constOffset,
-    uint32_t varOffset, uint32_t constOffsets, uint32_t sample, uint32_t minLod) {
+    uint32_t varOffset, uint32_t constOffsets, uint32_t sample, uint32_t minLod,
+    uint32_t residencyCodeId) {
   assert(insertPoint && "null insert point");
 
   // The Lod and Grad image operands requires explicit-lod instructions.
   // Otherwise we use implicit-lod instructions.
-  const bool mustUseExplicitInstr = lod || (grad.first && grad.second);
+  const bool isExplicit = lod || (grad.first && grad.second);
+  const bool isSparse = (residencyCodeId != 0);
 
   // minLod is only valid with Implicit instructions and Grad instructions.
   // This means that we cannot have Lod and minLod together because Lod requires
   // explicit insturctions. So either lod or minLod or both must be zero.
   assert(lod == 0 || minLod == 0);
 
+  uint32_t retType = texelType;
+  if (isSparse) {
+    requireCapability(spv::Capability::SparseResidency);
+    retType = getSparseResidencyStructType(texelType);
+  }
+
   // An OpSampledImage is required to do the image sampling.
   const uint32_t sampledImgId = theContext.takeNextId();
   const uint32_t sampledImgTy = getSampledImageType(imageType);
   instBuilder.opSampledImage(sampledImgTy, sampledImgId, image, sampler).x();
   insertPoint->appendInstruction(std::move(constructSite));
 
-  const uint32_t texelId = theContext.takeNextId();
+  uint32_t texelId = theContext.takeNextId();
   llvm::SmallVector<uint32_t, 4> params;
   const auto mask =
       composeImageOperandsMask(bias, lod, grad, constOffset, varOffset,
                                constOffsets, sample, minLod, &params);
 
-  // If depth-comparison is needed when sampling, we use the OpImageSampleDref*
-  // instructions.
-  if (compareVal) {
-    if (mustUseExplicitInstr) {
-      instBuilder.opImageSampleDrefExplicitLod(texelType, texelId, sampledImgId,
-                                               coordinate, compareVal, mask);
-    } else {
-      instBuilder.opImageSampleDrefImplicitLod(
-          texelType, texelId, sampledImgId, coordinate, compareVal,
-          llvm::Optional<spv::ImageOperandsMask>(mask));
-    }
-  } else {
-    if (mustUseExplicitInstr) {
-      instBuilder.opImageSampleExplicitLod(texelType, texelId, sampledImgId,
-                                           coordinate, mask);
-    } else {
-      instBuilder.opImageSampleImplicitLod(
-          texelType, texelId, sampledImgId, coordinate,
-          llvm::Optional<spv::ImageOperandsMask>(mask));
-    }
-  }
+  instBuilder.opImageSample(retType, texelId, sampledImgId, coordinate,
+                            compareVal, mask, isExplicit, isSparse);
 
   for (const auto param : params)
     instBuilder.idRef(param);
   instBuilder.x();
   insertPoint->appendInstruction(std::move(constructSite));
 
+  if (isSparse) {
+    // Write the Residency Code
+    const auto status = createCompositeExtract(getUint32Type(), texelId, {0});
+    createStore(residencyCodeId, status);
+    // Extract the real result from the struct
+    texelId = createCompositeExtract(texelType, texelId, {1});
+  }
+
   return texelId;
 }
 

+ 7 - 4
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -2841,7 +2841,7 @@ uint32_t SPIRVEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr,
     return theBuilder.createImageSample(
         retType, imageType, image, sampler, coordinate, /*compareVal*/ 0,
         /*bias*/ 0, /*lod*/ 0, std::make_pair(0, 0), constOffset, varOffset,
-        /*constOffsets*/ 0, /*sampleNumber*/ 0, /*minLod*/ clamp);
+        /*constOffsets*/ 0, /*sampleNumber*/ 0, /*minLod*/ clamp, status);
   } else {
     return theBuilder.createImageGather(
         retType, imageType, image, sampler, coordinate,
@@ -2886,6 +2886,7 @@ SPIRVEmitter::processTextureSampleBiasLevel(const CXXMemberCallExpr *expr,
   const auto numArgs = expr->getNumArgs();
   const bool hasStatusArg =
       expr->getArg(numArgs - 1)->getType()->isUnsignedIntegerType();
+  const auto status = hasStatusArg ? doExpr(expr->getArg(numArgs - 1)) : 0;
 
   uint32_t clamp = 0;
   // The .SampleLevel() methods do not take the clamp argument.
@@ -2924,7 +2925,7 @@ SPIRVEmitter::processTextureSampleBiasLevel(const CXXMemberCallExpr *expr,
   return theBuilder.createImageSample(
       retType, imageType, image, sampler, coordinate, /*compareVal*/ 0, bias,
       lod, std::make_pair(0, 0), constOffset, varOffset, /*constOffsets*/ 0,
-      /*sampleNumber*/ 0, /*minLod*/ clamp);
+      /*sampleNumber*/ 0, /*minLod*/ clamp, status);
 }
 
 uint32_t SPIRVEmitter::processTextureSampleGrad(const CXXMemberCallExpr *expr) {
@@ -2949,6 +2950,7 @@ uint32_t SPIRVEmitter::processTextureSampleGrad(const CXXMemberCallExpr *expr) {
   const auto numArgs = expr->getNumArgs();
   const bool hasStatusArg =
       expr->getArg(numArgs - 1)->getType()->isUnsignedIntegerType();
+  const auto status = hasStatusArg ? doExpr(expr->getArg(numArgs - 1)) : 0;
 
   uint32_t clamp = 0;
   if (numArgs > 4 && expr->getArg(4)->getType()->isFloatingType())
@@ -2979,7 +2981,7 @@ uint32_t SPIRVEmitter::processTextureSampleGrad(const CXXMemberCallExpr *expr) {
   return theBuilder.createImageSample(
       retType, imageType, image, sampler, coordinate, /*compareVal*/ 0,
       /*bias*/ 0, /*lod*/ 0, std::make_pair(ddx, ddy), constOffset, varOffset,
-      /*constOffsets*/ 0, /*sampleNumber*/ 0, /*minLod*/ clamp);
+      /*constOffsets*/ 0, /*sampleNumber*/ 0, /*minLod*/ clamp, status);
 }
 
 uint32_t
@@ -3032,6 +3034,7 @@ SPIRVEmitter::processTextureSampleCmpCmpLevelZero(const CXXMemberCallExpr *expr,
   const auto numArgs = expr->getNumArgs();
   const bool hasStatusArg =
       expr->getArg(numArgs - 1)->getType()->isUnsignedIntegerType();
+  const auto status = hasStatusArg ? doExpr(expr->getArg(numArgs - 1)) : 0;
 
   uint32_t clamp = 0;
   // The .SampleCmpLevelZero() methods do not take the clamp argument.
@@ -3065,7 +3068,7 @@ SPIRVEmitter::processTextureSampleCmpCmpLevelZero(const CXXMemberCallExpr *expr,
   return theBuilder.createImageSample(
       retType, imageType, image, sampler, coordinate, compareVal, /*bias*/ 0,
       lod, std::make_pair(0, 0), constOffset, varOffset, /*constOffsets*/ 0,
-      /*sampleNumber*/ 0, /*minLod*/ clamp);
+      /*sampleNumber*/ 0, /*minLod*/ clamp, status);
 }
 
 SpirvEvalInfo

+ 25 - 0
tools/clang/test/CodeGenSPIRV/texture.array.sample-bias.hlsl

@@ -10,11 +10,14 @@ TextureCubeArray <float4> t3 : register(t3);
 
 // CHECK: OpCapability ImageGatherExtended
 // CHECK: OpCapability MinLod
+// CHECK: OpCapability SparseResidency
 
 // CHECK: %type_sampled_image = OpTypeSampledImage %type_1d_image_array
 // CHECK: %type_sampled_image_0 = OpTypeSampledImage %type_2d_image_array
 // CHECK: %type_sampled_image_1 = OpTypeSampledImage %type_cube_image_array
 
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4float
+
 // CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_1
 // CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_1
 // CHECK: [[v4fc:%\d+]] = OpConstantComposite %v4float %float_0_1 %float_0_2 %float_0_3 %float_1
@@ -53,5 +56,27 @@ float4 main(int2 offset : A) : SV_Target {
 // CHECK-NEXT:            {{%\d+}} = OpImageSampleImplicitLod %v4float [[sampledImg]] [[v4fc]] Bias|MinLod %float_0_5 %float_2_5
     float4 val5 = t3.SampleBias(gSampler, float4(0.1, 0.2, 0.3, 1), 0.5, /*clamp*/ 2.5f);
 
+    uint status;
+// CHECK:             [[clamp:%\d+]] = OpLoad %float %clamp
+// CHECK-NEXT:           [[t1:%\d+]] = OpLoad %type_1d_image_array %t1
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t1]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleImplicitLod %SparseResidencyStruct [[sampledImg]] [[v2fc]] Bias|ConstOffset|MinLod %float_0_5 %int_1 [[clamp]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val6 [[result]]
+    float4 val6 = t1.SampleBias(gSampler, float2(0.1, 1), 0.5, 1, clamp, status);
+    
+// CHECK:                [[t3:%\d+]] = OpLoad %type_cube_image_array %t3
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t3]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleImplicitLod %SparseResidencyStruct [[sampledImg]] [[v4fc]] Bias|MinLod %float_0_5 %float_2_5
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val7 [[result]]
+    float4 val7 = t3.SampleBias(gSampler, float4(0.1, 0.2, 0.3, 1), 0.5, /*clamp*/ 2.5f, status);
+    
     return 1.0;
 }

+ 28 - 0
tools/clang/test/CodeGenSPIRV/texture.array.sample-cmp-level-zero.hlsl

@@ -6,6 +6,10 @@ Texture1DArray   <float4> t1 : register(t1);
 Texture2DArray   <float3> t2 : register(t2);
 TextureCubeArray <float>  t3 : register(t3);
 
+// CHECK: OpCapability SparseResidency
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %float
+
 // CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_1
 // CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_1
 // CHECK: [[v4fc:%\d+]] = OpConstantComposite %v4float %float_0_1 %float_0_2 %float_0_3 %float_1
@@ -33,5 +37,29 @@ float4 main(int2 offset: A, float comparator: B) : SV_Target {
 // CHECK-NEXT:            {{%\d+}} = OpImageSampleDrefExplicitLod %float [[sampledImg]] [[v4fc]] [[comparator]] Lod %float_0
     float val3 = t3.SampleCmpLevelZero(gSampler, float4(0.1, 0.2, 0.3, 1), comparator);
 
+    uint status;
+// CHECK:                [[t2:%\d+]] = OpLoad %type_2d_image_array %t2
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT:       [[offset:%\d+]] = OpLoad %v2int %offset
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleDrefExplicitLod %SparseResidencyStruct [[sampledImg]] [[v3fc]] [[comparator]] Lod|Offset %float_0 [[offset]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val4 [[result]]
+    float val4 = t2.SampleCmpLevelZero(gSampler, float3(0.1, 0.2, 1), comparator, offset, status);
+
+// CHECK:                [[t3:%\d+]] = OpLoad %type_cube_image_array %t3
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t3]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleDrefExplicitLod %SparseResidencyStruct [[sampledImg]] [[v4fc]] [[comparator]] Lod %float_0
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val5 [[result]]
+    float val5 = t3.SampleCmpLevelZero(gSampler, float4(0.1, 0.2, 0.3, 1), comparator, status);
+
     return 1.0;
 }

+ 28 - 0
tools/clang/test/CodeGenSPIRV/texture.array.sample-cmp.hlsl

@@ -7,6 +7,9 @@ Texture2DArray   <float3> t2 : register(t2);
 TextureCubeArray <float>  t3 : register(t3);
 
 // CHECK: OpCapability MinLod
+// CHECK: OpCapability SparseResidency
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %float
 
 // CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_1
 // CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_1
@@ -51,6 +54,31 @@ float4 main(int2 offset: A, float comparator: B) : SV_Target {
 // CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t3]] [[gSampler]]
 // CHECK-NEXT:            {{%\d+}} = OpImageSampleDrefImplicitLod %float [[sampledImg]] [[v4fc]] [[comparator]] MinLod %float_1_5
     float val5 = t3.SampleCmp(gSampler, float4(0.1, 0.2, 0.3, 1), comparator, /*clamp*/ 1.5);
+
+    uint status;
+// CHECK:             [[clamp:%\d+]] = OpLoad %float %clamp
+// CHECK-NEXT:           [[t2:%\d+]] = OpLoad %type_2d_image_array %t2
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT:       [[offset:%\d+]] = OpLoad %v2int %offset
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleDrefImplicitLod %SparseResidencyStruct [[sampledImg]] [[v3fc]] [[comparator]] Offset|MinLod [[offset]] [[clamp]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val6 [[result]]
+    float val6 = t2.SampleCmp(gSampler, float3(0.1, 0.2, 1), comparator, offset, clamp, status);
+
+// CHECK:                [[t3:%\d+]] = OpLoad %type_cube_image_array %t3
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t3]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleDrefImplicitLod %SparseResidencyStruct [[sampledImg]] [[v4fc]] [[comparator]] MinLod %float_1_5
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val7 [[result]]
+    float val7 = t3.SampleCmp(gSampler, float4(0.1, 0.2, 0.3, 1), comparator, /*clamp*/ 1.5, status);
     
     return 1.0;
 }

+ 27 - 1
tools/clang/test/CodeGenSPIRV/texture.array.sample-grad.hlsl

@@ -10,11 +10,14 @@ TextureCubeArray <float4> t3 : register(t3);
 
 // CHECK: OpCapability ImageGatherExtended
 // CHECK: OpCapability MinLod
+// CHECK: OpCapability SparseResidency
 
 // CHECK: %type_sampled_image = OpTypeSampledImage %type_1d_image
 // CHECK: %type_sampled_image_0 = OpTypeSampledImage %type_2d_image
 // CHECK: %type_sampled_image_1 = OpTypeSampledImage %type_cube_image
 
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4float
+
 // CHECK: [[v2f_0_1:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_0_1
 // CHECK: [[v3f_0_1:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_1 %float_0_1
 // CHECK: [[v2f_0_2:%\d+]] = OpConstantComposite %v2float %float_0_2 %float_0_2
@@ -57,6 +60,29 @@ float4 main(int2 offset : A) : SV_Target {
 // CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t3]] [[gSampler]]
 // CHECK-NEXT:            {{%\d+}} = OpImageSampleExplicitLod %v4float [[sampledImg]] [[v4f_0_1]] Grad|MinLod [[v3f_0_2]] [[v3f_0_3]] [[clamp]]
     float4 val5 = t3.SampleGrad(gSampler, float4(0.1, 0.1, 0.1, 0.1), float3(0.2, 0.2, 0.2), float3(0.3, 0.3, 0.3), clamp);
-    
+
+    uint status;
+// CHECK:                [[t2:%\d+]] = OpLoad %type_2d_image_array %t2
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:       [[offset:%\d+]] = OpLoad %v2int %offset
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleExplicitLod %SparseResidencyStruct [[sampledImg]] [[v3f_0_1]] Grad|Offset|MinLod [[v2f_0_2]] [[v2f_0_3]] [[offset]] %float_2_5
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val6 [[result]]
+    float4 val6 = t2.SampleGrad(gSampler, float3(0.1, 0.1, 0.1), float2(0.2, 0.2), float2(0.3, 0.3), offset, /*clamp*/2.5, status);
+
+// CHECK:             [[clamp:%\d+]] = OpLoad %float %clamp
+// CHECK-NEXT:           [[t3:%\d+]] = OpLoad %type_cube_image_array %t3
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t3]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleExplicitLod %SparseResidencyStruct [[sampledImg]] [[v4f_0_1]] Grad|MinLod [[v3f_0_2]] [[v3f_0_3]] [[clamp]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val7 [[result]]
+    float4 val7 = t3.SampleGrad(gSampler, float4(0.1, 0.1, 0.1, 0.1), float3(0.2, 0.2, 0.2), float3(0.3, 0.3, 0.3), clamp, status);
+
     return 1.0;
 }

+ 25 - 0
tools/clang/test/CodeGenSPIRV/texture.array.sample-level.hlsl

@@ -9,11 +9,14 @@ Texture2DArray   <float4> t2 : register(t2);
 TextureCubeArray <float4> t3 : register(t3);
 
 // CHECK: OpCapability ImageGatherExtended
+// CHECK: OpCapability SparseResidency
 
 // CHECK: %type_sampled_image = OpTypeSampledImage %type_1d_image_array
 // CHECK: %type_sampled_image_0 = OpTypeSampledImage %type_2d_image_array
 // CHECK: %type_sampled_image_1 = OpTypeSampledImage %type_cube_image_array
 
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4float
+
 // CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_1
 // CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_1
 // CHECK: [[v4fc:%\d+]] = OpConstantComposite %v4float %float_0_1 %float_0_2 %float_0_3 %float_1
@@ -38,5 +41,27 @@ float4 main(int2 offset : A) : SV_Target {
 // CHECK-NEXT:            {{%\d+}} = OpImageSampleExplicitLod %v4float [[sampledImg]] [[v4fc]] Lod %float_30
     float4 val3 = t3.SampleLevel(gSampler, float4(0.1, 0.2, 0.3, 1), 30);
 
+    uint status;
+// CHECK:                [[t2:%\d+]] = OpLoad %type_2d_image_array %t2
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:       [[offset:%\d+]] = OpLoad %v2int %offset
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleExplicitLod %SparseResidencyStruct [[sampledImg]] [[v3fc]] Lod|Offset %float_20 [[offset]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val4 [[result]]
+    float4 val4 = t2.SampleLevel(gSampler, float3(0.1, 0.2, 1), 20, offset, status);
+
+// CHECK:                [[t3:%\d+]] = OpLoad %type_cube_image_array %t3
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t3]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleExplicitLod %SparseResidencyStruct [[sampledImg]] [[v4fc]] Lod %float_30
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val5 [[result]]
+    float4 val5 = t3.SampleLevel(gSampler, float4(0.1, 0.2, 0.3, 1), 30, status);
+
     return 1.0;
 }

+ 25 - 0
tools/clang/test/CodeGenSPIRV/texture.array.sample.hlsl

@@ -9,11 +9,14 @@ Texture2DArray   <float4> t2 : register(t2);
 TextureCubeArray <float4> t3 : register(t3);
 
 // CHECK: OpCapability MinLod
+// CHECK: OpCapability SparseResidency
 
 // CHECK: %type_sampled_image = OpTypeSampledImage %type_1d_image_array
 // CHECK: %type_sampled_image_0 = OpTypeSampledImage %type_2d_image_array
 // CHECK: %type_sampled_image_1 = OpTypeSampledImage %type_cube_image_array
 
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4float
+
 // CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_1
 // CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_1
 // CHECK: [[v4fc:%\d+]] = OpConstantComposite %v4float %float_0_1 %float_0_2 %float_0_3 %float_1
@@ -51,5 +54,27 @@ float4 main() : SV_Target {
 // CHECK-NEXT:            {{%\d+}} = OpImageSampleImplicitLod %v4float [[sampledImg]] [[v4fc]] MinLod %float_1_5
     float4 val5 = t3.Sample(gSampler, float4(0.1, 0.2, 0.3, 1), /*clamp*/ 1.5);
 
+    uint status;
+// CHECK:             [[clamp:%\d+]] = OpLoad %float %clamp
+// CHECK-NEXT:           [[t1:%\d+]] = OpLoad %type_1d_image_array %t1
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t1]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleImplicitLod %SparseResidencyStruct [[sampledImg]] [[v2fc]] ConstOffset|MinLod %int_1 [[clamp]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val6 [[result]]
+    float4 val6 = t1.Sample(gSampler, float2(0.1, 1), 1, clamp, status);
+
+// CHECK:                [[t3:%\d+]] = OpLoad %type_cube_image_array %t3
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t3]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleImplicitLod %SparseResidencyStruct [[sampledImg]] [[v4fc]] MinLod %float_1_5
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val7 [[result]]
+    float4 val7 = t3.Sample(gSampler, float4(0.1, 0.2, 0.3, 1), /*clamp*/ 1.5, status);
+
     return 1.0;
 }

+ 28 - 1
tools/clang/test/CodeGenSPIRV/texture.sample-bias.hlsl

@@ -11,12 +11,15 @@ TextureCube <float4> t4 : register(t4);
 
 // CHECK: OpCapability ImageGatherExtended
 // CHECK: OpCapability MinLod
+// CHECK: OpCapability SparseResidency
 
 // CHECK: %type_sampled_image = OpTypeSampledImage %type_1d_image
 // CHECK: %type_sampled_image_0 = OpTypeSampledImage %type_2d_image
 // CHECK: %type_sampled_image_1 = OpTypeSampledImage %type_3d_image
 // CHECK: %type_sampled_image_2 = OpTypeSampledImage %type_cube_image
 
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4float
+
 // CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_0_2
 // CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_2 %int_2
 // CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_0_3
@@ -61,6 +64,30 @@ float4 main(int3 offset: A) : SV_Target {
 // CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_2 [[t4]] [[gSampler]]
 // CHECK-NEXT:            {{%\d+}} = OpImageSampleImplicitLod %v4float [[sampledImg]] [[v3fc]] Bias|MinLod %float_0_5 %float_2_5
     float4 val6 = t4.SampleBias(gSampler, float3(0.1, 0.2, 0.3), 0.5, /*clamp*/ 2.5);
-    
+
+    uint status;
+// CHECK:             [[clamp:%\d+]] = OpLoad %float %clamp
+// CHECK-NEXT:           [[t3:%\d+]] = OpLoad %type_3d_image %t3
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:       [[offset:%\d+]] = OpLoad %v3int %offset
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t3]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleImplicitLod %SparseResidencyStruct [[sampledImg]] [[v3fc]] Bias|Offset|MinLod %float_0_5 [[offset]] [[clamp]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val7 [[result]]
+    float4 val7 = t3.SampleBias(gSampler, float3(0.1, 0.2, 0.3), 0.5, offset, clamp, status);
+
+// CHECK:                [[t4:%\d+]] = OpLoad %type_cube_image %t4
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_2 [[t4]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleImplicitLod %SparseResidencyStruct [[sampledImg]] [[v3fc]] Bias|MinLod %float_0_5 %float_2_5
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val8 [[result]]
+    float4 val8 = t4.SampleBias(gSampler, float3(0.1, 0.2, 0.3), 0.5, /*clamp*/ 2.5, status);
+
     return 1.0;
 }
+// CHECK-WHOLE-SPIR-V:

+ 28 - 1
tools/clang/test/CodeGenSPIRV/texture.sample-cmp-level-zero.hlsl

@@ -7,6 +7,10 @@ Texture2D   <float2> t2 : register(t2);
 TextureCube <float>  t4 : register(t4);
 // No .SampleCmp() for Texture3D.
 
+// CHECK: OpCapability SparseResidency
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %float
+
 // CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_0_2
 // CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_0_3
 
@@ -33,6 +37,29 @@ float4 main(int2 offset: A, float comparator: B) : SV_Target {
 // CHECK-NEXT:            {{%\d+}} = OpImageSampleDrefExplicitLod %float [[sampledImg]] [[v3fc]] [[comparator]] Lod %float_0
     float val4 = t4.SampleCmpLevelZero(gSampler, float3(0.1, 0.2, 0.3), comparator);
 
+    uint status;
+// CHECK:                [[t2:%\d+]] = OpLoad %type_2d_image %t2
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT:       [[offset:%\d+]] = OpLoad %v2int %offset
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleDrefExplicitLod %SparseResidencyStruct [[sampledImg]] [[v2fc]] [[comparator]] Lod|Offset %float_0 [[offset]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val5 [[result]]
+    float val5 = t2.SampleCmpLevelZero(gSampler, float2(0.1, 0.2), comparator, offset, status);
+
+// CHECK:                [[t4:%\d+]] = OpLoad %type_cube_image %t4
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t4]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleDrefExplicitLod %SparseResidencyStruct [[sampledImg]] [[v3fc]] [[comparator]] Lod %float_0
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val6 [[result]]
+    float val6 = t4.SampleCmpLevelZero(gSampler, float3(0.1, 0.2, 0.3), comparator, status);
+
     return 1.0;
 }
-

+ 28 - 0
tools/clang/test/CodeGenSPIRV/texture.sample-cmp.hlsl

@@ -8,6 +8,9 @@ TextureCube <float>  t4 : register(t4);
 // No .SampleCmp() for Texture3D.
 
 // CHECK: OpCapability MinLod
+// CHECK: OpCapability SparseResidency
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %float
 
 // CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_0_2
 // CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_0_3
@@ -52,5 +55,30 @@ float4 main(int2 offset: A, float comparator: B) : SV_Target {
 // CHECK-NEXT:            {{%\d+}} = OpImageSampleDrefImplicitLod %float [[sampledImg]] [[v3fc]] [[comparator]] MinLod %float_2_5
     float val6 = t4.SampleCmp(gSampler, float3(0.1, 0.2, 0.3), comparator, /*clamp*/2.5);
 
+    uint status;
+// CHECK:             [[clamp:%\d+]] = OpLoad %float %clamp
+// CHECK-NEXT:           [[t2:%\d+]] = OpLoad %type_2d_image %t2
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT:       [[offset:%\d+]] = OpLoad %v2int %offset
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleDrefImplicitLod %SparseResidencyStruct [[sampledImg]] [[v2fc]] [[comparator]] Offset|MinLod [[offset]] [[clamp]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val7 [[result]]
+    float val7 = t2.SampleCmp(gSampler, float2(0.1, 0.2), comparator, offset, clamp, status);
+
+// CHECK:                [[t4:%\d+]] = OpLoad %type_cube_image %t4
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t4]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleDrefImplicitLod %SparseResidencyStruct [[sampledImg]] [[v3fc]] [[comparator]] MinLod %float_2_5
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val8 [[result]]
+    float val8 = t4.SampleCmp(gSampler, float3(0.1, 0.2, 0.3), comparator, /*clamp*/2.5, status);
+
     return 1.0;
 }

+ 26 - 0
tools/clang/test/CodeGenSPIRV/texture.sample-grad.hlsl

@@ -11,12 +11,15 @@ TextureCube <float4> t4 : register(t4);
 
 // CHECK: OpCapability ImageGatherExtended
 // CHECK: OpCapability MinLod
+// CHECK: OpCapability SparseResidency
 
 // CHECK: %type_sampled_image = OpTypeSampledImage %type_1d_image
 // CHECK: %type_sampled_image_0 = OpTypeSampledImage %type_2d_image
 // CHECK: %type_sampled_image_1 = OpTypeSampledImage %type_3d_image
 // CHECK: %type_sampled_image_2 = OpTypeSampledImage %type_cube_image
 
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4float
+
 // CHECK: [[v2f_0_1:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_0_1
 // CHECK: [[v2f_0_2:%\d+]] = OpConstantComposite %v2float %float_0_2 %float_0_2
 // CHECK: [[v2f_0_3:%\d+]] = OpConstantComposite %v2float %float_0_3 %float_0_3
@@ -66,5 +69,28 @@ float4 main(int2 offset : A) : SV_Target {
 // CHECK-NEXT:            {{%\d+}} = OpImageSampleExplicitLod %v4float [[sampledImg]] [[v3f_0_1]] Grad|MinLod [[v3f_0_2]] [[v3f_0_3]] %float_3_5
     float4 val6 = t4.SampleGrad(gSampler, float3(0.1, 0.1, 0.1), float3(0.2, 0.2, 0.2), float3(0.3, 0.3, 0.3), /*clamp*/3.5);
 
+    uint status;
+// CHECK:             [[clamp:%\d+]] = OpLoad %float %clamp
+// CHECK-NEXT:           [[t2:%\d+]] = OpLoad %type_2d_image %t2
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:       [[offset:%\d+]] = OpLoad %v2int %offset
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleExplicitLod %SparseResidencyStruct [[sampledImg]] [[v2f_0_1]] Grad|Offset|MinLod [[v2f_0_2]] [[v2f_0_3]] [[offset]] [[clamp]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val7 [[result]]
+    float4 val7 = t2.SampleGrad(gSampler, float2(0.1, 0.1), float2(0.2, 0.2), float2(0.3, 0.3), offset, clamp, status);
+
+// CHECK:                [[t4:%\d+]] = OpLoad %type_cube_image %t4
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_2 [[t4]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleExplicitLod %SparseResidencyStruct [[sampledImg]] [[v3f_0_1]] Grad|MinLod [[v3f_0_2]] [[v3f_0_3]] %float_3_5
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val8 [[result]]
+    float4 val8 = t4.SampleGrad(gSampler, float3(0.1, 0.1, 0.1), float3(0.2, 0.2, 0.2), float3(0.3, 0.3, 0.3), /*clamp*/3.5, status);
+
     return 1.0;
 }

+ 25 - 0
tools/clang/test/CodeGenSPIRV/texture.sample-level.hlsl

@@ -10,12 +10,15 @@ Texture3D   <float4> t3 : register(t3);
 TextureCube <float4> t4 : register(t4);
 
 // CHECK: OpCapability ImageGatherExtended
+// CHECK: OpCapability SparseResidency
 
 // CHECK: %type_sampled_image = OpTypeSampledImage %type_1d_image
 // CHECK: %type_sampled_image_0 = OpTypeSampledImage %type_2d_image
 // CHECK: %type_sampled_image_1 = OpTypeSampledImage %type_3d_image
 // CHECK: %type_sampled_image_2 = OpTypeSampledImage %type_cube_image
 
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4float
+
 // CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_0_2
 // CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_2 %int_2
 // CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_0_3
@@ -46,5 +49,27 @@ float4 main(int3 offset: A) : SV_Target {
 // CHECK-NEXT:            {{%\d+}} = OpImageSampleExplicitLod %v4float [[sampledImg]] [[v3fc]] Lod %float_10
     float4 val4 = t4.SampleLevel(gSampler, float3(0.1, 0.2, 0.3), 10);
 
+    uint status;
+// CHECK:                [[t3:%\d+]] = OpLoad %type_3d_image %t3
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:       [[offset:%\d+]] = OpLoad %v3int %offset
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t3]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleExplicitLod %SparseResidencyStruct [[sampledImg]] [[v3fc]] Lod|Offset %float_10 [[offset]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val5 [[result]]
+    float4 val5 = t3.SampleLevel(gSampler, float3(0.1, 0.2, 0.3), 10, offset, status);
+
+// CHECK:                [[t4:%\d+]] = OpLoad %type_cube_image %t4
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_2 [[t4]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleExplicitLod %SparseResidencyStruct [[sampledImg]] [[v3fc]] Lod %float_10
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val6 [[result]]
+    float4 val6 = t4.SampleLevel(gSampler, float3(0.1, 0.2, 0.3), 10, status);
+
     return 1.0;
 }

+ 26 - 0
tools/clang/test/CodeGenSPIRV/texture.sample.hlsl

@@ -11,12 +11,15 @@ TextureCube <float4> t4 : register(t4);
 
 // CHECK: OpCapability ImageGatherExtended
 // CHECK: OpCapability MinLod
+// CHECK: OpCapability SparseResidency
 
 // CHECK: %type_sampled_image = OpTypeSampledImage %type_1d_image
 // CHECK: %type_sampled_image_0 = OpTypeSampledImage %type_2d_image
 // CHECK: %type_sampled_image_1 = OpTypeSampledImage %type_3d_image
 // CHECK: %type_sampled_image_2 = OpTypeSampledImage %type_cube_image
 
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4float
+
 // CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_0_2
 // CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_0_3
 // CHECK: [[v3ic:%\d+]] = OpConstantComposite %v3int %int_3 %int_3 %int_3
@@ -62,5 +65,28 @@ float4 main(int2 offset: A) : SV_Target {
 // CHECK-NEXT:            {{%\d+}} = OpImageSampleImplicitLod %v4float [[sampledImg]] [[v3fc]] MinLod %float_2
     float4 val6 = t4.Sample(gSampler, float3(0.1, 0.2, 0.3), /*clamp*/ 2.0f);
 
+    uint status;
+// CHECK:             [[clamp:%\d+]] = OpLoad %float %clamp
+// CHECK-NEXT:           [[t2:%\d+]] = OpLoad %type_2d_image %t2
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:       [[offset:%\d+]] = OpLoad %v2int %offset
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleImplicitLod %SparseResidencyStruct [[sampledImg]] [[v2fc]] Offset|MinLod [[offset]] [[clamp]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val7 [[result]]
+    float4 val7 = t2.Sample(gSampler, float2(0.1, 0.2), offset, clamp, status);
+
+// CHECK:                [[t4:%\d+]] = OpLoad %type_cube_image %t4
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_2 [[t4]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseSampleImplicitLod %SparseResidencyStruct [[sampledImg]] [[v3fc]] MinLod %float_2
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val8 [[result]]
+    float4 val8 = t4.Sample(gSampler, float3(0.1, 0.2, 0.3), /*clamp*/ 2.0f, status);
+    
     return 1.0;
 }