Jelajahi Sumber

[spirv] Add support for .SampleCmp() and .SampleCmpLevelZero() (#689)

Lei Zhang 8 tahun lalu
induk
melakukan
050755b4d8

+ 19 - 2
docs/SPIR-V.rst

@@ -1385,6 +1385,23 @@ operands ``Bias``.
 
 
 The overload with the status parameter are not supported.
 The overload with the status parameter are not supported.
 
 
+``.SampleCmp(sampler, location, comparator[, offset])``
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Not available to ``Texture3D``, ``Texture2DMS``, and ``Texture2DMSArray``.
+
+The translation is similar to ``.Sample()``, but the
+``OpImageSampleDrefImplicitLod`` instruction are used.
+
+``.SampleCmpLevelZero(sampler, location, comparator[, offset])``
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Not available to ``Texture3D``, ``Texture2DMS``, and ``Texture2DMSArray``.
+
+The translation is similar to ``.Sample()``, but the
+``OpImageSampleDrefExplicitLod`` instruction are used, with the additional
+``Lod`` image operands set to 0.0.
+
 ``.Gather()``
 ``.Gather()``
 +++++++++++++
 +++++++++++++
 
 
@@ -1567,8 +1584,8 @@ The ``OpImageQuerySize`` instruction is used to find the width.
 
 
 ``.GetDimensions(width, elements)``
 ``.GetDimensions(width, elements)``
 +++++++++++++++++++++++++++++++++++
 +++++++++++++++++++++++++++++++++++
-The ``OpImageQuerySize`` instruction is used to get a uint2. The first element is the width, and the second
-is the elements.
+The ``OpImageQuerySize`` instruction is used to get a uint2. The first element
+is the width, and the second is the elements.
 
 
 ``RWTexture2D``
 ``RWTexture2D``
 ~~~~~~~~~~~~~~~
 ~~~~~~~~~~~~~~~

+ 5 - 1
tools/clang/include/clang/SPIRV/ModuleBuilder.h

@@ -158,6 +158,9 @@ public:
 
 
   /// \brief Creates SPIR-V instructions for sampling the given image.
   /// \brief Creates SPIR-V instructions for sampling the given image.
   ///
   ///
+  /// If compareVal is given a non-zero value, *Dref* variants of OpImageSample*
+  /// will be generated.
+  ///
   /// If lod or grad is given a non-zero value, *ExplicitLod variants of
   /// If lod or grad is given a non-zero value, *ExplicitLod variants of
   /// OpImageSample* will be generated; otherwise, *ImplicitLod variant will
   /// OpImageSample* will be generated; otherwise, *ImplicitLod variant will
   /// be generated.
   /// be generated.
@@ -167,7 +170,8 @@ public:
   /// respectively.
   /// respectively.
   uint32_t createImageSample(uint32_t texelType, uint32_t imageType,
   uint32_t createImageSample(uint32_t texelType, uint32_t imageType,
                              uint32_t image, uint32_t sampler,
                              uint32_t image, uint32_t sampler,
-                             uint32_t coordinate, uint32_t bias, uint32_t lod,
+                             uint32_t coordinate, uint32_t bias,
+                             uint32_t compareVal, uint32_t lod,
                              std::pair<uint32_t, uint32_t> grad,
                              std::pair<uint32_t, uint32_t> grad,
                              uint32_t constOffset, uint32_t varOffset,
                              uint32_t constOffset, uint32_t varOffset,
                              uint32_t constOffsets, uint32_t sample);
                              uint32_t constOffsets, uint32_t sample);

+ 26 - 8
tools/clang/lib/SPIRV/ModuleBuilder.cpp

@@ -333,7 +333,7 @@ spv::ImageOperandsMask ModuleBuilder::composeImageOperandsMask(
 
 
 uint32_t ModuleBuilder::createImageSample(
 uint32_t ModuleBuilder::createImageSample(
     uint32_t texelType, uint32_t imageType, uint32_t image, uint32_t sampler,
     uint32_t texelType, uint32_t imageType, uint32_t image, uint32_t sampler,
-    uint32_t coordinate, uint32_t bias, uint32_t lod,
+    uint32_t coordinate, uint32_t compareVal, uint32_t bias, uint32_t lod,
     std::pair<uint32_t, uint32_t> grad, uint32_t constOffset,
     std::pair<uint32_t, uint32_t> grad, uint32_t constOffset,
     uint32_t varOffset, uint32_t constOffsets, uint32_t sample) {
     uint32_t varOffset, uint32_t constOffsets, uint32_t sample) {
   assert(insertPoint && "null insert point");
   assert(insertPoint && "null insert point");
@@ -348,15 +348,33 @@ uint32_t ModuleBuilder::createImageSample(
   llvm::SmallVector<uint32_t, 4> params;
   llvm::SmallVector<uint32_t, 4> params;
   const auto mask = composeImageOperandsMask(
   const auto mask = composeImageOperandsMask(
       bias, lod, grad, constOffset, varOffset, constOffsets, sample, &params);
       bias, lod, grad, constOffset, varOffset, constOffsets, sample, &params);
-  // The Lod and Grad image operands requires explicit-lod instructions.
-  if (lod || (grad.first && grad.second)) {
-    instBuilder.opImageSampleExplicitLod(texelType, texelId, sampledImgId,
-                                         coordinate, mask);
+
+  // If depth-comparison is needed when sampling, we use the OpImageSampleDref*
+  // instructions.
+  if (compareVal) {
+    // The Lod and Grad image operands requires explicit-lod instructions.
+    // Otherwise we use implicit-lod instructions.
+    if (lod || (grad.first && grad.second)) {
+      instBuilder.opImageSampleDrefExplicitLod(texelType, texelId, sampledImgId,
+                                               coordinate, compareVal, mask);
+    } else {
+      instBuilder.opImageSampleDrefImplicitLod(
+          texelType, texelId, sampledImgId, coordinate, compareVal,
+          llvm::Optional<spv::ImageOperandsMask>(mask));
+    }
   } else {
   } else {
-    instBuilder.opImageSampleImplicitLod(
-        texelType, texelId, sampledImgId, coordinate,
-        llvm::Optional<spv::ImageOperandsMask>(mask));
+    // The Lod and Grad image operands requires explicit-lod instructions.
+    // Otherwise we use implicit-lod instructions.
+    if (lod || (grad.first && grad.second)) {
+      instBuilder.opImageSampleExplicitLod(texelType, texelId, sampledImgId,
+                                           coordinate, mask);
+    } else {
+      instBuilder.opImageSampleImplicitLod(
+          texelType, texelId, sampledImgId, coordinate,
+          llvm::Optional<spv::ImageOperandsMask>(mask));
+    }
   }
   }
+
   for (const auto param : params)
   for (const auto param : params)
     instBuilder.idRef(param);
     instBuilder.idRef(param);
   instBuilder.x();
   instBuilder.x();

+ 45 - 5
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -2039,6 +2039,10 @@ SPIRVEmitter::processIntrinsicMemberCall(const CXXMemberCallExpr *expr,
     return processTextureSampleBiasLevel(expr, /*isBias=*/false);
     return processTextureSampleBiasLevel(expr, /*isBias=*/false);
   case IntrinsicOp::MOP_SampleGrad:
   case IntrinsicOp::MOP_SampleGrad:
     return processTextureSampleGrad(expr);
     return processTextureSampleGrad(expr);
+  case IntrinsicOp::MOP_SampleCmp:
+    return processTextureSampleCmpCmpLevelZero(expr, /*isCmp=*/true);
+  case IntrinsicOp::MOP_SampleCmpLevelZero:
+    return processTextureSampleCmpCmpLevelZero(expr, /*isCmp=*/false);
   case IntrinsicOp::MOP_GatherRed:
   case IntrinsicOp::MOP_GatherRed:
     return processTextureGatherRGBA(expr, 0);
     return processTextureGatherRGBA(expr, 0);
   case IntrinsicOp::MOP_GatherGreen:
   case IntrinsicOp::MOP_GatherGreen:
@@ -2116,7 +2120,8 @@ uint32_t SPIRVEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr,
 
 
   if (isSample) {
   if (isSample) {
     return theBuilder.createImageSample(
     return theBuilder.createImageSample(
-        retType, imageType, image, sampler, coordinate, /*bias*/ 0,
+        retType, imageType, image, sampler, coordinate, /*compareVal*/ 0,
+        /*bias*/ 0,
         /*lod*/ 0, std::make_pair(0, 0), constOffset, varOffset,
         /*lod*/ 0, std::make_pair(0, 0), constOffset, varOffset,
         /*constOffsets*/ 0, /*sampleNumber*/ 0);
         /*constOffsets*/ 0, /*sampleNumber*/ 0);
   } else {
   } else {
@@ -2163,8 +2168,8 @@ SPIRVEmitter::processTextureSampleBiasLevel(const CXXMemberCallExpr *expr,
       typeTranslator.translateType(expr->getDirectCallee()->getReturnType());
       typeTranslator.translateType(expr->getDirectCallee()->getReturnType());
 
 
   return theBuilder.createImageSample(
   return theBuilder.createImageSample(
-      retType, imageType, image, sampler, coordinate, bias, lod,
-      std::make_pair(0, 0), constOffset, varOffset, /*constOffsets*/ 0,
+      retType, imageType, image, sampler, coordinate, /*compareVal*/ 0, bias,
+      lod, std::make_pair(0, 0), constOffset, varOffset, /*constOffsets*/ 0,
       /*sampleNumber*/ 0);
       /*sampleNumber*/ 0);
 }
 }
 
 
@@ -2193,11 +2198,46 @@ uint32_t SPIRVEmitter::processTextureSampleGrad(const CXXMemberCallExpr *expr) {
       typeTranslator.translateType(expr->getDirectCallee()->getReturnType());
       typeTranslator.translateType(expr->getDirectCallee()->getReturnType());
 
 
   return theBuilder.createImageSample(
   return theBuilder.createImageSample(
-      retType, imageType, image, sampler, coordinate, /*bias*/ 0, /*lod*/ 0,
-      std::make_pair(ddx, ddy), constOffset, varOffset, /*constOffsets*/ 0,
+      retType, imageType, image, sampler, coordinate, /*compareVal*/ 0,
+      /*bias*/ 0, /*lod*/ 0, std::make_pair(ddx, ddy), constOffset, varOffset,
+      /*constOffsets*/ 0,
       /*sampleNumber*/ 0);
       /*sampleNumber*/ 0);
 }
 }
 
 
+uint32_t
+SPIRVEmitter::processTextureSampleCmpCmpLevelZero(const CXXMemberCallExpr *expr,
+                                                  const bool isCmp) {
+  // .SampleCmp() Signature:
+  //
+  // float Object.SampleCmp(
+  //   SamplerComparisonState S,
+  //   float Location,
+  //   float CompareValue,
+  //   [int Offset]
+  // );
+  //
+  // .SampleCmpLevelZero() is identical to .SampleCmp() on mipmap level 0 only.
+  const auto *imageExpr = expr->getImplicitObjectArgument();
+
+  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 = doExpr(expr->getArg(2));
+  // .SampleCmp() has a fourth optional paramter for offset.
+  uint32_t constOffset = 0, varOffset = 0;
+  handleOptionalOffsetInMethodCall(expr, 3, &constOffset, &varOffset);
+  const uint32_t lod = isCmp ? 0 : theBuilder.getConstantFloat32(0);
+
+  const auto retType =
+      typeTranslator.translateType(expr->getDirectCallee()->getReturnType());
+  const auto imageType = typeTranslator.translateType(imageExpr->getType());
+
+  return theBuilder.createImageSample(
+      retType, imageType, image, sampler, coordinate, compareVal, /*bias*/ 0,
+      lod, std::make_pair(0, 0), constOffset, varOffset,
+      /*constOffsets*/ 0, /*sampleNumber*/ 0);
+}
+
 SpirvEvalInfo
 SpirvEvalInfo
 SPIRVEmitter::processBufferTextureLoad(const CXXMemberCallExpr *expr) {
 SPIRVEmitter::processBufferTextureLoad(const CXXMemberCallExpr *expr) {
   // Signature:
   // Signature:

+ 6 - 1
tools/clang/lib/SPIRV/SPIRVEmitter.h

@@ -495,9 +495,14 @@ private:
   uint32_t processTextureSampleBiasLevel(const CXXMemberCallExpr *expr,
   uint32_t processTextureSampleBiasLevel(const CXXMemberCallExpr *expr,
                                          bool isBias);
                                          bool isBias);
 
 
-  /// \brief Processes .SampleGrad()  method call for texture objects.
+  /// \brief Processes .SampleGrad() method call for texture objects.
   uint32_t processTextureSampleGrad(const CXXMemberCallExpr *expr);
   uint32_t processTextureSampleGrad(const CXXMemberCallExpr *expr);
 
 
+  /// \brief Processes .SampleCmp() or .SampleCmpLevelZero() method call for
+  /// texture objects.
+  uint32_t processTextureSampleCmpCmpLevelZero(const CXXMemberCallExpr *expr,
+                                               bool isCmp);
+
   /// \brief Handles .Gather{Red|Green|Blue|Alpha}() calls on texture types.
   /// \brief Handles .Gather{Red|Green|Blue|Alpha}() calls on texture types.
   uint32_t processTextureGatherRGBA(const CXXMemberCallExpr *expr,
   uint32_t processTextureGatherRGBA(const CXXMemberCallExpr *expr,
                                     uint32_t component);
                                     uint32_t component);

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

@@ -0,0 +1,37 @@
+// Run: %dxc -T ps_6_0 -E main
+
+SamplerComparisonState gSampler : register(s1);
+
+Texture1DArray   <float4> t1 : register(t1);
+Texture2DArray   <float3> t2 : register(t2);
+TextureCubeArray <float>  t3 : register(t3);
+
+// 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
+
+float4 main(int2 offset: A, float comparator: B) : SV_Target {
+// CHECK:              [[t1:%\d+]] = OpLoad %type_1d_image_array %t1
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t1]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleDrefExplicitLod %float [[sampledImg]] [[v2fc]] [[comparator]] Lod|ConstOffset %float_0 %int_1
+    float val1 = t1.SampleCmpLevelZero(gSampler, float2(0.1, 1), comparator, 1);
+
+// 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:            {{%\d+}} = OpImageSampleDrefExplicitLod %float [[sampledImg]] [[v3fc]] [[comparator]] Lod|Offset %float_0 [[offset]]
+    float val2 = t2.SampleCmpLevelZero(gSampler, float3(0.1, 0.2, 1), comparator, offset);
+
+// 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:            {{%\d+}} = OpImageSampleDrefExplicitLod %float [[sampledImg]] [[v4fc]] [[comparator]] Lod %float_0
+    float val3 = t3.SampleCmpLevelZero(gSampler, float4(0.1, 0.2, 0.3, 1), comparator);
+
+    return 1.0;
+}

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

@@ -0,0 +1,37 @@
+// Run: %dxc -T ps_6_0 -E main
+
+SamplerComparisonState gSampler : register(s1);
+
+Texture1DArray   <float4> t1 : register(t1);
+Texture2DArray   <float3> t2 : register(t2);
+TextureCubeArray <float>  t3 : register(t3);
+
+// 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
+
+float4 main(int2 offset: A, float comparator: B) : SV_Target {
+// CHECK:              [[t1:%\d+]] = OpLoad %type_1d_image_array %t1
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t1]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleDrefImplicitLod %float [[sampledImg]] [[v2fc]] [[comparator]] ConstOffset %int_1
+    float val1 = t1.SampleCmp(gSampler, float2(0.1, 1), comparator, 1);
+
+// 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:            {{%\d+}} = OpImageSampleDrefImplicitLod %float [[sampledImg]] [[v3fc]] [[comparator]] Offset [[offset]]
+    float val2 = t2.SampleCmp(gSampler, float3(0.1, 0.2, 1), comparator, offset);
+
+// 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:            {{%\d+}} = OpImageSampleDrefImplicitLod %float [[sampledImg]] [[v4fc]] [[comparator]]
+    float val3 = t3.SampleCmp(gSampler, float4(0.1, 0.2, 0.3, 1), comparator);
+
+    return 1.0;
+}

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

@@ -0,0 +1,38 @@
+// Run: %dxc -T ps_6_0 -E main
+
+SamplerComparisonState gSampler : register(s1);
+
+Texture1D   <float4> t1 : register(t1);
+Texture2D   <float2> t2 : register(t2);
+TextureCube <float>  t4 : register(t4);
+// No .SampleCmp() for Texture3D.
+
+// 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
+
+float4 main(int2 offset: A, float comparator: B) : SV_Target {
+// CHECK:              [[t1:%\d+]] = OpLoad %type_1d_image %t1
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t1]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleDrefExplicitLod %float [[sampledImg]] %float_0_1 [[comparator]] Lod|ConstOffset %float_0 %int_5
+    float val1 = t1.SampleCmpLevelZero(gSampler, 0.1, comparator, 5);
+
+// 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:            {{%\d+}} = OpImageSampleDrefExplicitLod %float [[sampledImg]] [[v2fc]] [[comparator]] Lod|Offset %float_0 [[offset]]
+    float val2 = t2.SampleCmpLevelZero(gSampler, float2(0.1, 0.2), comparator, offset);
+
+// 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:            {{%\d+}} = OpImageSampleDrefExplicitLod %float [[sampledImg]] [[v3fc]] [[comparator]] Lod %float_0
+    float val4 = t4.SampleCmpLevelZero(gSampler, float3(0.1, 0.2, 0.3), comparator);
+
+    return 1.0;
+}
+

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

@@ -0,0 +1,37 @@
+// Run: %dxc -T ps_6_0 -E main
+
+SamplerComparisonState gSampler : register(s1);
+
+Texture1D   <float4> t1 : register(t1);
+Texture2D   <float2> t2 : register(t2);
+TextureCube <float>  t4 : register(t4);
+// No .SampleCmp() for Texture3D.
+
+// 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
+
+float4 main(int2 offset: A, float comparator: B) : SV_Target {
+// CHECK:              [[t1:%\d+]] = OpLoad %type_1d_image %t1
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t1]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleDrefImplicitLod %float [[sampledImg]] %float_0_1 [[comparator]] ConstOffset %int_5
+    float val1 = t1.SampleCmp(gSampler, 0.1, comparator, 5);
+
+// 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:            {{%\d+}} = OpImageSampleDrefImplicitLod %float [[sampledImg]] [[v2fc]] [[comparator]] Offset [[offset]]
+    float val2 = t2.SampleCmp(gSampler, float2(0.1, 0.2), comparator, offset);
+
+// 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:            {{%\d+}} = OpImageSampleDrefImplicitLod %float [[sampledImg]] [[v3fc]] [[comparator]]
+    float val4 = t4.SampleCmp(gSampler, float3(0.1, 0.2, 0.3), comparator);
+
+    return 1.0;
+}

+ 10 - 0
tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp

@@ -424,6 +424,16 @@ TEST_F(FileTest, TextureSampleGrad) { runFileTest("texture.sample-grad.hlsl"); }
 TEST_F(FileTest, TextureArraySampleGrad) {
 TEST_F(FileTest, TextureArraySampleGrad) {
   runFileTest("texture.array.sample-grad.hlsl");
   runFileTest("texture.array.sample-grad.hlsl");
 }
 }
+TEST_F(FileTest, TextureSampleCmp) { runFileTest("texture.sample-cmp.hlsl"); }
+TEST_F(FileTest, TextureArraySampleCmp) {
+  runFileTest("texture.array.sample-cmp.hlsl");
+}
+TEST_F(FileTest, TextureSampleCmpLevelZero) {
+  runFileTest("texture.sample-cmp-level-zero.hlsl");
+}
+TEST_F(FileTest, TextureArraySampleCmpLevelZero) {
+  runFileTest("texture.array.sample-cmp-level-zero.hlsl");
+}
 
 
 TEST_F(FileTest, StructuredBufferLoad) {
 TEST_F(FileTest, StructuredBufferLoad) {
   runFileTest("method.structured-buffer.load.hlsl");
   runFileTest("method.structured-buffer.load.hlsl");