Przeglądaj źródła

[spirv] Support Load methods that take Status arg. (#905)

Ehsan 7 lat temu
rodzic
commit
1d4509f35d

+ 61 - 25
docs/SPIR-V.rst

@@ -1611,6 +1611,8 @@ Since Buffers are represented as ``OpTypeImage`` with ``Sampled`` set to 1
 operation. The return value of ``OpImageFetch`` is always a four-component
 operation. The return value of ``OpImageFetch`` is always a four-component
 vector; so proper additional instructions are generated to truncate the vector
 vector; so proper additional instructions are generated to truncate the vector
 and return the desired number of elements.
 and return the desired number of elements.
+If an output unsigned integer ``status`` argument is present, ``OpImageSparseFetch``
+is used instead. The resulting SPIR-V ``Residency Code`` will be written to ``status``.
 
 
 ``operator[]``
 ``operator[]``
 ++++++++++++++
 ++++++++++++++
@@ -1628,7 +1630,8 @@ Since Buffers are represented as ``OpTypeImage`` with dimension of ``Buffer``,
 +++++++++++
 +++++++++++
 Since RWBuffers are represented as ``OpTypeImage`` with ``Sampled`` set to 2
 Since RWBuffers are represented as ``OpTypeImage`` with ``Sampled`` set to 2
 (meaning to be used without a sampler), ``OpImageRead`` is used to perform this
 (meaning to be used without a sampler), ``OpImageRead`` is used to perform this
-operation.
+operation. If an output unsigned integer ``status`` argument is present, ``OpImageSparseRead``
+is used instead. The resulting SPIR-V ``Residency Code`` will be written to ``status``.
 
 
 ``operator[]``
 ``operator[]``
 ++++++++++++++
 ++++++++++++++
@@ -1780,8 +1783,8 @@ for that texture type.
 Common texture methods
 Common texture methods
 ~~~~~~~~~~~~~~~~~~~~~~
 ~~~~~~~~~~~~~~~~~~~~~~
 
 
-``.Sample(sampler, location[, offset])``
-++++++++++++++++++++++++++++++++++++++++
+``.Sample(sampler, location[, offset][, clamp][, Status])``
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 
 Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
 Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
 
 
@@ -1790,12 +1793,15 @@ since texture types are represented as ``OpTypeImage``. An ``OpSampledImage`` is
 created based on the ``sampler`` passed to the function. The resulting sampled
 created based on the ``sampler`` passed to the function. The resulting sampled
 image and the ``location`` passed to the function are used as arguments to
 image and the ``location`` passed to the function are used as arguments to
 ``OpImageSampleImplicitLod``, with the optional ``offset`` tranlated into
 ``OpImageSampleImplicitLod``, with the optional ``offset`` tranlated into
-addtional SPIR-V image operands ``ConstOffset`` or ``Offset`` on it.
+addtional SPIR-V image operands ``ConstOffset`` or ``Offset`` on it. The optional
+``clamp`` argument will be translated to the ``MinLod`` image operand.
 
 
-The overload with the status parameter are not supported.
+If an output unsigned integer ``status`` argument is present,
+``OpImageSparseSampleImplicitLod`` is used instead. The resulting SPIR-V
+``Residency Code`` will be written to ``status``.
 
 
-``.SampleLevel(sampler, location, lod[, offset])``
-++++++++++++++++++++++++++++++++++++++++++++++++++
+``.SampleLevel(sampler, location, lod[, offset][, Status])``
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 
 Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
 Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
 
 
@@ -1807,21 +1813,26 @@ is attached to the instruction as an SPIR-V image operands ``Lod``. The optional
 ``offset`` is also tranlated into addtional SPIR-V image operands ``ConstOffset``
 ``offset`` is also tranlated into addtional SPIR-V image operands ``ConstOffset``
 or ``Offset`` on it.
 or ``Offset`` on it.
 
 
-The overload with the status parameter are not supported.
+If an output unsigned integer ``status`` argument is present,
+``OpImageSparseSampleExplicitLod`` is used instead. The resulting SPIR-V
+``Residency Code`` will be written to ``status``.
 
 
-``.SampleGrad(sampler, location, ddx, ddy[, offset])``
-++++++++++++++++++++++++++++++++++++++++++++++++++++++
+``.SampleGrad(sampler, location, ddx, ddy[, offset][, clamp][, Status])``
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 
 Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
 Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
 
 
 Similarly to ``.SampleLevel``, the ``ddx`` and ``ddy`` parameter are attached to
 Similarly to ``.SampleLevel``, the ``ddx`` and ``ddy`` parameter are attached to
 the ``OpImageSampleExplicitLod`` instruction as an SPIR-V image operands
 the ``OpImageSampleExplicitLod`` instruction as an SPIR-V image operands
-``Grad``.
+``Grad``. The optional ``clamp`` argument will be translated into the ``MinLod``
+image operand.
 
 
-The overload with the status parameter are not supported.
+If an output unsigned integer ``status`` argument is present,
+``OpImageSparseSampleExplicitLod`` is used instead. The resulting SPIR-V
+``Residency Code`` will be written to ``status``.
 
 
-``.SampleBias(sampler, location, bias[, offset])``
-++++++++++++++++++++++++++++++++++++++++++++++++++
+``.SampleBias(sampler, location, bias[, offset][, clamp][, Status])``
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 
 Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
 Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
 
 
@@ -1829,18 +1840,24 @@ The translation is similar to ``.Sample()``, with the ``bias`` parameter
 attached to the ``OpImageSampleImplicitLod`` instruction as an SPIR-V image
 attached to the ``OpImageSampleImplicitLod`` instruction as an SPIR-V image
 operands ``Bias``.
 operands ``Bias``.
 
 
-The overload with the status parameter are not supported.
+If an output unsigned integer ``status`` argument is present,
+``OpImageSparseSampleImplicitLod`` is used instead. The resulting SPIR-V
+``Residency Code`` will be written to ``status``.
 
 
-``.SampleCmp(sampler, location, comparator[, offset])``
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++
+``.SampleCmp(sampler, location, comparator[, offset][, clamp][, Status])``
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 
 Not available to ``Texture3D``, ``Texture2DMS``, and ``Texture2DMSArray``.
 Not available to ``Texture3D``, ``Texture2DMS``, and ``Texture2DMSArray``.
 
 
 The translation is similar to ``.Sample()``, but the
 The translation is similar to ``.Sample()``, but the
 ``OpImageSampleDrefImplicitLod`` instruction are used.
 ``OpImageSampleDrefImplicitLod`` instruction are used.
 
 
-``.SampleCmpLevelZero(sampler, location, comparator[, offset])``
-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+If an output unsigned integer ``status`` argument is present,
+``OpImageSparseSampleDrefImplicitLod`` is used instead. The resulting SPIR-V
+``Residency Code`` will be written to ``status``.
+
+``.SampleCmpLevelZero(sampler, location, comparator[, offset][, Status])``
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 
 Not available to ``Texture3D``, ``Texture2DMS``, and ``Texture2DMSArray``.
 Not available to ``Texture3D``, ``Texture2DMS``, and ``Texture2DMSArray``.
 
 
@@ -1848,6 +1865,10 @@ The translation is similar to ``.Sample()``, but the
 ``OpImageSampleDrefExplicitLod`` instruction are used, with the additional
 ``OpImageSampleDrefExplicitLod`` instruction are used, with the additional
 ``Lod`` image operands set to 0.0.
 ``Lod`` image operands set to 0.0.
 
 
+If an output unsigned integer ``status`` argument is present,
+``OpImageSparseSampleDrefExplicitLod`` is used instead. The resulting SPIR-V
+``Residency Code`` will be written to ``status``.
+
 ``.Gather()``
 ``.Gather()``
 +++++++++++++
 +++++++++++++
 
 
@@ -1857,7 +1878,9 @@ Available to ``Texture2D``, ``Texture2DArray``, ``TextureCube``, and
 The translation is similar to ``.Sample()``, but the ``OpImageGather``
 The translation is similar to ``.Sample()``, but the ``OpImageGather``
 instruction is used, with component setting to 0.
 instruction is used, with component setting to 0.
 
 
-The overload with the status parameter are not supported.
+If an output unsigned integer ``status`` argument is present,
+``OpImageSparseGather`` is used instead. The resulting SPIR-V
+``Residency Code`` will be written to ``status``.
 
 
 ``.GatherRed()``, ``.GatherGreen()``, ``.GatherBlue()``, ``.GatherAlpha()``
 ``.GatherRed()``, ``.GatherGreen()``, ``.GatherBlue()``, ``.GatherAlpha()``
 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -1873,7 +1896,9 @@ There are a few overloads for these functions:
 - For those overloads taking 4 offset parameters, those offset parameters will
 - For those overloads taking 4 offset parameters, those offset parameters will
   be conveyed as an additional ``ConstOffsets`` image operands to the
   be conveyed as an additional ``ConstOffsets`` image operands to the
   instruction. So those offset parameters must all be constant values.
   instruction. So those offset parameters must all be constant values.
-- Those overloads with the status parameter are not supported.
+- For those overloads with the ``status`` parameter, ``OpImageSparseGather``
+  is used instead, and the resulting SPIR-V ``Residency Code`` will be
+  written to ``status``.
 
 
 ``.GatherCmp()``
 ``.GatherCmp()``
 ++++++++++++++++
 ++++++++++++++++
@@ -1884,7 +1909,10 @@ Available to ``Texture2D``, ``Texture2DArray``, ``TextureCube``, and
 The translation is similar to ``.Sample()``, but the ``OpImageDrefGather``
 The translation is similar to ``.Sample()``, but the ``OpImageDrefGather``
 instruction is used.
 instruction is used.
 
 
-The overload with the status parameter are not supported.
+For the overload with the output unsigned integer ``status`` argument,
+``OpImageSparseDrefGather`` is used instead. The resulting SPIR-V
+``Residency Code`` will be written to ``status``.
+
 
 
 ``.GatherCmpRed()``
 ``.GatherCmpRed()``
 +++++++++++++++++++
 +++++++++++++++++++
@@ -1894,8 +1922,6 @@ Available to ``Texture2D``, ``Texture2DArray``, ``TextureCube``, and
 
 
 The translation is the same as ``.GatherCmp()``.
 The translation is the same as ``.GatherCmp()``.
 
 
-The overload with the status parameter are not supported.
-
 ``.Load(location[, sampleIndex][, offset])``
 ``.Load(location[, sampleIndex][, offset])``
 ++++++++++++++++++++++++++++++++++++++++++++
 ++++++++++++++++++++++++++++++++++++++++++++
 
 
@@ -1908,7 +1934,9 @@ The return value of ``OpImageFetch`` is always a four-component vector; so
 proper additional instructions are generated to truncate the vector and return
 proper additional instructions are generated to truncate the vector and return
 the desired number of elements.
 the desired number of elements.
 
 
-The overload with the status parameter are not supported.
+For the overload with the output unsigned integer ``status`` argument,
+``OpImageSparseFetch`` is used instead. The resulting SPIR-V
+``Residency Code`` will be written to ``status``.
 
 
 ``operator[]``
 ``operator[]``
 ++++++++++++++
 ++++++++++++++
@@ -2034,6 +2062,10 @@ Since read-write texture types are represented as ``OpTypeImage`` with
 ``Sampled`` set to 2 (meaning to be used without a sampler), ``OpImageRead`` is
 ``Sampled`` set to 2 (meaning to be used without a sampler), ``OpImageRead`` is
 used to perform this operation.
 used to perform this operation.
 
 
+For the overload with the output unsigned integer ``status`` argument,
+``OpImageSparseRead`` is used instead. The resulting SPIR-V
+``Residency Code`` will be written to ``status``.
+
 ``operator[]``
 ``operator[]``
 ++++++++++++++
 ++++++++++++++
 Using ``operator[]`` for reading is handled similarly as ``.Load()``, while for
 Using ``operator[]`` for reading is handled similarly as ``.Load()``, while for
@@ -2299,3 +2331,7 @@ either because of no Vulkan equivalents at the moment, or because of deprecation
   sample currently being processed.) The compiler will emit an error.
   sample currently being processed.) The compiler will emit an error.
 * ``SV_InnerCoverage`` semantic does not have a Vulkan equivalent. The compiler
 * ``SV_InnerCoverage`` semantic does not have a Vulkan equivalent. The compiler
   will emit an error.
   will emit an error.
