Ver código fonte

[spirv] Better reflection support via new extensions (#1111)

This commit uses the HlslCounterBufferGOOGLE decoration to link
the main RW/Append/Consume StructuredBuffer with its associated
counter buffer. It also uses HLSLSemanticGOOGLE to decorate
stage IO variables with their semantic strings from the source code.
Lei Zhang 7 anos atrás
pai
commit
0d8a15a61a
27 arquivos alterados com 341 adições e 60 exclusões
  1. 19 0
      docs/SPIR-V.rst
  2. 1 0
      include/dxc/Support/HLSLOptions.h
  3. 2 0
      include/dxc/Support/HLSLOptions.td
  4. 2 0
      lib/DxcSupport/HLSLOptions.cpp
  5. 14 2
      tools/clang/include/clang/SPIRV/Decoration.h
  6. 1 0
      tools/clang/include/clang/SPIRV/EmitSPIRVOptions.h
  7. 11 1
      tools/clang/include/clang/SPIRV/ModuleBuilder.h
  8. 11 4
      tools/clang/lib/SPIRV/DeclResultIdMapper.cpp
  9. 4 1
      tools/clang/lib/SPIRV/DeclResultIdMapper.h
  10. 33 7
      tools/clang/lib/SPIRV/Decoration.cpp
  11. 61 15
      tools/clang/lib/SPIRV/GlPerVertex.cpp
  12. 10 4
      tools/clang/lib/SPIRV/GlPerVertex.h
  13. 26 3
      tools/clang/lib/SPIRV/ModuleBuilder.cpp
  14. 6 4
      tools/clang/lib/SPIRV/SPIRVEmitter.cpp
  15. 10 3
      tools/clang/lib/SPIRV/TypeTranslator.cpp
  16. 4 2
      tools/clang/lib/SPIRV/TypeTranslator.h
  17. 22 1
      tools/clang/test/CodeGenSPIRV/spirv.interface.ds.hlsl
  18. 16 2
      tools/clang/test/CodeGenSPIRV/spirv.interface.gs.hlsl
  19. 23 1
      tools/clang/test/CodeGenSPIRV/spirv.interface.hs.hlsl
  20. 10 1
      tools/clang/test/CodeGenSPIRV/spirv.interface.ps.hlsl
  21. 16 1
      tools/clang/test/CodeGenSPIRV/spirv.interface.vs.hlsl
  22. 11 1
      tools/clang/test/CodeGenSPIRV/spirv.legal.sbuffer.counter.hlsl
  23. 6 1
      tools/clang/test/CodeGenSPIRV/type.append-structured-buffer.hlsl
  24. 6 1
      tools/clang/test/CodeGenSPIRV/type.consume-structured-buffer.hlsl
  25. 11 1
      tools/clang/test/CodeGenSPIRV/type.structured-buffer.hlsl
  26. 1 0
      tools/clang/tools/dxcompiler/dxcompilerobj.cpp
  27. 4 4
      tools/clang/unittests/SPIRV/ModuleBuilderTest.cpp

+ 19 - 0
docs/SPIR-V.rst

@@ -365,6 +365,24 @@ operand in ``OpSource`` instruction. For ``*s_<major>_<minor>``, the "Verison"
 operand in ``OpSource`` will be set as ``<major>`` * 100 + ``<minor>`` * 10.
 operand in ``OpSource`` will be set as ``<major>`` * 100 + ``<minor>`` * 10.
 For example, ``vs_5_1`` will have 510, ``ps_6_2`` will have 620.
 For example, ``vs_5_1`` will have 510, ``ps_6_2`` will have 620.
 
 
+HLSL Semantic
+~~~~~~~~~~~~~
+
+HLSL semantic strings are by default not emitted into the SPIR-V binary module.
+If you need them, by specifying ``-fspv-reflect``, the compiler will use
+the ``Op*DecorateStringGOOGLE`` instruction in `SPV_GOOGLE_hlsl_funtionality1 <https://github.com/KhronosGroup/SPIRV-Registry/blob/master/extensions/GOOGLE/SPV_GOOGLE_hlsl_functionality1.asciidoc>`_
+extension to emit them.
+
+Counter buffers for RW/Append/Consume StructuredBuffer
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The association between a counter buffer and its main RW/Append/Consume
+StructuredBuffer is conveyed by ``OpDecorateId <structured-buffer-id>
+HLSLCounterBufferGOOGLE <counter-buffer-id>`` instruction from the
+`SPV_GOOGLE_hlsl_funtionality1 <https://github.com/KhronosGroup/SPIRV-Registry/blob/master/extensions/GOOGLE/SPV_GOOGLE_hlsl_functionality1.asciidoc>`_
+extension. This information is by default missing; you need to specify
+``-fspv-reflect`` to direct the compiler to emit them.
+
 Read-only vs. read-write resource types
 Read-only vs. read-write resource types
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 
@@ -2608,6 +2626,7 @@ codegen for Vulkan:
 - ``-fvk-stage-io-order={alpha|decl}``: Assigns the stage input/output variable
 - ``-fvk-stage-io-order={alpha|decl}``: Assigns the stage input/output variable
   location number according to alphabetical order or declaration order. See
   location number according to alphabetical order or declaration order. See
   `HLSL semantic and Vulkan Location`_ for more details.
   `HLSL semantic and Vulkan Location`_ for more details.
+- ``-fspv-reflect``: Emits additional SPIR-V instructions to aid reflection.
 
 
 Unsupported HLSL Features
 Unsupported HLSL Features
 =========================
 =========================

+ 1 - 0
include/dxc/Support/HLSLOptions.h

@@ -163,6 +163,7 @@ public:
   bool VkIgnoreUnusedResources; // OPT_fvk_ignore_used_resources
   bool VkIgnoreUnusedResources; // OPT_fvk_ignore_used_resources
   bool VkInvertY; // OPT_fvk_invert_y
   bool VkInvertY; // OPT_fvk_invert_y
   bool VkUseGlslLayout; // OPT_fvk_use_glsl_layout
   bool VkUseGlslLayout; // OPT_fvk_use_glsl_layout
+  bool SpvEnableReflect; // OPT_fspv_reflect
   llvm::StringRef VkStageIoOrder; // OPT_fvk_stage_io_order
   llvm::StringRef VkStageIoOrder; // OPT_fvk_stage_io_order
   llvm::SmallVector<uint32_t, 4> VkBShift; // OPT_fvk_b_shift
   llvm::SmallVector<uint32_t, 4> VkBShift; // OPT_fvk_b_shift
   llvm::SmallVector<uint32_t, 4> VkTShift; // OPT_fvk_t_shift
   llvm::SmallVector<uint32_t, 4> VkTShift; // OPT_fvk_t_shift

+ 2 - 0
include/dxc/Support/HLSLOptions.td

@@ -252,6 +252,8 @@ def fvk_invert_y: Flag<["-"], "fvk-invert-y">, Group<spirv_Group>, Flags<[CoreOp
   HelpText<"Invert SV_Position.y in VS/DS/GS to accommodate Vulkan's coordinate system">;
   HelpText<"Invert SV_Position.y in VS/DS/GS to accommodate Vulkan's coordinate system">;
 def fvk_use_glsl_layout: Flag<["-"], "fvk-use-glsl-layout">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
 def fvk_use_glsl_layout: Flag<["-"], "fvk-use-glsl-layout">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
   HelpText<"Use conventional GLSL std140/std430 layout for resources">;
   HelpText<"Use conventional GLSL std140/std430 layout for resources">;
+def fspv_reflect: Flag<["-"], "fspv-reflect">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
+  HelpText<"Emit additional SPIR-V instructions to aid reflection">;
 // SPIRV Change Ends
 // SPIRV Change Ends
 
 
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////

+ 2 - 0
lib/DxcSupport/HLSLOptions.cpp

@@ -484,6 +484,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
   const bool genSpirv = opts.GenSPIRV = Args.hasFlag(OPT_spirv, OPT_INVALID, false);
   const bool genSpirv = opts.GenSPIRV = Args.hasFlag(OPT_spirv, OPT_INVALID, false);
   opts.VkInvertY = Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false);
   opts.VkInvertY = Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false);
   opts.VkUseGlslLayout = Args.hasFlag(OPT_fvk_use_glsl_layout, OPT_INVALID, false);
   opts.VkUseGlslLayout = Args.hasFlag(OPT_fvk_use_glsl_layout, OPT_INVALID, false);
+  opts.SpvEnableReflect = Args.hasFlag(OPT_fspv_reflect, OPT_INVALID, false);
   opts.VkIgnoreUnusedResources = Args.hasFlag(OPT_fvk_ignore_unused_resources, OPT_INVALID, false);
   opts.VkIgnoreUnusedResources = Args.hasFlag(OPT_fvk_ignore_unused_resources, OPT_INVALID, false);
 
 
   // Collects the arguments for -fvk-{b|s|t|u}-shift.
   // Collects the arguments for -fvk-{b|s|t|u}-shift.