+* Since ``StructuredBuffer``, ``RWStructuredBuffer``, ``ByteAddressBuffer``, and
+  ``RWByteAddressBuffer`` are not represented as image types in SPIR-V, using the
+  output unsigned integer ``status`` argument in their ``Load*`` methods is not
+  supported. Using these methods with the ``status`` argument will cause a compiler error.

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

@@ -865,6 +865,14 @@ public:
                 llvm::Optional<spv::ImageOperandsMask> image_operands,
                 llvm::Optional<spv::ImageOperandsMask> image_operands,
                 bool is_explicit, bool is_sparse);
                 bool is_explicit, bool is_sparse);
 
 
+  // All-in-one method for creating different types of
+  // OpImageRead*/OpImageFetch*.
+  InstBuilder &
+  opImageFetchRead(uint32_t result_type, uint32_t result_id, uint32_t image,
+                   uint32_t coordinate,
+                   llvm::Optional<spv::ImageOperandsMask> image_operands,
+                   bool is_fetch, bool is_sparse);
+
   // Methods for supplying additional parameters.
   // Methods for supplying additional parameters.
   InstBuilder &fPFastMathMode(spv::FPFastMathModeMask);
   InstBuilder &fPFastMathMode(spv::FPFastMathModeMask);
   InstBuilder &fPRoundingMode(spv::FPRoundingMode);
   InstBuilder &fPRoundingMode(spv::FPRoundingMode);

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

@@ -191,11 +191,16 @@ public:
   /// doImageFetch is true, OpImageFetch is used. OpImageRead is used otherwise.
   /// doImageFetch is true, OpImageFetch is used. OpImageRead is used otherwise.
   /// OpImageFetch should be used for sampled images. OpImageRead should be used
   /// OpImageFetch should be used for sampled images. OpImageRead should be used
   /// for images without a sampler.
   /// for images without a sampler.
+  ///
+  /// 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 createImageFetchOrRead(bool doImageFetch, uint32_t texelType,
   uint32_t createImageFetchOrRead(bool doImageFetch, uint32_t texelType,
                                   QualType imageType, uint32_t image,
                                   QualType imageType, uint32_t image,
                                   uint32_t coordinate, uint32_t lod,
                                   uint32_t coordinate, uint32_t lod,
                                   uint32_t constOffset, uint32_t varOffset,
                                   uint32_t constOffset, uint32_t varOffset,
-                                  uint32_t constOffsets, uint32_t sample);
+                                  uint32_t constOffsets, uint32_t sample,
+                                  uint32_t residencyCodeId);
 
 
   /// \brief Creates SPIR-V instructions for writing to the given image.
   /// \brief Creates SPIR-V instructions for writing to the given image.
   void createImageWrite(QualType imageType, uint32_t imageId, uint32_t coordId,
   void createImageWrite(QualType imageType, uint32_t imageId, uint32_t coordId,

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

@@ -112,6 +112,28 @@ InstBuilder &InstBuilder::opImageSample(
   return *this;
   return *this;
 }
 }
 
 
+InstBuilder &InstBuilder::opImageFetchRead(
+    uint32_t result_type, uint32_t result_id, uint32_t image,
+    uint32_t coordinate, llvm::Optional<spv::ImageOperandsMask> image_operands,
+    bool is_fetch, bool is_sparse) {
+  spv::Op op =
+      is_fetch
+          ? (is_sparse ? spv::Op::OpImageSparseFetch : spv::Op::OpImageFetch)
+          : (is_sparse ? spv::Op::OpImageSparseRead : spv::Op::OpImageRead);
+
+  TheInst.emplace_back(static_cast<uint32_t>(op));
+  TheInst.emplace_back(result_type);
+  TheInst.emplace_back(result_id);
+  TheInst.emplace_back(image);
+  TheInst.emplace_back(coordinate);
+  if (image_operands.hasValue()) {
+    const auto &val = image_operands.getValue();
+    encodeImageOperands(val);
+  }
+
+  return *this;
+}
+
 void InstBuilder::encodeString(std::string value) {
 void InstBuilder::encodeString(std::string value) {
   const auto &words = string::encodeSPIRVString(value);
   const auto &words = string::encodeSPIRVString(value);
   TheInst.insert(TheInst.end(), words.begin(), words.end());
   TheInst.insert(TheInst.end(), words.begin(), words.end());

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

@@ -429,30 +429,44 @@ void ModuleBuilder::createImageWrite(QualType imageType, uint32_t imageId,
 uint32_t ModuleBuilder::createImageFetchOrRead(
 uint32_t ModuleBuilder::createImageFetchOrRead(
     bool doImageFetch, uint32_t texelType, QualType imageType, uint32_t image,
     bool doImageFetch, uint32_t texelType, QualType imageType, uint32_t image,
     uint32_t coordinate, uint32_t lod, uint32_t constOffset, uint32_t varOffset,
     uint32_t coordinate, uint32_t lod, uint32_t constOffset, uint32_t varOffset,
-    uint32_t constOffsets, uint32_t sample) {
+    uint32_t constOffsets, uint32_t sample, uint32_t residencyCodeId) {
   assert(insertPoint && "null insert point");
   assert(insertPoint && "null insert point");
 
 
-  // TODO: Update ImageFetch/ImageRead to accept minLod if necessary.
   llvm::SmallVector<uint32_t, 2> params;
   llvm::SmallVector<uint32_t, 2> params;
   const auto mask =
   const auto mask =
       llvm::Optional<spv::ImageOperandsMask>(composeImageOperandsMask(
       llvm::Optional<spv::ImageOperandsMask>(composeImageOperandsMask(
           /*bias*/ 0, lod, std::make_pair(0, 0), constOffset, varOffset,
           /*bias*/ 0, lod, std::make_pair(0, 0), constOffset, varOffset,
           constOffsets, sample, /*minLod*/ 0, &params));
           constOffsets, sample, /*minLod*/ 0, &params));
 
 
-  const uint32_t texelId = theContext.takeNextId();
-  if (doImageFetch) {
-    instBuilder.opImageFetch(texelType, texelId, image, coordinate, mask);
-  } else {
+  const bool isSparse = (residencyCodeId != 0);
+  uint32_t retType = texelType;
+  if (isSparse) {
+    requireCapability(spv::Capability::SparseResidency);
+    retType = getSparseResidencyStructType(texelType);
+  }
+
+  if (!doImageFetch) {
     requireCapability(
     requireCapability(
         TypeTranslator::getCapabilityForStorageImageReadWrite(imageType));
         TypeTranslator::getCapabilityForStorageImageReadWrite(imageType));
-    instBuilder.opImageRead(texelType, texelId, image, coordinate, mask);
   }
   }
 
 
+  uint32_t texelId = theContext.takeNextId();
+  instBuilder.opImageFetchRead(retType, texelId, image, coordinate, mask,
+                               doImageFetch, isSparse);
+
   for (const auto param : params)
   for (const auto param : params)
     instBuilder.idRef(param);
     instBuilder.idRef(param);
   instBuilder.x();
   instBuilder.x();
   insertPoint->appendInstruction(std::move(constructSite));
   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;
   return texelId;
 }
 }
 
 

+ 64 - 36
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -2350,11 +2350,9 @@ uint32_t SPIRVEmitter::processTextureGatherCmp(const CXXMemberCallExpr *expr) {
       /*sampleNumber*/ 0, status);
       /*sampleNumber*/ 0, status);
 }
 }
 
 
-SpirvEvalInfo SPIRVEmitter::processBufferTextureLoad(const Expr *object,
-                                                     const uint32_t locationId,
-                                                     uint32_t constOffset,
-                                                     uint32_t varOffset,
-                                                     uint32_t lod) {
+SpirvEvalInfo SPIRVEmitter::processBufferTextureLoad(
+    const Expr *object, const uint32_t locationId, uint32_t constOffset,
+    uint32_t varOffset, uint32_t lod, uint32_t residencyCode) {
   // Loading for Buffer and RWBuffer translates to an OpImageFetch.
   // Loading for Buffer and RWBuffer translates to an OpImageFetch.
   // The result type of an OpImageFetch must be a vec4 of float or int.
   // The result type of an OpImageFetch must be a vec4 of float or int.
   const auto type = object->getType();
   const auto type = object->getType();
@@ -2393,10 +2391,9 @@ SpirvEvalInfo SPIRVEmitter::processBufferTextureLoad(const Expr *object,
 
 
   // OpImageFetch and OpImageRead can only fetch a vector of 4 elements.
   // OpImageFetch and OpImageRead can only fetch a vector of 4 elements.
   const uint32_t texelTypeId = theBuilder.getVecType(elemTypeId, 4u);
   const uint32_t texelTypeId = theBuilder.getVecType(elemTypeId, 4u);
-  const uint32_t texel =
-      theBuilder.createImageFetchOrRead(doFetch, texelTypeId, type, objectId,
-                                        locationId, lod, constOffset, varOffset,
-                                        /*constOffsets*/ 0, sampleNumber);
+  const uint32_t texel = theBuilder.createImageFetchOrRead(
+      doFetch, texelTypeId, type, objectId, locationId, lod, constOffset,
+      varOffset, /*constOffsets*/ 0, sampleNumber, residencyCode);
 
 
   uint32_t retVal = texel;
   uint32_t retVal = texel;
   // If the result type is a vec1, vec2, or vec3, some extra processing
   // If the result type is a vec1, vec2, or vec3, some extra processing
@@ -2436,7 +2433,7 @@ SpirvEvalInfo SPIRVEmitter::processByteAddressBufferLoadStore(
            typeTranslator.isByteAddressBuffer(type));
            typeTranslator.isByteAddressBuffer(type));
     if (expr->getNumArgs() == 2) {
     if (expr->getNumArgs() == 2) {
       emitError(
       emitError(
-          "(RW)ByteAddressBuffer::Load(in address, out status) unimplemented",
+          "(RW)ByteAddressBuffer::Load(in address, out status) not supported",
           expr->getExprLoc());
           expr->getExprLoc());
       return 0;
       return 0;
     }
     }
@@ -2512,8 +2509,9 @@ SpirvEvalInfo SPIRVEmitter::processByteAddressBufferLoadStore(
 SpirvEvalInfo
 SpirvEvalInfo
 SPIRVEmitter::processStructuredBufferLoad(const CXXMemberCallExpr *expr) {
 SPIRVEmitter::processStructuredBufferLoad(const CXXMemberCallExpr *expr) {
   if (expr->getNumArgs() == 2) {
   if (expr->getNumArgs() == 2) {
-    emitError("(RW)StructuredBuffer::Load(int, int) unimplemented",
-              expr->getExprLoc());
+    emitError(
+        "(RW)StructuredBuffer::Load(in location, out status) not supported",
+        expr->getExprLoc());
     return 0;
     return 0;
   }
   }
 
 
@@ -2644,19 +2642,6 @@ void SPIRVEmitter::handleOffsetInMethodCall(const CXXMemberCallExpr *expr,
     *varOffset = doExpr(expr->getArg(index));
     *varOffset = doExpr(expr->getArg(index));
 };
 };
 
 
-void SPIRVEmitter::handleOptionalOffsetInMethodCall(
-    const CXXMemberCallExpr *expr, uint32_t index, uint32_t *constOffset,
-    uint32_t *varOffset) {
-  *constOffset = *varOffset = 0; // Initialize both first
-
-  if (expr->getNumArgs() == index + 1) { // Has offset argument
-    if (*constOffset = tryToEvaluateAsConst(expr->getArg(index)))
-      return; // Constant offset
-    else
-      *varOffset = doExpr(expr->getArg(index));
-  }
-}
-
 SpirvEvalInfo
 SpirvEvalInfo
 SPIRVEmitter::processIntrinsicMemberCall(const CXXMemberCallExpr *expr,
 SPIRVEmitter::processIntrinsicMemberCall(const CXXMemberCallExpr *expr,
                                          hlsl::IntrinsicOp opcode) {
                                          hlsl::IntrinsicOp opcode) {
@@ -3074,12 +3059,38 @@ SPIRVEmitter::processTextureSampleCmpCmpLevelZero(const CXXMemberCallExpr *expr,
 SpirvEvalInfo
 SpirvEvalInfo
 SPIRVEmitter::processBufferTextureLoad(const CXXMemberCallExpr *expr) {
 SPIRVEmitter::processBufferTextureLoad(const CXXMemberCallExpr *expr) {
   // Signature:
   // Signature:
+  // For Texture1D, Texture1DArray, Texture2D, Texture2DArray, Texture3D:
+  // ret Object.Load(int Location
+  //                 [, int Offset]
+  //                 [, uint status]);
+  //
+  // For Texture2DMS and Texture2DMSArray, there is one additional argument:
   // ret Object.Load(int Location
   // ret Object.Load(int Location
   //                 [, int SampleIndex]
   //                 [, int SampleIndex]
-  //                 [, int Offset]);
+  //                 [, int Offset]
+  //                 [, uint status]);
+  //
+  // For (RW)Buffer, RWTexture1D, RWTexture1DArray, RWTexture2D,
+  // RWTexture2DArray, RWTexture3D: 
+  // ret Object.Load (int Location
+  //                  [, uint status]);
+  //
+  // Note: (RW)ByteAddressBuffer and (RW)StructuredBuffer types also have Load
+  // methods that take an additional Status argument. However, since these types
+  // are not represented as OpTypeImage in SPIR-V, we don't have a way of
+  // figuring out the Residency Code for them. Therefore having the Status
+  // argument for these types is not supported.
+  //
+  // For (RW)ByteAddressBuffer:
+  // ret Object.{Load,Load2,Load3,Load4} (int Location
+  //                                      [, uint status]);
+  //
+  // For (RW)StructuredBuffer:
+  // ret Object.Load (int Location
+  //                  [, uint status]);
+  //
 
 
   const auto *object = expr->getImplicitObjectArgument();
   const auto *object = expr->getImplicitObjectArgument();
-  const auto *location = expr->getArg(0);
   const auto objectType = object->getType();
   const auto objectType = object->getType();
 
 
   if (typeTranslator.isRWByteAddressBuffer(objectType) ||
   if (typeTranslator.isRWByteAddressBuffer(objectType) ||
@@ -3089,10 +3100,23 @@ SPIRVEmitter::processBufferTextureLoad(const CXXMemberCallExpr *expr) {
   if (TypeTranslator::isStructuredBuffer(objectType))
   if (TypeTranslator::isStructuredBuffer(objectType))
     return processStructuredBufferLoad(expr);
     return processStructuredBufferLoad(expr);
 
 
+  const auto numArgs = expr->getNumArgs();
+  const auto *location = expr->getArg(0);
+  const bool isTextureMS = TypeTranslator::isTextureMS(objectType);
+  const bool hasStatusArg =
+      expr->getArg(numArgs - 1)->getType()->isUnsignedIntegerType();
+  const auto status = hasStatusArg ? doExpr(expr->getArg(numArgs - 1)) : 0;
+
   if (TypeTranslator::isBuffer(objectType) ||
   if (TypeTranslator::isBuffer(objectType) ||
-      TypeTranslator::isRWBuffer(objectType) ||
-      TypeTranslator::isRWTexture(objectType))
-    return processBufferTextureLoad(object, doExpr(location));
+    TypeTranslator::isRWBuffer(objectType) ||
+    TypeTranslator::isRWTexture(objectType))
+    return processBufferTextureLoad(object, doExpr(location), /*constOffset*/ 0,
+                                    /*varOffset*/ 0, /*lod*/ 0,
+                                    /*residencyCode*/ status);
+
+  // Subtract 1 for status (if it exists), and 1 for sampleIndex (if it exists),
+  // and 1 for location.
+  const bool hasOffsetArg = numArgs - hasStatusArg - isTextureMS - 1 > 0;
 
 
   if (TypeTranslator::isTexture(objectType)) {
   if (TypeTranslator::isTexture(objectType)) {
     // .Load() has a second optional paramter for offset.
     // .Load() has a second optional paramter for offset.
@@ -3100,12 +3124,13 @@ SPIRVEmitter::processBufferTextureLoad(const CXXMemberCallExpr *expr) {
     uint32_t constOffset = 0, varOffset = 0;
     uint32_t constOffset = 0, varOffset = 0;
     uint32_t coordinate = locationId, lod = 0;
     uint32_t coordinate = locationId, lod = 0;
 
 
-    if (TypeTranslator::isTextureMS(objectType)) {
+    if (isTextureMS) {
       // SampleIndex is only available when the Object is of Texture2DMS or
       // SampleIndex is only available when the Object is of Texture2DMS or
       // Texture2DMSArray types. Under those cases, Offset will be the third
       // Texture2DMSArray types. Under those cases, Offset will be the third
       // parameter (index 2).
       // parameter (index 2).
       lod = doExpr(expr->getArg(1));
       lod = doExpr(expr->getArg(1));
-      handleOptionalOffsetInMethodCall(expr, 2, &constOffset, &varOffset);
+      if(hasOffsetArg)
+        handleOffsetInMethodCall(expr, 2, &constOffset, &varOffset);
     } else {
     } else {
       // For Texture Load() functions, the location parameter is a vector
       // For Texture Load() functions, the location parameter is a vector
       // that consists of both the coordinate and the mipmap level (via the
       // that consists of both the coordinate and the mipmap level (via the
@@ -3114,11 +3139,12 @@ SPIRVEmitter::processBufferTextureLoad(const CXXMemberCallExpr *expr) {
       splitVecLastElement(location->getType(), locationId, &coordinate, &lod);
       splitVecLastElement(location->getType(), locationId, &coordinate, &lod);
       // For textures other than Texture2DMS(Array), offset should be the
       // For textures other than Texture2DMS(Array), offset should be the
       // second parameter (index 1).
       // second parameter (index 1).
-      handleOptionalOffsetInMethodCall(expr, 1, &constOffset, &varOffset);
+      if(hasOffsetArg)
+        handleOffsetInMethodCall(expr, 1, &constOffset, &varOffset);
     }
     }
 
 
     return processBufferTextureLoad(object, coordinate, constOffset, varOffset,
     return processBufferTextureLoad(object, coordinate, constOffset, varOffset,
-                                    lod);
+                                    lod, status);
   }
   }
   emitError("Load() of the given object type unimplemented",
   emitError("Load() of the given object type unimplemented",
             object->getExprLoc());
             object->getExprLoc());
@@ -3158,13 +3184,15 @@ SPIRVEmitter::doCXXOperatorCallExpr(const CXXOperatorCallExpr *expr) {
                                ? theBuilder.getConstantUint32(0)
                                ? theBuilder.getConstantUint32(0)
                                : 0;
                                : 0;
       return processBufferTextureLoad(baseExpr, doExpr(indexExpr),
       return processBufferTextureLoad(baseExpr, doExpr(indexExpr),
-                                      /*constOffset*/ 0, /*varOffset*/ 0, lod);
+                                      /*constOffset*/ 0, /*varOffset*/ 0, lod,
+                                      /*residencyCode*/ 0);
     }
     }
     // .mips[][] or .sample[][] must use the correct slice.
     // .mips[][] or .sample[][] must use the correct slice.
     if (isTextureMipsSampleIndexing(expr, &baseExpr, &indexExpr, &lodExpr)) {
     if (isTextureMipsSampleIndexing(expr, &baseExpr, &indexExpr, &lodExpr)) {
       const uint32_t lod = doExpr(lodExpr);
       const uint32_t lod = doExpr(lodExpr);
       return processBufferTextureLoad(baseExpr, doExpr(indexExpr),
       return processBufferTextureLoad(baseExpr, doExpr(indexExpr),
-                                      /*constOffset*/ 0, /*varOffset*/ 0, lod);
+                                      /*constOffset*/ 0, /*varOffset*/ 0, lod,
+                                      /*residencyCode*/ 0);
     }
     }
   }
   }
 
 

+ 5 - 11
tools/clang/lib/SPIRV/SPIRVEmitter.h

@@ -576,14 +576,6 @@ private:
   void processSwitchStmtUsingIfStmts(const SwitchStmt *switchStmt);
   void processSwitchStmtUsingIfStmts(const SwitchStmt *switchStmt);
 
 
 private:
 private:
-  /// Handles the optional offset argument in the given method call at the given
-  /// argument index.
-  /// If there exists an offset argument, writes the <result-id> to either
-  /// *constOffset or *varOffset, depending on the constantness of the offset.
-  void handleOptionalOffsetInMethodCall(const CXXMemberCallExpr *expr,
-                                        uint32_t index, uint32_t *constOffset,
-                                        uint32_t *varOffset);
-
   /// Handles the offset argument in the given method call at the given argument
   /// 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
   /// index. Panics if the argument at the given index does not exist. Writes
   /// the <result-id> to either *constOffset or *varOffset, depending on the
   /// the <result-id> to either *constOffset or *varOffset, depending on the
@@ -598,10 +590,12 @@ private:
   /// \brief Loads one element from the given Buffer/RWBuffer/Texture object at
   /// \brief Loads one element from the given Buffer/RWBuffer/Texture object at
   /// the given location. The type of the loaded element matches the type in the
   /// the given location. The type of the loaded element matches the type in the
   /// declaration for the Buffer/Texture object.
   /// declaration for the Buffer/Texture object.
+  /// If residencyCodeId is not zero,  the SPIR-V instruction for storing the
+  /// resulting residency code will also be emitted.
   SpirvEvalInfo processBufferTextureLoad(const Expr *object, uint32_t location,
   SpirvEvalInfo processBufferTextureLoad(const Expr *object, uint32_t location,
-                                         uint32_t constOffset = 0,
-                                         uint32_t varOffst = 0,
-                                         uint32_t lod = 0);
+                                         uint32_t constOffset,
+                                         uint32_t varOffset, uint32_t lod,
+                                         uint32_t residencyCode);
 
 
   /// \brief Processes .Sample() and .Gather() method calls for texture objects.
   /// \brief Processes .Sample() and .Gather() method calls for texture objects.
   uint32_t processTextureSampleGather(const CXXMemberCallExpr *expr,
   uint32_t processTextureSampleGather(const CXXMemberCallExpr *expr,

+ 42 - 15
tools/clang/test/CodeGenSPIRV/method.buffer.load.hlsl

@@ -15,66 +15,93 @@ RWBuffer<int4> int4buf;
 RWBuffer<uint4> uint4buf;
 RWBuffer<uint4> uint4buf;
 RWBuffer<float4> float4buf;
 RWBuffer<float4> float4buf;
 
 
+// CHECK: OpCapability SparseResidency
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4float
+
 void main() {
 void main() {
   int address;
   int address;
 
 
 // CHECK:      [[img1:%\d+]] = OpLoad %type_buffer_image %intbuf
 // CHECK:      [[img1:%\d+]] = OpLoad %type_buffer_image %intbuf
 // CHECK:      [[f1:%\d+]] = OpImageFetch %v4int [[img1]] {{%\d+}} None
 // CHECK:      [[f1:%\d+]] = OpImageFetch %v4int [[img1]] {{%\d+}} None
 // CHECK-NEXT: {{%\d+}} = OpCompositeExtract %int [[f1]] 0
 // CHECK-NEXT: {{%\d+}} = OpCompositeExtract %int [[f1]] 0
-  int int1 = intbuf.Load(address);
+  int i1 = intbuf.Load(address);
 
 
 // CHECK:      [[img2:%\d+]] = OpLoad %type_buffer_image_0 %uintbuf
 // CHECK:      [[img2:%\d+]] = OpLoad %type_buffer_image_0 %uintbuf
 // CHECK:      [[f2:%\d+]] = OpImageFetch %v4uint [[img2]] {{%\d+}} None
 // CHECK:      [[f2:%\d+]] = OpImageFetch %v4uint [[img2]] {{%\d+}} None
 // CHECK-NEXT: {{%\d+}} = OpCompositeExtract %uint [[f2]] 0
 // CHECK-NEXT: {{%\d+}} = OpCompositeExtract %uint [[f2]] 0
-  uint uint1 = uintbuf.Load(address);
+  uint u1 = uintbuf.Load(address);
 
 
 // CHECK:      [[img3:%\d+]] = OpLoad %type_buffer_image_1 %floatbuf
 // CHECK:      [[img3:%\d+]] = OpLoad %type_buffer_image_1 %floatbuf
 // CHECK:      [[f3:%\d+]] = OpImageFetch %v4float [[img3]] {{%\d+}} None
 // CHECK:      [[f3:%\d+]] = OpImageFetch %v4float [[img3]] {{%\d+}} None
 // CHECK-NEXT: {{%\d+}} = OpCompositeExtract %float [[f3]] 0
 // CHECK-NEXT: {{%\d+}} = OpCompositeExtract %float [[f3]] 0
-  float float1 = floatbuf.Load(address);
+  float f1 = floatbuf.Load(address);
 
 
 // CHECK:      [[img4:%\d+]] = OpLoad %type_buffer_image_2 %int2buf
 // CHECK:      [[img4:%\d+]] = OpLoad %type_buffer_image_2 %int2buf
 // CHECK:      [[f4:%\d+]] = OpImageRead %v4int [[img4]] {{%\d+}} None
 // CHECK:      [[f4:%\d+]] = OpImageRead %v4int [[img4]] {{%\d+}} None
 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v2int [[f4]] [[f4]] 0 1
 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v2int [[f4]] [[f4]] 0 1
-  int2 int2 = int2buf.Load(address);
+  int2 i2 = int2buf.Load(address);
 
 
 // CHECK:      [[img5:%\d+]] = OpLoad %type_buffer_image_3 %uint2buf
 // CHECK:      [[img5:%\d+]] = OpLoad %type_buffer_image_3 %uint2buf
 // CHECK:      [[f5:%\d+]] = OpImageRead %v4uint [[img5]] {{%\d+}} None
 // CHECK:      [[f5:%\d+]] = OpImageRead %v4uint [[img5]] {{%\d+}} None
 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v2uint [[f5]] [[f5]] 0 1
 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v2uint [[f5]] [[f5]] 0 1
-  uint2 uint2 = uint2buf.Load(address);
+  uint2 u2 = uint2buf.Load(address);
 
 
 // CHECK:      [[img6:%\d+]] = OpLoad %type_buffer_image_4 %float2buf
 // CHECK:      [[img6:%\d+]] = OpLoad %type_buffer_image_4 %float2buf
 // CHECK:      [[f6:%\d+]] = OpImageRead %v4float [[img6]] {{%\d+}} None
 // CHECK:      [[f6:%\d+]] = OpImageRead %v4float [[img6]] {{%\d+}} None
 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v2float [[f6]] [[f6]] 0 1
 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v2float [[f6]] [[f6]] 0 1
-  float2 float2 = float2buf.Load(address);
+  float2 f2 = float2buf.Load(address);
 
 
 // CHECK:      [[img7:%\d+]] = OpLoad %type_buffer_image_5 %int3buf
 // CHECK:      [[img7:%\d+]] = OpLoad %type_buffer_image_5 %int3buf
 // CHECK:      [[f7:%\d+]] = OpImageFetch %v4int [[img7]] {{%\d+}} None
 // CHECK:      [[f7:%\d+]] = OpImageFetch %v4int [[img7]] {{%\d+}} None
 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v3int [[f7]] [[f7]] 0 1 2
 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v3int [[f7]] [[f7]] 0 1 2
-  int3 int3 = int3buf.Load(address);
+  int3 i3 = int3buf.Load(address);
 
 
 // CHECK:      [[img8:%\d+]] = OpLoad %type_buffer_image_6 %uint3buf
 // CHECK:      [[img8:%\d+]] = OpLoad %type_buffer_image_6 %uint3buf
 // CHECK:      [[f8:%\d+]] = OpImageFetch %v4uint [[img8]] {{%\d+}} None
 // CHECK:      [[f8:%\d+]] = OpImageFetch %v4uint [[img8]] {{%\d+}} None
 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v3uint [[f8]] [[f8]] 0 1 2
 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v3uint [[f8]] [[f8]] 0 1 2
-  uint3 uint3 = uint3buf.Load(address);
+  uint3 u3 = uint3buf.Load(address);
 
 
 // CHECK:      [[img9:%\d+]] = OpLoad %type_buffer_image_7 %float3buf
 // CHECK:      [[img9:%\d+]] = OpLoad %type_buffer_image_7 %float3buf
 // CHECK:      [[f9:%\d+]] = OpImageFetch %v4float [[img9]] {{%\d+}} None
 // CHECK:      [[f9:%\d+]] = OpImageFetch %v4float [[img9]] {{%\d+}} None
 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v3float [[f9]] [[f9]] 0 1 2
 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v3float [[f9]] [[f9]] 0 1 2
-  float3 float3 = float3buf.Load(address);
+  float3 f3 = float3buf.Load(address);
 
 
 // CHECK:      [[img10:%\d+]] = OpLoad %type_buffer_image_8 %int4buf
 // CHECK:      [[img10:%\d+]] = OpLoad %type_buffer_image_8 %int4buf
 // CHECK:      {{%\d+}} = OpImageRead %v4int [[img10]] {{%\d+}} None
 // CHECK:      {{%\d+}} = OpImageRead %v4int [[img10]] {{%\d+}} None
-// CHECK-NEXT: OpStore %int4 {{%\d+}}
-  int4 int4 = int4buf.Load(address);
+// CHECK-NEXT: OpStore %i4 {{%\d+}}
+  int4 i4 = int4buf.Load(address);
 
 
 // CHECK:      [[img11:%\d+]] = OpLoad %type_buffer_image_9 %uint4buf
 // CHECK:      [[img11:%\d+]] = OpLoad %type_buffer_image_9 %uint4buf
 // CHECK:      {{%\d+}} = OpImageRead %v4uint [[img11]] {{%\d+}} None
 // CHECK:      {{%\d+}} = OpImageRead %v4uint [[img11]] {{%\d+}} None
-// CHECK-NEXT: OpStore %uint4 {{%\d+}}
-  uint4 uint4 = uint4buf.Load(address);
+// CHECK-NEXT: OpStore %u4 {{%\d+}}
+  uint4 u4 = uint4buf.Load(address);
 
 
 // CHECK:      [[img12:%\d+]] = OpLoad %type_buffer_image_10 %float4buf
 // CHECK:      [[img12:%\d+]] = OpLoad %type_buffer_image_10 %float4buf
 // CHECK:      {{%\d+}} = OpImageRead %v4float [[img12]] {{%\d+}} None
 // CHECK:      {{%\d+}} = OpImageRead %v4float [[img12]] {{%\d+}} None
-// CHECK-NEXT: OpStore %float4 {{%\d+}}
-  float4 float4 = float4buf.Load(address);
+// CHECK-NEXT: OpStore %f4 {{%\d+}}
+  float4 f4 = float4buf.Load(address);
+
+///////////////////////////////
+// Using the Status argument //  
+///////////////////////////////
+  uint status;
+
+// CHECK:              [[img3:%\d+]] = OpLoad %type_buffer_image_1 %floatbuf
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseFetch %SparseResidencyStruct [[img3]] {{%\d+}} None
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:     [[v4result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %float [[v4result]] 0
+// CHECK-NEXT:                         OpStore %r1 [[result]]
+  float  r1 = floatbuf.Load(address, status);  // Test for Buffer
+
+// CHECK:              [[img6:%\d+]] = OpLoad %type_buffer_image_4 %float2buf
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseRead %SparseResidencyStruct [[img6]] {{%\d+}} None
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:     [[v4result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:       [[result:%\d+]] = OpVectorShuffle %v2float [[v4result]] [[v4result]] 0 1
+// CHECK-NEXT:                         OpStore %r2 [[result]]
+  float2 r2 = float2buf.Load(address, status);  // Test for RWBuffer
 }
 }

+ 51 - 0
tools/clang/test/CodeGenSPIRV/method.rwtexture.load.hlsl

@@ -6,6 +6,12 @@ RWTexture3D<float3> float3buf;
 RWTexture1DArray<float4> float4buf;
 RWTexture1DArray<float4> float4buf;
 RWTexture2DArray<int3> int3buf;
 RWTexture2DArray<int3> int3buf;
 
 
+// CHECK: OpCapability SparseResidency
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4int
+// CHECK: %SparseResidencyStruct_0 = OpTypeStruct %uint %v4uint
+// CHECK: %SparseResidencyStruct_1 = OpTypeStruct %uint %v4float
+
 void main() {
 void main() {
 
 
 // CHECK:      [[img1:%\d+]] = OpLoad %type_1d_image %intbuf
 // CHECK:      [[img1:%\d+]] = OpLoad %type_1d_image %intbuf
@@ -36,4 +42,49 @@ void main() {
 // CHECK-NEXT: [[r5:%\d+]] = OpVectorShuffle %v3int [[ret5]] [[ret5]] 0 1 2
 // CHECK-NEXT: [[r5:%\d+]] = OpVectorShuffle %v3int [[ret5]] [[ret5]] 0 1 2
 // CHECK-NEXT: OpStore %e [[r5]]
 // CHECK-NEXT: OpStore %e [[r5]]
   int3 e   = int3buf.Load(0);
   int3 e   = int3buf.Load(0);
+
+  uint status;
+// CHECK:              [[img1:%\d+]] = OpLoad %type_1d_image %intbuf
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseRead %SparseResidencyStruct [[img1]] %int_0 None
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:     [[v4result:%\d+]] = OpCompositeExtract %v4int [[structResult]] 1
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %int [[v4result]] 0
+// CHECK-NEXT:                         OpStore %a2 [[result]]
+  int    a2 = intbuf.Load(0, status);
+
+// CHECK:              [[img2:%\d+]] = OpLoad %type_2d_image %uint2buf
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseRead %SparseResidencyStruct_0 [[img2]] {{%\d+}} None
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:     [[v4result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:       [[result:%\d+]] = OpVectorShuffle %v2uint [[v4result]] [[v4result]] 0 1
+// CHECK-NEXT:                         OpStore %b2 [[result]]
+  uint2  b2 = uint2buf.Load(0, status);
+
+// CHECK:              [[img3:%\d+]] = OpLoad %type_3d_image %float3buf
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseRead %SparseResidencyStruct_1 [[img3]] {{%\d+}} None
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:     [[v4result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:       [[result:%\d+]] = OpVectorShuffle %v3float [[v4result]] [[v4result]] 0 1 2
+// CHECK-NEXT:                         OpStore %c2 [[result]]
+  float3 c2 = float3buf.Load(0, status);
+
+// CHECK:              [[img4:%\d+]] = OpLoad %type_1d_image_array %float4buf
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseRead %SparseResidencyStruct_1 [[img4]] {{%\d+}} None
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:     [[v4result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %d2 [[v4result]]
+  float4 d2 = float4buf.Load(0, status);
+
+// CHECK:              [[img5:%\d+]] = OpLoad %type_2d_image_array %int3buf
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseRead %SparseResidencyStruct [[img5]] {{%\d+}} None
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:     [[v4result:%\d+]] = OpCompositeExtract %v4int [[structResult]] 1
+// CHECK-NEXT:       [[result:%\d+]] = OpVectorShuffle %v3int [[v4result]] [[v4result]] 0 1 2
+// CHECK-NEXT:                         OpStore %e2 [[result]]
+  int3   e2 = int3buf.Load(0, status);
 }
 }

+ 27 - 4
tools/clang/test/CodeGenSPIRV/texture.array.load.hlsl

@@ -4,7 +4,12 @@ Texture1DArray <float4> t1 : register(t1);
 Texture2DArray <float4> t2 : register(t2);
 Texture2DArray <float4> t2 : register(t2);
 // .Load() does not support TextureCubeArray.
 // .Load() does not support TextureCubeArray.
 
 
+// CHECK: OpCapability SparseResidency
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4float
+
 // CHECK: [[v3ic:%\d+]] = OpConstantComposite %v3int %int_1 %int_2 %int_3
 // CHECK: [[v3ic:%\d+]] = OpConstantComposite %v3int %int_1 %int_2 %int_3
+// CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
 
 
 float4 main(int4 location: A) : SV_Target {
 float4 main(int4 location: A) : SV_Target {
 
 
@@ -21,9 +26,27 @@ float4 main(int4 location: A) : SV_Target {
 // CHECK-NEXT:       {{%\d+}} = OpImageFetch %v4float [[t2]] [[coord]] Lod [[lod]]
 // CHECK-NEXT:       {{%\d+}} = OpImageFetch %v4float [[t2]] [[coord]] Lod [[lod]]
     float4 val2 = t2.Load(location);
     float4 val2 = t2.Load(location);
 
 
+    uint status;
+// CHECK:            [[coord:%\d+]] = OpVectorShuffle %v2int [[v3ic]] [[v3ic]] 0 1
+// CHECK-NEXT:         [[lod:%\d+]] = OpCompositeExtract %int [[v3ic]] 2
+// CHECK-NEXT:          [[t1:%\d+]] = OpLoad %type_1d_image_array %t1
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseFetch %SparseResidencyStruct [[t1]] [[coord]] Lod|ConstOffset [[lod]] %int_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 %val3 [[result]]
+    float4 val3 = t1.Load(int3(1, 2, 3), 10, status);
+
+// CHECK:              [[loc:%\d+]] = OpLoad %v4int %location
+// CHECK-NEXT:       [[coord:%\d+]] = OpVectorShuffle %v3int [[loc]] [[loc]] 0 1 2
+// CHECK-NEXT:         [[lod:%\d+]] = OpCompositeExtract %int [[loc]] 3
+// CHECK-NEXT:          [[t2:%\d+]] = OpLoad %type_2d_image_array %t2
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseFetch %SparseResidencyStruct [[t2]] [[coord]] Lod|ConstOffset [[lod]] [[v2ic]]
+// 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.Load(location, int2(1, 2), status);
+    
     return 1.0;
     return 1.0;
 }
 }
-
-
-
-

+ 68 - 0
tools/clang/test/CodeGenSPIRV/texture.load.hlsl

@@ -13,12 +13,18 @@ Texture2DMS     <float>  t7 : register(t7);
 Texture2DMSArray<float3> t8 : register(t8);
 Texture2DMSArray<float3> t8 : register(t8);
 
 
 // CHECK: OpCapability ImageGatherExtended
 // CHECK: OpCapability ImageGatherExtended
+// CHECK: OpCapability SparseResidency
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4float
+// CHECK: %SparseResidencyStruct_0 = OpTypeStruct %uint %v4int
+// CHECK: %SparseResidencyStruct_1 = OpTypeStruct %uint %v4uint
 
 
 // CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
 // CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
 // CHECK: [[v4ic:%\d+]] = OpConstantComposite %v4int %int_1 %int_2 %int_3 %int_4
 // CHECK: [[v4ic:%\d+]] = OpConstantComposite %v4int %int_1 %int_2 %int_3 %int_4
 // CHECK: [[v3ic:%\d+]] = OpConstantComposite %v3int %int_3 %int_3 %int_3
 // CHECK: [[v3ic:%\d+]] = OpConstantComposite %v3int %int_3 %int_3 %int_3
 
 
 float4 main(int3 location: A, int offset: B) : SV_Target {
 float4 main(int3 location: A, int offset: B) : SV_Target {
+    uint status;
 
 
 // CHECK:      [[coord:%\d+]] = OpCompositeExtract %int [[v2ic]] 0
 // CHECK:      [[coord:%\d+]] = OpCompositeExtract %int [[v2ic]] 0
 // CHECK-NEXT:   [[lod:%\d+]] = OpCompositeExtract %int [[v2ic]] 1
 // CHECK-NEXT:   [[lod:%\d+]] = OpCompositeExtract %int [[v2ic]] 1
@@ -88,5 +94,67 @@ float4 main(int3 location: A, int offset: B) : SV_Target {
 // CHECK-NEXT:     {{%\d+}} = OpVectorShuffle %v3float [[f81]] [[f81]] 0 1 2
 // CHECK-NEXT:     {{%\d+}} = OpVectorShuffle %v3float [[f81]] [[f81]] 0 1 2
     val8 = t8.Load(pos3, sampleIndex, int2(1,2));
     val8 = t8.Load(pos3, sampleIndex, int2(1,2));
 
 
+/////////////////////////////////
+/// Using the Status argument ///
+/////////////////////////////////
+
+// CHECK:            [[coord:%\d+]] = OpCompositeExtract %int [[v2ic]] 0
+// CHECK-NEXT:         [[lod:%\d+]] = OpCompositeExtract %int [[v2ic]] 1
+// CHECK-NEXT:      [[offset:%\d+]] = OpLoad %int %offset
+// CHECK-NEXT:          [[t4:%\d+]] = OpLoad %type_1d_image %t4
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseFetch %SparseResidencyStruct [[t4]] [[coord]] Lod|Offset [[lod]] [[offset]]
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:    [[v4result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:      [[result:%\d+]] = OpCompositeExtract %float [[v4result]] 0
+// CHECK-NEXT:                        OpStore %val14 [[result]]
+    float  val14 = t4.Load(int2(1,2), offset, status);
+
+// CHECK:              [[loc:%\d+]] = OpLoad %v3int %location
+// CHECK-NEXT:       [[coord:%\d+]] = OpVectorShuffle %v2int [[loc]] [[loc]] 0 1
+// CHECK-NEXT:         [[lod:%\d+]] = OpCompositeExtract %int [[loc]] 2
+// CHECK-NEXT:          [[t5:%\d+]] = OpLoad %type_2d_image_0 %t5
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseFetch %SparseResidencyStruct_0 [[t5]] [[coord]] Lod|ConstOffset [[lod]] [[v2ic]]
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:    [[v4result:%\d+]] = OpCompositeExtract %v4int [[structResult]] 1
+// CHECK-NEXT:      [[result:%\d+]] = OpVectorShuffle %v2int [[v4result]] [[v4result]] 0 1
+// CHECK-NEXT:                        OpStore %val15 [[result]]
+    int2   val15 = t5.Load(location, int2(1,2), status);
+
+// CHECK:            [[coord:%\d+]] = OpVectorShuffle %v3int [[v4ic]] [[v4ic]] 0 1 2
+// CHECK-NEXT:         [[lod:%\d+]] = OpCompositeExtract %int [[v4ic]] 3
+// CHECK-NEXT:          [[t6:%\d+]] = OpLoad %type_3d_image_0 %t6
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseFetch %SparseResidencyStruct_1 [[t6]] [[coord]] Lod|ConstOffset [[lod]] [[v3ic]]
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:    [[v4result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
+// CHECK-NEXT:      [[result:%\d+]] = OpVectorShuffle %v3uint [[v4result]] [[v4result]] 0 1 2
+// CHECK-NEXT:                        OpStore %val16 [[result]]
+    uint3  val16 = t6.Load(int4(1, 2, 3, 4), 3, status);
+
+// CHECK:             [[pos1:%\d+]] = OpLoad %v2int %pos2
+// CHECK-NEXT:         [[si1:%\d+]] = OpLoad %int %sampleIndex
+// CHECK-NEXT:     [[offset2:%\d+]] = OpLoad %v2int %offset2
+// CHECK-NEXT:         [[t71:%\d+]] = OpLoad %type_2d_image_1 %t7
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseFetch %SparseResidencyStruct [[t71]] [[pos1]] Offset|Sample [[offset2]] [[si1]]
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:    [[v4result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:      [[result:%\d+]] = OpCompositeExtract %float [[v4result]] 0
+// CHECK-NEXT:                        OpStore %val17 [[result]]
+    float  val17 = t7.Load(pos2, sampleIndex, offset2, status);
+
+// CHECK:             [[pos3:%\d+]] = OpLoad %v3int %pos3
+// CHECK-NEXT:         [[si3:%\d+]] = OpLoad %int %sampleIndex
+// CHECK-NEXT:         [[t81:%\d+]] = OpLoad %type_2d_image_array %t8
+// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseFetch %SparseResidencyStruct [[t81]] [[pos3]] ConstOffset|Sample [[v2ic]] [[si3]]
+// CHECK-NEXT:      [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                        OpStore %status [[status]]
+// CHECK-NEXT:    [[v4result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:      [[result:%\d+]] = OpVectorShuffle %v3float [[v4result]] [[v4result]] 0 1 2
+// CHECK-NEXT:                        OpStore %val18 [[result]]
+    float3 val18 = t8.Load(pos3, sampleIndex, int2(1,2), status);
+    
     return 1.0;
     return 1.0;
 }
 }