@@ -524,6 +525,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
   if (Args.hasFlag(OPT_spirv, OPT_INVALID, false) ||
   if (Args.hasFlag(OPT_spirv, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_use_glsl_layout, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_use_glsl_layout, OPT_INVALID, false) ||
+      Args.hasFlag(OPT_fspv_reflect, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_ignore_unused_resources, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_ignore_unused_resources, OPT_INVALID, false) ||
       !Args.getLastArgValue(OPT_fvk_stage_io_order_EQ).empty() ||
       !Args.getLastArgValue(OPT_fvk_stage_io_order_EQ).empty() ||
       !Args.getLastArgValue(OPT_fvk_b_shift).empty() ||
       !Args.getLastArgValue(OPT_fvk_b_shift).empty() ||

+ 14 - 2
tools/clang/include/clang/SPIRV/Decoration.h

@@ -12,8 +12,10 @@
 #include <vector>
 #include <vector>
 
 
 #include "spirv/unified1/spirv.hpp11"
 #include "spirv/unified1/spirv.hpp11"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
 
 
 namespace clang {
 namespace clang {
 namespace spirv {
 namespace spirv {
@@ -129,6 +131,11 @@ public:
   static const Decoration *getViewportRelativeNV(SPIRVContext &ctx);
   static const Decoration *getViewportRelativeNV(SPIRVContext &ctx);
   static const Decoration *getSecondaryViewportRelativeNV(SPIRVContext &ctx,
   static const Decoration *getSecondaryViewportRelativeNV(SPIRVContext &ctx,
                                                           uint32_t offset);
                                                           uint32_t offset);
+  static const Decoration *getHlslCounterBufferGOOGLE(SPIRVContext &ctx,
+                                                      uint32_t id);
+  static const Decoration *
+  getHlslSemanticGOOGLE(SPIRVContext &ctx, llvm::StringRef semantic,
+                        llvm ::Optional<uint32_t> memberIdx = llvm::None);
 
 
   bool operator==(const Decoration &other) const {
   bool operator==(const Decoration &other) const {
     return id == other.id && args == other.args &&
     return id == other.id && args == other.args &&
@@ -143,14 +150,19 @@ public:
 
 
 private:
 private:
   /// \brief prevent public APIs from creating Decoration objects.
   /// \brief prevent public APIs from creating Decoration objects.
-  Decoration(spv::Decoration dec_id, llvm::SmallVector<uint32_t, 2> arg = {},
+  Decoration(spv::Decoration dec_id, llvm::ArrayRef<uint32_t> arg = {},
              llvm::Optional<uint32_t> idx = llvm::None)
              llvm::Optional<uint32_t> idx = llvm::None)
-      : id(dec_id), args(arg), memberIndex(idx) {}
+      : id(dec_id), args(arg.begin(), arg.end()), memberIndex(idx) {}
 
 
   /// \brief Sets the index of the structure member to which the decoration
   /// \brief Sets the index of the structure member to which the decoration
   /// applies.
   /// applies.
   void setMemberIndex(llvm::Optional<uint32_t> idx) { memberIndex = idx; }
   void setMemberIndex(llvm::Optional<uint32_t> idx) { memberIndex = idx; }
 
 
+  /// \brief Returns the OpDecorate* variant to use for the given decoration and
+  /// struct member index.
+  static spv::Op getDecorateOpcode(spv::Decoration,
+                                   const llvm::Optional<uint32_t> &memberIndex);
+
   /// \brief Returns the unique decoration pointer within the given context.
   /// \brief Returns the unique decoration pointer within the given context.
   static const Decoration *getUniqueDecoration(SPIRVContext &ctx,
   static const Decoration *getUniqueDecoration(SPIRVContext &ctx,
                                                const Decoration &d);
                                                const Decoration &d);

+ 1 - 0
tools/clang/include/clang/SPIRV/EmitSPIRVOptions.h

@@ -23,6 +23,7 @@ struct EmitSPIRVOptions {
   bool useGlslLayout;
   bool useGlslLayout;
   bool ignoreUnusedResources;
   bool ignoreUnusedResources;
   bool enable16BitTypes;
   bool enable16BitTypes;
+  bool enableReflect;
   llvm::StringRef stageIoOrder;
   llvm::StringRef stageIoOrder;
   llvm::SmallVector<uint32_t, 4> bShift;
   llvm::SmallVector<uint32_t, 4> bShift;
   llvm::SmallVector<uint32_t, 4> tShift;
   llvm::SmallVector<uint32_t, 4> tShift;

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

@@ -35,7 +35,7 @@ namespace spirv {
 class ModuleBuilder {
 class ModuleBuilder {
 public:
 public:
   /// \brief Constructs a ModuleBuilder with the given SPIR-V context.
   /// \brief Constructs a ModuleBuilder with the given SPIR-V context.
-  explicit ModuleBuilder(SPIRVContext *);
+  explicit ModuleBuilder(SPIRVContext *, bool enablReflect);
 
 
   /// \brief Returns the associated SPIRVContext.
   /// \brief Returns the associated SPIRVContext.
   inline SPIRVContext *getSPIRVContext();
   inline SPIRVContext *getSPIRVContext();
@@ -381,6 +381,14 @@ public:
   /// attchment index number.
   /// attchment index number.
   void decorateInputAttachmentIndex(uint32_t targetId, uint32_t indexNumber);
   void decorateInputAttachmentIndex(uint32_t targetId, uint32_t indexNumber);
 
 
+  /// \brief Decorates the given main buffer with the given counter buffer.
+  void decorateCounterBufferId(uint32_t mainBufferId, uint32_t counterBufferId);
+
+  /// \brief Decorates the given target <result-id> with the given HLSL semantic
+  /// string.
+  void decorateHlslSemantic(uint32_t targetId, llvm::StringRef semantic,
+                            llvm::Optional<uint32_t> memberIdx = llvm::None);
+
   /// \brief Decorates the given target <result-id> with the given decoration
   /// \brief Decorates the given target <result-id> with the given decoration
   /// (without additional parameters).
   /// (without additional parameters).
   void decorate(uint32_t targetId, spv::Decoration);
   void decorate(uint32_t targetId, spv::Decoration);
@@ -463,6 +471,8 @@ private:
   SPIRVContext &theContext; ///< The SPIR-V context.
   SPIRVContext &theContext; ///< The SPIR-V context.
   SPIRVModule theModule;    ///< The module under building.
   SPIRVModule theModule;    ///< The module under building.
 
 
+  const bool allowReflect; ///< Whether allow reflect instructions.
+
   std::unique_ptr<Function> theFunction; ///< The function under building.
   std::unique_ptr<Function> theFunction; ///< The function under building.
   OrderedBasicBlockMap basicBlocks;      ///< The basic blocks under building.
   OrderedBasicBlockMap basicBlocks;      ///< The basic blocks under building.
   BasicBlock *insertPoint;               ///< The current insertion point.
   BasicBlock *insertPoint;               ///< The current insertion point.

+ 11 - 4
tools/clang/lib/SPIRV/DeclResultIdMapper.cpp

@@ -345,7 +345,7 @@ void DeclResultIdMapper::createCounterVarForDecl(const DeclaratorDecl *decl) {
 
 
   if (!counterVars.count(decl) &&
   if (!counterVars.count(decl) &&
       TypeTranslator::isRWAppendConsumeSBuffer(declType)) {
       TypeTranslator::isRWAppendConsumeSBuffer(declType)) {
-    createCounterVar(decl, /*isAlias=*/true);
+    createCounterVar(decl, /*declId=*/0, /*isAlias=*/true);
   } else if (!fieldCounterVars.count(decl) && declType->isStructureType() &&
   } else if (!fieldCounterVars.count(decl) && declType->isStructureType() &&
              // Exclude other resource types which are represented as structs
              // Exclude other resource types which are represented as structs
              !hlsl::IsHLSLResourceType(declType)) {
              !hlsl::IsHLSLResourceType(declType)) {
@@ -439,7 +439,7 @@ SpirvEvalInfo DeclResultIdMapper::createExternVar(const VarDecl *var) {
   if (isACRWSBuffer) {
   if (isACRWSBuffer) {
     // For {Append|Consume|RW}StructuredBuffer, we need to always create another
     // For {Append|Consume|RW}StructuredBuffer, we need to always create another
     // variable for its associated counter.
     // variable for its associated counter.
-    createCounterVar(var, /*isAlias=*/false);
+    createCounterVar(var, id, /*isAlias=*/false);
   }
   }
 
 
   return info;
   return info;
@@ -725,7 +725,7 @@ void DeclResultIdMapper::registerSpecConstant(const VarDecl *decl,
 }
 }
 
 
 void DeclResultIdMapper::createCounterVar(
 void DeclResultIdMapper::createCounterVar(
-    const DeclaratorDecl *decl, bool isAlias,
+    const DeclaratorDecl *decl, uint32_t declId, bool isAlias,
     const llvm::SmallVector<uint32_t, 4> *indices) {
     const llvm::SmallVector<uint32_t, 4> *indices) {
   std::string counterName = "counter.var." + decl->getName().str();
   std::string counterName = "counter.var." + decl->getName().str();
   if (indices) {
   if (indices) {
@@ -756,6 +756,8 @@ void DeclResultIdMapper::createCounterVar(
                               getResourceBinding(decl),
                               getResourceBinding(decl),
                               decl->getAttr<VKBindingAttr>(),
                               decl->getAttr<VKBindingAttr>(),
                               decl->getAttr<VKCounterBindingAttr>(), true);
                               decl->getAttr<VKCounterBindingAttr>(), true);
+    assert(declId);
+    theBuilder.decorateCounterBufferId(declId, counterId);
   }
   }
 
 
   if (indices)
   if (indices)
@@ -778,7 +780,7 @@ void DeclResultIdMapper::createFieldCounterVars(
 
 
     const QualType fieldType = field->getType();
     const QualType fieldType = field->getType();
     if (TypeTranslator::isRWAppendConsumeSBuffer(fieldType))
     if (TypeTranslator::isRWAppendConsumeSBuffer(fieldType))
-      createCounterVar(rootDecl, /*isAlias=*/true, indices);
+      createCounterVar(rootDecl, /*declId=*/0, /*isAlias=*/true, indices);
     else if (fieldType->isStructureType() &&
     else if (fieldType->isStructureType() &&
              !hlsl::IsHLSLResourceType(fieldType))
              !hlsl::IsHLSLResourceType(fieldType))
       // Go recursively into all nested structs
       // Go recursively into all nested structs
@@ -1319,6 +1321,11 @@ bool DeclResultIdMapper::createStageVars(const hlsl::SigPoint *sigPoint,
     stageVar.setSpirvId(varId);
     stageVar.setSpirvId(varId);
     stageVar.setLocationAttr(decl->getAttr<VKLocationAttr>());
     stageVar.setLocationAttr(decl->getAttr<VKLocationAttr>());
     stageVars.push_back(stageVar);
     stageVars.push_back(stageVar);
+
+    // Emit OpDecorate* instructions to link this stage variable with the HLSL
+    // semantic it is created for
+    theBuilder.decorateHlslSemantic(varId, stageVar.getSemanticStr());
+
     // We have semantics attached to this decl, which means it must be a
     // We have semantics attached to this decl, which means it must be a
     // function/parameter/variable. All are DeclaratorDecls.
     // function/parameter/variable. All are DeclaratorDecls.
     stageVarIds[cast<DeclaratorDecl>(decl)] = varId;
     stageVarIds[cast<DeclaratorDecl>(decl)] = varId;

+ 4 - 1
tools/clang/lib/SPIRV/DeclResultIdMapper.h

@@ -596,12 +596,15 @@ private:
   /// structured buffer. Handles AssocCounter#1 and AssocCounter#2 (see the
   /// structured buffer. Handles AssocCounter#1 and AssocCounter#2 (see the
   /// comment of CounterVarFields).
   /// comment of CounterVarFields).
   ///
   ///
+  /// declId is the SPIR-V <result-id> for the given decl. It should be non-zero
+  /// for non-alias buffers.
+  ///
   /// The counter variable will be created as an alias variable (of
   /// The counter variable will be created as an alias variable (of
   /// pointer-to-pointer type in Private storage class) if isAlias is true.
   /// pointer-to-pointer type in Private storage class) if isAlias is true.
   ///
   ///
   /// Note: isAlias - legalization specific code
   /// Note: isAlias - legalization specific code
   void
   void
-  createCounterVar(const DeclaratorDecl *decl, bool isAlias,
+  createCounterVar(const DeclaratorDecl *decl, uint32_t declId, bool isAlias,
                    const llvm::SmallVector<uint32_t, 4> *indices = nullptr);
                    const llvm::SmallVector<uint32_t, 4> *indices = nullptr);
   /// Creates all assoicated counter variables by recursively visiting decl's
   /// Creates all assoicated counter variables by recursively visiting decl's
   /// fields. Handles AssocCounter#3 and AssocCounter#4 (see the comment of
   /// fields. Handles AssocCounter#3 and AssocCounter#4 (see the comment of

+ 33 - 7
tools/clang/lib/SPIRV/Decoration.cpp

@@ -281,20 +281,32 @@ Decoration::getSecondaryViewportRelativeNV(SPIRVContext &context,
   return getUniqueDecoration(context, d);
   return getUniqueDecoration(context, d);
 }
 }
 
 
+const Decoration *Decoration::getHlslCounterBufferGOOGLE(SPIRVContext &context,
+                                                         uint32_t id) {
+  Decoration d = Decoration(spv::Decoration::HlslCounterBufferGOOGLE, {id});
+  return getUniqueDecoration(context, d);
+}
+
+const Decoration *
+Decoration::getHlslSemanticGOOGLE(SPIRVContext &context,
+                                  llvm::StringRef semantic,
+                                  llvm ::Optional<uint32_t> member_idx) {
+  Decoration d = Decoration(spv::Decoration::HlslSemanticGOOGLE,
+                            string::encodeSPIRVString(semantic));
+  d.setMemberIndex(member_idx);
+  return getUniqueDecoration(context, d);
+}
+
 std::vector<uint32_t> Decoration::withTargetId(uint32_t targetId) const {
 std::vector<uint32_t> Decoration::withTargetId(uint32_t targetId) const {
   std::vector<uint32_t> words;
   std::vector<uint32_t> words;
 
 
   // TODO: we are essentially duplicate the work InstBuilder is responsible for.
   // TODO: we are essentially duplicate the work InstBuilder is responsible for.
   // Should figure out a way to unify them.
   // Should figure out a way to unify them.
   words.reserve(3 + args.size() + (memberIndex.hasValue() ? 1 : 0));
   words.reserve(3 + args.size() + (memberIndex.hasValue() ? 1 : 0));
-  if (memberIndex.hasValue()) {
-    words.push_back(static_cast<uint32_t>(spv::Op::OpMemberDecorate));
-    words.push_back(targetId);
+  words.push_back(static_cast<uint32_t>(getDecorateOpcode(id, memberIndex)));
+  words.push_back(targetId);
+  if (memberIndex.hasValue())
     words.push_back(*memberIndex);
     words.push_back(*memberIndex);
-  } else {
-    words.push_back(static_cast<uint32_t>(spv::Op::OpDecorate));
-    words.push_back(targetId);
-  }
   words.push_back(static_cast<uint32_t>(id));
   words.push_back(static_cast<uint32_t>(id));
   words.insert(words.end(), args.begin(), args.end());
   words.insert(words.end(), args.begin(), args.end());
   words.front() |= static_cast<uint32_t>(words.size()) << 16;
   words.front() |= static_cast<uint32_t>(words.size()) << 16;
@@ -302,5 +314,19 @@ std::vector<uint32_t> Decoration::withTargetId(uint32_t targetId) const {
   return words;
   return words;
 }
 }
 
 
+spv::Op
+Decoration::getDecorateOpcode(spv::Decoration decoration,
+                              const llvm::Optional<uint32_t> &memberIndex) {
+  if (decoration == spv::Decoration::HlslCounterBufferGOOGLE)
+    return spv::Op::OpDecorateId;
+
+  if (decoration == spv::Decoration::HlslSemanticGOOGLE)
+    return memberIndex.hasValue() ? spv::Op::OpMemberDecorateStringGOOGLE
+                                  : spv::Op::OpDecorateStringGOOGLE;
+
+  return memberIndex.hasValue() ? spv::Op::OpMemberDecorate
+                                : spv::Op::OpDecorate;
+}
+
 } // end namespace spirv
 } // end namespace spirv
 } // end namespace clang
 } // end namespace clang

+ 61 - 15
tools/clang/lib/SPIRV/GlPerVertex.cpp

@@ -18,6 +18,12 @@ namespace clang {
 namespace spirv {
 namespace spirv {
 
 
 namespace {
 namespace {
+constexpr uint32_t gPositionIndex = 0;
+constexpr uint32_t gPointSizeIndex = 1;
+constexpr uint32_t gClipDistanceIndex = 2;
+constexpr uint32_t gCullDistanceIndex = 3;
+constexpr uint32_t gGlPerVertexSize = 4;
+
 /// \brief Returns true if the given decl has a semantic string attached and
 /// \brief Returns true if the given decl has a semantic string attached and
 /// writes the info to *semanticStr, *semantic, and *semanticIndex.
 /// writes the info to *semanticStr, *semantic, and *semanticIndex.
 // TODO: duplication! Same as the one in DeclResultIdMapper.cpp
 // TODO: duplication! Same as the one in DeclResultIdMapper.cpp
@@ -64,7 +70,8 @@ GlPerVertex::GlPerVertex(const hlsl::ShaderModel &sm, ASTContext &context,
       outIsGrouped(true), inBlockVar(0), outBlockVar(0), inClipVar(0),
       outIsGrouped(true), inBlockVar(0), outBlockVar(0), inClipVar(0),
       inCullVar(0), outClipVar(0), outCullVar(0), inArraySize(0),
       inCullVar(0), outClipVar(0), outCullVar(0), inArraySize(0),
       outArraySize(0), inClipArraySize(1), outClipArraySize(1),
       outArraySize(0), inClipArraySize(1), outClipArraySize(1),
-      inCullArraySize(1), outCullArraySize(1) {}
+      inCullArraySize(1), outCullArraySize(1), inSemanticStrs(4, ""),
+      outSemanticStrs(4, "") {}
 
 
 void GlPerVertex::generateVars(uint32_t inArrayLen, uint32_t outArrayLen) {
 void GlPerVertex::generateVars(uint32_t inArrayLen, uint32_t outArrayLen) {
   // Calling this method twice is an internal error.
   // Calling this method twice is an internal error.
@@ -142,18 +149,18 @@ void GlPerVertex::requireCapabilityIfNecessary() {
     theBuilder.requireCapability(spv::Capability::CullDistance);
     theBuilder.requireCapability(spv::Capability::CullDistance);
 }
 }
 
 
-bool GlPerVertex::recordClipCullDistanceDecl(const DeclaratorDecl *decl,
+bool GlPerVertex::recordGlPerVertexDeclFacts(const DeclaratorDecl *decl,
                                              bool asInput) {
                                              bool asInput) {
   const QualType type = getTypeOrFnRetType(decl);
   const QualType type = getTypeOrFnRetType(decl);
 
 
   if (type->isVoidType())
   if (type->isVoidType())
     return true;
     return true;
 
 
-  return doClipCullDistanceDecl(decl, type, asInput);
+  return doGlPerVertexFacts(decl, type, asInput);
 }
 }
 
 
-bool GlPerVertex::doClipCullDistanceDecl(const DeclaratorDecl *decl,
-                                         QualType baseType, bool asInput) {
+bool GlPerVertex::doGlPerVertexFacts(const DeclaratorDecl *decl,
+                                     QualType baseType, bool asInput) {
 
 
   llvm::StringRef semanticStr;
   llvm::StringRef semanticStr;
   const hlsl::Semantic *semantic = {};
   const hlsl::Semantic *semantic = {};
@@ -165,7 +172,7 @@ bool GlPerVertex::doClipCullDistanceDecl(const DeclaratorDecl *decl,
       // Go through each field to see if there is any usage of
       // Go through each field to see if there is any usage of
       // SV_ClipDistance/SV_CullDistance.
       // SV_ClipDistance/SV_CullDistance.
       for (const auto *field : structDecl->fields()) {
       for (const auto *field : structDecl->fields()) {
-        if (!doClipCullDistanceDecl(field, field->getType(), asInput))
+        if (!doGlPerVertexFacts(field, field->getType(), asInput))
           return false;
           return false;
       }
       }
       return true;
       return true;
@@ -174,23 +181,23 @@ bool GlPerVertex::doClipCullDistanceDecl(const DeclaratorDecl *decl,
     // For these HS/DS/GS specific data types, semantic strings are attached
     // For these HS/DS/GS specific data types, semantic strings are attached
     // to the underlying struct's fields.
     // to the underlying struct's fields.
     if (hlsl::IsHLSLInputPatchType(baseType)) {
     if (hlsl::IsHLSLInputPatchType(baseType)) {
-      return doClipCullDistanceDecl(
+      return doGlPerVertexFacts(
           decl, hlsl::GetHLSLInputPatchElementType(baseType), asInput);
           decl, hlsl::GetHLSLInputPatchElementType(baseType), asInput);
     }
     }
     if (hlsl::IsHLSLOutputPatchType(baseType)) {
     if (hlsl::IsHLSLOutputPatchType(baseType)) {
-      return doClipCullDistanceDecl(
+      return doGlPerVertexFacts(
           decl, hlsl::GetHLSLOutputPatchElementType(baseType), asInput);
           decl, hlsl::GetHLSLOutputPatchElementType(baseType), asInput);
     }
     }
 
 
     if (hlsl::IsHLSLStreamOutputType(baseType)) {
     if (hlsl::IsHLSLStreamOutputType(baseType)) {
-      return doClipCullDistanceDecl(
+      return doGlPerVertexFacts(
           decl, hlsl::GetHLSLOutputPatchElementType(baseType), asInput);
           decl, hlsl::GetHLSLOutputPatchElementType(baseType), asInput);
     }
     }
     if (hasGSPrimitiveTypeQualifier(decl)) {
     if (hasGSPrimitiveTypeQualifier(decl)) {
       // GS inputs have an additional arrayness that we should remove to check
       // GS inputs have an additional arrayness that we should remove to check
       // the underlying type instead.
       // the underlying type instead.
       baseType = astContext.getAsConstantArrayType(baseType)->getElementType();
       baseType = astContext.getAsConstantArrayType(baseType)->getElementType();
-      return doClipCullDistanceDecl(decl, baseType, asInput);
+      return doGlPerVertexFacts(decl, baseType, asInput);
     }
     }
 
 
     emitError("semantic string missing for shader %select{output|input}0 "
     emitError("semantic string missing for shader %select{output|input}0 "
@@ -206,16 +213,45 @@ bool GlPerVertex::doClipCullDistanceDecl(const DeclaratorDecl *decl,
   SemanticIndexToTypeMap *typeMap = nullptr;
   SemanticIndexToTypeMap *typeMap = nullptr;
   uint32_t *blockArraySize = asInput ? &inArraySize : &outArraySize;
   uint32_t *blockArraySize = asInput ? &inArraySize : &outArraySize;
   bool isCull = false;
   bool isCull = false;
+  auto *semanticStrs = asInput ? &inSemanticStrs : &outSemanticStrs;
+  auto index = gGlPerVertexSize; // The index of this semantic in gl_PerVertex
 
 
   switch (semantic->GetKind()) {
   switch (semantic->GetKind()) {
+  case hlsl::Semantic::Kind::Position:
+    index = gPositionIndex;
+    break;
   case hlsl::Semantic::Kind::ClipDistance:
   case hlsl::Semantic::Kind::ClipDistance:
     typeMap = asInput ? &inClipType : &outClipType;
     typeMap = asInput ? &inClipType : &outClipType;
+    index = gClipDistanceIndex;
     break;
     break;
   case hlsl::Semantic::Kind::CullDistance:
   case hlsl::Semantic::Kind::CullDistance:
     typeMap = asInput ? &inCullType : &outCullType;
     typeMap = asInput ? &inCullType : &outCullType;
     isCull = true;
     isCull = true;
+    index = gCullDistanceIndex;
     break;
     break;
-  default:
+  }
+
+  // PointSize does not have corresponding SV semantic; it uses
+  // [[vk::builtin("PointSize")]] instead.
+  if (const auto *builtinAttr = decl->getAttr<VKBuiltInAttr>())
+    if (builtinAttr->getBuiltIn() == "PointSize")
+      index = gPointSizeIndex;
+
+  // Remember the semantic strings provided by the developer so that we can
+  // emit OpDecorate* instructions properly for them
+  if (index < gGlPerVertexSize) {
+    if ((*semanticStrs)[index].empty())
+      (*semanticStrs)[index] = semanticStr;
+    // We can have multiple ClipDistance/CullDistance semantics mapping to the
+    // same variable. For those cases, it is not appropriate to use any one of
+    // them as the semantic. Use the standard one without index.
+    else if (index == gClipDistanceIndex)
+      (*semanticStrs)[index] = "SV_ClipDistance";
+    else if (index == gCullDistanceIndex)
+      (*semanticStrs)[index] = "SV_CullDistance";
+  }
+
+  if (index < gClipDistanceIndex || index > gCullDistanceIndex) {
     // Annotated with something other than SV_ClipDistance or SV_CullDistance.
     // Annotated with something other than SV_ClipDistance or SV_CullDistance.
     // We don't care about such cases.
     // We don't care about such cases.
     return true;
     return true;
@@ -321,18 +357,20 @@ uint32_t GlPerVertex::createBlockVar(bool asInput, uint32_t arraySize) {
   const llvm::StringRef typeName = "type.gl_PerVertex";
   const llvm::StringRef typeName = "type.gl_PerVertex";
   spv::StorageClass sc = spv::StorageClass::Input;
   spv::StorageClass sc = spv::StorageClass::Input;
   llvm::StringRef varName = "gl_PerVertexIn";
   llvm::StringRef varName = "gl_PerVertexIn";
+  auto *semanticStrs = &inSemanticStrs;
   uint32_t clipSize = inClipArraySize;
   uint32_t clipSize = inClipArraySize;
   uint32_t cullSize = inCullArraySize;
   uint32_t cullSize = inCullArraySize;
 
 
   if (!asInput) {
   if (!asInput) {
     sc = spv::StorageClass::Output;
     sc = spv::StorageClass::Output;
     varName = "gl_PerVertexOut";
     varName = "gl_PerVertexOut";
+    semanticStrs = &outSemanticStrs;
     clipSize = outClipArraySize;
     clipSize = outClipArraySize;
     cullSize = outCullArraySize;
     cullSize = outCullArraySize;
   }
   }
 
 
-  uint32_t typeId =
-      typeTranslator.getGlPerVertexStruct(clipSize, cullSize, typeName);
+  uint32_t typeId = typeTranslator.getGlPerVertexStruct(
+      clipSize, cullSize, typeName, *semanticStrs);
 
 
   // Handle the extra arrayness over the block
   // Handle the extra arrayness over the block
   if (arraySize != 0) {
   if (arraySize != 0) {
@@ -362,7 +400,11 @@ uint32_t GlPerVertex::createClipDistanceVar(bool asInput, uint32_t arraySize) {
   spv::StorageClass sc =
   spv::StorageClass sc =
       asInput ? spv::StorageClass::Input : spv::StorageClass::Output;
       asInput ? spv::StorageClass::Input : spv::StorageClass::Output;
 
 
-  return theBuilder.addStageBuiltinVar(type, sc, spv::BuiltIn::ClipDistance);
+  auto id = theBuilder.addStageBuiltinVar(type, sc, spv::BuiltIn::ClipDistance);
+  theBuilder.decorateHlslSemantic(
+      id, asInput ? inSemanticStrs[gClipDistanceIndex]
+                  : outSemanticStrs[gClipDistanceIndex]);
+  return id;
 }
 }
 
 
 uint32_t GlPerVertex::createCullDistanceVar(bool asInput, uint32_t arraySize) {
 uint32_t GlPerVertex::createCullDistanceVar(bool asInput, uint32_t arraySize) {
@@ -371,7 +413,11 @@ uint32_t GlPerVertex::createCullDistanceVar(bool asInput, uint32_t arraySize) {
   spv::StorageClass sc =
   spv::StorageClass sc =
       asInput ? spv::StorageClass::Input : spv::StorageClass::Output;
       asInput ? spv::StorageClass::Input : spv::StorageClass::Output;
 
 
-  return theBuilder.addStageBuiltinVar(type, sc, spv::BuiltIn::CullDistance);
+  auto id = theBuilder.addStageBuiltinVar(type, sc, spv::BuiltIn::CullDistance);
+  theBuilder.decorateHlslSemantic(
+      id, asInput ? inSemanticStrs[gCullDistanceIndex]
+                  : outSemanticStrs[gCullDistanceIndex]);
+  return id;
 }
 }
 
 
 bool GlPerVertex::tryToAccess(hlsl::SigPoint::Kind sigPointKind,
 bool GlPerVertex::tryToAccess(hlsl::SigPoint::Kind sigPointKind,

+ 10 - 4
tools/clang/lib/SPIRV/GlPerVertex.h

@@ -61,7 +61,9 @@ public:
 
 
   /// Records a declaration of SV_ClipDistance/SV_CullDistance so later
   /// Records a declaration of SV_ClipDistance/SV_CullDistance so later
   /// we can caculate the ClipDistance/CullDistance array layout.
   /// we can caculate the ClipDistance/CullDistance array layout.
-  bool recordClipCullDistanceDecl(const DeclaratorDecl *decl, bool asInput);
+  /// Also records the semantic strings provided for the builtins in
+  /// gl_PerVertex.
+  bool recordGlPerVertexDeclFacts(const DeclaratorDecl *decl, bool asInput);
 
 
   /// Calculates the layout for ClipDistance/CullDistance arrays.
   /// Calculates the layout for ClipDistance/CullDistance arrays.
   void calculateClipCullDistanceArraySize();
   void calculateClipCullDistanceArraySize();
@@ -150,12 +152,11 @@ private:
                                   QualType fromType, uint32_t fromValue) const;
                                   QualType fromType, uint32_t fromValue) const;
   /// Emits SPIR-V instructions to write a field in gl_PerVertex.
   /// Emits SPIR-V instructions to write a field in gl_PerVertex.
   bool writeField(hlsl::Semantic::Kind semanticKind, uint32_t semanticIndex,
   bool writeField(hlsl::Semantic::Kind semanticKind, uint32_t semanticIndex,
-
                   llvm::Optional<uint32_t> invocationId, uint32_t *value);
                   llvm::Optional<uint32_t> invocationId, uint32_t *value);
 
 
   /// Internal implementation for recordClipCullDistanceDecl().
   /// Internal implementation for recordClipCullDistanceDecl().
-  bool doClipCullDistanceDecl(const DeclaratorDecl *decl, QualType type,
-                              bool asInput);
+  bool doGlPerVertexFacts(const DeclaratorDecl *decl, QualType type,
+                          bool asInput);
 
 
 private:
 private:
   using SemanticIndexToTypeMap = llvm::DenseMap<uint32_t, QualType>;
   using SemanticIndexToTypeMap = llvm::DenseMap<uint32_t, QualType>;
@@ -216,6 +217,11 @@ private:
   /// offsets in the float array.
   /// offsets in the float array.
   SemanticIndexToArrayOffsetMap inClipOffset, outClipOffset;
   SemanticIndexToArrayOffsetMap inClipOffset, outClipOffset;
   SemanticIndexToArrayOffsetMap inCullOffset, outCullOffset;
   SemanticIndexToArrayOffsetMap inCullOffset, outCullOffset;
+
+  /// Keeps track of the semantic strings provided in the source code for the
+  /// builtins in gl_PerVertex.
+  llvm::SmallVector<std::string, 4> inSemanticStrs;
+  llvm::SmallVector<std::string, 4> outSemanticStrs;
 };
 };
 
 
 } // end namespace spirv
 } // end namespace spirv

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

@@ -18,9 +18,9 @@
 namespace clang {
 namespace clang {
 namespace spirv {
 namespace spirv {
 
 
-ModuleBuilder::ModuleBuilder(SPIRVContext *C)
-    : theContext(*C), theModule(), theFunction(nullptr), insertPoint(nullptr),
-      instBuilder(nullptr), glslExtSetId(0) {
+ModuleBuilder::ModuleBuilder(SPIRVContext *C, bool reflect)
+    : theContext(*C), theModule(), allowReflect(reflect), theFunction(nullptr),
+      insertPoint(nullptr), instBuilder(nullptr), glslExtSetId(0) {
   instBuilder.setConsumer([this](std::vector<uint32_t> &&words) {
   instBuilder.setConsumer([this](std::vector<uint32_t> &&words) {
     this->constructSite = std::move(words);
     this->constructSite = std::move(words);
   });
   });
@@ -807,12 +807,35 @@ void ModuleBuilder::decorateDSetBinding(uint32_t targetId, uint32_t setNumber,
   d = Decoration::getBinding(theContext, bindingNumber);
   d = Decoration::getBinding(theContext, bindingNumber);
   theModule.addDecoration(d, targetId);
   theModule.addDecoration(d, targetId);
 }
 }
+
 void ModuleBuilder::decorateInputAttachmentIndex(uint32_t targetId,
 void ModuleBuilder::decorateInputAttachmentIndex(uint32_t targetId,
                                                  uint32_t indexNumber) {
                                                  uint32_t indexNumber) {
   const auto *d = Decoration::getInputAttachmentIndex(theContext, indexNumber);
   const auto *d = Decoration::getInputAttachmentIndex(theContext, indexNumber);
   theModule.addDecoration(d, targetId);
   theModule.addDecoration(d, targetId);
 }
 }
 
 
+void ModuleBuilder::decorateCounterBufferId(uint32_t mainBufferId,
+                                            uint32_t counterBufferId) {
+  if (allowReflect) {
+    addExtension("SPV_GOOGLE_hlsl_functionality1");
+    theModule.addDecoration(
+        Decoration::getHlslCounterBufferGOOGLE(theContext, counterBufferId),
+        mainBufferId);
+  }
+}
+
+void ModuleBuilder::decorateHlslSemantic(uint32_t targetId,
+                                         llvm::StringRef semantic,
+                                         llvm::Optional<uint32_t> memberIdx) {
+  if (allowReflect) {
+    addExtension("SPV_GOOGLE_decorate_string");
+    addExtension("SPV_GOOGLE_hlsl_functionality1");
+    theModule.addDecoration(
+        Decoration::getHlslSemanticGOOGLE(theContext, semantic, memberIdx),
+        targetId);
+  }
+}
+
 void ModuleBuilder::decorateLocation(uint32_t targetId, uint32_t location) {
 void ModuleBuilder::decorateLocation(uint32_t targetId, uint32_t location) {
   const Decoration *d =
   const Decoration *d =
       Decoration::getLocation(theContext, location, llvm::None);
       Decoration::getLocation(theContext, location, llvm::None);

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

@@ -519,7 +519,7 @@ SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci,
       entryFunctionName(ci.getCodeGenOpts().HLSLEntryFunction),
       entryFunctionName(ci.getCodeGenOpts().HLSLEntryFunction),
       shaderModel(*hlsl::ShaderModel::GetByName(
       shaderModel(*hlsl::ShaderModel::GetByName(
           ci.getCodeGenOpts().HLSLProfile.c_str())),
           ci.getCodeGenOpts().HLSLProfile.c_str())),
-      theContext(), theBuilder(&theContext),
+      theContext(), theBuilder(&theContext, options.enableReflect),
       declIdMapper(shaderModel, astContext, theBuilder, spirvOptions),
       declIdMapper(shaderModel, astContext, theBuilder, spirvOptions),
       typeTranslator(astContext, theBuilder, diags, options),
       typeTranslator(astContext, theBuilder, diags, options),
       entryFunctionId(0), curFunction(nullptr), curThis(0),
       entryFunctionId(0), curFunction(nullptr), curThis(0),
@@ -8943,16 +8943,18 @@ bool SPIRVEmitter::emitEntryFunctionWrapper(const FunctionDecl *decl,
   // SV_ClipDistance/SV_CullDistance variables into one float array, thus we
   // SV_ClipDistance/SV_CullDistance variables into one float array, thus we
   // need to calculate the total size of the array and the offset of each
   // need to calculate the total size of the array and the offset of each
   // variable within that array.
   // variable within that array.
+  // Also go through all parameters to record the semantic strings provided for
+  // the builtins in gl_PerVertex.
   for (const auto *param : decl->params()) {
   for (const auto *param : decl->params()) {
     if (canActAsInParmVar(param))
     if (canActAsInParmVar(param))
-      if (!declIdMapper.glPerVertex.recordClipCullDistanceDecl(param, true))
+      if (!declIdMapper.glPerVertex.recordGlPerVertexDeclFacts(param, true))
         return false;
         return false;
     if (canActAsOutParmVar(param))
     if (canActAsOutParmVar(param))
-      if (!declIdMapper.glPerVertex.recordClipCullDistanceDecl(param, false))
+      if (!declIdMapper.glPerVertex.recordGlPerVertexDeclFacts(param, false))
         return false;
         return false;
   }
   }
   // Also consider the SV_ClipDistance/SV_CullDistance in the return type
   // Also consider the SV_ClipDistance/SV_CullDistance in the return type
-  if (!declIdMapper.glPerVertex.recordClipCullDistanceDecl(decl, false))
+  if (!declIdMapper.glPerVertex.recordGlPerVertexDeclFacts(decl, false))
     return false;
     return false;
 
 
   // Calculate the total size of the ClipDistance/CullDistance array and the
   // Calculate the total size of the ClipDistance/CullDistance array and the

+ 10 - 3
tools/clang/lib/SPIRV/TypeTranslator.cpp

@@ -619,9 +619,9 @@ uint32_t TypeTranslator::getACSBufferCounter() {
                                   decorations);
                                   decorations);
 }
 }
 
 
-uint32_t TypeTranslator::getGlPerVertexStruct(uint32_t clipArraySize,
-                                              uint32_t cullArraySize,
-                                              llvm::StringRef name) {
+uint32_t TypeTranslator::getGlPerVertexStruct(
+    uint32_t clipArraySize, uint32_t cullArraySize, llvm::StringRef name,
+    const llvm::SmallVector<std::string, 4> &fieldSemantics) {
   const uint32_t f32Type = theBuilder.getFloat32Type();
   const uint32_t f32Type = theBuilder.getFloat32Type();
   const uint32_t v4f32Type = theBuilder.getVecType(f32Type, 4);
   const uint32_t v4f32Type = theBuilder.getVecType(f32Type, 4);
   const uint32_t clipType = theBuilder.getArrayType(
   const uint32_t clipType = theBuilder.getArrayType(
@@ -641,6 +641,13 @@ uint32_t TypeTranslator::getGlPerVertexStruct(uint32_t clipArraySize,
       Decoration::getBuiltIn(ctx, spv::BuiltIn::CullDistance, 3));
       Decoration::getBuiltIn(ctx, spv::BuiltIn::CullDistance, 3));
   decorations.push_back(Decoration::getBlock(ctx));
   decorations.push_back(Decoration::getBlock(ctx));
 
 
+  if (spirvOptions.enableReflect) {
+    for (uint32_t i = 0; i < 4; ++i)
+      if (!fieldSemantics[i].empty())
+        decorations.push_back(
+            Decoration::getHlslSemanticGOOGLE(ctx, fieldSemantics[i], i));
+  }
+
   return theBuilder.getStructType({v4f32Type, f32Type, clipType, cullType},
   return theBuilder.getStructType({v4f32Type, f32Type, clipType, cullType},
                                   name, {}, decorations);
                                   name, {}, decorations);
 }
 }

+ 4 - 2
tools/clang/lib/SPIRV/TypeTranslator.h

@@ -68,8 +68,10 @@ public:
   ///   float  gl_ClipDistance[];
   ///   float  gl_ClipDistance[];
   ///   float  gl_CullDistance[];
   ///   float  gl_CullDistance[];
   /// };
   /// };
-  uint32_t getGlPerVertexStruct(uint32_t clipArraySize, uint32_t cullArraySize,
-                                llvm::StringRef structName);
+  uint32_t
+  getGlPerVertexStruct(uint32_t clipArraySize, uint32_t cullArraySize,
+                       llvm::StringRef structName,
+                       const llvm::SmallVector<std::string, 4> &fieldSemantics);
 
 
   /// \brief Returns true if the given type is a (RW)StructuredBuffer type.
   /// \brief Returns true if the given type is a (RW)StructuredBuffer type.
   static bool isStructuredBuffer(QualType type);
   static bool isStructuredBuffer(QualType type);

+ 22 - 1
tools/clang/test/CodeGenSPIRV/spirv.interface.ds.hlsl

@@ -1,9 +1,12 @@
-// Run: %dxc -T ds_6_0 -E main
+// Run: %dxc -T ds_6_0 -E main -fspv-reflect
 
 
 // CHECK: OpCapability ClipDistance
 // CHECK: OpCapability ClipDistance
 // CHECK: OpCapability CullDistance
 // CHECK: OpCapability CullDistance
 // CHECK: OpCapability Tessellation
 // CHECK: OpCapability Tessellation
 
 
+// CHECK: OpExtension "SPV_GOOGLE_decorate_string"
+// CHECK: OpExtension "SPV_GOOGLE_hlsl_functionality1"
+
 // HS PCF output
 // HS PCF output
 
 
 struct HsPcfOut {
 struct HsPcfOut {
@@ -72,19 +75,37 @@ struct DsOut {
 // CHECK: OpMemberDecorate %type_gl_PerVertex 3 BuiltIn CullDistance
 // CHECK: OpMemberDecorate %type_gl_PerVertex 3 BuiltIn CullDistance
 // CHECK: OpDecorate %type_gl_PerVertex Block
 // CHECK: OpDecorate %type_gl_PerVertex Block
 
 
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex 0 HlslSemanticGOOGLE "SV_Position"
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex 1 HlslSemanticGOOGLE "PSIZE"
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex 2 HlslSemanticGOOGLE "SV_ClipDistance"
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex 3 HlslSemanticGOOGLE "SV_CullDistance"
+
 // CHECK: OpMemberDecorate %type_gl_PerVertex_0 0 BuiltIn Position
 // CHECK: OpMemberDecorate %type_gl_PerVertex_0 0 BuiltIn Position
 // CHECK: OpMemberDecorate %type_gl_PerVertex_0 1 BuiltIn PointSize
 // CHECK: OpMemberDecorate %type_gl_PerVertex_0 1 BuiltIn PointSize
 // CHECK: OpMemberDecorate %type_gl_PerVertex_0 2 BuiltIn ClipDistance
 // CHECK: OpMemberDecorate %type_gl_PerVertex_0 2 BuiltIn ClipDistance
 // CHECK: OpMemberDecorate %type_gl_PerVertex_0 3 BuiltIn CullDistance
 // CHECK: OpMemberDecorate %type_gl_PerVertex_0 3 BuiltIn CullDistance
 // CHECK: OpDecorate %type_gl_PerVertex_0 Block
 // CHECK: OpDecorate %type_gl_PerVertex_0 Block
 
 
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex_0 0 HlslSemanticGOOGLE "SV_Position"
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex_0 1 HlslSemanticGOOGLE "PSIZE"
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex_0 2 HlslSemanticGOOGLE "SV_ClipDistance"
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex_0 3 HlslSemanticGOOGLE "SV_CullDistance"
+
+// CHECK: OpDecorateStringGOOGLE %in_var_TEXCOORD HlslSemanticGOOGLE "TEXCOORD"
+// CHECK: OpDecorateStringGOOGLE %in_var_BAR HlslSemanticGOOGLE "BAR"
 // CHECK: OpDecorate %gl_TessCoord BuiltIn TessCoord
 // CHECK: OpDecorate %gl_TessCoord BuiltIn TessCoord
+// CHECK: OpDecorateStringGOOGLE %gl_TessCoord HlslSemanticGOOGLE "SV_DomainLocation"
 // CHECK: OpDecorate %gl_TessCoord Patch
 // CHECK: OpDecorate %gl_TessCoord Patch
 // CHECK: OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter
 // CHECK: OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter
+// CHECK: OpDecorateStringGOOGLE %gl_TessLevelOuter HlslSemanticGOOGLE "SV_TessFactor"
 // CHECK: OpDecorate %gl_TessLevelOuter Patch
 // CHECK: OpDecorate %gl_TessLevelOuter Patch
 // CHECK: OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner
 // CHECK: OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner
+// CHECK: OpDecorateStringGOOGLE %gl_TessLevelInner HlslSemanticGOOGLE "SV_InsideTessFactor"
 // CHECK: OpDecorate %gl_TessLevelInner Patch
 // CHECK: OpDecorate %gl_TessLevelInner Patch
+// CHECK: OpDecorateStringGOOGLE %in_var_FOO HlslSemanticGOOGLE "FOO"
 // CHECK: OpDecorate %in_var_FOO Patch
 // CHECK: OpDecorate %in_var_FOO Patch
+// CHECK: OpDecorateStringGOOGLE %out_var_FOO HlslSemanticGOOGLE "FOO"
+// CHECK: OpDecorateStringGOOGLE %out_var_BAR HlslSemanticGOOGLE "BAR"
 // CHECK: OpDecorate %in_var_BAR Location 0
 // CHECK: OpDecorate %in_var_BAR Location 0
 // CHECK: OpDecorate %in_var_FOO Location 1
 // CHECK: OpDecorate %in_var_FOO Location 1
 // CHECK: OpDecorate %in_var_TEXCOORD Location 2
 // CHECK: OpDecorate %in_var_TEXCOORD Location 2

+ 16 - 2
tools/clang/test/CodeGenSPIRV/spirv.interface.gs.hlsl

@@ -1,9 +1,12 @@
-// Run: %dxc -T gs_6_0 -E main
+// Run: %dxc -T gs_6_0 -E main -fspv-reflect
 
 
 // CHECK: OpCapability ClipDistance
 // CHECK: OpCapability ClipDistance
 // CHECK: OpCapability CullDistance
 // CHECK: OpCapability CullDistance
 // CHECK: OpCapability Geometry
 // CHECK: OpCapability Geometry
 
 
+// CHECK: OpExtension "SPV_GOOGLE_decorate_string"
+// CHECK: OpExtension "SPV_GOOGLE_hlsl_functionality1"
+
 struct GsPerVertexIn {
 struct GsPerVertexIn {
     float4 pos   : SV_Position;      // Builtin Position
     float4 pos   : SV_Position;      // Builtin Position
     float3 clip2 : SV_ClipDistance2; // Builtin ClipDistance
     float3 clip2 : SV_ClipDistance2; // Builtin ClipDistance
@@ -43,11 +46,22 @@ struct GsPerVertexOut {
 // CHECK: OpMemberDecorate %type_gl_PerVertex 3 BuiltIn CullDistance
 // CHECK: OpMemberDecorate %type_gl_PerVertex 3 BuiltIn CullDistance
 // CHECK: OpDecorate %type_gl_PerVertex Block
 // CHECK: OpDecorate %type_gl_PerVertex Block
 
 
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex 0 HlslSemanticGOOGLE "SV_Position"
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex 1 HlslSemanticGOOGLE "PSIZE"
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex 2 HlslSemanticGOOGLE "SV_ClipDistance"
+
 // CHECK: OpDecorate %gl_ClipDistance BuiltIn ClipDistance
 // CHECK: OpDecorate %gl_ClipDistance BuiltIn ClipDistance
+// CHECK: OpDecorateStringGOOGLE %gl_ClipDistance HlslSemanticGOOGLE "SV_ClipDistance"
 // CHECK: OpDecorate %gl_CullDistance BuiltIn CullDistance
 // CHECK: OpDecorate %gl_CullDistance BuiltIn CullDistance
+// CHECK: OpDecorateStringGOOGLE %gl_CullDistance HlslSemanticGOOGLE "SV_CullDistance"
+// CHECK: OpDecorateStringGOOGLE %in_var_BAR HlslSemanticGOOGLE "BAR"
+// CHECK: OpDecorateStringGOOGLE %in_var_FOO HlslSemanticGOOGLE "FOO"
 // CHECK: OpDecorate %gl_Position BuiltIn Position
 // CHECK: OpDecorate %gl_Position BuiltIn Position
+// CHECK: OpDecorateStringGOOGLE %gl_Position HlslSemanticGOOGLE "SV_Position"
+// CHECK: OpDecorateStringGOOGLE %out_var_FOO HlslSemanticGOOGLE "FOO"
 // CHECK: OpDecorate %gl_PointSize BuiltIn PointSize
 // CHECK: OpDecorate %gl_PointSize BuiltIn PointSize
-
+// CHECK: OpDecorateStringGOOGLE %gl_PointSize HlslSemanticGOOGLE "PSIZE"
+// CHECK: OpDecorateStringGOOGLE %out_var_BAR HlslSemanticGOOGLE "BAR"
 // CHECK: OpDecorate %in_var_BAR Location 0
 // CHECK: OpDecorate %in_var_BAR Location 0
 // CHECK: OpDecorate %in_var_FOO Location 1
 // CHECK: OpDecorate %in_var_FOO Location 1
 // CHECK: OpDecorate %out_var_FOO Location 0
 // CHECK: OpDecorate %out_var_FOO Location 0

+ 23 - 1
tools/clang/test/CodeGenSPIRV/spirv.interface.hs.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T hs_6_0 -E main
+// Run: %dxc -T hs_6_0 -E main -fspv-reflect
 
 
 #define NumOutPoints 2
 #define NumOutPoints 2
 
 
@@ -6,6 +6,9 @@
 // CHECK: OpCapability CullDistance
 // CHECK: OpCapability CullDistance
 // CHECK: OpCapability Tessellation
 // CHECK: OpCapability Tessellation
 
 
+// CHECK: OpExtension "SPV_GOOGLE_decorate_string"
+// CHECK: OpExtension "SPV_GOOGLE_hlsl_functionality1"
+
 // Input control point
 // Input control point
 struct HsCpIn
 struct HsCpIn
 {
 {
@@ -72,19 +75,38 @@ struct HsPcfOut
 // CHECK: OpMemberDecorate %type_gl_PerVertex 3 BuiltIn CullDistance
 // CHECK: OpMemberDecorate %type_gl_PerVertex 3 BuiltIn CullDistance
 // CHECK: OpDecorate %type_gl_PerVertex Block
 // CHECK: OpDecorate %type_gl_PerVertex Block
 
 
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex 0 HlslSemanticGOOGLE "SV_Position"
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex 1 HlslSemanticGOOGLE "PSIZE"
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex 2 HlslSemanticGOOGLE "SV_ClipDistance"
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex 3 HlslSemanticGOOGLE "SV_CullDistance"
+
 // CHECK: OpMemberDecorate %type_gl_PerVertex_0 0 BuiltIn Position
 // CHECK: OpMemberDecorate %type_gl_PerVertex_0 0 BuiltIn Position
 // CHECK: OpMemberDecorate %type_gl_PerVertex_0 1 BuiltIn PointSize
 // CHECK: OpMemberDecorate %type_gl_PerVertex_0 1 BuiltIn PointSize
 // CHECK: OpMemberDecorate %type_gl_PerVertex_0 2 BuiltIn ClipDistance
 // CHECK: OpMemberDecorate %type_gl_PerVertex_0 2 BuiltIn ClipDistance
 // CHECK: OpMemberDecorate %type_gl_PerVertex_0 3 BuiltIn CullDistance
 // CHECK: OpMemberDecorate %type_gl_PerVertex_0 3 BuiltIn CullDistance
 // CHECK: OpDecorate %type_gl_PerVertex_0 Block
 // CHECK: OpDecorate %type_gl_PerVertex_0 Block
 
 
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex_0 0 HlslSemanticGOOGLE "SV_Position"
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex_0 1 HlslSemanticGOOGLE "PSIZE"
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex_0 2 HlslSemanticGOOGLE "SV_ClipDistance"
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex_0 3 HlslSemanticGOOGLE "SV_CullDistance"
+
+// CHECK: OpDecorateStringGOOGLE %in_var_BAZ HlslSemanticGOOGLE "BAZ"
 // CHECK: OpDecorate %gl_InvocationID BuiltIn InvocationId
 // CHECK: OpDecorate %gl_InvocationID BuiltIn InvocationId
+// CHECK: OpDecorateStringGOOGLE %gl_InvocationID HlslSemanticGOOGLE "SV_OutputControlPointID"
 // CHECK: OpDecorate %gl_PrimitiveID BuiltIn PrimitiveId
 // CHECK: OpDecorate %gl_PrimitiveID BuiltIn PrimitiveId
+// CHECK: OpDecorateStringGOOGLE %gl_PrimitiveID HlslSemanticGOOGLE "SV_PrimitiveID"
+// CHECK: OpDecorateStringGOOGLE %out_var_FOO HlslSemanticGOOGLE "FOO"
+// CHECK: OpDecorateStringGOOGLE %out_var_BAR HlslSemanticGOOGLE "BAR"
 // CHECK: OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter
 // CHECK: OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter
+// CHECK: OpDecorateStringGOOGLE %gl_TessLevelOuter HlslSemanticGOOGLE "SV_TessFactor"
 // CHECK: OpDecorate %gl_TessLevelOuter Patch
 // CHECK: OpDecorate %gl_TessLevelOuter Patch
 // CHECK: OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner
 // CHECK: OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner
+// CHECK: OpDecorateStringGOOGLE %gl_TessLevelInner HlslSemanticGOOGLE "SV_InsideTessFactor"
 // CHECK: OpDecorate %gl_TessLevelInner Patch
 // CHECK: OpDecorate %gl_TessLevelInner Patch
+// CHECK: OpDecorateStringGOOGLE %out_var_TEXCOORD HlslSemanticGOOGLE "TEXCOORD"
 // CHECK: OpDecorate %out_var_TEXCOORD Patch
 // CHECK: OpDecorate %out_var_TEXCOORD Patch
+// CHECK: OpDecorateStringGOOGLE %out_var_WEIGHT HlslSemanticGOOGLE "WEIGHT"
 // CHECK: OpDecorate %out_var_WEIGHT Patch
 // CHECK: OpDecorate %out_var_WEIGHT Patch
 // CHECK: OpDecorate %in_var_BAZ Location 0
 // CHECK: OpDecorate %in_var_BAZ Location 0
 // CHECK: OpDecorate %out_var_BAR Location 0
 // CHECK: OpDecorate %out_var_BAR Location 0

+ 10 - 1
tools/clang/test/CodeGenSPIRV/spirv.interface.ps.hlsl

@@ -1,8 +1,11 @@
-// Run: %dxc -T ps_6_0 -E main
+// Run: %dxc -T ps_6_0 -E main -fspv-reflect
 
 
 // CHECK: OpCapability ClipDistance
 // CHECK: OpCapability ClipDistance
 // CHECK: OpCapability CullDistance
 // CHECK: OpCapability CullDistance
 
 
+// CHECK: OpExtension "SPV_GOOGLE_decorate_string"
+// CHECK: OpExtension "SPV_GOOGLE_hlsl_functionality1"
+
 struct Inner {
 struct Inner {
     float2 cull2 : SV_CullDistance2;            // Builtin CullDistance
     float2 cull2 : SV_CullDistance2;            // Builtin CullDistance
     float3 foo   : FOO;                         // Input variable
     float3 foo   : FOO;                         // Input variable
@@ -17,8 +20,14 @@ struct PsIn {
 // CHECK: OpEntryPoint Fragment %main "main" %gl_ClipDistance %gl_CullDistance %gl_FragCoord %in_var_FOO %in_var_BAR %out_var_SV_Target
 // CHECK: OpEntryPoint Fragment %main "main" %gl_ClipDistance %gl_CullDistance %gl_FragCoord %in_var_FOO %in_var_BAR %out_var_SV_Target
 
 
 // CHECK: OpDecorate %gl_ClipDistance BuiltIn ClipDistance
 // CHECK: OpDecorate %gl_ClipDistance BuiltIn ClipDistance
+// CHECK: OpDecorateStringGOOGLE %gl_ClipDistance HlslSemanticGOOGLE "SV_ClipDistance"
 // CHECK: OpDecorate %gl_CullDistance BuiltIn CullDistance
 // CHECK: OpDecorate %gl_CullDistance BuiltIn CullDistance
+// CHECK: OpDecorateStringGOOGLE %gl_CullDistance HlslSemanticGOOGLE "SV_CullDistance"
 // CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
 // CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
+// CHECK: OpDecorateStringGOOGLE %gl_FragCoord HlslSemanticGOOGLE "SV_Position"
+// CHECK: OpDecorateStringGOOGLE %in_var_FOO HlslSemanticGOOGLE "FOO"
+// CHECK: OpDecorateStringGOOGLE %in_var_BAR HlslSemanticGOOGLE "BAR"
+// CHECK: OpDecorateStringGOOGLE %out_var_SV_Target HlslSemanticGOOGLE "SV_Target"
 // CHECK: OpDecorate %in_var_FOO Location 0
 // CHECK: OpDecorate %in_var_FOO Location 0
 // CHECK: OpDecorate %in_var_BAR Location 1
 // CHECK: OpDecorate %in_var_BAR Location 1
 // CHECK: OpDecorate %out_var_SV_Target Location 0
 // CHECK: OpDecorate %out_var_SV_Target Location 0

+ 16 - 1
tools/clang/test/CodeGenSPIRV/spirv.interface.vs.hlsl

@@ -1,8 +1,11 @@
-// Run: %dxc -T vs_6_0 -E main
+// Run: %dxc -T vs_6_0 -E main -fspv-reflect
 
 
 // CHECK: OpCapability ClipDistance
 // CHECK: OpCapability ClipDistance
 // CHECK: OpCapability CullDistance
 // CHECK: OpCapability CullDistance
 
 
+// CHECK: OpExtension "SPV_GOOGLE_decorate_string"
+// CHECK: OpExtension "SPV_GOOGLE_hlsl_functionality1"
+
 // CHECK: OpEntryPoint Vertex %main "main" %gl_PerVertexOut %in_var_TEXCOORD %in_var_SV_Position %in_var_SV_ClipDistance %in_var_SV_CullDistance0 %out_var_COLOR %out_var_TEXCOORD
 // CHECK: OpEntryPoint Vertex %main "main" %gl_PerVertexOut %in_var_TEXCOORD %in_var_SV_Position %in_var_SV_ClipDistance %in_var_SV_CullDistance0 %out_var_COLOR %out_var_TEXCOORD
 
 
 // CHECK: OpMemberDecorate %type_gl_PerVertex 0 BuiltIn Position
 // CHECK: OpMemberDecorate %type_gl_PerVertex 0 BuiltIn Position
@@ -11,6 +14,18 @@
 // CHECK: OpMemberDecorate %type_gl_PerVertex 3 BuiltIn CullDistance
 // CHECK: OpMemberDecorate %type_gl_PerVertex 3 BuiltIn CullDistance
 // CHECK: OpDecorate %type_gl_PerVertex Block
 // CHECK: OpDecorate %type_gl_PerVertex Block
 
 
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex 0 HlslSemanticGOOGLE "SV_Position"
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex 1 HlslSemanticGOOGLE "PSize"
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex 2 HlslSemanticGOOGLE "SV_ClipDistance"
+// CHECK: OpMemberDecorateStringGOOGLE %type_gl_PerVertex 3 HlslSemanticGOOGLE "SV_CullDistance"
+
+// CHECK: OpDecorateStringGOOGLE %in_var_TEXCOORD HlslSemanticGOOGLE "TEXCOORD"
+// CHECK: OpDecorateStringGOOGLE %in_var_SV_Position HlslSemanticGOOGLE "SV_Position"
+// CHECK: OpDecorateStringGOOGLE %in_var_SV_ClipDistance HlslSemanticGOOGLE "SV_ClipDistance"
+// CHECK: OpDecorateStringGOOGLE %in_var_SV_CullDistance0 HlslSemanticGOOGLE "SV_CullDistance0"
+// CHECK: OpDecorateStringGOOGLE %out_var_COLOR HlslSemanticGOOGLE "COLOR"
+// CHECK: OpDecorateStringGOOGLE %out_var_TEXCOORD HlslSemanticGOOGLE "TEXCOORD"
+
 // CHECK: OpDecorate %in_var_TEXCOORD Location 0
 // CHECK: OpDecorate %in_var_TEXCOORD Location 0
 // CHECK: OpDecorate %in_var_SV_Position Location 1
 // CHECK: OpDecorate %in_var_SV_Position Location 1
 // CHECK: OpDecorate %in_var_SV_ClipDistance Location 2
 // CHECK: OpDecorate %in_var_SV_ClipDistance Location 2

+ 11 - 1
tools/clang/test/CodeGenSPIRV/spirv.legal.sbuffer.counter.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T ps_6_0 -E main
+// Run: %dxc -T ps_6_0 -E main -fspv-reflect
 
 
 struct S1 {
 struct S1 {
     float4 f;
     float4 f;
@@ -12,6 +12,16 @@ struct S3 {
     float2 f;
     float2 f;
 };
 };
 
 
+// Do not generate decorations for alias buffers
+
+// CHECK-NOT: OpDecorateId %staticgRWSBuffer HlslCounterBufferGOOGLE
+// CHECK-NOT: OpDecorateId %staticgASBuffer HlslCounterBufferGOOGLE
+// CHECK-NOT: OpDecorateId %staticgCSBuffer HlslCounterBufferGOOGLE
+
+// CHECK-NOT: OpDecorateId %localRWSBuffer HlslCounterBufferGOOGLE
+// CHECK-NOT: OpDecorateId %localASBuffer HlslCounterBufferGOOGLE
+// CHECK-NOT: OpDecorateId %localCSBuffer HlslCounterBufferGOOGLE
+
 RWStructuredBuffer<S1>      selectRWSBuffer(RWStructuredBuffer<S1>    paramRWSBuffer, bool selector);
 RWStructuredBuffer<S1>      selectRWSBuffer(RWStructuredBuffer<S1>    paramRWSBuffer, bool selector);
 AppendStructuredBuffer<S2>  selectASBuffer(AppendStructuredBuffer<S2>  paramASBuffer,  bool selector);
 AppendStructuredBuffer<S2>  selectASBuffer(AppendStructuredBuffer<S2>  paramASBuffer,  bool selector);
 ConsumeStructuredBuffer<S3> selectCSBuffer(ConsumeStructuredBuffer<S3> paramCSBuffer,  bool selector);
 ConsumeStructuredBuffer<S3> selectCSBuffer(ConsumeStructuredBuffer<S3> paramCSBuffer,  bool selector);

+ 6 - 1
tools/clang/test/CodeGenSPIRV/type.append-structured-buffer.hlsl

@@ -1,4 +1,6 @@
-// Run: %dxc -T vs_6_0 -E main
+// Run: %dxc -T vs_6_0 -E main -fspv-reflect
+
+// CHECK: OpExtension "SPV_GOOGLE_hlsl_functionality1"
 
 
 // CHECK: OpName %type_AppendStructuredBuffer_v4float "type.AppendStructuredBuffer.v4float"
 // CHECK: OpName %type_AppendStructuredBuffer_v4float "type.AppendStructuredBuffer.v4float"
 // CHECK: OpName %buffer1 "buffer1"
 // CHECK: OpName %buffer1 "buffer1"
@@ -11,6 +13,9 @@
 
 
 // CHECK: OpName %counter_var_buffer2 "counter.var.buffer2"
 // CHECK: OpName %counter_var_buffer2 "counter.var.buffer2"
 
 
+// CHECK: OpDecorateId %buffer1 HlslCounterBufferGOOGLE %counter_var_buffer1
+// CHECK: OpDecorateId %buffer2 HlslCounterBufferGOOGLE %counter_var_buffer2
+
 // CHECK: %type_AppendStructuredBuffer_v4float = OpTypeStruct %_runtimearr_v4float
 // CHECK: %type_AppendStructuredBuffer_v4float = OpTypeStruct %_runtimearr_v4float
 // CHECK: %_ptr_Uniform_type_AppendStructuredBuffer_v4float = OpTypePointer Uniform %type_AppendStructuredBuffer_v4float
 // CHECK: %_ptr_Uniform_type_AppendStructuredBuffer_v4float = OpTypePointer Uniform %type_AppendStructuredBuffer_v4float
 
 

+ 6 - 1
tools/clang/test/CodeGenSPIRV/type.consume-structured-buffer.hlsl

@@ -1,4 +1,6 @@
-// Run: %dxc -T vs_6_0 -E main
+// Run: %dxc -T vs_6_0 -E main -fspv-reflect
+
+// CHECK: OpExtension "SPV_GOOGLE_hlsl_functionality1"
 
 
 // CHECK: OpName %type_ConsumeStructuredBuffer_v4float "type.ConsumeStructuredBuffer.v4float"
 // CHECK: OpName %type_ConsumeStructuredBuffer_v4float "type.ConsumeStructuredBuffer.v4float"
 // CHECK: OpName %buffer1 "buffer1"
 // CHECK: OpName %buffer1 "buffer1"
@@ -11,6 +13,9 @@
 
 
 // CHECK: OpName %counter_var_buffer2 "counter.var.buffer2"
 // CHECK: OpName %counter_var_buffer2 "counter.var.buffer2"
 
 
+// CHECK: OpDecorateId %buffer1 HlslCounterBufferGOOGLE %counter_var_buffer1
+// CHECK: OpDecorateId %buffer2 HlslCounterBufferGOOGLE %counter_var_buffer2
+
 // CHECK: %type_ConsumeStructuredBuffer_v4float = OpTypeStruct %_runtimearr_v4float
 // CHECK: %type_ConsumeStructuredBuffer_v4float = OpTypeStruct %_runtimearr_v4float
 // CHECK: %_ptr_Uniform_type_ConsumeStructuredBuffer_v4float = OpTypePointer Uniform %type_ConsumeStructuredBuffer_v4float
 // CHECK: %_ptr_Uniform_type_ConsumeStructuredBuffer_v4float = OpTypePointer Uniform %type_ConsumeStructuredBuffer_v4float
 
 

+ 11 - 1
tools/clang/test/CodeGenSPIRV/type.structured-buffer.hlsl

@@ -1,4 +1,6 @@
-// Run: %dxc -T ps_6_0 -E main
+// Run: %dxc -T ps_6_0 -E main -fspv-reflect
+
+// CHECK: OpExtension "SPV_GOOGLE_hlsl_functionality1"
 
 
 // CHECK: OpName %type_StructuredBuffer_S "type.StructuredBuffer.S"
 // CHECK: OpName %type_StructuredBuffer_S "type.StructuredBuffer.S"
 // CHECK: OpName %type_StructuredBuffer_T "type.StructuredBuffer.T"
 // CHECK: OpName %type_StructuredBuffer_T "type.StructuredBuffer.T"
@@ -6,6 +8,9 @@
 // CHECK: OpName %type_RWStructuredBuffer_S "type.RWStructuredBuffer.S"
 // CHECK: OpName %type_RWStructuredBuffer_S "type.RWStructuredBuffer.S"
 // CHECK: OpName %type_RWStructuredBuffer_T "type.RWStructuredBuffer.T"
 // CHECK: OpName %type_RWStructuredBuffer_T "type.RWStructuredBuffer.T"
 
 
+// CHECK: OpDecorateId %mySBuffer3 HlslCounterBufferGOOGLE %counter_var_mySBuffer3
+// CHECK: OpDecorateId %mySBuffer4 HlslCounterBufferGOOGLE %counter_var_mySBuffer4
+
 // CHECK: %S = OpTypeStruct %float %v3float %mat2v3float
 // CHECK: %S = OpTypeStruct %float %v3float %mat2v3float
 // CHECK: %_runtimearr_S = OpTypeRuntimeArray %S
 // CHECK: %_runtimearr_S = OpTypeRuntimeArray %S
 // CHECK: %type_StructuredBuffer_S = OpTypeStruct %_runtimearr_S
 // CHECK: %type_StructuredBuffer_S = OpTypeStruct %_runtimearr_S
@@ -24,6 +29,9 @@ struct S {
 // CHECK: %type_RWStructuredBuffer_S = OpTypeStruct %_runtimearr_S
 // CHECK: %type_RWStructuredBuffer_S = OpTypeStruct %_runtimearr_S
 // CHECK: %_ptr_Uniform_type_RWStructuredBuffer_S = OpTypePointer Uniform %type_RWStructuredBuffer_S
 // CHECK: %_ptr_Uniform_type_RWStructuredBuffer_S = OpTypePointer Uniform %type_RWStructuredBuffer_S
 
 
+// CHECK: %type_ACSBuffer_counter = OpTypeStruct %int
+// CHECK: %_ptr_Uniform_type_ACSBuffer_counter = OpTypePointer Uniform %type_ACSBuffer_counter
+
 // CHECK: %type_RWStructuredBuffer_T = OpTypeStruct %_runtimearr_T
 // CHECK: %type_RWStructuredBuffer_T = OpTypeStruct %_runtimearr_T
 // CHECK: %_ptr_Uniform_type_RWStructuredBuffer_T = OpTypePointer Uniform %type_RWStructuredBuffer_T
 // CHECK: %_ptr_Uniform_type_RWStructuredBuffer_T = OpTypePointer Uniform %type_RWStructuredBuffer_T
 struct T {
 struct T {
@@ -39,8 +47,10 @@ StructuredBuffer<S> mySBuffer1 : register(t1);
 StructuredBuffer<T> mySBuffer2 : register(t2);
 StructuredBuffer<T> mySBuffer2 : register(t2);
 
 
 // CHECK: %mySBuffer3 = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_S Uniform
 // CHECK: %mySBuffer3 = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_S Uniform
+// CHECK: %counter_var_mySBuffer3 = OpVariable %_ptr_Uniform_type_ACSBuffer_counter Uniform
 RWStructuredBuffer<S> mySBuffer3 : register(u3);
 RWStructuredBuffer<S> mySBuffer3 : register(u3);
 // CHECK: %mySBuffer4 = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_T Uniform
 // CHECK: %mySBuffer4 = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_T Uniform
+// CHECK: %counter_var_mySBuffer4 = OpVariable %_ptr_Uniform_type_ACSBuffer_counter Uniform
 RWStructuredBuffer<T> mySBuffer4 : register(u4);
 RWStructuredBuffer<T> mySBuffer4 : register(u4);
 
 
 float4 main() : SV_Target {
 float4 main() : SV_Target {

+ 1 - 0
tools/clang/tools/dxcompiler/dxcompilerobj.cpp

@@ -470,6 +470,7 @@ public:
           spirvOpts.disableValidation = opts.DisableValidation;
           spirvOpts.disableValidation = opts.DisableValidation;
           spirvOpts.invertY = opts.VkInvertY;
           spirvOpts.invertY = opts.VkInvertY;
           spirvOpts.useGlslLayout = opts.VkUseGlslLayout;
           spirvOpts.useGlslLayout = opts.VkUseGlslLayout;
+          spirvOpts.enableReflect = opts.SpvEnableReflect;
           spirvOpts.ignoreUnusedResources = opts.VkIgnoreUnusedResources;
           spirvOpts.ignoreUnusedResources = opts.VkIgnoreUnusedResources;
           spirvOpts.defaultRowMajor = opts.DefaultRowMajor;
           spirvOpts.defaultRowMajor = opts.DefaultRowMajor;
           spirvOpts.stageIoOrder = opts.VkStageIoOrder;
           spirvOpts.stageIoOrder = opts.VkStageIoOrder;

+ 4 - 4
tools/clang/unittests/SPIRV/ModuleBuilderTest.cpp

@@ -7,8 +7,8 @@
 //
 //
 //===----------------------------------------------------------------------===//
 //===----------------------------------------------------------------------===//
 
 
-#include "spirv/unified1/spirv.hpp11"
 #include "clang/SPIRV/ModuleBuilder.h"
 #include "clang/SPIRV/ModuleBuilder.h"
+#include "spirv/unified1/spirv.hpp11"
 
 
 #include "SPIRVTestUtils.h"
 #include "SPIRVTestUtils.h"
 
 
@@ -21,7 +21,7 @@ using ::testing::ElementsAre;
 
 
 TEST(ModuleBuilder, TakeModuleDirectlyCreatesHeader) {
 TEST(ModuleBuilder, TakeModuleDirectlyCreatesHeader) {
   SPIRVContext context;
   SPIRVContext context;
-  ModuleBuilder builder(&context);
+  ModuleBuilder builder(&context, false);
 
 
   EXPECT_THAT(builder.takeModule(),
   EXPECT_THAT(builder.takeModule(),
               ElementsAre(spv::MagicNumber, 0x00010000, 14u << 16, 1u, 0u));
               ElementsAre(spv::MagicNumber, 0x00010000, 14u << 16, 1u, 0u));
@@ -29,7 +29,7 @@ TEST(ModuleBuilder, TakeModuleDirectlyCreatesHeader) {
 
 
 TEST(ModuleBuilder, CreateFunction) {
 TEST(ModuleBuilder, CreateFunction) {
   SPIRVContext context;
   SPIRVContext context;
-  ModuleBuilder builder(&context);
+  ModuleBuilder builder(&context, false);
 
 
   const auto rType = context.takeNextId();
   const auto rType = context.takeNextId();
   const auto fType = context.takeNextId();
   const auto fType = context.takeNextId();
@@ -47,7 +47,7 @@ TEST(ModuleBuilder, CreateFunction) {
 
 
 TEST(ModuleBuilder, CreateBasicBlock) {
 TEST(ModuleBuilder, CreateBasicBlock) {
   SPIRVContext context;
   SPIRVContext context;
-  ModuleBuilder builder(&context);
+  ModuleBuilder builder(&context, false);
 
 
   const auto rType = context.takeNextId();
   const auto rType = context.takeNextId();
   const auto fType = context.takeNextId();
   const auto fType = context.takeNextId();