Browse Source

[spirv] generate OpenCL.DebugInfo.100 instructions (#3155)

OpenCL.DebugInfo.100
is a SPIR-V extended instruction set that provides DWARF style debug information.
This PR allows DXC SPIR-V backend to generate the rich HLSL debug information
using OpenCL.DebugInfo.100 instructions.
Jaebaek Seo 5 years ago
parent
commit
7f985ff472
74 changed files with 4669 additions and 453 deletions
  1. 1 1
      external/SPIRV-Tools
  2. 1 0
      include/dxc/Support/SPIRVOptions.h
  3. 11 0
      lib/DxcSupport/HLSLOptions.cpp
  4. 26 0
      tools/clang/include/clang/SPIRV/SpirvBasicBlock.h
  5. 58 3
      tools/clang/include/clang/SPIRV/SpirvBuilder.h
  6. 149 1
      tools/clang/include/clang/SPIRV/SpirvContext.h
  7. 26 0
      tools/clang/include/clang/SPIRV/SpirvFunction.h
  8. 761 2
      tools/clang/include/clang/SPIRV/SpirvInstruction.h
  9. 13 2
      tools/clang/include/clang/SPIRV/SpirvModule.h
  10. 4 2
      tools/clang/include/clang/SPIRV/SpirvType.h
  11. 21 0
      tools/clang/include/clang/SPIRV/SpirvVisitor.h
  12. 3 0
      tools/clang/lib/SPIRV/CMakeLists.txt
  13. 426 0
      tools/clang/lib/SPIRV/DebugTypeVisitor.cpp
  14. 106 0
      tools/clang/lib/SPIRV/DebugTypeVisitor.h
  15. 56 6
      tools/clang/lib/SPIRV/DeclResultIdMapper.cpp
  16. 14 2
      tools/clang/lib/SPIRV/DeclResultIdMapper.h
  17. 604 146
      tools/clang/lib/SPIRV/EmitVisitor.cpp
  18. 50 6
      tools/clang/lib/SPIRV/EmitVisitor.h
  19. 39 3
      tools/clang/lib/SPIRV/LowerTypeVisitor.cpp
  20. 7 6
      tools/clang/lib/SPIRV/LowerTypeVisitor.h
  21. 217 0
      tools/clang/lib/SPIRV/SortDebugInfoVisitor.cpp
  22. 59 0
      tools/clang/lib/SPIRV/SortDebugInfoVisitor.h
  23. 14 5
      tools/clang/lib/SPIRV/SpirvBasicBlock.cpp
  24. 121 1
      tools/clang/lib/SPIRV/SpirvBuilder.cpp
  25. 181 1
      tools/clang/lib/SPIRV/SpirvContext.cpp
  26. 150 12
      tools/clang/lib/SPIRV/SpirvEmitter.cpp
  27. 5 0
      tools/clang/lib/SPIRV/SpirvEmitter.h
  28. 14 3
      tools/clang/lib/SPIRV/SpirvFunction.cpp
  29. 182 0
      tools/clang/lib/SPIRV/SpirvInstruction.cpp
  30. 26 9
      tools/clang/lib/SPIRV/SpirvModule.cpp
  31. 43 0
      tools/clang/test/CodeGenSPIRV/rich.debug.cbuffer.hlsl
  32. 10 0
      tools/clang/test/CodeGenSPIRV/rich.debug.debugcompilationunit.hlsl
  33. 34 0
      tools/clang/test/CodeGenSPIRV/rich.debug.debugdeclare.hlsl
  34. 30 0
      tools/clang/test/CodeGenSPIRV/rich.debug.debugdeclare.without.init.hlsl
  35. 36 0
      tools/clang/test/CodeGenSPIRV/rich.debug.debuglexicalblock.hlsl
  36. 62 0
      tools/clang/test/CodeGenSPIRV/rich.debug.debugscope.hlsl
  37. 9 0
      tools/clang/test/CodeGenSPIRV/rich.debug.debugsource.hlsl
  38. 41 0
      tools/clang/test/CodeGenSPIRV/rich.debug.debugsource.multiple.hlsl
  39. 36 0
      tools/clang/test/CodeGenSPIRV/rich.debug.function.hlsl
  40. 34 0
      tools/clang/test/CodeGenSPIRV/rich.debug.function.param.hlsl
  41. 50 0
      tools/clang/test/CodeGenSPIRV/rich.debug.function.parent.hlsl
  42. 34 0
      tools/clang/test/CodeGenSPIRV/rich.debug.global-variable.hlsl
  43. 48 0
      tools/clang/test/CodeGenSPIRV/rich.debug.local-variable.hlsl
  44. 56 0
      tools/clang/test/CodeGenSPIRV/rich.debug.member.function.param.hlsl
  45. 43 0
      tools/clang/test/CodeGenSPIRV/rich.debug.member.function.without-call.hlsl
  46. 33 0
      tools/clang/test/CodeGenSPIRV/rich.debug.rwtexture.hlsl
  47. 16 0
      tools/clang/test/CodeGenSPIRV/rich.debug.sampler.hlsl
  48. 13 0
      tools/clang/test/CodeGenSPIRV/rich.debug.sort.type.template.hlsl
  49. 68 0
      tools/clang/test/CodeGenSPIRV/rich.debug.structured-buffer.hlsl
  50. 33 0
      tools/clang/test/CodeGenSPIRV/rich.debug.switch.debugscope.hlsl
  51. 40 0
      tools/clang/test/CodeGenSPIRV/rich.debug.texture.hlsl
  52. 25 0
      tools/clang/test/CodeGenSPIRV/rich.debug.type.array-from-same-type.hlsl
  53. 36 0
      tools/clang/test/CodeGenSPIRV/rich.debug.type.array.hlsl
  54. 11 0
      tools/clang/test/CodeGenSPIRV/rich.debug.type.bool.hlsl
  55. 22 0
      tools/clang/test/CodeGenSPIRV/rich.debug.type.composite.before.function.hlsl
  56. 15 0
      tools/clang/test/CodeGenSPIRV/rich.debug.type.composite.empty.hlsl
  57. 51 0
      tools/clang/test/CodeGenSPIRV/rich.debug.type.composite.hlsl
  58. 16 0
      tools/clang/test/CodeGenSPIRV/rich.debug.type.float.hlsl
  59. 28 0
      tools/clang/test/CodeGenSPIRV/rich.debug.type.function.hlsl
  60. 26 0
      tools/clang/test/CodeGenSPIRV/rich.debug.type.int.hlsl
  61. 14 0
      tools/clang/test/CodeGenSPIRV/rich.debug.type.matrix.hlsl
  62. 58 0
      tools/clang/test/CodeGenSPIRV/rich.debug.type.member.function.hlsl
  63. 17 0
      tools/clang/test/CodeGenSPIRV/rich.debug.type.vector.hlsl
  64. 0 2
      tools/clang/test/CodeGenSPIRV/spirv.debug.ctrl.line.hlsl
  65. 0 17
      tools/clang/test/CodeGenSPIRV/spirv.debug.ctrl.source.hlsl
  66. 2 1
      tools/clang/test/CodeGenSPIRV/spirv.debug.o3.option.hlsl
  67. 5 28
      tools/clang/test/CodeGenSPIRV/spirv.debug.opline.entry.hlsl
  68. 12 75
      tools/clang/test/CodeGenSPIRV/spirv.debug.opline.function.hlsl
  69. 8 29
      tools/clang/test/CodeGenSPIRV/spirv.debug.opline.include.hlsl
  70. 24 82
      tools/clang/test/CodeGenSPIRV/spirv.debug.opline.variables.hlsl
  71. 1 4
      tools/clang/test/CodeGenSPIRV/spirv.debug.opsource.hlsl
  72. 1 0
      tools/clang/unittests/SPIRV/CMakeLists.txt
  73. 139 4
      tools/clang/unittests/SPIRV/CodeGenSpirvTest.cpp
  74. 44 0
      tools/clang/unittests/SPIRV/SpirvDebugInstructionTest.cpp

+ 1 - 1
external/SPIRV-Tools

@@ -1 +1 @@
-Subproject commit 13a65b1aee425a97b9ca73d81212d99fd2bf9227
+Subproject commit 2c60d16a646b7b4d1541e278dda7133cf6feaa9b

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

@@ -42,6 +42,7 @@ struct SpirvCodeGenOptions {
   bool debugInfoLine;
   bool debugInfoSource;
   bool debugInfoTool;
+  bool debugInfoRich;
   bool defaultRowMajor;
   bool disableValidation;
   bool enable16BitTypes;

+ 11 - 0
lib/DxcSupport/HLSLOptions.cpp

@@ -817,6 +817,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
 
   opts.SpirvOptions.debugInfoFile = opts.SpirvOptions.debugInfoSource = false;
   opts.SpirvOptions.debugInfoLine = opts.SpirvOptions.debugInfoTool = false;
+  opts.SpirvOptions.debugInfoRich = false;
   if (Args.hasArg(OPT_fspv_debug_EQ)) {
     opts.DebugInfo = true;
     for (const Arg *A : Args.filtered(OPT_fspv_debug_EQ)) {
@@ -832,6 +833,16 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
         opts.SpirvOptions.debugInfoLine = true;
       } else if (v == "tool") {
         opts.SpirvOptions.debugInfoTool = true;
+      } else if (v == "rich") {
+        opts.SpirvOptions.debugInfoFile = true;
+        opts.SpirvOptions.debugInfoSource = false;
+        opts.SpirvOptions.debugInfoLine = true;
+        opts.SpirvOptions.debugInfoRich = true;
+      } else if (v == "rich-with-source") {
+        opts.SpirvOptions.debugInfoFile = true;
+        opts.SpirvOptions.debugInfoSource = true;
+        opts.SpirvOptions.debugInfoLine = true;
+        opts.SpirvOptions.debugInfoRich = true;
       } else {
         errors << "unknown SPIR-V debug info control parameter: " << v;
         return 1;

+ 26 - 0
tools/clang/include/clang/SPIRV/SpirvBasicBlock.h

@@ -70,10 +70,29 @@ public:
   /// OpLoopMerge instruction. Returns nullptr otherwise.
   SpirvBasicBlock *getContinueTarget() const { return continueTarget; }
 
+  /// Get/set DebugScope for this basic block.
+  SpirvDebugScope *getDebugScope() const { return debugScope; }
+  void setDebugScope(SpirvDebugScope *scope) {
+    assert(debugScope == nullptr);
+    debugScope = scope;
+  }
+
+  /// Deletes existing debugScope and sets scope as the new debugScope.
+  void updateDebugScope(SpirvDebugScope *scope) {
+    if (debugScope != nullptr) {
+      debugScope->releaseMemory();
+      debugScope = nullptr;
+    }
+    setDebugScope(scope);
+  }
+
   /// Adds an instruction to the vector of instructions belonging to this basic
   /// block.
   void addInstruction(SpirvInstruction *inst) { instructions.push_back(inst); }
 
+  /// Return true if instructions is empty. Otherwise, return false.
+  bool empty() { return instructions.empty(); }
+
   /// Returns true if the last instruction in this basic block is a termination
   /// instruction.
   bool hasTerminator() const;
@@ -106,6 +125,13 @@ private:
   /// The continue merge targets if this basic block is a header block
   /// of structured control flow.
   SpirvBasicBlock *continueTarget;
+
+  /// DebugScope that groups all instructions in this basic block.
+  /// TODO: There can be multiple DebugScope instructions in a basic block.
+  ///       Currently, we do not find an actual case that DXC has to emit
+  ///       multiple DebugScope instructions in a basic block, but update it
+  ///       when we find the actual case.
+  SpirvDebugScope *debugScope;
 };
 
 } // end namespace spirv

+ 58 - 3
tools/clang/include/clang/SPIRV/SpirvBuilder.h

@@ -103,6 +103,10 @@ public:
   /// for the basic block. On failure, returns zero.
   SpirvBasicBlock *createBasicBlock(llvm::StringRef name = "");
 
+  /// \brief Creates a SPIR-V DebugScope (OpenCL.DebugInfo.100 instruction).
+  /// On success, returns the <id> of DebugScope. On failure, returns nullptr.
+  SpirvDebugScope *createDebugScope(SpirvDebugInstruction *scope);
+
   /// \brief Adds the basic block with the given label as a successor to the
   /// current basic block.
   void addSuccessor(SpirvBasicBlock *successorBB);
@@ -126,6 +130,9 @@ public:
   /// \brief Sets insertion point to the given basic block.
   inline void setInsertPoint(SpirvBasicBlock *bb) { insertPoint = bb; }
 
+  /// \brief Gets insertion point.
+  inline SpirvBasicBlock *getInsertPoint() { return insertPoint; }
+
   // === Instruction at the current Insertion Point ===
 
   /// \brief Creates a composite construct instruction with the given
@@ -445,6 +452,44 @@ public:
   /// \brief Creates an OpDemoteToHelperInvocationEXT instruction.
   SpirvInstruction *createDemoteToHelperInvocationEXT(SourceLocation);
 
+  // === SPIR-V Rich Debug Info Creation ===
+  SpirvDebugSource *createDebugSource(llvm::StringRef file,
+                                      llvm::StringRef text = "");
+
+  SpirvDebugCompilationUnit *createDebugCompilationUnit(SpirvDebugSource *);
+
+  SpirvDebugLexicalBlock *
+  createDebugLexicalBlock(SpirvDebugSource *, uint32_t line, uint32_t column,
+                          SpirvDebugInstruction *parent);
+
+  SpirvDebugLocalVariable *createDebugLocalVariable(
+      QualType debugType, llvm::StringRef varName, SpirvDebugSource *src,
+      uint32_t line, uint32_t column, SpirvDebugInstruction *parentScope,
+      uint32_t flags, llvm::Optional<uint32_t> argNumber = llvm::None);
+
+  SpirvDebugGlobalVariable *createDebugGlobalVariable(
+      QualType debugType, llvm::StringRef varName, SpirvDebugSource *src,
+      uint32_t line, uint32_t column, SpirvDebugInstruction *parentScope,
+      llvm::StringRef linkageName, SpirvVariable *var, uint32_t flags,
+      llvm::Optional<SpirvInstruction *> staticMemberDebugType = llvm::None);
+
+  // Get a DebugInfoNone if exists. Otherwise, create one and return it.
+  SpirvDebugInfoNone *getOrCreateDebugInfoNone();
+
+  // Get a null DebugExpression if exists. Otherwise, create one and return it.
+  SpirvDebugExpression *getOrCreateNullDebugExpression();
+
+  SpirvDebugDeclare *createDebugDeclare(
+      SpirvDebugLocalVariable *dbgVar, SpirvInstruction *var,
+      llvm::Optional<SpirvDebugExpression *> dbgExpr = llvm::None);
+
+  SpirvDebugFunction *
+  createDebugFunction(const FunctionDecl *decl, llvm::StringRef name,
+                      SpirvDebugSource *src, uint32_t fnLine, uint32_t fnColumn,
+                      SpirvDebugInstruction *parentScope,
+                      llvm::StringRef linkageName, uint32_t flags,
+                      uint32_t scopeLine, SpirvFunction *fn);
+
   /// \brief Create SPIR-V instructions for KHR RayQuery ops
   SpirvInstruction *
   createRayQueryOpsKHR(spv::Op opcode, QualType resultType,
@@ -464,7 +509,7 @@ public:
   /// content. Returns the SpirvString instruction of the file name.
   inline SpirvString *setDebugSource(uint32_t major, uint32_t minor,
                                      const std::vector<llvm::StringRef> &name,
-                                     llvm::StringRef content);
+                                     llvm::StringRef content = "");
 
   /// \brief Adds an execution mode to the module under construction.
   inline void addExecutionMode(SpirvFunction *entryPoint, spv::ExecutionMode em,
@@ -474,6 +519,11 @@ public:
   /// construction.
   void addModuleProcessed(llvm::StringRef process);
 
+  /// \brief If not added already, adds an OpExtInstImport (import of extended
+  /// instruction set) of the OpenCL.DebugInfo.100 instruction set. Returns the
+  /// imported instruction set.
+  SpirvExtInstImport *getOpenCLDebugInfoExtInstSet();
+
   /// \brief Adds a stage input/ouput variable whose value is of the given type.
   ///
   /// Note: the corresponding pointer type of the given type will not be
@@ -627,6 +677,11 @@ private:
   /// Used as caches for all created builtin variables to avoid duplication.
   llvm::SmallVector<BuiltInVarInfo, 16> builtinVars;
 
+  SpirvDebugInfoNone *debugNone;
+
+  /// DebugExpression that does not reference any DebugOperation
+  SpirvDebugExpression *nullDebugExpr;
+
   // To avoid generating multiple OpStrings for the same string literal
   // the SpirvBuilder will generate and reuse them.
   llvm::DenseMap<std::string, SpirvString *, StringMapInfo> stringLiterals;
@@ -667,7 +722,7 @@ SpirvBuilder::setDebugSource(uint32_t major, uint32_t minor,
     SpirvSource *debugSource = new (context)
         SpirvSource(/*SourceLocation*/ {}, spv::SourceLanguage::HLSL, version,
                     fileString, content);
-    mod->addDebugSource(debugSource);
+    mod->addSource(debugSource);
     if (!mainSource)
       mainSource = debugSource;
   }
@@ -678,7 +733,7 @@ SpirvBuilder::setDebugSource(uint32_t major, uint32_t minor,
     mainSource = new (context)
         SpirvSource(/*SourceLocation*/ {}, spv::SourceLanguage::HLSL, version,
                     nullptr, content);
-    mod->addDebugSource(mainSource);
+    mod->addSource(mainSource);
   }
   return mainSource->getFile();
 }

+ 149 - 1
tools/clang/include/clang/SPIRV/SpirvContext.h

@@ -12,16 +12,38 @@
 #include <array>
 
 #include "dxc/DXIL/DxilShaderModel.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/Frontend/FrontendAction.h"
 #include "clang/SPIRV/SpirvInstruction.h"
 #include "clang/SPIRV/SpirvType.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/Support/Allocator.h"
 
 namespace clang {
 namespace spirv {
 
+class SpirvModule;
+
+struct RichDebugInfo {
+  RichDebugInfo(SpirvDebugSource *src, SpirvDebugCompilationUnit *cu)
+      : source(src), compilationUnit(cu) {
+    scopeStack.push_back(cu);
+  }
+  RichDebugInfo() : source(nullptr), compilationUnit(nullptr), scopeStack() {}
+
+  // The HLL source code
+  SpirvDebugSource *source;
+
+  // The compilation unit (topmost debug info node)
+  SpirvDebugCompilationUnit *compilationUnit;
+
+  // Stack of lexical scopes
+  std::vector<SpirvDebugInstruction *> scopeStack;
+};
+
 // Provides DenseMapInfo for spv::StorageClass so that we can use
 // spv::StorageClass as key to DenseMap.
 //
@@ -139,10 +161,66 @@ public:
   /// Deallocates the memory pointed by the given pointer.
   void deallocate(void *ptr) const {}
 
+  // === DebugTypes ===
+
+  // TODO: Replace uint32_t with an enum for encoding.
+  SpirvDebugType *getDebugTypeBasic(const SpirvType *spirvType,
+                                    llvm::StringRef name, SpirvConstant *size,
+                                    uint32_t encoding);
+
+  SpirvDebugType *getDebugTypeMember(llvm::StringRef name, SpirvDebugType *type,
+                                     SpirvDebugSource *source, uint32_t line,
+                                     uint32_t column,
+                                     SpirvDebugInstruction *parent,
+                                     uint32_t flags, uint32_t offsetInBits,
+                                     uint32_t sizeInBits, const APValue *value);
+
+  SpirvDebugTypeComposite *getDebugTypeComposite(const SpirvType *spirvType,
+                                                 llvm::StringRef name,
+                                                 SpirvDebugSource *source,
+                                                 uint32_t line, uint32_t column,
+                                                 SpirvDebugInstruction *parent,
+                                                 llvm::StringRef linkageName,
+                                                 uint32_t flags, uint32_t tag);
+
+  SpirvDebugType *getDebugType(const SpirvType *spirvType);
+
+  SpirvDebugType *getDebugTypeArray(const SpirvType *spirvType,
+                                    SpirvDebugInstruction *elemType,
+                                    llvm::ArrayRef<uint32_t> elemCount);
+
+  SpirvDebugType *getDebugTypeVector(const SpirvType *spirvType,
+                                     SpirvDebugInstruction *elemType,
+                                     uint32_t elemCount);
+
+  SpirvDebugType *getDebugTypeFunction(const SpirvType *spirvType,
+                                       uint32_t flags, SpirvDebugType *ret,
+                                       llvm::ArrayRef<SpirvDebugType *> params);
+
+  SpirvDebugTypeTemplate *createDebugTypeTemplate(
+      const ClassTemplateSpecializationDecl *templateType,
+      SpirvDebugInstruction *target,
+      const llvm::SmallVector<SpirvDebugTypeTemplateParameter *, 2> &params);
+
+  SpirvDebugTypeTemplate *
+  getDebugTypeTemplate(const ClassTemplateSpecializationDecl *templateType);
+
+  SpirvDebugTypeTemplateParameter *createDebugTypeTemplateParameter(
+      const TemplateArgument *templateArg, llvm::StringRef name,
+      SpirvDebugType *type, SpirvInstruction *value, SpirvDebugSource *source,
+      uint32_t line, uint32_t column);
+
+  SpirvDebugTypeTemplateParameter *
+  getDebugTypeTemplateParameter(const TemplateArgument *templateArg);
+
+  // Moves all debug type instructions to module and makes the data structures
+  // that contain the debug type instructions empty. After calling this method,
+  // module will have the ownership of debug type instructions.
+  void moveDebugTypesToModule(SpirvModule *module);
+
   // === Types ===
 
   const VoidType *getVoidType() const { return voidType; }
-
   const BoolType *getBoolType() const { return boolType; }
   const IntegerType *getSIntType(uint32_t bitwidth);
   const IntegerType *getUIntType(uint32_t bitwidth);
@@ -237,6 +315,47 @@ public:
     return curShaderModelKind == ShaderModelKind::Amplification;
   }
 
+  /// Function to get all RichDebugInfo (i.e., the current status of
+  /// compilation units).
+  llvm::StringMap<RichDebugInfo> &getDebugInfo() { return debugInfo; }
+
+  /// Function to let the lexical scope stack grow when it enters a
+  /// new lexical scope.
+  void pushDebugLexicalScope(RichDebugInfo *info, SpirvDebugInstruction *scope);
+
+  /// Function to pop the last element from the lexical scope stack.
+  void popDebugLexicalScope(RichDebugInfo *info) {
+    info->scopeStack.pop_back();
+    currentLexicalScope = info->scopeStack.back();
+  }
+
+  /// Function to get the last lexical scope that the SpirvEmitter
+  /// class instance entered.
+  SpirvDebugInstruction *getCurrentLexicalScope() {
+    return currentLexicalScope;
+  }
+
+  /// Function to add/get the mapping from a SPIR-V type to its Decl for
+  /// a struct type.
+  void registerStructDeclForSpirvType(const SpirvType *spvTy,
+                                      const DeclContext *decl) {
+    assert(spvTy != nullptr && decl != nullptr);
+    spvStructTypeToDecl[spvTy] = decl;
+  }
+  const DeclContext *getStructDeclForSpirvType(const SpirvType *spvTy) {
+    return spvStructTypeToDecl[spvTy];
+  }
+
+  /// Function to add/get the mapping from a FunctionDecl to its DebugFunction.
+  void registerDebugFunctionForDecl(const FunctionDecl *decl,
+                                    SpirvDebugFunction *fn) {
+    assert(decl != nullptr && fn != nullptr);
+    declToDebugFunction[decl] = fn;
+  }
+  SpirvDebugFunction *getDebugFunctionForDecl(const FunctionDecl *decl) {
+    return declToDebugFunction[decl];
+  }
+
 private:
   /// \brief The allocator used to create SPIR-V entity objects.
   ///
@@ -294,6 +413,35 @@ private:
   // Major/Minor hlsl profile version.
   uint32_t majorVersion;
   uint32_t minorVersion;
+
+  /// File name to rich debug info map. When the main source file
+  /// includes header files, we create an element of debugInfo for
+  /// each file. RichDebugInfo includes DebugSource,
+  /// DebugCompilationUnit and scopeStack which keeps lexical scopes
+  /// recursively.
+  llvm::StringMap<RichDebugInfo> debugInfo;
+  SpirvDebugInstruction *currentLexicalScope;
+
+  // Mapping from SPIR-V type to debug type instruction.
+  // The purpose is not to generate several DebugType* instructions for the same
+  // type if the type is used for several variables.
+  llvm::MapVector<const SpirvType *, SpirvDebugType *> debugTypes;
+
+  // Mapping from template decl to DebugTypeTemplate.
+  llvm::MapVector<const ClassTemplateSpecializationDecl *,
+                  SpirvDebugTypeTemplate *>
+      typeTemplates;
+
+  // Mapping from template parameter decl to DebugTypeTemplateParameter.
+  llvm::MapVector<const TemplateArgument *, SpirvDebugTypeTemplateParameter *>
+      typeTemplateParams;
+
+  // Mapping from SPIR-V type to Decl for a struct type.
+  llvm::DenseMap<const SpirvType *, const DeclContext *> spvStructTypeToDecl;
+
+  // Mapping from FunctionDecl to SPIR-V debug function.
+  llvm::DenseMap<const FunctionDecl *, SpirvDebugFunction *>
+      declToDebugFunction;
 };
 
 } // end namespace spirv

+ 26 - 0
tools/clang/include/clang/SPIRV/SpirvFunction.h

@@ -80,6 +80,9 @@ public:
   llvm::StringRef getFunctionName() const { return functionName; }
 
   void addParameter(SpirvFunctionParameter *);
+  void addParameterDebugDeclare(SpirvDebugDeclare *inst) {
+    debugDeclares.push_back(inst);
+  }
   void addVariable(SpirvVariable *);
   void addBasicBlock(SpirvBasicBlock *);
 
@@ -93,6 +96,20 @@ public:
   void setRValue() { rvalue = true; }
   bool isRValue() { return rvalue; }
 
+  /// Get/set DebugScope for this function.
+  SpirvDebugScope *getDebugScope() const { return debugScope; }
+  void setDebugScope(SpirvDebugScope *scope) { debugScope = scope; }
+
+  bool isEntryFunctionWrapper() const { return isWrapperOfEntry; }
+  void setEntryFunctionWrapper() { isWrapperOfEntry = true; }
+
+  /// Returns true if this is a member function of a struct or class.
+  bool isMemberFunction() const {
+    if (parameters.empty())
+      return false;
+    return parameters[0]->getDebugName() == "param.this";
+  }
+
 private:
   uint32_t functionId;    ///< This function's <result-id>
   QualType astReturnType; ///< The return type
@@ -125,6 +142,15 @@ private:
 
   /// Basic blocks inside this function.
   std::vector<SpirvBasicBlock *> basicBlocks;
+
+  /// True if it is a wrapper function for an entry point function.
+  bool isWrapperOfEntry;
+
+  /// DebugScope that groups all instructions in this function.
+  SpirvDebugScope *debugScope;
+
+  /// DebugDeclare instructions for parameters to this function.
+  llvm::SmallVector<SpirvDebugDeclare *, 8> debugDeclares;
 };
 
 } // end namespace spirv

+ 761 - 2
tools/clang/include/clang/SPIRV/SpirvInstruction.h

@@ -11,6 +11,7 @@
 #include "dxc/Support/SPIRVOptions.h"
 #include "spirv/unified1/GLSL.std.450.h"
 #include "spirv/unified1/spirv.hpp11"
+#include "clang/AST/APValue.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/SourceLocation.h"
 #include "llvm/ADT/APFloat.h"
@@ -31,6 +32,9 @@ class SpirvType;
 class SpirvVariable;
 class SpirvString;
 class Visitor;
+class DebugTypeComposite;
+class SpirvDebugDeclare;
+class FunctionType;
 
 #define DEFINE_RELEASE_MEMORY_FOR_CLASS(cls)                                   \
   void releaseMemory() override { this->~cls(); }
@@ -50,9 +54,7 @@ public:
     IK_ExecutionMode,   // OpExecutionMode
     IK_String,          // OpString (debug)
     IK_Source,          // OpSource (debug)
-    IK_Name,            // Op*Name (debug)
     IK_ModuleProcessed, // OpModuleProcessed (debug)
-    IK_LineInfo,        // OpLine (debug)
     IK_Decoration,      // Op*Decorate
     IK_Type,            // OpType*
     IK_Variable,        // OpVariable
@@ -123,6 +125,28 @@ public:
     IK_Store,                     // OpStore
     IK_UnaryOp,                   // Unary operations
     IK_VectorShuffle,             // OpVectorShuffle
+
+    // For DebugInfo instructions defined in OpenCL.DebugInfo.100
+    IK_DebugInfoNone,
+    IK_DebugCompilationUnit,
+    IK_DebugSource,
+    IK_DebugFunctionDecl,
+    IK_DebugFunction,
+    IK_DebugLocalVariable,
+    IK_DebugGlobalVariable,
+    IK_DebugOperation,
+    IK_DebugExpression,
+    IK_DebugDeclare,
+    IK_DebugLexicalBlock,
+    IK_DebugScope,
+    IK_DebugTypeBasic,
+    IK_DebugTypeArray,
+    IK_DebugTypeVector,
+    IK_DebugTypeFunction,
+    IK_DebugTypeComposite,
+    IK_DebugTypeMember,
+    IK_DebugTypeTemplate,
+    IK_DebugTypeTemplateParameter,
   };
 
   // All instruction classes should include a releaseMemory method.
@@ -527,6 +551,17 @@ public:
   }
 
   bool invokeVisitor(Visitor *v) override;
+
+  void setDebugDeclare(SpirvDebugDeclare *decl) { debugDecl = decl; }
+  SpirvDebugDeclare *getDebugDeclare() const { return debugDecl; }
+
+private:
+  // When we turn on the rich debug info generation option, we want
+  // to keep the function parameter information (like a local
+  // variable). Since DebugDeclare instruction maps a
+  // DebugLocalVariable instruction to OpFunctionParameter instruction,
+  // we keep a pointer to SpirvDebugDeclare in SpirvFunctionParameter.
+  SpirvDebugDeclare *debugDecl;
 };
 
 /// \brief Merge instructions include OpLoopMerge and OpSelectionMerge
@@ -1943,6 +1978,730 @@ public:
   bool invokeVisitor(Visitor *v) override;
 };
 
+/// \breif Base class for all OpenCL.DebugInfo.100 extension instructions.
+/// Note that all of these instructions should be added to the SPIR-V module as
+/// an OpExtInst instructions. So, all of these instructions must:
+/// 1) contain the result-id of the extended instruction set
+/// 2) have OpTypeVoid as their Result Type.
+/// 3) contain additional QualType and SpirvType for the debug type.
+class SpirvDebugInstruction : public SpirvInstruction {
+public:
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() >= IK_DebugInfoNone &&
+           inst->getKind() <= IK_DebugTypeTemplateParameter;
+  }
+
+  void setDebugType(SpirvDebugInstruction *type) { debugType = type; }
+  void setInstructionSet(SpirvExtInstImport *set) { instructionSet = set; }
+  SpirvExtInstImport *getInstructionSet() const { return instructionSet; }
+  uint32_t getDebugOpcode() const { return debugOpcode; }
+  QualType getDebugQualType() const { return debugQualType; }
+  const SpirvType *getDebugSpirvType() const { return debugSpirvType; }
+  SpirvDebugInstruction *getDebugType() const { return debugType; }
+  void setDebugQualType(QualType type) { debugQualType = type; }
+  void setDebugSpirvType(const SpirvType *type) { debugSpirvType = type; }
+
+  virtual SpirvDebugInstruction *getParentScope() const { return nullptr; }
+
+protected:
+  // TODO: Replace opcode type with an enum, when it is available in
+  // SPIRV-Headers.
+  SpirvDebugInstruction(Kind kind, uint32_t opcode);
+
+private:
+  // TODO: Replace this with an enum, when it is available in SPIRV-Headers.
+  uint32_t debugOpcode;
+
+  QualType debugQualType;
+  const SpirvType *debugSpirvType;
+
+  // The constructor for SpirvDebugInstruction sets the debug type to nullptr.
+  // A type lowering IMR pass will set debug types for all debug instructions
+  // that do contain a debug type.
+  SpirvDebugInstruction *debugType;
+
+  // The pointer to the debug info extended instruction set.
+  // This is not required by the constructor, and can be set via any IMR pass.
+  SpirvExtInstImport *instructionSet;
+};
+
+class SpirvDebugInfoNone : public SpirvDebugInstruction {
+public:
+  SpirvDebugInfoNone();
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugInfoNone)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugInfoNone;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+};
+
+class SpirvDebugSource : public SpirvDebugInstruction {
+public:
+  SpirvDebugSource(llvm::StringRef file, llvm::StringRef text);
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugSource)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugSource;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  llvm::StringRef getFile() const { return file; }
+  llvm::StringRef getContent() const { return text; }
+
+private:
+  std::string file;
+  std::string text;
+};
+
+class SpirvDebugCompilationUnit : public SpirvDebugInstruction {
+public:
+  SpirvDebugCompilationUnit(uint32_t spirvVersion, uint32_t dwarfVersion,
+                            SpirvDebugSource *src);
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugCompilationUnit)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugCompilationUnit;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  uint32_t getSpirvVersion() const { return spirvVersion; }
+  uint32_t getDwarfVersion() const { return dwarfVersion; }
+  SpirvDebugSource *getDebugSource() const { return source; }
+  spv::SourceLanguage getLanguage() const { return lang; }
+
+private:
+  uint32_t spirvVersion;
+  uint32_t dwarfVersion;
+  SpirvDebugSource *source;
+  spv::SourceLanguage lang;
+};
+
+// This class is not actually used. It can be cleaned up.
+class SpirvDebugFunctionDeclaration : public SpirvDebugInstruction {
+public:
+  SpirvDebugFunctionDeclaration(llvm::StringRef name, SpirvDebugSource *src,
+                                uint32_t fnLine, uint32_t fnColumn,
+                                SpirvDebugInstruction *parentScope,
+                                llvm::StringRef linkageName, uint32_t flags);
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugFunctionDeclaration)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugFunctionDecl;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  SpirvDebugSource *getSource() const { return source; }
+  uint32_t getLine() const { return fnLine; }
+  uint32_t getColumn() const { return fnColumn; }
+  void setParent(SpirvDebugInstruction *scope) { parentScope = scope; }
+  SpirvDebugInstruction *getParentScope() const override { return parentScope; }
+  llvm::StringRef getLinkageName() const { return linkageName; }
+  uint32_t getFlags() const { return flags; }
+
+private:
+  SpirvDebugSource *source;
+  // Source line number at which the function appears
+  uint32_t fnLine;
+  // Source column number at which the function appears
+  uint32_t fnColumn;
+  // Debug instruction which represents the parent lexical scope
+  SpirvDebugInstruction *parentScope;
+  std::string linkageName;
+  // TODO: Replace this with an enum, when it is available in SPIRV-Headers
+  uint32_t flags;
+};
+
+class SpirvDebugFunction : public SpirvDebugInstruction {
+public:
+  SpirvDebugFunction(llvm::StringRef name, SpirvDebugSource *src,
+                     uint32_t fnLine, uint32_t fnColumn,
+                     SpirvDebugInstruction *parentScope,
+                     llvm::StringRef linkageName, uint32_t flags,
+                     uint32_t scopeLine, SpirvFunction *fn);
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugFunction)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugFunction;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  SpirvDebugSource *getSource() const { return source; }
+  uint32_t getLine() const { return fnLine; }
+  uint32_t getColumn() const { return fnColumn; }
+  void setParent(SpirvDebugInstruction *scope) { parentScope = scope; }
+  SpirvDebugInstruction *getParentScope() const override { return parentScope; }
+  llvm::StringRef getLinkageName() const { return linkageName; }
+  uint32_t getFlags() const { return flags; }
+  uint32_t getScopeLine() const { return scopeLine; }
+  SpirvFunction *getSpirvFunction() const { return fn; }
+
+  void setFunctionType(clang::spirv::FunctionType *t) { fnType = t; }
+  clang::spirv::FunctionType *getFunctionType() const { return fnType; }
+
+  void setDebugInfoNone(SpirvDebugInfoNone *none) { debugNone = none; }
+  SpirvDebugInfoNone *getDebugInfoNone() const { return debugNone; }
+
+private:
+  SpirvDebugSource *source;
+  // Source line number at which the function appears
+  uint32_t fnLine;
+  // Source column number at which the function appears
+  uint32_t fnColumn;
+  // Debug instruction which represents the parent lexical scope
+  SpirvDebugInstruction *parentScope;
+  std::string linkageName;
+  // TODO: Replace this with an enum, when it is available in SPIRV-Headers
+  uint32_t flags;
+  // Line number in the source program at which the function scope begins
+  uint32_t scopeLine;
+  // The function to which this debug instruction belongs
+  SpirvFunction *fn;
+
+  // When fn is nullptr, we want to put DebugInfoNone for Function operand
+  // of DebugFunction. Note that the spec must allow it (which will be
+  // discussed). We can consider this debugNone is a fallback of fn.
+  SpirvDebugInfoNone *debugNone;
+
+  // When the function debug info is generated by LowerTypeVisitor (not
+  // SpirvEmitter), we do not generate SpirvFunction. We only generate
+  // SpirvDebugFunction. Similar to fnType of SpirvFunction, we want to
+  // keep the function type info in this fnType.
+  clang::spirv::FunctionType *fnType;
+};
+
+class SpirvDebugLocalVariable : public SpirvDebugInstruction {
+public:
+  SpirvDebugLocalVariable(QualType debugQualType, llvm::StringRef varName,
+                          SpirvDebugSource *src, uint32_t line, uint32_t column,
+                          SpirvDebugInstruction *parentScope, uint32_t flags,
+                          llvm::Optional<uint32_t> argNumber = llvm::None);
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugLocalVariable)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugLocalVariable;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  SpirvDebugSource *getSource() const { return source; }
+  uint32_t getLine() const { return line; }
+  uint32_t getColumn() const { return column; }
+  SpirvDebugInstruction *getParentScope() const override { return parentScope; }
+  uint32_t getFlags() const { return flags; }
+  llvm::Optional<uint32_t> getArgNumber() const { return argNumber; }
+
+private:
+  SpirvDebugSource *source;
+  uint32_t line;
+  uint32_t column;
+  SpirvDebugInstruction *parentScope;
+  // TODO: Replace this with an enum, when it is available in SPIRV-Headers
+  uint32_t flags;
+  llvm::Optional<uint32_t> argNumber;
+};
+
+class SpirvDebugGlobalVariable : public SpirvDebugInstruction {
+public:
+  SpirvDebugGlobalVariable(
+      QualType debugQualType, llvm::StringRef varName, SpirvDebugSource *src,
+      uint32_t line, uint32_t column, SpirvDebugInstruction *parentScope,
+      llvm::StringRef linkageName, SpirvVariable *var, uint32_t flags,
+      llvm::Optional<SpirvInstruction *> staticMemberDebugType = llvm::None);
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugGlobalVariable)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugGlobalVariable;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  SpirvDebugSource *getSource() const { return source; }
+  uint32_t getLine() const { return line; }
+  uint32_t getColumn() const { return column; }
+  SpirvDebugInstruction *getParentScope() const override { return parentScope; }
+  llvm::StringRef getLinkageName() const { return linkageName; }
+  uint32_t getFlags() const { return flags; }
+  SpirvInstruction *getVariable() const { return var; }
+  llvm::Optional<SpirvInstruction *> getStaticMemberDebugDecl() const {
+    return staticMemberDebugDecl;
+  }
+
+private:
+  SpirvDebugSource *source;
+  uint32_t line;
+  uint32_t column;
+  SpirvDebugInstruction *parentScope;
+  std::string linkageName;
+  SpirvVariable *var;
+  // TODO: Replace this with an enum, when it is available in SPIRV-Headers
+  uint32_t flags;
+  llvm::Optional<SpirvInstruction *> staticMemberDebugDecl;
+};
+
+class SpirvDebugOperation : public SpirvDebugInstruction {
+public:
+  SpirvDebugOperation(uint32_t operationOpCode,
+                      llvm::ArrayRef<int32_t> operands = {});
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugOperation)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugOperation;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  uint32_t getOperationOpcode() { return operationOpcode; }
+
+private:
+  uint32_t operationOpcode;
+  llvm::SmallVector<int32_t, 2> operands;
+};
+
+class SpirvDebugExpression : public SpirvDebugInstruction {
+public:
+  SpirvDebugExpression(llvm::ArrayRef<SpirvDebugOperation *> operations = {});
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugExpression)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugExpression;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  llvm::ArrayRef<SpirvDebugOperation *> getOperations() const {
+    return operations;
+  }
+
+private:
+  llvm::SmallVector<SpirvDebugOperation *, 4> operations;
+};
+
+class SpirvDebugDeclare : public SpirvDebugInstruction {
+public:
+  SpirvDebugDeclare(SpirvDebugLocalVariable *, SpirvInstruction *,
+                    SpirvDebugExpression *);
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugDeclare)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugDeclare;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  SpirvDebugLocalVariable *getDebugLocalVariable() const { return debugVar; }
+  SpirvInstruction *getVariable() const { return var; }
+  SpirvDebugExpression *getDebugExpression() const { return expression; }
+
+private:
+  SpirvDebugLocalVariable *debugVar;
+  SpirvInstruction *var;
+  SpirvDebugExpression *expression;
+};
+
+class SpirvDebugLexicalBlock : public SpirvDebugInstruction {
+public:
+  SpirvDebugLexicalBlock(SpirvDebugSource *source, uint32_t line,
+                         uint32_t column, SpirvDebugInstruction *parent);
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugLexicalBlock)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugLexicalBlock;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  SpirvDebugSource *getSource() const { return source; }
+  uint32_t getLine() const { return line; }
+  uint32_t getColumn() const { return column; }
+  SpirvDebugInstruction *getParentScope() const override { return parent; }
+
+private:
+  SpirvDebugSource *source;
+  uint32_t line;
+  uint32_t column;
+  SpirvDebugInstruction *parent;
+};
+
+/// Represent DebugScope. DebugScope has two operands: a lexical scope
+/// and DebugInlinedAt. The DebugInlinedAt is an optional argument
+/// and it is only used when we inline a function. Since DXC does not
+/// conduct the inlining, we do not add DebugInlinedAt operand.
+class SpirvDebugScope : public SpirvDebugInstruction {
+public:
+  SpirvDebugScope(SpirvDebugInstruction *);
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugScope)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugScope;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  SpirvDebugInstruction *getScope() const { return scope; }
+
+private:
+  SpirvDebugInstruction *scope;
+};
+
+/// The following classes represent debug types defined in the
+/// OpenCL.DebugInfo.100 spec.
+///
+/// Note: While debug type and SPIR-V type are very similar, they are not quite
+/// identical. For example: the debug type contains the HLL string name of the
+/// type. Another example: two structs with similar definitions in different
+/// lexical scopes translate into 1 SPIR-V type, but translate into 2 different
+/// debug type instructions.
+///
+/// Note: DebugTypeComposite contains a vector of its members, which can be
+/// DebugTypeMember or DebugFunction. The former is a type, and the latter is a
+/// SPIR-V instruction. This somewhat tips the sclae in favor of using the
+/// SpirvInstruction base class for representing debug types.
+///
+/// TODO: Add support for the following debug types:
+///   DebugTypePointer,
+///   DebugTypeQualifier,
+///   DebugTypedef,
+///   DebugTypeEnum,
+///   DebugTypeInheritance,
+///   DebugTypePtrToMember,
+///   DebugTypeTemplate,
+///   DebugTypeTemplateParameter,
+///   DebugTypeTemplateTemplateParameter,
+///   DebugTypeTemplateParameterPack,
+
+class SpirvDebugType : public SpirvDebugInstruction {
+public:
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() >= IK_DebugTypeBasic &&
+           inst->getKind() <= IK_DebugTypeTemplateParameter;
+  }
+
+  virtual uint32_t getSizeInBits() const { return 0u; }
+
+protected:
+  SpirvDebugType(Kind kind, uint32_t opcode)
+      : SpirvDebugInstruction(kind, opcode) {}
+};
+
+/// Represents basic debug types, including boolean, float, integer.
+class SpirvDebugTypeBasic : public SpirvDebugType {
+public:
+  SpirvDebugTypeBasic(llvm::StringRef name, SpirvConstant *size,
+                      uint32_t encoding);
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugTypeBasic)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugTypeBasic;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  SpirvConstant *getSize() const { return size; }
+  uint32_t getEncoding() const { return encoding; }
+  uint32_t getSizeInBits() const override;
+
+private:
+  SpirvConstant *size;
+  // TODO: Replace uint32_t with enum from SPIRV-Headers once available.
+  // 0, Unspecified
+  // 1, Address
+  // 2, Boolean
+  // 3, Float
+  // 4, Signed
+  // 5, SignedChar
+  // 6, Unsigned
+  // 7, UnsignedChar
+  uint32_t encoding;
+};
+
+/// Represents array debug types
+class SpirvDebugTypeArray : public SpirvDebugType {
+public:
+  SpirvDebugTypeArray(SpirvDebugType *elemType,
+                      llvm::ArrayRef<uint32_t> elemCount);
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugTypeArray)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugTypeArray;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  SpirvDebugType *getElementType() const { return elementType; }
+  llvm::SmallVector<uint32_t, 2> &getElementCount() { return elementCount; }
+
+  uint32_t getSizeInBits() const override {
+    // TODO: avoid integer overflow
+    uint32_t nElem = elementType->getSizeInBits();
+    for (auto k : elementCount)
+      nElem *= k;
+    return nElem;
+  }
+
+private:
+  SpirvDebugType *elementType;
+  llvm::SmallVector<uint32_t, 2> elementCount;
+};
+
+/// Represents vector debug types
+class SpirvDebugTypeVector : public SpirvDebugType {
+public:
+  SpirvDebugTypeVector(SpirvDebugType *elemType, uint32_t elemCount);
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugTypeVector)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugTypeVector;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  SpirvDebugType *getElementType() const { return elementType; }
+  uint32_t getElementCount() const { return elementCount; }
+
+  uint32_t getSizeInBits() const override {
+    return elementCount * elementType->getSizeInBits();
+  }
+
+private:
+  SpirvDebugType *elementType;
+  uint32_t elementCount;
+};
+
+/// Represents a function debug type. Includes the function return type and
+/// parameter types.
+class SpirvDebugTypeFunction : public SpirvDebugType {
+public:
+  SpirvDebugTypeFunction(uint32_t flags, SpirvDebugType *ret,
+                         llvm::ArrayRef<SpirvDebugType *> params);
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugTypeFunction)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugTypeFunction;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  uint32_t getDebugFlags() const { return debugFlags; }
+  SpirvDebugType *getReturnType() const { return returnType; }
+  llvm::ArrayRef<SpirvDebugType *> getParamTypes() const { return paramTypes; }
+
+private:
+  // TODO: Replace uint32_t with enum in the SPIRV-Headers once it is available.
+  uint32_t debugFlags;
+  // Return Type is a debug instruction which represents type of return value of
+  // the function. If the function has no return value, this operand is
+  // OpTypeVoid, in which case we will use nullptr for this member.
+  SpirvDebugType *returnType;
+  llvm::SmallVector<SpirvDebugType *, 4> paramTypes;
+};
+
+/// Represents debug information for a template type parameter.
+class SpirvDebugTypeTemplateParameter : public SpirvDebugType {
+public:
+  SpirvDebugTypeTemplateParameter(llvm::StringRef name, SpirvDebugType *type,
+                                  SpirvInstruction *value,
+                                  SpirvDebugSource *source, uint32_t line,
+                                  uint32_t column);
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugTypeTemplateParameter)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugTypeTemplateParameter;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  SpirvDebugType *getActualType() const { return actualType; }
+  void setValue(SpirvInstruction *c) { value = c; }
+  SpirvInstruction *getValue() const { return value; }
+  SpirvDebugSource *getSource() const { return source; }
+  uint32_t getLine() const { return line; }
+  uint32_t getColumn() const { return column; }
+
+private:
+  SpirvDebugType *actualType; //< Type for type param
+  SpirvInstruction *value;    //< Value. It must be null for type.
+  SpirvDebugSource *source;   //< DebugSource containing this type
+  uint32_t line;              //< Line number
+  uint32_t column;            //< Column number
+};
+
+/// Represents debug information for a template type.
+class SpirvDebugTypeTemplate : public SpirvDebugType {
+public:
+  SpirvDebugTypeTemplate(
+      SpirvDebugInstruction *target,
+      const llvm::SmallVector<SpirvDebugTypeTemplateParameter *, 2> &params);
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugTypeTemplate)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugTypeTemplate;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  llvm::SmallVector<SpirvDebugTypeTemplateParameter *, 2> getParams() {
+    return params;
+  }
+  SpirvDebugInstruction *getTarget() const { return target; }
+
+private:
+  // A debug instruction representing class, struct or function which has
+  // template parameter(s).
+  SpirvDebugInstruction *target;
+
+  // Debug instructions representing the template parameters for this
+  // particular instantiation. It must be DebugTypeTemplateParameter
+  // or DebugTypeTemplateTemplateParameter.
+  // TODO: change the type to SpirvDebugType * when we support
+  // DebugTypeTemplateTemplateParameter.
+  llvm::SmallVector<SpirvDebugTypeTemplateParameter *, 2> params;
+};
+
+/// Represents the debug type of a struct/union/class member.
+/// Note: We have intentionally left out the pointer to the parent composite
+/// type.
+class SpirvDebugTypeMember : public SpirvDebugType {
+public:
+  SpirvDebugTypeMember(llvm::StringRef name, SpirvDebugType *type,
+                       SpirvDebugSource *source, uint32_t line_,
+                       uint32_t column_, SpirvDebugInstruction *parent,
+                       uint32_t flags, uint32_t offsetInBits,
+                       uint32_t sizeInBits, const APValue *value = nullptr);
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugTypeMember)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugTypeMember;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  SpirvDebugInstruction *getParentScope() const override { return parent; }
+
+  SpirvDebugSource *getSource() const { return source; }
+  uint32_t getLine() const { return line; }
+  uint32_t getColumn() const { return column; }
+  uint32_t getOffsetInBits() const { return offsetInBits; }
+  uint32_t getDebugFlags() const { return debugFlags; }
+  uint32_t getSizeInBits() const override { return sizeInBits; }
+  const APValue *getValue() const { return value; }
+
+private:
+  SpirvDebugSource *source; //< DebugSource
+  uint32_t line;            //< Line number
+  uint32_t column;          //< Column number
+
+  SpirvDebugInstruction *parent; //< The parent DebugTypeComposite
+
+  uint32_t offsetInBits; //< Offset (in bits) of this member in the struct
+  uint32_t sizeInBits;   //< Size (in bits) of this member in the struct
+  // TODO: Replace uint32_t with enum in the SPIRV-Headers once it is
+  // available.
+  uint32_t debugFlags;
+  const APValue *value; //< Value (if static member)
+};
+
+class SpirvDebugTypeComposite : public SpirvDebugType {
+public:
+  SpirvDebugTypeComposite(llvm::StringRef name, SpirvDebugSource *source,
+                          uint32_t line, uint32_t column,
+                          SpirvDebugInstruction *parent,
+                          llvm::StringRef linkageName, uint32_t flags,
+                          uint32_t tag);
+
+  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvDebugTypeComposite)
+
+  static bool classof(const SpirvInstruction *inst) {
+    return inst->getKind() == IK_DebugTypeComposite;
+  }
+
+  bool invokeVisitor(Visitor *v) override;
+
+  llvm::SmallVector<SpirvDebugInstruction *, 4> getMembers() { return members; }
+  void appendMember(SpirvDebugInstruction *member) {
+    members.push_back(member);
+  }
+  void
+  setMembers(const llvm::SmallVector<SpirvDebugInstruction *, 4> &memberTypes) {
+    members = memberTypes;
+  }
+
+  SpirvDebugInstruction *getParentScope() const override { return parent; }
+  uint32_t getTag() const { return tag; }
+  SpirvDebugSource *getSource() const { return source; }
+  uint32_t getLine() const { return line; }
+  uint32_t getColumn() const { return column; }
+  llvm::StringRef getLinkageName() const { return linkageName; }
+  uint32_t getDebugFlags() const { return debugFlags; }
+
+  void setSizeInBits(uint32_t size_) { sizeInBits = size_; }
+  uint32_t getSizeInBits() const override { return sizeInBits; }
+
+  void markAsOpaqueType(SpirvDebugInfoNone *none) {
+    // If it was already marked as a opaque type, just return. For example,
+    // `debugName` can be "@@Texture2D" if we call this method twice.
+    if (debugNone == none && !debugName.empty() && debugName[0] == '@')
+      return;
+    debugName = std::string("@") + debugName;
+    debugNone = none;
+  }
+  SpirvDebugInfoNone *getDebugInfoNone() const { return debugNone; }
+
+private:
+  SpirvDebugSource *source; //< DebugSource containing this type
+  uint32_t line;            //< Line number
+  uint32_t column;          //< Column number
+
+  // The parent lexical scope. Must be one of the following:
+  // DebugCompilationUnit, DebugFunction, DebugLexicalBlock or other
+  // DebugTypeComposite
+  SpirvDebugInstruction *parent; //< The parent lexical scope
+
+  std::string linkageName; //< Linkage name
+  uint32_t sizeInBits;     //< Size (in bits) of an instance of composite
+
+  // TODO: Replace uint32_t with enum in the SPIRV-Headers once it is
+  // available.
+  uint32_t debugFlags;
+  // TODO: Replace uint32_t with enum in the SPIRV-Headers once it is
+  // available.
+  uint32_t tag;
+
+  // Pointer to members inside this composite type.
+  // Note: Members must be ids of DebugTypeMember, DebugFunction or
+  // DebugTypeInheritance. Since DebugFunction may be a member, we cannot use a
+  // vector of SpirvDebugType.
+  llvm::SmallVector<SpirvDebugInstruction *, 4> members;
+
+  // When it is DebugTypeComposite for HLSL resource type i.e., opaque
+  // type, we must put DebugInfoNone for Size operand.
+  SpirvDebugInfoNone *debugNone;
+};
+
 #undef DECLARE_INVOKE_VISITOR_FOR_CLASS
 
 } // namespace spirv

+ 13 - 2
tools/clang/include/clang/SPIRV/SpirvModule.h

@@ -12,6 +12,7 @@
 #include <vector>
 
 #include "clang/SPIRV/SpirvInstruction.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SmallVector.h"
@@ -134,7 +135,14 @@ public:
   void addString(SpirvString *);
 
   // Adds the debug source to the module.
-  void addDebugSource(SpirvSource *);
+  void addSource(SpirvSource *);
+
+  // Adds the given debug info instruction to debugInstructions.
+  void addDebugInfo(SpirvDebugInstruction *);
+
+  llvm::SmallVector<SpirvDebugInstruction *, 32> &getDebugInfo() {
+    return debugInstructions;
+  }
 
   // Adds the given OpModuleProcessed to the module.
   void addModuleProcessed(SpirvModuleProcessed *);
@@ -163,7 +171,7 @@ private:
   llvm::SmallVector<SpirvEntryPoint *, 1> entryPoints;
   llvm::SmallVector<SpirvExecutionMode *, 4> executionModes;
   llvm::SmallVector<SpirvString *, 4> constStrings;
-  std::vector<SpirvSource *> debugSources;
+  std::vector<SpirvSource *> sources;
   std::vector<SpirvModuleProcessed *> moduleProcesses;
 
   // Use a set for storing decoration. This will ensure that we don't apply the
@@ -183,6 +191,9 @@ private:
   // A vector of all functions that have been visited in the AST tree. This
   // vector is not in any particular order, and may contain unused functions.
   llvm::SetVector<SpirvFunction *> allFunctions;
+
+  // Keep all OpenCL.DebugInfo.100 instructions.
+  llvm::SmallVector<SpirvDebugInstruction *, 32> debugInstructions;
 };
 
 } // end namespace spirv

+ 4 - 2
tools/clang/include/clang/SPIRV/SpirvType.h

@@ -294,7 +294,7 @@ public:
               llvm::Optional<uint32_t> matrixStride_ = llvm::None,
               llvm::Optional<bool> isRowMajor_ = llvm::None,
               bool relaxedPrecision = false, bool precise = false)
-        : type(type_), name(name_), offset(offset_),
+        : type(type_), name(name_), offset(offset_), sizeInBytes(llvm::None),
           matrixStride(matrixStride_), isRowMajor(isRowMajor_),
           isRelaxedPrecision(relaxedPrecision), isPrecise(precise) {
       // A StructType may not contain any hybrid types.
@@ -307,8 +307,10 @@ public:
     const SpirvType *type;
     // The field's name.
     std::string name;
-    // The integer offset for this field.
+    // The integer offset in bytes for this field.
     llvm::Optional<uint32_t> offset;
+    // The integer size in bytes for this field.
+    llvm::Optional<uint32_t> sizeInBytes;
     // The matrix stride for this field (if applicable).
     llvm::Optional<uint32_t> matrixStride;
     // The majorness of this field (if applicable).

+ 21 - 0
tools/clang/include/clang/SPIRV/SpirvVisitor.h

@@ -115,6 +115,27 @@ public:
   DEFINE_VISIT_METHOD(SpirvArrayLength)
   DEFINE_VISIT_METHOD(SpirvRayTracingOpNV)
   DEFINE_VISIT_METHOD(SpirvDemoteToHelperInvocationEXT)
+  DEFINE_VISIT_METHOD(SpirvDebugInfoNone)
+  DEFINE_VISIT_METHOD(SpirvDebugSource)
+  DEFINE_VISIT_METHOD(SpirvDebugCompilationUnit)
+  DEFINE_VISIT_METHOD(SpirvDebugFunctionDeclaration)
+  DEFINE_VISIT_METHOD(SpirvDebugFunction)
+  DEFINE_VISIT_METHOD(SpirvDebugLocalVariable)
+  DEFINE_VISIT_METHOD(SpirvDebugGlobalVariable)
+  DEFINE_VISIT_METHOD(SpirvDebugOperation)
+  DEFINE_VISIT_METHOD(SpirvDebugExpression)
+  DEFINE_VISIT_METHOD(SpirvDebugDeclare)
+  DEFINE_VISIT_METHOD(SpirvDebugLexicalBlock)
+  DEFINE_VISIT_METHOD(SpirvDebugScope)
+  DEFINE_VISIT_METHOD(SpirvDebugTypeBasic)
+  DEFINE_VISIT_METHOD(SpirvDebugTypeArray)
+  DEFINE_VISIT_METHOD(SpirvDebugTypeVector)
+  DEFINE_VISIT_METHOD(SpirvDebugTypeFunction)
+  DEFINE_VISIT_METHOD(SpirvDebugTypeComposite)
+  DEFINE_VISIT_METHOD(SpirvDebugTypeMember)
+  DEFINE_VISIT_METHOD(SpirvDebugTypeTemplate)
+  DEFINE_VISIT_METHOD(SpirvDebugTypeTemplateParameter)
+
   DEFINE_VISIT_METHOD(SpirvRayQueryOpKHR)
 #undef DEFINE_VISIT_METHOD
 

+ 3 - 0
tools/clang/lib/SPIRV/CMakeLists.txt

@@ -8,6 +8,7 @@ add_clang_library(clangSPIRV
   BlockReadableOrder.cpp
   CapabilityVisitor.cpp
   DeclResultIdMapper.cpp
+  DebugTypeVisitor.cpp
   EmitSpirvAction.cpp
   EmitVisitor.cpp
   FeatureManager.cpp
@@ -15,6 +16,7 @@ add_clang_library(clangSPIRV
   InitListHandler.cpp
   LiteralTypeVisitor.cpp
   LowerTypeVisitor.cpp
+  SortDebugInfoVisitor.cpp
   NonUniformVisitor.cpp
   PreciseVisitor.cpp
   RawBufferMethods.cpp
@@ -40,3 +42,4 @@ add_clang_library(clangSPIRV
 
 target_include_directories(clangSPIRV PUBLIC ${SPIRV_HEADER_INCLUDE_DIR})
 target_include_directories(clangSPIRV PRIVATE ${SPIRV_TOOLS_INCLUDE_DIR})
+add_dependencies(clangSPIRV TablegenHLSLOptions)

+ 426 - 0
tools/clang/lib/SPIRV/DebugTypeVisitor.cpp

@@ -0,0 +1,426 @@
+//===--- DebugTypeVisitor.cpp - SPIR-V type to debug type impl ---*- C++ -*-==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <sstream>
+
+#include "DebugTypeVisitor.h"
+#include "LowerTypeVisitor.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/SPIRV/SpirvBuilder.h"
+#include "clang/SPIRV/SpirvModule.h"
+
+namespace clang {
+namespace spirv {
+
+void addTemplateTypeAndItsParamsToModule(SpirvModule *module,
+                                         SpirvDebugTypeTemplate *tempType) {
+  assert(module && "module is nullptr");
+  assert(tempType && "tempType is nullptr");
+
+  for (auto *param : tempType->getParams()) {
+    module->addDebugInfo(param);
+  }
+  module->addDebugInfo(tempType);
+}
+
+void DebugTypeVisitor::setDefaultDebugInfo(SpirvDebugInstruction *instr) {
+  instr->setAstResultType(astContext.VoidTy);
+  instr->setResultType(context.getVoidType());
+  instr->setInstructionSet(spvBuilder.getOpenCLDebugInfoExtInstSet());
+}
+
+SpirvDebugInfoNone *DebugTypeVisitor::getDebugInfoNone() {
+  auto *debugNone = spvBuilder.getOrCreateDebugInfoNone();
+  setDefaultDebugInfo(debugNone);
+  return debugNone;
+}
+
+SpirvDebugTypeComposite *DebugTypeVisitor::createDebugTypeComposite(
+    const SpirvType *type, const SourceLocation &loc, uint32_t tag) {
+  const auto &sm = astContext.getSourceManager();
+  uint32_t line = sm.getPresumedLineNumber(loc);
+  uint32_t column = sm.getPresumedColumnNumber(loc);
+  StringRef linkageName = type->getName();
+
+  // TODO: Update linkageName using astContext.createMangleContext().
+  std::string name = type->getName();
+
+  RichDebugInfo *debugInfo = &spvContext.getDebugInfo().begin()->second;
+  const char *file = sm.getPresumedLoc(loc).getFilename();
+  if (file)
+    debugInfo = &spvContext.getDebugInfo()[file];
+  return spvContext.getDebugTypeComposite(
+      type, name, debugInfo->source, line, column,
+      /* parent */ debugInfo->compilationUnit, linkageName, 3u, tag);
+}
+
+void DebugTypeVisitor::addDebugTypeForMemberVariables(
+    SpirvDebugTypeComposite *debugTypeComposite, const StructType *type,
+    llvm::function_ref<SourceLocation()> location, unsigned numBases) {
+  llvm::SmallVector<SpirvDebugInstruction *, 4> members;
+  uint32_t compositeSizeInBits = 0;
+  const auto &sm = astContext.getSourceManager();
+  for (auto &field : type->getFields()) {
+    // Skip base classes
+    // TODO: Handle class inheritance correctly.
+    if (numBases != 0) {
+      --numBases;
+      continue;
+    }
+
+    // Lower this member's debug type.
+    auto *memberDebugType = lowerToDebugType(field.type);
+
+    // TODO: We are currently in the discussion about how to handle
+    // a variable type with unknown physical layout. Add proper flags
+    // or operations for variables with the unknown physical layout.
+    // For example, we do not have physical layout for a local variable.
+
+    // Get offset (in bits) of this member within the composite.
+    uint32_t offsetInBits = field.offset.hasValue()
+                                ? offsetInBits = *field.offset * 8
+                                : compositeSizeInBits;
+    // Get size (in bits) of this member within the composite.
+    uint32_t sizeInBits = field.sizeInBytes.hasValue()
+                              ? *field.sizeInBytes * 8
+                              : memberDebugType->getSizeInBits();
+
+    const SourceLocation loc = location();
+    uint32_t line = sm.getPresumedLineNumber(loc);
+    uint32_t column = sm.getPresumedColumnNumber(loc);
+
+    // TODO: Replace 2u and 3u with valid flags when debug info extension is
+    // placed in SPIRV-Header.
+    auto *debugInstr = spvContext.getDebugTypeMember(
+        field.name, memberDebugType, debugTypeComposite->getSource(), line,
+        column, debugTypeComposite,
+        /* flags */ 3u, offsetInBits, sizeInBits, /* value */ nullptr);
+    assert(debugInstr);
+
+    setDefaultDebugInfo(debugInstr);
+    members.push_back(debugInstr);
+
+    compositeSizeInBits = offsetInBits + sizeInBits;
+  }
+  debugTypeComposite->setMembers(members);
+  debugTypeComposite->setSizeInBits(compositeSizeInBits);
+}
+
+void DebugTypeVisitor::lowerDebugTypeMembers(
+    SpirvDebugTypeComposite *debugTypeComposite, const StructType *type,
+    const DeclContext *decl) {
+  if (const auto *recordDecl = dyn_cast<RecordDecl>(decl)) {
+    auto fieldIter = recordDecl->field_begin();
+    auto fieldEnd = recordDecl->field_end();
+    unsigned numBases = 0;
+    if (const auto *cxxRecordDecl = dyn_cast<CXXRecordDecl>(recordDecl))
+      numBases = cxxRecordDecl->getNumBases();
+    addDebugTypeForMemberVariables(
+        debugTypeComposite, type,
+        [&fieldIter, &fieldEnd]() {
+          assert(fieldIter != fieldEnd);
+          (void)fieldEnd;
+          auto location = fieldIter->getLocation();
+          ++fieldIter;
+          return location;
+        },
+        numBases);
+  } else if (const auto *hlslBufferDecl = dyn_cast<HLSLBufferDecl>(decl)) {
+    auto subDeclIter = hlslBufferDecl->decls_begin();
+    auto subDeclEnd = hlslBufferDecl->decls_end();
+    addDebugTypeForMemberVariables(
+        debugTypeComposite, type,
+        [&subDeclIter, &subDeclEnd]() {
+          assert(subDeclIter != subDeclEnd);
+          (void)subDeclEnd;
+          auto location = subDeclIter->getLocation();
+          ++subDeclIter;
+          return location;
+        },
+        0);
+  } else {
+    assert(false && "Uknown DeclContext for DebugTypeMember generation");
+  }
+
+  // Push member functions to DebugTypeComposite Members operand.
+  for (auto *subDecl : decl->decls()) {
+    if (const auto *methodDecl = dyn_cast<FunctionDecl>(subDecl)) {
+      // TODO: if dbgFunction is NULL, it is a member function without
+      // function calls. We have to generate its type and insert it to
+      // members.
+      if (auto *dbgFunction = spvContext.getDebugFunctionForDecl(methodDecl)) {
+        dbgFunction->setParent(debugTypeComposite);
+        debugTypeComposite->appendMember(dbgFunction);
+      }
+    }
+  }
+}
+
+SpirvDebugTypeTemplate *DebugTypeVisitor::lowerDebugTypeTemplate(
+    const ClassTemplateSpecializationDecl *templateDecl,
+    SpirvDebugTypeComposite *debugTypeComposite) {
+  // Reuse already lowered DebugTypeTemplate.
+  auto *debugTypeTemplate = spvContext.getDebugTypeTemplate(templateDecl);
+  if (debugTypeTemplate != nullptr)
+    return debugTypeTemplate;
+
+  llvm::SmallVector<SpirvDebugTypeTemplateParameter *, 2> tempTypeParams;
+  const auto &argList = templateDecl->getTemplateArgs();
+  for (unsigned i = 0; i < argList.size(); ++i) {
+    // Reuse already lowered DebugTypeTemplateParameter.
+    auto *debugTypeTemplateParam =
+        spvContext.getDebugTypeTemplateParameter(&argList[i]);
+    if (debugTypeTemplateParam != nullptr) {
+      tempTypeParams.push_back(debugTypeTemplateParam);
+      continue;
+    }
+
+    // TODO: Handle other kinds e.g., value, template template type.
+    if (argList[i].getKind() != clang::TemplateArgument::ArgKind::Type)
+      continue;
+
+    // Lower DebugTypeTemplateParameter.
+    const auto *spvType = spvTypeVisitor.lowerType(
+        argList[i].getAsType(), currentDebugInstructionLayoutRule, llvm::None,
+        debugTypeComposite->getSourceLocation());
+    debugTypeTemplateParam = spvContext.createDebugTypeTemplateParameter(
+        &argList[i], "TemplateParam", lowerToDebugType(spvType),
+        getDebugInfoNone(), debugTypeComposite->getSource(),
+        debugTypeComposite->getLine(), debugTypeComposite->getColumn());
+    tempTypeParams.push_back(debugTypeTemplateParam);
+    setDefaultDebugInfo(debugTypeTemplateParam);
+  }
+
+  debugTypeTemplate = spvContext.createDebugTypeTemplate(
+      templateDecl, debugTypeComposite, tempTypeParams);
+  setDefaultDebugInfo(debugTypeTemplate);
+  return debugTypeTemplate;
+}
+
+SpirvDebugType *
+DebugTypeVisitor::lowerToDebugTypeComposite(const SpirvType *type) {
+  const auto *decl = spvContext.getStructDeclForSpirvType(type);
+  assert(decl != nullptr && "Lowering DebugTypeComposite needs DeclContext");
+
+  uint32_t tag = 1u;
+  if (const auto *recordDecl = dyn_cast<RecordDecl>(decl)) {
+    if (recordDecl->isStruct())
+      tag = 1;
+    else if (recordDecl->isClass())
+      tag = 0;
+    else if (recordDecl->isUnion())
+      tag = 2;
+    else
+      assert(!"DebugTypeComposite must be a struct, class, or union.");
+  }
+  SourceLocation loc = {};
+  if (const auto *declDecl = dyn_cast<Decl>(decl))
+    loc = declDecl->getLocation();
+  auto *debugTypeComposite = createDebugTypeComposite(type, loc, tag);
+  setDefaultDebugInfo(debugTypeComposite);
+
+  if (const auto *templateDecl =
+          dyn_cast<ClassTemplateSpecializationDecl>(decl)) {
+    // The size of an opaque type must be DebugInfoNone and its name must
+    // start with "@".
+    debugTypeComposite->markAsOpaqueType(getDebugInfoNone());
+    return lowerDebugTypeTemplate(templateDecl, debugTypeComposite);
+  } else {
+    // If SpirvType is StructType, it is a normal struct/class. Otherwise,
+    // it must be an image or a sampler type that is an opaque type.
+    if (const StructType *structType = dyn_cast<StructType>(type))
+      lowerDebugTypeMembers(debugTypeComposite, structType, decl);
+    else
+      debugTypeComposite->markAsOpaqueType(getDebugInfoNone());
+    return debugTypeComposite;
+  }
+}
+
+SpirvDebugType *DebugTypeVisitor::lowerToDebugType(const SpirvType *spirvType) {
+  SpirvDebugType *debugType = nullptr;
+
+  switch (spirvType->getKind()) {
+  case SpirvType::TK_Bool: {
+    llvm::StringRef name = "bool";
+    // TODO: Should we use 1 bit for booleans or 32 bits?
+    uint32_t size = 32;
+    // TODO: Use enums rather than uint32_t.
+    uint32_t encoding = 2u;
+    SpirvConstant *sizeInstruction = spvBuilder.getConstantInt(
+        astContext.UnsignedIntTy, llvm::APInt(32, size));
+    sizeInstruction->setResultType(spvContext.getUIntType(32));
+    debugType = spvContext.getDebugTypeBasic(spirvType, name, sizeInstruction,
+                                             encoding);
+    break;
+  }
+  case SpirvType::TK_Integer: {
+    auto *intType = dyn_cast<IntegerType>(spirvType);
+    const uint32_t size = intType->getBitwidth();
+    const bool isSigned = intType->isSignedInt();
+    SpirvConstant *sizeInstruction = spvBuilder.getConstantInt(
+        astContext.UnsignedIntTy, llvm::APInt(32, size));
+    sizeInstruction->setResultType(spvContext.getUIntType(32));
+    // TODO: Use enums rather than uint32_t.
+    uint32_t encoding = isSigned ? 4u : 6u;
+    std::string debugName = "";
+    if (size == 32) {
+      debugName = isSigned ? "int" : "uint";
+    } else {
+      std::ostringstream stream;
+      stream << (isSigned ? "int" : "uint") << size << "_t";
+      debugName = stream.str();
+    }
+    debugType = spvContext.getDebugTypeBasic(spirvType, debugName,
+                                             sizeInstruction, encoding);
+    break;
+  }
+  case SpirvType::TK_Float: {
+    auto *floatType = dyn_cast<FloatType>(spirvType);
+    const uint32_t size = floatType->getBitwidth();
+    SpirvConstant *sizeInstruction = spvBuilder.getConstantInt(
+        astContext.UnsignedIntTy, llvm::APInt(32, size));
+    sizeInstruction->setResultType(spvContext.getUIntType(32));
+    // TODO: Use enums rather than uint32_t.
+    uint32_t encoding = 3u;
+    std::string debugName = "";
+    if (size == 32) {
+      debugName = "float";
+    } else {
+      std::ostringstream stream;
+      stream << "float" << size << "_t";
+      debugName = stream.str();
+    }
+    debugType = spvContext.getDebugTypeBasic(spirvType, debugName,
+                                             sizeInstruction, encoding);
+    break;
+  }
+  case SpirvType::TK_Image:
+  case SpirvType::TK_Sampler:
+  case SpirvType::TK_Struct: {
+    debugType = lowerToDebugTypeComposite(spirvType);
+    break;
+  }
+  // TODO: Add DebugTypeComposite for class and union.
+  // TODO: Add DebugTypeEnum.
+  case SpirvType::TK_Array: {
+    auto *arrType = dyn_cast<ArrayType>(spirvType);
+    SpirvDebugInstruction *elemDebugType =
+        lowerToDebugType(arrType->getElementType());
+
+    llvm::SmallVector<uint32_t, 4> counts;
+    if (auto *dbgArrType = dyn_cast<SpirvDebugTypeArray>(elemDebugType)) {
+      counts.insert(counts.end(), dbgArrType->getElementCount().begin(),
+                    dbgArrType->getElementCount().end());
+      elemDebugType = dbgArrType->getElementType();
+    }
+    counts.push_back(arrType->getElementCount());
+
+    debugType = spvContext.getDebugTypeArray(spirvType, elemDebugType, counts);
+    break;
+  }
+  // TODO: Handle TK_RuntimeArray. We need spec updates for the bindless array.
+  case SpirvType::TK_Vector: {
+    auto *vecType = dyn_cast<VectorType>(spirvType);
+    SpirvDebugInstruction *elemDebugType =
+        lowerToDebugType(vecType->getElementType());
+    debugType = spvContext.getDebugTypeVector(spirvType, elemDebugType,
+                                              vecType->getElementCount());
+    break;
+  }
+  case SpirvType::TK_Matrix: {
+    // TODO: I temporarily use a DebugTypeArray for a matrix type.
+    // However, when the debug info extension supports matrix type
+    // e.g., DebugTypeMatrix, we must replace DebugTypeArray with
+    // DebugTypeMatrix.
+    auto *matType = dyn_cast<MatrixType>(spirvType);
+    SpirvDebugInstruction *elemDebugType =
+        lowerToDebugType(matType->getElementType());
+    debugType = spvContext.getDebugTypeArray(
+        spirvType, elemDebugType, {matType->numRows(), matType->numCols()});
+    break;
+  }
+  case SpirvType::TK_Pointer: {
+    debugType = lowerToDebugType(
+        dyn_cast<SpirvPointerType>(spirvType)->getPointeeType());
+    break;
+  }
+  case SpirvType::TK_Function: {
+    auto *fnType = dyn_cast<FunctionType>(spirvType);
+    // Special case: There is no DebugType for void. So if the function return
+    // type is void, we set it to nullptr.
+    SpirvDebugType *returnType = nullptr;
+    if (!isa<VoidType>(fnType->getReturnType())) {
+      auto *loweredRetTy = lowerToDebugType(fnType->getReturnType());
+      returnType = dyn_cast<SpirvDebugType>(loweredRetTy);
+      assert(returnType && "Function return type info must be SpirvDebugType");
+    }
+    llvm::SmallVector<SpirvDebugType *, 4> params;
+    for (const auto *paramType : fnType->getParamTypes()) {
+      params.push_back(dyn_cast<SpirvDebugType>(lowerToDebugType(paramType)));
+    }
+    // TODO: Add mechanism to properly calculate the flags.
+    // The info needed probably resides in clang::FunctionDecl.
+    // This info can either be stored in the SpirvFunction class. Or,
+    // alternatively the info can be stored in the SpirvContext.
+    const uint32_t flags = 3u;
+    debugType =
+        spvContext.getDebugTypeFunction(spirvType, flags, returnType, params);
+    break;
+  }
+  }
+
+  if (!debugType) {
+    emitError("Fail to lower SpirvType %0 to a debug type")
+        << spirvType->getName();
+    return nullptr;
+  }
+
+  setDefaultDebugInfo(debugType);
+  return debugType;
+}
+
+bool DebugTypeVisitor::visitInstruction(SpirvInstruction *instr) {
+  if (auto *debugInstr = dyn_cast<SpirvDebugInstruction>(instr)) {
+    setDefaultDebugInfo(debugInstr);
+
+    // The following instructions are the only debug instructions that contain a
+    // debug type:
+    // DebugGlobalVariable
+    // DebugLocalVariable
+    // DebugFunction
+    if (isa<SpirvDebugGlobalVariable>(debugInstr) ||
+        isa<SpirvDebugLocalVariable>(debugInstr)) {
+      currentDebugInstructionLayoutRule = debugInstr->getLayoutRule();
+      const SpirvType *spirvType = debugInstr->getDebugSpirvType();
+      assert(spirvType != nullptr);
+      SpirvDebugInstruction *debugType = lowerToDebugType(spirvType);
+      debugInstr->setDebugType(debugType);
+    }
+    if (auto *debugFunction = dyn_cast<SpirvDebugFunction>(debugInstr)) {
+      currentDebugInstructionLayoutRule = SpirvLayoutRule::Void;
+      const SpirvType *spirvType =
+          debugFunction->getSpirvFunction()->getFunctionType();
+      if (spirvType) {
+        SpirvDebugInstruction *debugType = lowerToDebugType(spirvType);
+        debugInstr->setDebugType(debugType);
+      }
+    }
+  }
+
+  return true;
+}
+
+bool DebugTypeVisitor::visit(SpirvModule *module, Phase phase) {
+  if (phase == Phase::Done)
+    spvContext.moveDebugTypesToModule(module);
+  return true;
+}
+
+} // namespace spirv
+} // namespace clang

+ 106 - 0
tools/clang/lib/SPIRV/DebugTypeVisitor.h

@@ -0,0 +1,106 @@
+//===--- DebugTypeVisitor.h - Convert AST Type to Debug Type -----*- C++ -*-==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_SPIRV_DEBUGTYPEVISITOR_H
+#define LLVM_CLANG_LIB_SPIRV_DEBUGTYPEVISITOR_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/SPIRV/SpirvContext.h"
+#include "clang/SPIRV/SpirvVisitor.h"
+#include "llvm/ADT/Optional.h"
+
+namespace clang {
+namespace spirv {
+
+class SpirvBuilder;
+class LowerTypeVisitor;
+
+/// The class responsible to translate SPIR-V types into DebugType*
+/// types as defined in the OpenCL.DebugInfo.100 spec.
+/// This visitor must be run after the LowerTypeVisitor pass.
+class DebugTypeVisitor : public Visitor {
+public:
+  DebugTypeVisitor(ASTContext &astCtx, SpirvContext &spvCtx,
+                   const SpirvCodeGenOptions &opts, SpirvBuilder &builder,
+                   LowerTypeVisitor &lowerTypeVisitor)
+      : Visitor(opts, spvCtx), astContext(astCtx), spvContext(spvCtx),
+        spvBuilder(builder), spvTypeVisitor(lowerTypeVisitor),
+        currentDebugInstructionLayoutRule(SpirvLayoutRule::Void) {}
+
+  // Visiting different SPIR-V constructs.
+  bool visit(SpirvModule *module, Phase);
+  bool visit(SpirvBasicBlock *, Phase) { return true; }
+  bool visit(SpirvFunction *, Phase) { return true; }
+
+  /// The "sink" visit function for all instructions.
+  ///
+  /// By default, all other visit instructions redirect to this visit function.
+  /// So that you want override this visit function to handle all instructions,
+  /// regardless of their polymorphism.
+  bool visitInstruction(SpirvInstruction *);
+
+private:
+  /// Emits error to the diagnostic engine associated with this visitor.
+  template <unsigned N>
+  DiagnosticBuilder emitError(const char (&message)[N],
+                              SourceLocation srcLoc = {}) {
+    const auto diagId = astContext.getDiagnostics().getCustomDiagID(
+        clang::DiagnosticsEngine::Error, message);
+    return astContext.getDiagnostics().Report(srcLoc, diagId);
+  }
+
+  /// Lowers the type of the given instruction to the corresponding SPIR-V debug
+  /// type. Adds the debug type instructions to the module.
+  ///
+  /// The lowering is recursive. All the debug types that the target type
+  /// depends on will also be created.
+  SpirvDebugType *lowerToDebugType(const SpirvType *);
+
+  /// Lowers DebugTypeComposite.
+  SpirvDebugType *lowerToDebugTypeComposite(const SpirvType *);
+
+  /// Creates DebugTypeComposite for a struct type.
+  SpirvDebugTypeComposite *createDebugTypeComposite(const SpirvType *type,
+                                                    const SourceLocation &loc,
+                                                    uint32_t tag);
+
+  /// Adds DebugTypeMembers for member variables to DebugTypeComposite.
+  void addDebugTypeForMemberVariables(
+      SpirvDebugTypeComposite *debugTypeComposite, const StructType *type,
+      llvm::function_ref<SourceLocation()> location, unsigned numBases);
+
+  /// Lowers DebugTypeMembers of DebugTypeComposite.
+  void lowerDebugTypeMembers(SpirvDebugTypeComposite *debugTypeComposite,
+                             const StructType *type, const DeclContext *decl);
+
+  /// Lowers DebugTypeTemplate for composite type.
+  SpirvDebugTypeTemplate *
+  lowerDebugTypeTemplate(const ClassTemplateSpecializationDecl *templateDecl,
+                         SpirvDebugTypeComposite *debugTypeComposite);
+
+  /// Set the result type of debug instructions to OpTypeVoid.
+  /// According to the OpenCL.DebugInfo.100 spec, all debug instructions are
+  /// OpExtInst with result type of void.
+  void setDefaultDebugInfo(SpirvDebugInstruction *instr);
+
+  SpirvDebugInfoNone *getDebugInfoNone();
+
+private:
+  ASTContext &astContext;           /// AST context
+  SpirvContext &spvContext;         /// SPIR-V context
+  SpirvBuilder &spvBuilder;         ///< SPIR-V builder
+  LowerTypeVisitor &spvTypeVisitor; /// QualType to SPIR-V type visitor
+
+  SpirvLayoutRule currentDebugInstructionLayoutRule; /// SPIR-V layout rule
+};
+
+} // end namespace spirv
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_SPIRV_DEBUGTYPEVISITOR_H

+ 56 - 6
tools/clang/lib/SPIRV/DeclResultIdMapper.cpp

@@ -687,9 +687,11 @@ SpirvInstruction *DeclResultIdMapper::getDeclEvalInfo(const ValueDecl *decl,
 }
 
 SpirvFunctionParameter *
-DeclResultIdMapper::createFnParam(const ParmVarDecl *param) {
+DeclResultIdMapper::createFnParam(const ParmVarDecl *param,
+                                  uint32_t dbgArgNumber) {
   const auto type = getTypeOrFnRetType(param);
   const auto loc = param->getLocation();
+  const auto name = param->getName();
   SpirvFunctionParameter *fnParamInstr = spvBuilder.addFnParam(
       type, param->hasAttr<HLSLPreciseAttr>(), loc, param->getName());
   bool isAlias = false;
@@ -699,6 +701,20 @@ DeclResultIdMapper::createFnParam(const ParmVarDecl *param) {
   assert(astDecls[param].instr == nullptr);
   astDecls[param].instr = fnParamInstr;
 
+  if (spirvOptions.debugInfoRich) {
+    // Add DebugLocalVariable information
+    const auto &sm = astContext.getSourceManager();
+    const uint32_t line = sm.getPresumedLineNumber(loc);
+    const uint32_t column = sm.getPresumedColumnNumber(loc);
+    const auto *info = theEmitter.getOrCreateRichDebugInfo(loc);
+    // TODO: replace this with FlagIsLocal enum.
+    uint32_t flags = 1 << 2;
+    auto *debugLocalVar = spvBuilder.createDebugLocalVariable(
+        type, name, info->source, line, column, info->scopeStack.back(), flags,
+        dbgArgNumber);
+    spvBuilder.createDebugDeclare(debugLocalVar, fnParamInstr);
+  }
+
   return fnParamInstr;
 }
 
@@ -734,14 +750,37 @@ DeclResultIdMapper::createFnVar(const VarDecl *var,
   return varInstr;
 }
 
+SpirvDebugGlobalVariable *DeclResultIdMapper::createDebugGlobalVariable(
+    SpirvVariable *var, const QualType &type, const SourceLocation &loc,
+    const StringRef &name) {
+  if (spirvOptions.debugInfoRich) {
+    // Add DebugGlobalVariable information
+    const auto &sm = astContext.getSourceManager();
+    const uint32_t line = sm.getPresumedLineNumber(loc);
+    const uint32_t column = sm.getPresumedColumnNumber(loc);
+    const auto *info = theEmitter.getOrCreateRichDebugInfo(loc);
+    // TODO: replace this with FlagIsDefinition enum.
+    uint32_t flags = 1 << 3;
+    // TODO: update linkageName correctly.
+    auto *dbgGlobalVar = spvBuilder.createDebugGlobalVariable(
+        type, name, info->source, line, column, info->scopeStack.back(),
+        /* linkageName */ name, var, flags);
+    dbgGlobalVar->setDebugSpirvType(var->getResultType());
+    dbgGlobalVar->setLayoutRule(var->getLayoutRule());
+    return dbgGlobalVar;
+  }
+  return nullptr;
+}
+
 SpirvVariable *
 DeclResultIdMapper::createFileVar(const VarDecl *var,
                                   llvm::Optional<SpirvInstruction *> init) {
   const auto type = getTypeOrFnRetType(var);
   const auto loc = var->getLocation();
-  SpirvVariable *varInstr = spvBuilder.addModuleVar(
-      type, spv::StorageClass::Private, var->hasAttr<HLSLPreciseAttr>(),
-      var->getName(), init, loc);
+  const auto name = var->getName();
+  SpirvVariable *varInstr =
+      spvBuilder.addModuleVar(type, spv::StorageClass::Private,
+                              var->hasAttr<HLSLPreciseAttr>(), name, init, loc);
 
   bool isAlias = false;
   (void)getTypeAndCreateCounterForPotentialAliasVar(var, &isAlias);
@@ -750,6 +789,8 @@ DeclResultIdMapper::createFileVar(const VarDecl *var,
   assert(astDecls[var].instr == nullptr);
   astDecls[var].instr = varInstr;
 
+  createDebugGlobalVariable(varInstr, type, loc, name);
+
   return varInstr;
 }
 
@@ -811,13 +852,16 @@ SpirvVariable *DeclResultIdMapper::createExternVar(const VarDecl *var) {
     needsFlatteningCompositeResources = true;
   }
 
+  const auto name = var->getName();
   SpirvVariable *varInstr = spvBuilder.addModuleVar(
-      type, storageClass, var->hasAttr<HLSLPreciseAttr>(), var->getName(),
-      llvm::None, loc);
+      type, storageClass, var->hasAttr<HLSLPreciseAttr>(), name, llvm::None,
+      loc);
   varInstr->setLayoutRule(rule);
   DeclSpirvInfo info(varInstr);
   astDecls[var] = info;
 
+  createDebugGlobalVariable(varInstr, type, loc, name);
+
   // Variables in Workgroup do not need descriptor decorations.
   if (storageClass == spv::StorageClass::Workgroup)
     return varInstr;
@@ -978,6 +1022,12 @@ SpirvVariable *DeclResultIdMapper::createCTBuffer(const HLSLBufferDecl *decl) {
       bufferVar, decl, decl->getLocation(), getResourceBinding(decl),
       decl->getAttr<VKBindingAttr>(), decl->getAttr<VKCounterBindingAttr>());
 
+  auto *dbgGlobalVar = createDebugGlobalVariable(
+      bufferVar, QualType(), decl->getLocation(), decl->getName());
+  if (dbgGlobalVar != nullptr) {
+    // C/TBuffer needs HLSLBufferDecl for debug type lowering.
+    spvContext.registerStructDeclForSpirvType(bufferVar->getResultType(), decl);
+  }
   return bufferVar;
 }
 

+ 14 - 2
tools/clang/lib/SPIRV/DeclResultIdMapper.h

@@ -310,8 +310,13 @@ public:
                               uint32_t payloadMemOffset = 0);
 
   /// \brief Creates a function-scope paramter in the current function and
-  /// returns its instruction.
-  SpirvFunctionParameter *createFnParam(const ParmVarDecl *param);
+  /// returns its instruction. dbgArgNumber is used to specify the argument
+  /// number of param among function parameters, which will be used for the
+  /// debug information. Note that dbgArgNumber for the first function
+  /// parameter must have "1", not "0", which is what Clang generates for
+  /// LLVM debug metadata.
+  SpirvFunctionParameter *createFnParam(const ParmVarDecl *param,
+                                        uint32_t dbgArgNumber = 0);
 
   /// \brief Creates the counter variable associated with the given param.
   /// This is meant to be used for forward-declared functions and this objects
@@ -702,6 +707,13 @@ private:
   /// Returns true if the given SPIR-V stage variable has Input storage class.
   inline bool isInputStorageClass(const StageVar &v);
 
+  /// Creates DebugGlobalVariable and returns it if rich debug information
+  /// generation is enabled. Otherwise, returns nullptr.
+  SpirvDebugGlobalVariable *createDebugGlobalVariable(SpirvVariable *var,
+                                                      const QualType &type,
+                                                      const SourceLocation &loc,
+                                                      const StringRef &name);
+
   /// Determines the register type for a resource that does not have an
   /// explicit register() declaration.  Returns true if it is able to
   /// determine the register type and will set |*registerTypeOut| to

File diff suppressed because it is too large
+ 604 - 146
tools/clang/lib/SPIRV/EmitVisitor.cpp


+ 50 - 6
tools/clang/lib/SPIRV/EmitVisitor.h

@@ -196,7 +196,10 @@ public:
                     &annotationsBinary, &typeConstantBinary,
                     [this]() -> uint32_t { return takeNextId(); }),
         debugMainFileId(0), debugLine(0), debugColumn(0),
-        lastOpWasMergeInst(false) {}
+        lastOpWasMergeInst(false), inEntryFunctionWrapper(false),
+        hlslVersion(0) {}
+
+  ~EmitVisitor();
 
   // Visit different SPIR-V constructs for emitting.
   bool visit(SpirvModule *, Phase phase) override;
@@ -262,6 +265,26 @@ public:
   bool visit(SpirvDemoteToHelperInvocationEXT *) override;
   bool visit(SpirvRayQueryOpKHR *) override;
 
+  bool visit(SpirvDebugInfoNone *) override;
+  bool visit(SpirvDebugSource *) override;
+  bool visit(SpirvDebugCompilationUnit *) override;
+  bool visit(SpirvDebugLexicalBlock *) override;
+  bool visit(SpirvDebugScope *) override;
+  bool visit(SpirvDebugFunctionDeclaration *) override;
+  bool visit(SpirvDebugFunction *) override;
+  bool visit(SpirvDebugLocalVariable *) override;
+  bool visit(SpirvDebugDeclare *) override;
+  bool visit(SpirvDebugGlobalVariable *) override;
+  bool visit(SpirvDebugExpression *) override;
+  bool visit(SpirvDebugTypeBasic *) override;
+  bool visit(SpirvDebugTypeVector *) override;
+  bool visit(SpirvDebugTypeArray *) override;
+  bool visit(SpirvDebugTypeFunction *) override;
+  bool visit(SpirvDebugTypeComposite *) override;
+  bool visit(SpirvDebugTypeMember *) override;
+  bool visit(SpirvDebugTypeTemplate *) override;
+  bool visit(SpirvDebugTypeTemplateParameter *) override;
+
   using Visitor::visit;
 
   // Returns the assembled binary built up in this visitor.
@@ -282,7 +305,14 @@ private:
     return obj->getResultId();
   }
 
-  void emitDebugLine(spv::Op op, const SourceLocation &loc);
+  /// If we already created OpString for str, just return the id of the created
+  /// one. Otherwise, create it, keep it in stringIdMap, and return its id.
+  uint32_t getOrCreateOpStringId(llvm::StringRef str);
+
+  // Emits an OpLine instruction for the given operation into the given binary
+  // section.
+  void emitDebugLine(spv::Op op, const SourceLocation &loc,
+                     std::vector<uint32_t> *section);
 
   // Initiates the creation of a new instruction with the given Opcode.
   void initInstruction(spv::Op, const SourceLocation &);
@@ -293,8 +323,9 @@ private:
   void initInstruction(SpirvInstruction *);
 
   // Finalizes the current instruction by encoding the instruction size into the
-  // first word, and then appends the current instruction to the SPIR-V binary.
-  void finalizeInstruction();
+  // first word, and then appends the current instruction to the given SPIR-V
+  // binary section.
+  void finalizeInstruction(std::vector<uint32_t> *section);
 
   // Encodes the given string into the current instruction that is being built.
   void encodeString(llvm::StringRef value);
@@ -339,10 +370,15 @@ private:
   std::vector<uint32_t> annotationsBinary;
   // All type and constant instructions
   std::vector<uint32_t> typeConstantBinary;
+  // All global variable declarations (all OpVariable instructions whose Storage
+  // Class is not Function)
+  std::vector<uint32_t> globalVarsBinary;
+  // All Rich Debug Info instructions
+  std::vector<uint32_t> richDebugInfo;
   // All other instructions
   std::vector<uint32_t> mainBinary;
-  // File information for debugging that will be used by OpLine.
-  llvm::StringMap<uint32_t> debugFileIdMap;
+  // String literals to SpirvString objects
+  llvm::StringMap<uint32_t> stringIdMap;
   // Main file information for debugging that will be used by OpLine.
   uint32_t debugMainFileId;
   // One HLSL source line may result in several SPIR-V instructions. In order to
@@ -355,6 +391,14 @@ private:
   uint32_t debugColumn;
   // True if the last emitted instruction was OpSelectionMerge or OpLoopMerge.
   bool lastOpWasMergeInst;
+  // True if currently it enters an entry function wrapper.
+  bool inEntryFunctionWrapper;
+  // Set of files that we already dumped their source code in OpSource.
+  llvm::DenseSet<uint32_t> dumpedFiles;
+  uint32_t hlslVersion;
+  // Vector to contain SpirvInstruction objects created by this class. The
+  // destructor of this class will release them.
+  std::vector<SpirvInstruction *> spvInstructions;
 };
 
 } // namespace spirv

+ 39 - 3
tools/clang/lib/SPIRV/LowerTypeVisitor.cpp

@@ -74,6 +74,33 @@ bool LowerTypeVisitor::visitInstruction(SpirvInstruction *instr) {
     instr->setResultType(spirvType);
   }
 
+  // Lower QualType of DebugLocalVariable or DebugGlobalVariable to SpirvType.
+  // Since debug local/global variable must have a debug type, SpirvEmitter sets
+  // its QualType. Here we lower it to SpirvType and DebugTypeVisitor will lower
+  // the SpirvType to debug type.
+  if (auto *debugInstruction = dyn_cast<SpirvDebugInstruction>(instr)) {
+    const QualType debugQualType = debugInstruction->getDebugQualType();
+    if (!debugQualType.isNull()) {
+      assert(isa<SpirvDebugLocalVariable>(debugInstruction) ||
+             isa<SpirvDebugGlobalVariable>(debugInstruction));
+      const SpirvType *spirvType =
+          lowerType(debugQualType, instr->getLayoutRule(),
+                    /*isRowMajor*/ llvm::None, instr->getSourceLocation());
+      debugInstruction->setDebugSpirvType(spirvType);
+    } else if (const auto *debugSpirvType =
+                   debugInstruction->getDebugSpirvType()) {
+      // When it does not have a QualType, SpirvEmitter or DeclResultIdMapper
+      // generates a hybrid type. In that case, we keep the hybrid type for the
+      // DebugGlobalVariable, not QualType. We have to lower the hybrid type and
+      // update the SpirvType for the DebugGlobalVariable.
+      assert(isa<SpirvDebugGlobalVariable>(debugInstruction) &&
+             isa<HybridType>(debugSpirvType));
+      const SpirvType *loweredSpirvType = lowerType(
+          debugSpirvType, instr->getLayoutRule(), instr->getSourceLocation());
+      debugInstruction->setDebugSpirvType(loweredSpirvType);
+    }
+  }
+
   // Instruction-specific type updates
 
   const auto *resultType = instr->getResultType();
@@ -162,9 +189,12 @@ const SpirvType *LowerTypeVisitor::lowerType(const SpirvType *type,
     // lower all fields of the struct.
     auto loweredFields =
         populateLayoutInformation(hybridStruct->getFields(), rule);
-    return spvContext.getStructType(
+    const StructType *structType = spvContext.getStructType(
         loweredFields, hybridStruct->getStructName(),
         hybridStruct->isReadOnly(), hybridStruct->getInterfaceType());
+    if (const auto *decl = spvContext.getStructDeclForSpirvType(type))
+      spvContext.registerStructDeclForSpirvType(structType, decl);
+    return structType;
   }
   // Void, bool, int, float cannot be further lowered.
   // Matrices cannot contain hybrid types. Only matrices of scalars are valid.
@@ -362,8 +392,10 @@ const SpirvType *LowerTypeVisitor::lowerType(QualType type,
     // (ClassTemplateSpecializationDecl is a subclass of CXXRecordDecl, which
     // is then a subclass of RecordDecl.) So we need to check them before
     // checking the general struct type.
-    if (const auto *spvType = lowerResourceType(type, rule, srcLoc))
+    if (const auto *spvType = lowerResourceType(type, rule, srcLoc)) {
+      spvContext.registerStructDeclForSpirvType(spvType, decl);
       return spvType;
+    }
 
     // Collect all fields' information.
     llvm::SmallVector<HybridStructType::FieldInfo, 8> fields;
@@ -388,7 +420,10 @@ const SpirvType *LowerTypeVisitor::lowerType(QualType type,
 
     auto loweredFields = populateLayoutInformation(fields, rule);
 
-    return spvContext.getStructType(loweredFields, decl->getName());
+    const auto *spvStructType =
+        spvContext.getStructType(loweredFields, decl->getName());
+    spvContext.registerStructDeclForSpirvType(spvStructType, decl);
+    return spvStructType;
   }
 
   // Array type
@@ -805,6 +840,7 @@ LowerTypeVisitor::populateLayoutInformation(
 
     // Each structure-type member must have an Offset Decoration.
     loweredField.offset = offset;
+    loweredField.sizeInBytes = memberSize;
     offset += memberSize;
 
     // Each structure-type member that is a matrix or array-of-matrices must be

+ 7 - 6
tools/clang/lib/SPIRV/LowerTypeVisitor.h

@@ -41,6 +41,13 @@ public:
   /// regardless of their polymorphism.
   bool visitInstruction(SpirvInstruction *instr) override;
 
+  /// Lowers the given AST QualType into the corresponding SPIR-V type.
+  ///
+  /// The lowering is recursive; all the types that the target type depends
+  /// on will be created in SpirvContext.
+  const SpirvType *lowerType(QualType type, SpirvLayoutRule,
+                             llvm::Optional<bool> isRowMajor, SourceLocation);
+
 private:
   /// Emits error to the diagnostic engine associated with this visitor.
   template <unsigned N>
@@ -51,12 +58,6 @@ private:
     return astContext.getDiagnostics().Report(srcLoc, diagId);
   }
 
-  /// Lowers the given AST QualType into the corresponding SPIR-V type.
-  ///
-  /// The lowering is recursive; all the types that the target type depends
-  /// on will be created in SpirvContext.
-  const SpirvType *lowerType(QualType type, SpirvLayoutRule,
-                             llvm::Optional<bool> isRowMajor, SourceLocation);
   /// Lowers the given Hybrid type into a SPIR-V type.
   ///
   /// Uses the above lowerType method to lower the QualType components of hybrid

+ 217 - 0
tools/clang/lib/SPIRV/SortDebugInfoVisitor.cpp

@@ -0,0 +1,217 @@
+//===--- SortDebugInfoVisitor.cpp - Valid order debug instrs -----*- C++ -*-==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SortDebugInfoVisitor.h"
+
+namespace clang {
+namespace spirv {
+
+void SortDebugInfoVisitor::whileEachOperandOfDebugInstruction(
+    SpirvDebugInstruction *di,
+    llvm::function_ref<bool(SpirvDebugInstruction *)> visitor) {
+  if (di == nullptr)
+    return;
+  if (di->getDebugType() != nullptr) {
+    if (!visitor(di->getDebugType()))
+      return;
+  }
+  if (di->getParentScope() != nullptr) {
+    if (!visitor(di->getParentScope()))
+      return;
+  }
+
+  switch (di->getKind()) {
+  case SpirvInstruction::IK_DebugCompilationUnit: {
+    SpirvDebugCompilationUnit *inst = dyn_cast<SpirvDebugCompilationUnit>(di);
+    assert(inst != nullptr);
+    if (!visitor(inst->getDebugSource()))
+      break;
+  } break;
+  case SpirvInstruction::IK_DebugFunctionDecl: {
+    SpirvDebugFunctionDeclaration *inst =
+        dyn_cast<SpirvDebugFunctionDeclaration>(di);
+    assert(inst != nullptr);
+    if (!visitor(inst->getSource()))
+      break;
+  } break;
+  case SpirvInstruction::IK_DebugFunction: {
+    SpirvDebugFunction *inst = dyn_cast<SpirvDebugFunction>(di);
+    assert(inst != nullptr);
+    if (!visitor(inst->getSource()))
+      break;
+    if (!visitor(inst->getDebugInfoNone()))
+      break;
+  } break;
+  case SpirvInstruction::IK_DebugLocalVariable: {
+    SpirvDebugLocalVariable *inst = dyn_cast<SpirvDebugLocalVariable>(di);
+    assert(inst != nullptr);
+    if (!visitor(inst->getSource()))
+      break;
+  } break;
+  case SpirvInstruction::IK_DebugGlobalVariable: {
+    SpirvDebugGlobalVariable *inst = dyn_cast<SpirvDebugGlobalVariable>(di);
+    assert(inst != nullptr);
+    if (!visitor(inst->getSource()))
+      break;
+  } break;
+  case SpirvInstruction::IK_DebugExpression: {
+    SpirvDebugExpression *inst = dyn_cast<SpirvDebugExpression>(di);
+    assert(inst != nullptr);
+    for (auto *op : inst->getOperations())
+      if (!visitor(op))
+        break;
+  } break;
+  case SpirvInstruction::IK_DebugLexicalBlock: {
+    SpirvDebugLexicalBlock *inst = dyn_cast<SpirvDebugLexicalBlock>(di);
+    assert(inst != nullptr);
+    if (!visitor(inst->getSource()))
+      break;
+  } break;
+  case SpirvInstruction::IK_DebugTypeArray: {
+    SpirvDebugTypeArray *inst = dyn_cast<SpirvDebugTypeArray>(di);
+    assert(inst != nullptr);
+    if (!visitor(inst->getElementType()))
+      break;
+  } break;
+  case SpirvInstruction::IK_DebugTypeVector: {
+    SpirvDebugTypeVector *inst = dyn_cast<SpirvDebugTypeVector>(di);
+    assert(inst != nullptr);
+    if (!visitor(inst->getElementType()))
+      break;
+  } break;
+  case SpirvInstruction::IK_DebugTypeFunction: {
+    SpirvDebugTypeFunction *inst = dyn_cast<SpirvDebugTypeFunction>(di);
+    assert(inst != nullptr);
+    if (!visitor(inst->getReturnType()))
+      break;
+    for (auto *param : inst->getParamTypes())
+      if (!visitor(param))
+        break;
+  } break;
+  case SpirvInstruction::IK_DebugTypeComposite: {
+    SpirvDebugTypeComposite *inst = dyn_cast<SpirvDebugTypeComposite>(di);
+    assert(inst != nullptr);
+    // Note that DebugTypeComposite always has forward references to
+    // members. Therefore, the edge direction in DAG must be from
+    // DebugTypeMember to DebugTypeComposite. DO NOT visit members here.
+
+    // In terms of DebugTypeTemplate used for a HLSL resource, it has
+    // to reference DebugTypeComposite but DebugTypeComposite does not
+    // reference DebugTypeTemplate. DO NOT visit DebugTypeTemplate here.
+
+    if (!visitor(inst->getSource()))
+      break;
+    if (!visitor(inst->getDebugInfoNone()))
+      break;
+  } break;
+  case SpirvInstruction::IK_DebugTypeMember: {
+    SpirvDebugTypeMember *inst = dyn_cast<SpirvDebugTypeMember>(di);
+    assert(inst != nullptr);
+    if (!visitor(inst->getDebugType()))
+      break;
+    if (!visitor(inst->getSource()))
+      break;
+  } break;
+  case SpirvInstruction::IK_DebugTypeTemplate: {
+    SpirvDebugTypeTemplate *inst = dyn_cast<SpirvDebugTypeTemplate>(di);
+    assert(inst != nullptr);
+    if (!visitor(inst->getTarget()))
+      break;
+    for (auto *param : inst->getParams())
+      if (!visitor(param))
+        break;
+  } break;
+  case SpirvInstruction::IK_DebugTypeTemplateParameter: {
+    SpirvDebugTypeTemplateParameter *inst =
+        dyn_cast<SpirvDebugTypeTemplateParameter>(di);
+    assert(inst != nullptr);
+    if (!visitor(inst->getActualType()))
+      break;
+    // Value operand of DebugTypeTemplateParameter must be DebugInfoNone
+    // when it is used for a type not used for a integer value.
+    if (auto *value = dyn_cast<SpirvDebugInstruction>(inst->getValue())) {
+      if (!visitor(value))
+        break;
+    }
+    if (!visitor(inst->getSource()))
+      break;
+  } break;
+  case SpirvInstruction::IK_DebugInfoNone:
+  case SpirvInstruction::IK_DebugSource:
+  case SpirvInstruction::IK_DebugOperation:
+  case SpirvInstruction::IK_DebugTypeBasic:
+    break;
+  default:
+    // DebugDeclare and DebugScope must be placed within a function.
+    assert(false && "unsupported debug instruction");
+    break;
+  }
+}
+
+bool SortDebugInfoVisitor::visit(SpirvModule *mod, Phase phase) {
+  if (phase == Phase::Done)
+    return true;
+
+  auto &debugInstructions = mod->getDebugInfo();
+
+  // Keep the number of unique debug instructions to verify that it is not
+  // changed at the end of this visitor.
+  llvm::SmallSet<SpirvDebugInstruction *, 32> uniqueDebugInstructions;
+  uniqueDebugInstructions.insert(debugInstructions.begin(),
+                                 debugInstructions.end());
+  auto numberOfDebugInstrs = uniqueDebugInstructions.size();
+  (void)numberOfDebugInstrs;
+
+  // Collect nodes without predecessor.
+  llvm::SmallSet<SpirvDebugInstruction *, 32> visited;
+  for (auto *di : debugInstructions) {
+    whileEachOperandOfDebugInstruction(
+        di, [&visited](SpirvDebugInstruction *operand) {
+          if (operand != nullptr)
+            visited.insert(operand);
+          return true;
+        });
+  }
+  llvm::SmallVector<SpirvDebugInstruction *, 32> stack;
+  for (auto *di : debugInstructions) {
+    if (visited.count(di) == 0)
+      stack.push_back(di);
+  }
+
+  // Sort debug instructions in a post order. We puts successors in the first
+  // places of `debugInstructions`. For example, `DebugInfoNone` does not have
+  // any operand, which means it does not have any successors. We have to place
+  // it earlier than the instructions using it.
+  debugInstructions.clear();
+  visited.clear();
+  while (!stack.empty()) {
+    auto *di = stack.back();
+    visited.insert(di);
+    whileEachOperandOfDebugInstruction(
+        di, [&visited, &stack](SpirvDebugInstruction *operand) {
+          if (operand != nullptr && visited.count(operand) == 0) {
+            stack.push_back(operand);
+            return false;
+          }
+          return true;
+        });
+    if (stack.back() == di) {
+      debugInstructions.push_back(di);
+      stack.pop_back();
+    }
+  }
+
+  // The sort result must have the same number of debug instructions.
+  assert(numberOfDebugInstrs == debugInstructions.size());
+
+  return true;
+}
+
+} // end namespace spirv
+} // end namespace clang

+ 59 - 0
tools/clang/lib/SPIRV/SortDebugInfoVisitor.h

@@ -0,0 +1,59 @@
+//===--- SortDebugInfoVisitor.h - Debug instrs in Valid order ----*- C++ -*-==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_SPIRV_SORTDEBUGINFOVISITOR_H
+#define LLVM_CLANG_LIB_SPIRV_SORTDEBUGINFOVISITOR_H
+
+#include "clang/SPIRV/SpirvContext.h"
+#include "clang/SPIRV/SpirvInstruction.h"
+#include "clang/SPIRV/SpirvModule.h"
+#include "clang/SPIRV/SpirvVisitor.h"
+
+namespace clang {
+namespace spirv {
+
+class SpirvFunction;
+class SpirvBasicBlock;
+
+/// The class responsible to sort OpenCL.DebugInfo.100 instructions in a
+/// valid order without any invalid forward reference.
+class SortDebugInfoVisitor : public Visitor {
+public:
+  SortDebugInfoVisitor(SpirvContext &spvCtx, const SpirvCodeGenOptions &opts)
+      : Visitor(opts, spvCtx) {}
+
+  // Sorts debug instructions in a post order to remove invalid forward
+  // references. Note that the post order guarantees a successor node is not
+  // visited before its predecessor and this property can be used to sort
+  // instructions in a valid layout without any invalid forward reference.
+  bool visit(SpirvModule *, Phase);
+
+  // Visiting different SPIR-V constructs.
+  bool visit(SpirvFunction *, Phase) { return true; }
+  bool visit(SpirvBasicBlock *, Phase) { return true; }
+
+  /// The "sink" visit function for all instructions.
+  ///
+  /// By default, all other visit instructions redirect to this visit function.
+  /// So that you want override this visit function to handle all instructions,
+  /// regardless of their polymorphism.
+  bool visitInstruction(SpirvInstruction *) { return true; }
+
+private:
+  // Invokes visitor for each operand of the debug instruction `di`. If
+  // `visitor` returns false, it stops and returns.
+  void whileEachOperandOfDebugInstruction(
+      SpirvDebugInstruction *di,
+      llvm::function_ref<bool(SpirvDebugInstruction *)> visitor);
+};
+
+} // end namespace spirv
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_SPIRV_SORTDEBUGINFOVISITOR_H

+ 14 - 5
tools/clang/lib/SPIRV/SpirvBasicBlock.cpp

@@ -15,11 +15,13 @@ namespace spirv {
 
 SpirvBasicBlock::SpirvBasicBlock(llvm::StringRef name)
     : labelId(0), labelName(name), mergeTarget(nullptr),
-      continueTarget(nullptr) {}
+      continueTarget(nullptr), debugScope(nullptr) {}
 
 SpirvBasicBlock::~SpirvBasicBlock() {
   for (auto instructionNode : instructions)
     instructionNode.instruction->releaseMemory();
+  if (debugScope)
+    debugScope->releaseMemory();
 }
 
 bool SpirvBasicBlock::hasTerminator() const {
@@ -33,6 +35,9 @@ bool SpirvBasicBlock::invokeVisitor(Visitor *visitor,
   if (!visitor->visit(this, Visitor::Phase::Init))
     return false;
 
+  if (debugScope && !visitor->visit(debugScope))
+    return false;
+
   if (reverseOrder) {
     for (auto iter = instructions.rbegin(); iter != instructions.rend();
          ++iter) {
@@ -41,17 +46,21 @@ bool SpirvBasicBlock::invokeVisitor(Visitor *visitor,
     }
     // If a basic block is the first basic block of a function, it should
     // include all the variables of the function.
-    if (!vars.empty())
-      for (auto var = vars.rbegin(); var != vars.rend(); ++var)
+    if (!vars.empty()) {
+      for (auto var = vars.rbegin(); var != vars.rend(); ++var) {
         if (!(*var)->invokeVisitor(visitor))
           return false;
+      }
+    }
   } else {
     // If a basic block is the first basic block of a function, it should
     // include all the variables of the function.
-    if (!vars.empty())
-      for (auto *var : vars)
+    if (!vars.empty()) {
+      for (auto *var : vars) {
         if (!var->invokeVisitor(visitor))
           return false;
+      }
+    }
 
     for (auto iter = instructions.begin(); iter != instructions.end(); ++iter) {
       if (!iter->instruction->invokeVisitor(visitor))

+ 121 - 1
tools/clang/lib/SPIRV/SpirvBuilder.cpp

@@ -9,6 +9,7 @@
 
 #include "clang/SPIRV/SpirvBuilder.h"
 #include "CapabilityVisitor.h"
+#include "DebugTypeVisitor.h"
 #include "EmitVisitor.h"
 #include "LiteralTypeVisitor.h"
 #include "LowerTypeVisitor.h"
@@ -16,6 +17,7 @@
 #include "PreciseVisitor.h"
 #include "RelaxedPrecisionVisitor.h"
 #include "RemoveBufferBlockVisitor.h"
+#include "SortDebugInfoVisitor.h"
 #include "clang/SPIRV/AstTypeProbe.h"
 
 namespace clang {
@@ -24,7 +26,8 @@ namespace spirv {
 SpirvBuilder::SpirvBuilder(ASTContext &ac, SpirvContext &ctx,
                            const SpirvCodeGenOptions &opt)
     : astContext(ac), context(ctx), mod(llvm::make_unique<SpirvModule>()),
-      function(nullptr), spirvOptions(opt), builtinVars(), stringLiterals() {}
+      function(nullptr), spirvOptions(opt), builtinVars(), debugNone(nullptr),
+      nullDebugExpr(nullptr), stringLiterals() {}
 
 SpirvFunction *SpirvBuilder::createSpirvFunction(QualType returnType,
                                                  SourceLocation loc,
@@ -106,9 +109,18 @@ SpirvBasicBlock *SpirvBuilder::createBasicBlock(llvm::StringRef name) {
   assert(function && "found detached basic block");
   auto *bb = new (context) SpirvBasicBlock(name);
   function->addBasicBlock(bb);
+  if (auto *scope = context.getCurrentLexicalScope())
+    bb->setDebugScope(new (context) SpirvDebugScope(scope));
   return bb;
 }
 
+SpirvDebugScope *SpirvBuilder::createDebugScope(SpirvDebugInstruction *scope) {
+  assert(insertPoint && "null insert point");
+  auto *dbgScope = new (context) SpirvDebugScope(scope);
+  insertPoint->addInstruction(dbgScope);
+  return dbgScope;
+}
+
 void SpirvBuilder::addSuccessor(SpirvBasicBlock *successorBB) {
   assert(insertPoint && "null insert point");
   insertPoint->addSuccessor(successorBB);
@@ -807,6 +819,101 @@ SpirvBuilder::createDemoteToHelperInvocationEXT(SourceLocation loc) {
   return inst;
 }
 
+SpirvDebugSource *SpirvBuilder::createDebugSource(llvm::StringRef file,
+                                                  llvm::StringRef text) {
+  auto *inst = new (context) SpirvDebugSource(file, text);
+  mod->addDebugInfo(inst);
+  return inst;
+}
+
+SpirvDebugCompilationUnit *
+SpirvBuilder::createDebugCompilationUnit(SpirvDebugSource *source) {
+  auto *inst = new (context) SpirvDebugCompilationUnit(
+      /*version*/ 1, /*DWARF version*/ 4, source);
+  mod->addDebugInfo(inst);
+  return inst;
+}
+
+SpirvDebugLexicalBlock *
+SpirvBuilder::createDebugLexicalBlock(SpirvDebugSource *source, uint32_t line,
+                                      uint32_t column,
+                                      SpirvDebugInstruction *parent) {
+  assert(insertPoint && "null insert point");
+  auto *inst =
+      new (context) SpirvDebugLexicalBlock(source, line, column, parent);
+  mod->addDebugInfo(inst);
+  return inst;
+}
+
+SpirvDebugLocalVariable *SpirvBuilder::createDebugLocalVariable(
+    QualType debugQualType, llvm::StringRef varName, SpirvDebugSource *src,
+    uint32_t line, uint32_t column, SpirvDebugInstruction *parentScope,
+    uint32_t flags, llvm::Optional<uint32_t> argNumber) {
+  auto *inst = new (context) SpirvDebugLocalVariable(
+      debugQualType, varName, src, line, column, parentScope, flags, argNumber);
+  mod->addDebugInfo(inst);
+  return inst;
+}
+
+SpirvDebugGlobalVariable *SpirvBuilder::createDebugGlobalVariable(
+    QualType debugType, llvm::StringRef varName, SpirvDebugSource *src,
+    uint32_t line, uint32_t column, SpirvDebugInstruction *parentScope,
+    llvm::StringRef linkageName, SpirvVariable *var, uint32_t flags,
+    llvm::Optional<SpirvInstruction *> staticMemberDebugType) {
+  auto *inst = new (context) SpirvDebugGlobalVariable(
+      debugType, varName, src, line, column, parentScope, linkageName, var,
+      flags, staticMemberDebugType);
+  mod->addDebugInfo(inst);
+  return inst;
+}
+
+SpirvDebugInfoNone *SpirvBuilder::getOrCreateDebugInfoNone() {
+  if (debugNone)
+    return debugNone;
+
+  debugNone = new (context) SpirvDebugInfoNone();
+  mod->addDebugInfo(debugNone);
+  return debugNone;
+}
+
+SpirvDebugExpression *SpirvBuilder::getOrCreateNullDebugExpression() {
+  if (nullDebugExpr)
+    return nullDebugExpr;
+
+  nullDebugExpr = new (context) SpirvDebugExpression();
+  mod->addDebugInfo(nullDebugExpr);
+  return nullDebugExpr;
+}
+
+SpirvDebugDeclare *SpirvBuilder::createDebugDeclare(
+    SpirvDebugLocalVariable *dbgVar, SpirvInstruction *var,
+    llvm::Optional<SpirvDebugExpression *> dbgExpr) {
+  auto *decl = new (context)
+      SpirvDebugDeclare(dbgVar, var,
+                        dbgExpr.hasValue() ? dbgExpr.getValue()
+                                           : getOrCreateNullDebugExpression());
+  if (isa<SpirvFunctionParameter>(var)) {
+    assert(function && "found detached parameter");
+    function->addParameterDebugDeclare(decl);
+  } else {
+    assert(insertPoint && "null insert point");
+    insertPoint->addInstruction(decl);
+  }
+  return decl;
+}
+
+SpirvDebugFunction *SpirvBuilder::createDebugFunction(
+    const FunctionDecl *decl, llvm::StringRef name, SpirvDebugSource *src,
+    uint32_t line, uint32_t column, SpirvDebugInstruction *parentScope,
+    llvm::StringRef linkageName, uint32_t flags, uint32_t scopeLine,
+    SpirvFunction *fn) {
+  auto *inst = new (context) SpirvDebugFunction(
+      name, src, line, column, parentScope, linkageName, flags, scopeLine, fn);
+  mod->addDebugInfo(inst);
+  context.registerDebugFunctionForDecl(decl, inst);
+  return inst;
+}
+
 SpirvInstruction *
 SpirvBuilder::createRayQueryOpsKHR(spv::Op opcode, QualType resultType,
                                    ArrayRef<SpirvInstruction *> operands,
@@ -833,6 +940,10 @@ SpirvExtInstImport *SpirvBuilder::getExtInstSet(llvm::StringRef extName) {
   return set;
 }
 
+SpirvExtInstImport *SpirvBuilder::getOpenCLDebugInfoExtInstSet() {
+  return getExtInstSet("OpenCL.DebugInfo.100");
+}
+
 SpirvVariable *SpirvBuilder::addStageIOVar(QualType type,
                                            spv::StorageClass storageClass,
                                            std::string name, bool isPrecise,
@@ -1109,6 +1220,15 @@ std::vector<uint32_t> SpirvBuilder::takeModule() {
   // Lower types
   mod->invokeVisitor(&lowerTypeVisitor);
 
+  // Generate debug types (if needed)
+  if (spirvOptions.debugInfoRich) {
+    DebugTypeVisitor debugTypeVisitor(astContext, context, spirvOptions, *this,
+                                      lowerTypeVisitor);
+    SortDebugInfoVisitor sortDebugInfoVisitor(context, spirvOptions);
+    mod->invokeVisitor(&debugTypeVisitor);
+    mod->invokeVisitor(&sortDebugInfoVisitor);
+  }
+
   // Add necessary capabilities and extensions
   mod->invokeVisitor(&capabilityVisitor);
 

+ 181 - 1
tools/clang/lib/SPIRV/SpirvContext.cpp

@@ -11,6 +11,7 @@
 #include <tuple>
 
 #include "clang/SPIRV/SpirvContext.h"
+#include "clang/SPIRV/SpirvModule.h"
 
 namespace clang {
 namespace spirv {
@@ -19,7 +20,7 @@ SpirvContext::SpirvContext()
     : allocator(), voidType(nullptr), boolType(nullptr), sintTypes({}),
       uintTypes({}), floatTypes({}), samplerType(nullptr),
       curShaderModelKind(ShaderModelKind::Invalid), majorVersion(0),
-      minorVersion(0) {
+      minorVersion(0), currentLexicalScope(nullptr) {
   voidType = new (this) VoidType;
   boolType = new (this) BoolType;
   samplerType = new (this) SamplerType;
@@ -85,6 +86,15 @@ SpirvContext::~SpirvContext() {
 
   for (auto *hybridPtrType : hybridPointerTypes)
     hybridPtrType->~HybridPointerType();
+
+  for (auto &typePair : debugTypes)
+    typePair.second->releaseMemory();
+
+  for (auto &typePair : typeTemplates)
+    typePair.second->releaseMemory();
+
+  for (auto &typePair : typeTemplateParams)
+    typePair.second->releaseMemory();
 }
 
 inline uint32_t log2ForBitwidth(uint32_t bitwidth) {
@@ -336,5 +346,175 @@ const StructType *SpirvContext::getACSBufferCounterType() {
   return type;
 }
 
+SpirvDebugType *SpirvContext::getDebugTypeBasic(const SpirvType *spirvType,
+                                                llvm::StringRef name,
+                                                SpirvConstant *size,
+                                                uint32_t encoding) {
+  // Reuse existing debug type if possible.
+  if (debugTypes.find(spirvType) != debugTypes.end())
+    return debugTypes[spirvType];
+
+  auto *debugType = new (this) SpirvDebugTypeBasic(name, size, encoding);
+  debugTypes[spirvType] = debugType;
+  return debugType;
+}
+
+SpirvDebugType *
+SpirvContext::getDebugTypeMember(llvm::StringRef name, SpirvDebugType *type,
+                                 SpirvDebugSource *source, uint32_t line,
+                                 uint32_t column, SpirvDebugInstruction *parent,
+                                 uint32_t flags, uint32_t offsetInBits,
+                                 uint32_t sizeInBits, const APValue *value) {
+  // NOTE: Do not search it in debugTypes because it would have the same
+  // spirvType but has different parent i.e., type composite.
+
+  SpirvDebugTypeMember *debugType =
+      new (this) SpirvDebugTypeMember(name, type, source, line, column, parent,
+                                      flags, offsetInBits, sizeInBits, value);
+  return debugType;
+}
+
+SpirvDebugTypeComposite *SpirvContext::getDebugTypeComposite(
+    const SpirvType *spirvType, llvm::StringRef name, SpirvDebugSource *source,
+    uint32_t line, uint32_t column, SpirvDebugInstruction *parent,
+    llvm::StringRef linkageName, uint32_t flags, uint32_t tag) {
+  // Reuse existing debug type if possible.
+  auto it = debugTypes.find(spirvType);
+  if (it != debugTypes.end()) {
+    assert(it->second != nullptr && isa<SpirvDebugTypeComposite>(it->second));
+    return dyn_cast<SpirvDebugTypeComposite>(it->second);
+  }
+
+  auto *debugType = new (this) SpirvDebugTypeComposite(
+      name, source, line, column, parent, linkageName, flags, tag);
+  debugType->setDebugSpirvType(spirvType);
+  debugTypes[spirvType] = debugType;
+  return debugType;
+}
+
+SpirvDebugType *SpirvContext::getDebugType(const SpirvType *spirvType) {
+  auto it = debugTypes.find(spirvType);
+  if (it != debugTypes.end())
+    return it->second;
+  return nullptr;
+}
+
+SpirvDebugType *
+SpirvContext::getDebugTypeArray(const SpirvType *spirvType,
+                                SpirvDebugInstruction *elemType,
+                                llvm::ArrayRef<uint32_t> elemCount) {
+  // Reuse existing debug type if possible.
+  if (debugTypes.find(spirvType) != debugTypes.end())
+    return debugTypes[spirvType];
+
+  auto *eTy = dyn_cast<SpirvDebugType>(elemType);
+  assert(eTy && "Element type must be a SpirvDebugType.");
+  auto *debugType = new (this) SpirvDebugTypeArray(eTy, elemCount);
+  debugTypes[spirvType] = debugType;
+  return debugType;
+}
+
+SpirvDebugType *
+SpirvContext::getDebugTypeVector(const SpirvType *spirvType,
+                                 SpirvDebugInstruction *elemType,
+                                 uint32_t elemCount) {
+  // Reuse existing debug type if possible.
+  if (debugTypes.find(spirvType) != debugTypes.end())
+    return debugTypes[spirvType];
+
+  auto *eTy = dyn_cast<SpirvDebugType>(elemType);
+  assert(eTy && "Element type must be a SpirvDebugType.");
+  auto *debugType = new (this) SpirvDebugTypeVector(eTy, elemCount);
+  debugTypes[spirvType] = debugType;
+  return debugType;
+}
+
+SpirvDebugType *
+SpirvContext::getDebugTypeFunction(const SpirvType *spirvType, uint32_t flags,
+                                   SpirvDebugType *ret,
+                                   llvm::ArrayRef<SpirvDebugType *> params) {
+  // Reuse existing debug type if possible.
+  if (debugTypes.find(spirvType) != debugTypes.end())
+    return debugTypes[spirvType];
+
+  auto *debugType = new (this) SpirvDebugTypeFunction(flags, ret, params);
+  debugTypes[spirvType] = debugType;
+  return debugType;
+}
+
+SpirvDebugTypeTemplate *SpirvContext::createDebugTypeTemplate(
+    const ClassTemplateSpecializationDecl *templateType,
+    SpirvDebugInstruction *target,
+    const llvm::SmallVector<SpirvDebugTypeTemplateParameter *, 2> &params) {
+  auto *tempTy = getDebugTypeTemplate(templateType);
+  if (tempTy != nullptr)
+    return tempTy;
+  tempTy = new (this) SpirvDebugTypeTemplate(target, params);
+  typeTemplates[templateType] = tempTy;
+  return tempTy;
+}
+
+SpirvDebugTypeTemplate *SpirvContext::getDebugTypeTemplate(
+    const ClassTemplateSpecializationDecl *templateType) {
+  auto it = typeTemplates.find(templateType);
+  if (it != typeTemplates.end())
+    return it->second;
+  return nullptr;
+}
+
+SpirvDebugTypeTemplateParameter *SpirvContext::createDebugTypeTemplateParameter(
+    const TemplateArgument *templateArg, llvm::StringRef name,
+    SpirvDebugType *type, SpirvInstruction *value, SpirvDebugSource *source,
+    uint32_t line, uint32_t column) {
+  auto *param = getDebugTypeTemplateParameter(templateArg);
+  if (param != nullptr)
+    return param;
+  param = new (this)
+      SpirvDebugTypeTemplateParameter(name, type, value, source, line, column);
+  typeTemplateParams[templateArg] = param;
+  return param;
+}
+
+SpirvDebugTypeTemplateParameter *SpirvContext::getDebugTypeTemplateParameter(
+    const TemplateArgument *templateArg) {
+  auto it = typeTemplateParams.find(templateArg);
+  if (it != typeTemplateParams.end())
+    return it->second;
+  return nullptr;
+}
+
+void SpirvContext::pushDebugLexicalScope(RichDebugInfo *info,
+                                         SpirvDebugInstruction *scope) {
+  assert((isa<SpirvDebugLexicalBlock>(scope) ||
+          isa<SpirvDebugFunction>(scope) ||
+          isa<SpirvDebugCompilationUnit>(scope) ||
+          isa<SpirvDebugTypeComposite>(scope)) &&
+         "Given scope is not a lexical scope");
+  currentLexicalScope = scope;
+  info->scopeStack.push_back(scope);
+}
+
+void SpirvContext::moveDebugTypesToModule(SpirvModule *module) {
+  for (const auto &typePair : debugTypes) {
+    module->addDebugInfo(typePair.second);
+
+    if (auto *composite = dyn_cast<SpirvDebugTypeComposite>(typePair.second)) {
+      for (auto *member : composite->getMembers()) {
+        module->addDebugInfo(member);
+      }
+    }
+  }
+  for (const auto &typePair : typeTemplates) {
+    module->addDebugInfo(typePair.second);
+  }
+  for (const auto &typePair : typeTemplateParams) {
+    module->addDebugInfo(typePair.second);
+  }
+
+  debugTypes.clear();
+  typeTemplates.clear();
+  typeTemplateParams.clear();
+}
+
 } // end namespace spirv
 } // end namespace clang

+ 150 - 12
tools/clang/lib/SPIRV/SpirvEmitter.cpp

@@ -458,7 +458,7 @@ SpirvEmitter::SpirvEmitter(CompilerInstance &ci)
 
   // Set shader module version, source file name, and source file content (if
   // needed).
-  llvm::StringRef source = "";
+  llvm::StringRef source;
   std::vector<llvm::StringRef> fileNames;
   const auto &inputFiles = ci.getFrontendOpts().Inputs;
   // File name
@@ -478,6 +478,23 @@ SpirvEmitter::SpirvEmitter(CompilerInstance &ci)
                                              spvContext.getMinorVersion(),
                                              fileNames, source);
 
+  // OpenCL.DebugInfo.100 DebugSource
+  if (spirvOptions.debugInfoRich) {
+    auto *dbgSrc = spvBuilder.createDebugSource(mainSourceFile->getString());
+    // spvContext.getDebugInfo().insert() inserts {string key, RichDebugInfo}
+    // pair and returns {{string key, RichDebugInfo}, true /*Success*/}.
+    // spvContext.getDebugInfo().insert().first->second is a RichDebugInfo.
+    auto *richDebugInfo =
+        &spvContext.getDebugInfo()
+             .insert(
+                 {mainSourceFile->getString(),
+                  RichDebugInfo(dbgSrc,
+                                spvBuilder.createDebugCompilationUnit(dbgSrc))})
+             .first->second;
+    spvContext.pushDebugLexicalScope(richDebugInfo,
+                                     richDebugInfo->scopeStack.back());
+  }
+
   if (spirvOptions.debugInfoTool &&
       spirvOptions.targetEnv.compare("vulkan1.1") >= 0) {
     // Emit OpModuleProcessed to indicate the commit information.
@@ -580,7 +597,8 @@ void SpirvEmitter::HandleTranslationUnit(ASTContext &context) {
     needsLegalization = needsLegalization ||
                         declIdMapper.requiresLegalization() ||
                         spirvOptions.flattenResourceArrays ||
-                        declIdMapper.requiresFlatteningCompositeResources();
+                        declIdMapper.requiresFlatteningCompositeResources() ||
+                        spirvOptions.debugInfoRich;
 
     // Run legalization passes
     if (needsLegalization) {
@@ -598,7 +616,8 @@ void SpirvEmitter::HandleTranslationUnit(ASTContext &context) {
     }
 
     // Run optimization passes
-    if (theCompilerInstance.getCodeGenOpts().OptimizationLevel > 0) {
+    if (!spirvOptions.debugInfoRich &&
+        theCompilerInstance.getCodeGenOpts().OptimizationLevel > 0) {
       std::string messages;
       if (!spirvToolsOptimize(&m, &messages)) {
         emitFatalError("failed to optimize SPIR-V: %0", {}) << messages;
@@ -667,11 +686,64 @@ void SpirvEmitter::doDecl(const Decl *decl) {
   }
 }
 
+RichDebugInfo *
+SpirvEmitter::getOrCreateRichDebugInfo(const SourceLocation &loc) {
+  const StringRef file =
+      astContext.getSourceManager().getPresumedLoc(loc).getFilename();
+  auto &debugInfo = spvContext.getDebugInfo();
+  auto it = debugInfo.find(file);
+  if (it != debugInfo.end())
+    return &it->second;
+
+  auto *dbgSrc = spvBuilder.createDebugSource(file);
+  // debugInfo.insert() inserts {string key, RichDebugInfo} pair and
+  // returns {{string key, RichDebugInfo}, true /*Success*/}.
+  // debugInfo.insert().first->second is a RichDebugInfo.
+  return &debugInfo
+              .insert({file, RichDebugInfo(
+                                 dbgSrc, spvBuilder.createDebugCompilationUnit(
+                                             dbgSrc))})
+              .first->second;
+}
+
 void SpirvEmitter::doStmt(const Stmt *stmt,
                           llvm::ArrayRef<const Attr *> attrs) {
   if (const auto *compoundStmt = dyn_cast<CompoundStmt>(stmt)) {
-    for (auto *st : compoundStmt->body())
-      doStmt(st);
+    if (spirvOptions.debugInfoRich) {
+      // Any opening of curly braces ('{') starts a CompoundStmt in the AST
+      // tree. It also means we have a new lexical block!
+      const auto loc = stmt->getLocStart();
+      const auto &sm = astContext.getSourceManager();
+      const uint32_t line = sm.getPresumedLineNumber(loc);
+      const uint32_t column = sm.getPresumedColumnNumber(loc);
+      RichDebugInfo *info = getOrCreateRichDebugInfo(loc);
+
+      auto *debugLexicalBlock = spvBuilder.createDebugLexicalBlock(
+          info->source, line, column, info->scopeStack.back());
+
+      // Add this lexical block to the stack of lexical scopes.
+      spvContext.pushDebugLexicalScope(info, debugLexicalBlock);
+
+      // Update or add DebugScope.
+      if (spvBuilder.getInsertPoint()->empty()) {
+        spvBuilder.getInsertPoint()->updateDebugScope(
+            new (spvContext) SpirvDebugScope(debugLexicalBlock));
+      } else if (!spvBuilder.isCurrentBasicBlockTerminated()) {
+        spvBuilder.createDebugScope(debugLexicalBlock);
+      }
+
+      // Iterate over sub-statements
+      for (auto *st : compoundStmt->body())
+        doStmt(st);
+
+      // We are done with processing this compound statement. Remove its lexical
+      // block from the stack of lexical scopes.
+      spvContext.popDebugLexicalScope(info);
+    } else {
+      // Iterate over sub-statements
+      for (auto *st : compoundStmt->body())
+        doStmt(st);
+    }
   } else if (const auto *retStmt = dyn_cast<ReturnStmt>(stmt)) {
     doReturnStmt(retStmt);
   } else if (const auto *declStmt = dyn_cast<DeclStmt>(stmt)) {
@@ -939,6 +1011,7 @@ void SpirvEmitter::doFunctionDecl(const FunctionDecl *decl) {
   // This will allow the entry-point name to be something like
   // myNamespace::myEntrypointFunc.
   std::string funcName = getFnName(decl);
+  std::string debugFuncName = funcName;
 
   SpirvFunction *func = declIdMapper.getOrRegisterFn(decl);
 
@@ -959,6 +1032,32 @@ void SpirvEmitter::doFunctionDecl(const FunctionDecl *decl) {
   spvBuilder.beginFunction(retType, decl->getLocStart(), funcName,
                            decl->hasAttr<HLSLPreciseAttr>(), func);
 
+  auto loc = decl->getLocStart();
+  RichDebugInfo *info = nullptr;
+  const auto &sm = astContext.getSourceManager();
+  if (spirvOptions.debugInfoRich && decl->hasBody()) {
+    const uint32_t line = sm.getPresumedLineNumber(loc);
+    const uint32_t column = sm.getPresumedColumnNumber(loc);
+    info = getOrCreateRichDebugInfo(loc);
+
+    auto *source = info->source;
+    // Note that info->scopeStack.back() is a lexical scope of the function
+    // caller.
+    auto *parentScope = info->compilationUnit;
+    // TODO: figure out the proper flag based on the function decl.
+    // using FlagIsPublic for now.
+    uint32_t flags = 3u;
+    // The line number in the source program at which the function scope begins.
+    auto scopeLine = sm.getPresumedLineNumber(decl->getBody()->getLocStart());
+    SpirvDebugFunction *debugFunction = spvBuilder.createDebugFunction(
+        decl, debugFuncName, source, line, column, parentScope, "", flags,
+        scopeLine, func);
+    func->setDebugScope(new (spvContext) SpirvDebugScope(debugFunction));
+
+    spvContext.pushDebugLexicalScope(info, debugFunction);
+  }
+
+  bool isNonStaticMemberFn = false;
   if (const auto *memberFn = dyn_cast<CXXMethodDecl>(decl)) {
     if (!memberFn->isStatic()) {
       // For non-static member function, the first parameter should be the
@@ -973,6 +1072,23 @@ void SpirvEmitter::doFunctionDecl(const FunctionDecl *decl) {
         curThis->setContainsAliasComponent(true);
         needsLegalization = true;
       }
+
+      if (spirvOptions.debugInfoRich) {
+        // Add DebugLocalVariable information
+        const auto &sm = astContext.getSourceManager();
+        const uint32_t line = sm.getPresumedLineNumber(loc);
+        const uint32_t column = sm.getPresumedColumnNumber(loc);
+        if (!info)
+          info = getOrCreateRichDebugInfo(loc);
+        // TODO: replace this with FlagArtificial|FlagObjectPointer.
+        uint32_t flags = (1 << 5) | (1 << 8);
+        auto *debugLocalVar = spvBuilder.createDebugLocalVariable(
+            valueType, "this", info->source, line, column,
+            info->scopeStack.back(), flags, 1);
+        spvBuilder.createDebugDeclare(debugLocalVar, curThis);
+      }
+
+      isNonStaticMemberFn = true;
     }
   }
 
@@ -986,7 +1102,7 @@ void SpirvEmitter::doFunctionDecl(const FunctionDecl *decl) {
       // to pass the variable as function parameter in SPIR-V.
       continue;
     }
-    (void)declIdMapper.createFnParam(paramDecl);
+    (void)declIdMapper.createFnParam(paramDecl, i + 1 + isNonStaticMemberFn);
   }
 
   if (decl->hasBody()) {
@@ -1016,6 +1132,10 @@ void SpirvEmitter::doFunctionDecl(const FunctionDecl *decl) {
   }
 
   spvBuilder.endFunction();
+
+  if (spirvOptions.debugInfoRich) {
+    spvContext.popDebugLexicalScope(info);
+  }
 }
 
 bool SpirvEmitter::validateVKAttributes(const NamedDecl *decl) {
@@ -1179,6 +1299,8 @@ void SpirvEmitter::doVarDecl(const VarDecl *decl) {
   if (!validateVKAttributes(decl))
     return;
 
+  const auto loc = decl->getLocation();
+
   // HLSL has the 'string' type which can be used for rare purposes such as
   // printf (SPIR-V's DebugPrintf). SPIR-V does not have a 'char' or 'string'
   // type, and therefore any variable of such type should not be created.
@@ -1195,7 +1317,7 @@ void SpirvEmitter::doVarDecl(const VarDecl *decl) {
                                       decl)) {
     emitError("externally initialized non-floating-point column-major "
               "matrices not supported yet",
-              decl->getLocation());
+              loc);
   }
 
   // Reject arrays of RW/append/consume structured buffers. They have assoicated
@@ -1208,7 +1330,7 @@ void SpirvEmitter::doVarDecl(const VarDecl *decl) {
 
     if (isRWAppendConsumeSBuffer(type)) {
       emitError("arrays of RW/append/consume structured buffers unsupported",
-                decl->getLocation());
+                loc);
       return;
     }
   }
@@ -1250,7 +1372,6 @@ void SpirvEmitter::doVarDecl(const VarDecl *decl) {
     // We already know the variable is not externally visible here. If it does
     // not have local storage, it should be file scope variable.
     const bool isFileScopeVar = !decl->hasLocalStorage();
-
     if (isFileScopeVar)
       var = declIdMapper.createFileVar(decl, llvm::None);
     else
@@ -1273,16 +1394,29 @@ void SpirvEmitter::doVarDecl(const VarDecl *decl) {
     // Function local variables. Just emit OpStore at the current insert point.
     else if (const Expr *init = decl->getInit()) {
       if (auto *constInit = tryToEvaluateAsConst(init)) {
-        spvBuilder.createStore(var, constInit, decl->getLocation());
+        spvBuilder.createStore(var, constInit, loc);
       } else {
-        storeValue(var, loadIfGLValue(init), decl->getType(),
-                   decl->getLocation());
+        storeValue(var, loadIfGLValue(init), decl->getType(), loc);
       }
 
       // Update counter variable associated with local variables
       tryToAssignCounterVar(decl, init);
     }
 
+    if (!isFileScopeVar && spirvOptions.debugInfoRich) {
+      // Add DebugLocalVariable information
+      const auto &sm = astContext.getSourceManager();
+      const uint32_t line = sm.getPresumedLineNumber(loc);
+      const uint32_t column = sm.getPresumedColumnNumber(loc);
+      const auto *info = getOrCreateRichDebugInfo(loc);
+      // TODO: replace this with FlagIsLocal enum.
+      uint32_t flags = 1 << 2;
+      auto *debugLocalVar = spvBuilder.createDebugLocalVariable(
+          decl->getType(), decl->getName(), info->source, line, column,
+          info->scopeStack.back(), flags);
+      spvBuilder.createDebugDeclare(debugLocalVar, var);
+    }
+
     // Variables that are not externally visible and of opaque types should
     // request legalization.
     if (!needsLegalization && isOpaqueType(decl->getType()))
@@ -10775,6 +10909,10 @@ bool SpirvEmitter::emitEntryFunctionWrapper(const FunctionDecl *decl,
   // function calls. And the wrapper is the entry function.
   entryFunction = spvBuilder.beginFunction(
       astContext.VoidTy, decl->getLocStart(), decl->getName());
+
+  // Specify that entryFunction is an entry function wrapper.
+  entryFunction->setEntryFunctionWrapper();
+
   // Note this should happen before using declIdMapper for other tasks.
   declIdMapper.setEntryFunction(entryFunction);
 

+ 5 - 0
tools/clang/lib/SPIRV/SpirvEmitter.h

@@ -54,6 +54,11 @@ public:
   CompilerInstance &getCompilerInstance() { return theCompilerInstance; }
   SpirvCodeGenOptions &getSpirvOptions() { return spirvOptions; }
 
+  /// \brief If DebugSource and DebugCompilationUnit for loc are already
+  /// created, we just return RichDebugInfo containing it. Otherwise,
+  /// create DebugSource and DebugCompilationUnit for loc and return it.
+  RichDebugInfo *getOrCreateRichDebugInfo(const SourceLocation &loc);
+
   void doDecl(const Decl *decl);
   void doStmt(const Stmt *stmt, llvm::ArrayRef<const Attr *> attrs = {});
   SpirvInstruction *doExpr(const Expr *expr);

+ 14 - 3
tools/clang/lib/SPIRV/SpirvFunction.cpp

@@ -19,8 +19,8 @@ SpirvFunction::SpirvFunction(QualType returnType, SourceLocation loc,
                              llvm::StringRef name, bool isPrecise)
     : functionId(0), astReturnType(returnType), returnType(nullptr),
       fnType(nullptr), relaxedPrecision(false), precise(isPrecise),
-      containsAlias(false), rvalue(false), functionLoc(loc),
-      functionName(name) {}
+      containsAlias(false), rvalue(false), functionLoc(loc), functionName(name),
+      isWrapperOfEntry(false), debugScope(nullptr) {}
 
 SpirvFunction::~SpirvFunction() {
   for (auto *param : parameters)
@@ -29,14 +29,25 @@ SpirvFunction::~SpirvFunction() {
     var->releaseMemory();
   for (auto *bb : basicBlocks)
     bb->~SpirvBasicBlock();
+  if (debugScope)
+    debugScope->releaseMemory();
+  for (auto *dd : debugDeclares)
+    dd->releaseMemory();
 }
 
 bool SpirvFunction::invokeVisitor(Visitor *visitor, bool reverseOrder) {
   if (!visitor->visit(this, Visitor::Phase::Init))
     return false;
 
-  for (auto *param : parameters)
+  if (debugScope && !visitor->visit(debugScope))
+    return false;
+
+  for (auto *param : parameters) {
     visitor->visit(param);
+  }
+
+  for (auto *i : debugDeclares)
+    visitor->visit(i);
 
   // Collect basic blocks in a human-readable order that satisfies SPIR-V
   // validation rules.

+ 182 - 0
tools/clang/lib/SPIRV/SpirvInstruction.cpp

@@ -83,6 +83,26 @@ DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvVectorShuffle)
 DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvArrayLength)
 DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvRayTracingOpNV)
 DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDemoteToHelperInvocationEXT)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugInfoNone)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugSource)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugCompilationUnit)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugFunctionDeclaration)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugFunction)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugLocalVariable)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugGlobalVariable)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugOperation)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugExpression)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugDeclare)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugLexicalBlock)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugScope)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugTypeBasic)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugTypeArray)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugTypeVector)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugTypeFunction)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugTypeComposite)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugTypeMember)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugTypeTemplate)
+DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugTypeTemplateParameter)
 DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvRayQueryOpKHR)
 
 #undef DEFINE_INVOKE_VISITOR_FOR_CLASS
@@ -793,11 +813,173 @@ SpirvDemoteToHelperInvocationEXT::SpirvDemoteToHelperInvocationEXT(
                        spv::Op::OpDemoteToHelperInvocationEXT, /*QualType*/ {},
                        loc) {}
 
+// Note: we are using a null result type in the constructor. All debug
+// instructions should later get OpTypeVoid as their result type.
+SpirvDebugInstruction::SpirvDebugInstruction(Kind kind, uint32_t opcode)
+    : SpirvInstruction(kind, spv::Op::OpExtInst,
+                       /*result type */ {},
+                       /*SourceLocation*/ {}),
+      debugOpcode(opcode), debugSpirvType(nullptr), debugType(nullptr),
+      instructionSet(nullptr) {}
+
+SpirvDebugInfoNone::SpirvDebugInfoNone()
+    : SpirvDebugInstruction(IK_DebugInfoNone, /*opcode*/ 0u) {}
+
+SpirvDebugSource::SpirvDebugSource(llvm::StringRef f, llvm::StringRef t)
+    : SpirvDebugInstruction(IK_DebugSource, /*opcode*/ 35u), file(f), text(t) {}
+
+SpirvDebugCompilationUnit::SpirvDebugCompilationUnit(uint32_t spvVer,
+                                                     uint32_t dwarfVer,
+                                                     SpirvDebugSource *src)
+    : SpirvDebugInstruction(IK_DebugCompilationUnit, /*opcode*/ 1u),
+      spirvVersion(spvVer), dwarfVersion(dwarfVer), source(src),
+      lang(spv::SourceLanguage::HLSL) {}
+
+SpirvDebugFunction::SpirvDebugFunction(
+    llvm::StringRef name, SpirvDebugSource *src, uint32_t fline, uint32_t fcol,
+    SpirvDebugInstruction *parent, llvm::StringRef linkName, uint32_t flags_,
+    uint32_t bodyLine, SpirvFunction *func)
+    : SpirvDebugInstruction(IK_DebugFunction, /*opcode*/ 20u), source(src),
+      fnLine(fline), fnColumn(fcol), parentScope(parent), linkageName(linkName),
+      flags(flags_), scopeLine(bodyLine), fn(func), debugNone(nullptr),
+      fnType(nullptr) {
+  debugName = name;
+}
+
+SpirvDebugFunctionDeclaration::SpirvDebugFunctionDeclaration(
+    llvm::StringRef name, SpirvDebugSource *src, uint32_t fline, uint32_t fcol,
+    SpirvDebugInstruction *parent, llvm::StringRef linkName, uint32_t flags_)
+    : SpirvDebugInstruction(IK_DebugFunctionDecl, /*opcode*/ 19u), source(src),
+      fnLine(fline), fnColumn(fcol), parentScope(parent), linkageName(linkName),
+      flags(flags_) {
+  debugName = name;
+}
+
+SpirvDebugLocalVariable::SpirvDebugLocalVariable(
+    QualType debugQualType_, llvm::StringRef varName, SpirvDebugSource *src,
+    uint32_t lineNumber, uint32_t colNumber, SpirvDebugInstruction *parent,
+    uint32_t flags_, llvm::Optional<uint32_t> argNumber_)
+    : SpirvDebugInstruction(IK_DebugLocalVariable, /*opcode*/ 26u), source(src),
+      line(lineNumber), column(colNumber), parentScope(parent), flags(flags_),
+      argNumber(argNumber_) {
+  debugName = varName;
+  setDebugQualType(debugQualType_);
+}
+
+SpirvDebugGlobalVariable::SpirvDebugGlobalVariable(
+    QualType debugQualType, llvm::StringRef varName, SpirvDebugSource *src,
+    uint32_t line_, uint32_t column_, SpirvDebugInstruction *parent,
+    llvm::StringRef linkageName_, SpirvVariable *var_, uint32_t flags_,
+    llvm::Optional<SpirvInstruction *> staticMemberDebugDecl_)
+    : SpirvDebugInstruction(IK_DebugGlobalVariable, /*opcode*/ 18u),
+      source(src), line(line_), column(column_), parentScope(parent),
+      linkageName(linkageName_), var(var_), flags(flags_),
+      staticMemberDebugDecl(staticMemberDebugDecl_) {
+  debugName = varName;
+  setDebugQualType(debugQualType);
+  setDebugType(nullptr);
+}
+
+SpirvDebugOperation::SpirvDebugOperation(uint32_t operationOpCode_,
+                                         llvm::ArrayRef<int32_t> operands_)
+    : SpirvDebugInstruction(IK_DebugOperation, /*opcode*/ 30u),
+      operationOpcode(operationOpCode_),
+      operands(operands_.begin(), operands_.end()) {}
+
+SpirvDebugExpression::SpirvDebugExpression(
+    llvm::ArrayRef<SpirvDebugOperation *> operations_)
+    : SpirvDebugInstruction(IK_DebugExpression, /*opcode*/ 31u),
+      operations(operations_.begin(), operations_.end()) {}
+
+SpirvDebugDeclare::SpirvDebugDeclare(SpirvDebugLocalVariable *debugVar_,
+                                     SpirvInstruction *var_,
+                                     SpirvDebugExpression *expr)
+    : SpirvDebugInstruction(IK_DebugDeclare, /*opcode*/ 28u),
+      debugVar(debugVar_), var(var_), expression(expr) {}
+
+SpirvDebugLexicalBlock::SpirvDebugLexicalBlock(SpirvDebugSource *source_,
+                                               uint32_t line_, uint32_t column_,
+                                               SpirvDebugInstruction *parent_)
+    : SpirvDebugInstruction(IK_DebugLexicalBlock, /*opcode*/ 21u),
+      source(source_), line(line_), column(column_), parent(parent_) {}
+
+SpirvDebugScope::SpirvDebugScope(SpirvDebugInstruction *scope_)
+    : SpirvDebugInstruction(IK_DebugScope, /*opcode*/ 23u), scope(scope_) {}
+
+SpirvDebugTypeBasic::SpirvDebugTypeBasic(llvm::StringRef name,
+                                         SpirvConstant *size_,
+                                         uint32_t encoding_)
+    : SpirvDebugType(IK_DebugTypeBasic, /*opcode*/ 2u), size(size_),
+      encoding(encoding_) {
+  debugName = name;
+}
+
+uint32_t SpirvDebugTypeBasic::getSizeInBits() const {
+  auto *size_ = dyn_cast<SpirvConstantInteger>(size);
+  assert(size_ && "Size of DebugTypeBasic must be int type const.");
+  return size_->getValue().getLimitedValue();
+}
+
+SpirvDebugTypeArray::SpirvDebugTypeArray(SpirvDebugType *elemType,
+                                         llvm::ArrayRef<uint32_t> elemCount)
+    : SpirvDebugType(IK_DebugTypeArray, /*opcode*/ 5u), elementType(elemType),
+      elementCount(elemCount.begin(), elemCount.end()) {}
+
+SpirvDebugTypeVector::SpirvDebugTypeVector(SpirvDebugType *elemType,
+                                           uint32_t elemCount)
+    : SpirvDebugType(IK_DebugTypeVector, /*opcode*/ 6u), elementType(elemType),
+      elementCount(elemCount) {}
+
+SpirvDebugTypeFunction::SpirvDebugTypeFunction(
+    uint32_t flags, SpirvDebugType *ret,
+    llvm::ArrayRef<SpirvDebugType *> params)
+    : SpirvDebugType(IK_DebugTypeFunction, /*opcode*/ 8u), debugFlags(flags),
+      returnType(ret), paramTypes(params.begin(), params.end()) {}
+
+SpirvDebugTypeMember::SpirvDebugTypeMember(
+    llvm::StringRef name, SpirvDebugType *type, SpirvDebugSource *source_,
+    uint32_t line_, uint32_t column_, SpirvDebugInstruction *parent_,
+    uint32_t flags_, uint32_t offsetInBits_, uint32_t sizeInBits_,
+    const APValue *value_)
+    : SpirvDebugType(IK_DebugTypeMember, /*opcode*/ 11u), source(source_),
+      line(line_), column(column_), parent(parent_),
+      offsetInBits(offsetInBits_), sizeInBits(sizeInBits_), debugFlags(flags_),
+      value(value_) {
+  debugName = name;
+  setDebugType(type);
+}
+
+SpirvDebugTypeComposite::SpirvDebugTypeComposite(
+    llvm::StringRef name, SpirvDebugSource *source_, uint32_t line_,
+    uint32_t column_, SpirvDebugInstruction *parent_,
+    llvm::StringRef linkageName_, uint32_t flags_, uint32_t tag_)
+    : SpirvDebugType(IK_DebugTypeComposite, /*opcode*/ 10u), source(source_),
+      line(line_), column(column_), parent(parent_), linkageName(linkageName_),
+      debugFlags(flags_), tag(tag_), debugNone(nullptr) {
+  debugName = name;
+}
+
+SpirvDebugTypeTemplate::SpirvDebugTypeTemplate(
+    SpirvDebugInstruction *target_,
+    const llvm::SmallVector<SpirvDebugTypeTemplateParameter *, 2> &params_)
+    : SpirvDebugType(IK_DebugTypeTemplate, /*opcode*/ 14u), target(target_),
+      params(params_) {}
+
+SpirvDebugTypeTemplateParameter::SpirvDebugTypeTemplateParameter(
+    llvm::StringRef name, SpirvDebugType *type, SpirvInstruction *value_,
+    SpirvDebugSource *source_, uint32_t line_, uint32_t column_)
+    : SpirvDebugType(IK_DebugTypeTemplateParameter, /*opcode*/ 15u),
+      actualType(type), value(value_), source(source_), line(line_),
+      column(column_) {
+  debugName = name;
+}
+
 SpirvRayQueryOpKHR::SpirvRayQueryOpKHR(
     QualType resultType, spv::Op opcode,
     llvm::ArrayRef<SpirvInstruction *> vecOperands, bool flags,
     SourceLocation loc)
     : SpirvInstruction(IK_RayQueryOpKHR, opcode, resultType, loc),
       operands(vecOperands.begin(), vecOperands.end()), cullFlags(flags) {}
+
 } // namespace spirv
 } // namespace clang

+ 26 - 9
tools/clang/lib/SPIRV/SpirvModule.cpp

@@ -17,7 +17,7 @@ namespace spirv {
 SpirvModule::SpirvModule()
     : capabilities({}), extensions({}), extInstSets({}), memoryModel(nullptr),
       entryPoints({}), executionModes({}), moduleProcesses({}), decorations({}),
-      constants({}), variables({}), functions({}) {}
+      constants({}), variables({}), functions({}), debugInstructions({}) {}
 
 SpirvModule::~SpirvModule() {
   for (auto *cap : capabilities)
@@ -34,7 +34,7 @@ SpirvModule::~SpirvModule() {
     exec->releaseMemory();
   for (auto *str : constStrings)
     str->releaseMemory();
-  for (auto *d : debugSources)
+  for (auto *d : sources)
     d->releaseMemory();
   for (auto *mp : moduleProcesses)
     mp->releaseMemory();
@@ -44,6 +44,8 @@ SpirvModule::~SpirvModule() {
     constant->releaseMemory();
   for (auto *var : variables)
     var->releaseMemory();
+  for (auto *di : debugInstructions)
+    di->releaseMemory();
   for (auto *f : allFunctions)
     f->~SpirvFunction();
 }
@@ -69,6 +71,13 @@ bool SpirvModule::invokeVisitor(Visitor *visitor, bool reverseOrder) {
         return false;
     }
 
+    for (auto iter = debugInstructions.rbegin();
+         iter != debugInstructions.rend(); ++iter) {
+      auto *debugInstruction = *iter;
+      if (!debugInstruction->invokeVisitor(visitor))
+        return false;
+    }
+
     for (auto iter = variables.rbegin(); iter != variables.rend(); ++iter) {
       auto *var = *iter;
       if (!var->invokeVisitor(visitor))
@@ -96,9 +105,8 @@ bool SpirvModule::invokeVisitor(Visitor *visitor, bool reverseOrder) {
         return false;
     }
 
-    if (!debugSources.empty())
-      for (auto iter = debugSources.rbegin(); iter != debugSources.rend();
-           ++iter) {
+    if (!sources.empty())
+      for (auto iter = sources.rbegin(); iter != sources.rend(); ++iter) {
         auto *source = *iter;
         if (!source->invokeVisitor(visitor))
           return false;
@@ -177,8 +185,8 @@ bool SpirvModule::invokeVisitor(Visitor *visitor, bool reverseOrder) {
       if (!str->invokeVisitor(visitor))
         return false;
 
-    if (!debugSources.empty())
-      for (auto *source : debugSources)
+    if (!sources.empty())
+      for (auto *source : sources)
         if (!source->invokeVisitor(visitor))
           return false;
 
@@ -198,6 +206,10 @@ bool SpirvModule::invokeVisitor(Visitor *visitor, bool reverseOrder) {
       if (!var->invokeVisitor(visitor))
         return false;
 
+    for (auto *debugInstruction : debugInstructions)
+      if (!debugInstruction->invokeVisitor(visitor))
+        return false;
+
     for (auto fn : functions)
       if (!fn->invokeVisitor(visitor, reverseOrder))
         return false;
@@ -283,9 +295,14 @@ void SpirvModule::addString(SpirvString *str) {
   constStrings.push_back(str);
 }
 
-void SpirvModule::addDebugSource(SpirvSource *src) {
+void SpirvModule::addSource(SpirvSource *src) {
   assert(src);
-  debugSources.push_back(src);
+  sources.push_back(src);
+}
+
+void SpirvModule::addDebugInfo(SpirvDebugInstruction *info) {
+  assert(info);
+  debugInstructions.push_back(info);
 }
 
 void SpirvModule::addModuleProcessed(SpirvModuleProcessed *p) {

+ 43 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.cbuffer.hlsl

@@ -0,0 +1,43 @@
+// Run: %dxc -T vs_6_0 -E main -fspv-debug=rich
+
+struct S {
+    float  f1;  // Size: 32,  Offset: [ 0 -  32]
+    float3 f2;  // Size: 96,  Offset: [32 - 128]
+};
+
+cbuffer MyCbuffer : register(b1) {
+    bool     a;    // Size:  32, Offset: [  0 -  32]
+    int      b;    // Size:  32, Offset: [ 32 -  64]
+    uint2    c;    // Size:  64, Offset: [ 64 - 128]
+    float3x4 d;    // Size: 512, Offset: [128 - 640]
+    S        s;    // Size: 128, Offset: [640 - 768]
+    float    t[4]; // Size: 512, Offset: [768 - 1280]
+};
+
+cbuffer AnotherCBuffer : register(b2) {
+    float3 m;  // Size:  96, Offset: [ 0  -  96]
+    float4 n;  // Size: 128, Offset: [128 - 256]
+}
+
+// CHECK: [[AnotherCBuffer:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugTypeComposite {{%\d+}} Structure {{%\d+}} 17 9 {{%\d+}} {{%\d+}} %uint_256 FlagIsProtected|FlagIsPrivate [[m:%\d+]] [[n:%\d+]]
+// CHECK: [[n]] = OpExtInst %void [[ext]] DebugTypeMember {{%\d+}} {{%\d+}} {{%\d+}} 19 12 [[AnotherCBuffer]] %uint_128 %uint_128
+// CHECK: [[m]] = OpExtInst %void [[ext]] DebugTypeMember {{%\d+}} {{%\d+}} {{%\d+}} 18 12 [[AnotherCBuffer]] %uint_0 %uint_96
+
+// CHECK: [[S:%\d+]] = OpExtInst %void [[ext]] DebugTypeComposite {{%\d+}} Structure {{%\d+}} 3 8 {{%\d+}} {{%\d+}} %uint_128 FlagIsProtected|FlagIsPrivate [[f1:%\d+]] [[f2:%\d+]]
+// CHECK: [[f2]] = OpExtInst %void [[ext]] DebugTypeMember {{%\d+}} {{%\d+}} {{%\d+}} 5 12 [[S]] %uint_32 %uint_96
+// CHECK: [[f1]] = OpExtInst %void [[ext]] DebugTypeMember {{%\d+}} {{%\d+}} {{%\d+}} 4 11 [[S]] %uint_0 %uint_32
+
+// CHECK: [[MyCbuffer:%\d+]] = OpExtInst %void [[ext]] DebugTypeComposite {{%\d+}} Structure {{%\d+}} 8 9 {{%\d+}} {{%\d+}} %uint_1280 FlagIsProtected|FlagIsPrivate [[a:%\d+]] [[b:%\d+]] [[c:%\d+]] [[d:%\d+]] [[s:%\d+]] [[t:%\d+]]
+// CHECK: [[t]] = OpExtInst %void [[ext]] DebugTypeMember {{%\d+}} {{%\d+}} {{%\d+}} 14 11 [[MyCbuffer]] %uint_768 %uint_512
+// CHECK: [[s]] = OpExtInst %void [[ext]] DebugTypeMember {{%\d+}} [[S]] {{%\d+}} 13 7 [[MyCbuffer]] %uint_640 %uint_128
+// CHECK: [[d]] = OpExtInst %void [[ext]] DebugTypeMember {{%\d+}} {{%\d+}} {{%\d+}} 12 14 [[MyCbuffer]] %uint_128 %uint_512
+// CHECK: [[c]] = OpExtInst %void [[ext]] DebugTypeMember {{%\d+}} {{%\d+}} {{%\d+}} 11 11 [[MyCbuffer]] %uint_64 %uint_64
+// CHECK: [[b]] = OpExtInst %void [[ext]] DebugTypeMember {{%\d+}} {{%\d+}} {{%\d+}} 10 9 [[MyCbuffer]] %uint_32 %uint_32
+// CHECK: [[a]] = OpExtInst %void [[ext]] DebugTypeMember {{%\d+}} {{%\d+}} {{%\d+}} 9 10 [[MyCbuffer]] %uint_0 %uint_32
+
+// CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugGlobalVariable {{%\d+}} {{%\d+}} {{%\d+}} 17 9 {{%\d+}} {{%\d+}} %AnotherCBuffer
+// CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugGlobalVariable {{%\d+}} {{%\d+}} {{%\d+}} 8 9 {{%\d+}} {{%\d+}} %MyCbuffer
+
+float  main() : A {
+  return t[0] + m[0];
+}

+ 10 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.debugcompilationunit.hlsl

@@ -0,0 +1,10 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+// CHECK:      [[debugSet:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK:   [[debugSource:%\d+]] = OpExtInst %void [[debugSet]] DebugSource
+// CHECK:               {{%\d+}} = OpExtInst %void [[debugSet]] DebugCompilationUnit 1 4 [[debugSource]] HLSL
+
+float4 main(float4 color : COLOR) : SV_TARGET {
+  return color;
+}
+

+ 34 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.debugdeclare.hlsl

@@ -0,0 +1,34 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+// TODO: FlagIsPublic is shown as FlagIsProtected|FlagIsPrivate.
+
+// CHECK: [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK: [[y:%\d+]] = OpExtInst %void [[set]] DebugLocalVariable {{%\d+}} {{%\d+}} {{%\d+}} 23 23 {{%\d+}} FlagIsLocal 2
+// CHECK: [[x:%\d+]] = OpExtInst %void [[set]] DebugLocalVariable {{%\d+}} {{%\d+}} {{%\d+}} 23 14 {{%\d+}} FlagIsLocal 1
+// CHECK: [[condition:%\d+]] = OpExtInst %void [[set]] DebugLocalVariable {{%\d+}} {{%\d+}} {{%\d+}} 30 8 {{%\d+}} FlagIsLocal
+// CHECK: [[expr:%\d+]] = OpExtInst %void [[set]] DebugExpression
+// CHECK: [[color:%\d+]] = OpExtInst %void [[set]] DebugLocalVariable {{%\d+}} {{%\d+}} {{%\d+}} 28 20 {{%\d+}} FlagIsLocal 1
+
+// CHECK:        %color = OpFunctionParameter
+// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugDeclare [[color]] %color [[expr]]
+// CHECK:      %condition = OpVariable
+// CHECK:                 OpStore %condition %false
+// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugDeclare [[condition]] %condition [[expr]]
+
+// CHECK:            %x = OpFunctionParameter
+// CHECK:            %y = OpFunctionParameter
+// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugDeclare [[x]] %x [[expr]]
+// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugDeclare [[y]] %y [[expr]]
+
+void foo(int x, float y)
+{
+  x = x + y;
+}
+
+float4 main(float4 color : COLOR) : SV_TARGET
+{
+  bool condition = false;
+  foo(1, color.x);
+  return color;
+}
+

+ 30 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.debugdeclare.without.init.hlsl

@@ -0,0 +1,30 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+// CHECK:      %i = OpFunctionParameter %_ptr_Function_PS_INPUT
+// CHECK-NEXT: DebugDeclare {{%\d+}} %i
+// CHECK:      %ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function
+// CHECK:      %c = OpVariable %_ptr_Function_v4float Function
+// CHECK:      DebugDeclare {{%\d+}} %ps_output
+// CHECK:      DebugDeclare {{%\d+}} %c
+
+Texture2D g_tColor;
+
+SamplerState g_sAniso;
+
+struct PS_INPUT {
+  float2 vTextureCoords2 : TEXCOORD2;
+  float2 vTextureCoords3 : TEXCOORD3;
+};
+
+struct PS_OUTPUT {
+  float4 vColor : SV_Target0;
+};
+
+PS_OUTPUT main(PS_INPUT i) {
+  PS_OUTPUT ps_output;
+  float4 c;
+  c = g_tColor.Sample(g_sAniso, i.vTextureCoords2.xy);
+  c += g_tColor.Sample(g_sAniso, i.vTextureCoords3.xy);
+  ps_output.vColor = c;
+  return ps_output;
+}

+ 36 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.debuglexicalblock.hlsl

@@ -0,0 +1,36 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+// CHECK:      [[debugSet:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK:   [[debugSource:%\d+]] = OpExtInst %void [[debugSet]] DebugSource
+// CHECK:          [[main:%\d+]] = OpExtInst %void [[debugSet]] DebugFunction
+// CHECK: [[mainFnLexBlock:%\d+]] = OpExtInst %void [[debugSet]] DebugLexicalBlock [[debugSource]] 13 1 [[main]]
+// CHECK: [[whileLoopLexBlock:%\d+]] = OpExtInst %void [[debugSet]] DebugLexicalBlock [[debugSource]] 21 3 [[mainFnLexBlock]]
+// CHECK: [[ifStmtLexBlock:%\d+]] = OpExtInst %void [[debugSet]] DebugLexicalBlock [[debugSource]] 26 20 [[whileLoopLexBlock]]
+// CHECK: [[tempLexBlock:%\d+]] = OpExtInst %void [[debugSet]] DebugLexicalBlock [[debugSource]] 28 7 [[ifStmtLexBlock]]
+// CHECK: [[forLoopLexBlock:%\d+]] = OpExtInst %void [[debugSet]] DebugLexicalBlock [[debugSource]] 15 12 [[mainFnLexBlock]]
+
+float4 main(float4 color : COLOR) : SV_TARGET
+{
+  float4 c = 0.xxxx;
+  for (;;) {
+    float4 a = 0.xxxx;
+    float4 b = 1.xxxx;
+    c = c + a + b;
+  }
+  while (c.x)
+  {
+    float4 a = 0.xxxx;
+    float4 b = 1.xxxx;
+    c = c + a + b;
+
+    if (bool(c.x)) {
+      c = c + c;
+      {
+        c = c + c;
+      }
+    }
+  }
+
+  return color + c;
+}
+

+ 62 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.debugscope.hlsl

@@ -0,0 +1,62 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+// CHECK:  [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK: [[compUnit:%\d+]] = OpExtInst %void [[set]] DebugCompilationUnit
+// CHECK: [[main:%\d+]] = OpExtInst %void [[set]] DebugFunction
+// CHECK: [[mainFnLexBlock:%\d+]] = OpExtInst %void [[set]] DebugLexicalBlock {{%\d+}} 15 1 [[main]]
+// CHECK: [[whileLoopLexBlock:%\d+]] = OpExtInst %void [[set]] DebugLexicalBlock {{%\d+}} 35 3 [[mainFnLexBlock]]
+// CHECK: [[ifStmtLexBlock:%\d+]] = OpExtInst %void [[set]] DebugLexicalBlock {{%\d+}} 42 20 [[whileLoopLexBlock]]
+// CHECK: [[tempLexBlock:%\d+]] = OpExtInst %void [[set]] DebugLexicalBlock {{%\d+}} 47 7 [[ifStmtLexBlock]]
+// CHECK: [[forLoopLexBlock:%\d+]] = OpExtInst %void [[set]] DebugLexicalBlock {{%\d+}} 20 12 [[mainFnLexBlock]]
+
+float4 main(float4 color : COLOR) : SV_TARGET
+// CHECK:     %src_main = OpFunction
+// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugScope [[main]]
+{
+// CHECK:     %bb_entry = OpLabel
+// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugScope [[mainFnLexBlock]]
+
+  float4 c = 0.xxxx;
+  for (;;) {
+// CHECK:     %for_body = OpLabel
+// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugScope [[forLoopLexBlock]]
+    float4 a = 0.xxxx;
+    float4 b = 1.xxxx;
+    c = c + a + b;
+// CHECK: %for_continue = OpLabel
+// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugScope [[mainFnLexBlock]]
+  }
+// CHECK:    %for_merge = OpLabel
+// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugScope [[mainFnLexBlock]]
+
+// CHECK:  %while_check = OpLabel
+// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugScope [[mainFnLexBlock]]
+  while (c.x)
+  {
+// CHECK:   %while_body = OpLabel
+// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugScope [[whileLoopLexBlock]]
+    float4 a = 0.xxxx;
+    float4 b = 1.xxxx;
+    c = c + a + b;
+
+    if (bool(c.x)) {
+// CHECK:      %if_true = OpLabel
+// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugScope [[ifStmtLexBlock]]
+      c = c + c;
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugScope [[tempLexBlock]]
+      {
+        c = c + c;
+      }
+    }
+// CHECK:     %if_merge = OpLabel
+// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugScope [[whileLoopLexBlock]]
+
+// CHECK:%while_continue = OpLabel
+// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugScope [[mainFnLexBlock]]
+  }
+// CHECK:  %while_merge = OpLabel
+// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugScope [[mainFnLexBlock]]
+
+  return color + c;
+}
+

+ 9 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.debugsource.hlsl

@@ -0,0 +1,9 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich-with-source
+
+// CHECK:      [[debugSet:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK:               {{%\d+}} = OpExtInst %void [[debugSet]] DebugSource {{%\d+}} {{%\d+}}
+
+float4 main(float4 color : COLOR) : SV_TARGET {
+  return color;
+}
+

+ 41 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.debugsource.multiple.hlsl

@@ -0,0 +1,41 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich-with-source
+
+// CHECK:      [[debugSet:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+
+// CHECK: rich.debug.debugsource.multiple.hlsl
+// CHECK: spirv.debug.opline.include-file-3.hlsl
+// CHECK: [[file3_code:%\d+]] = OpString "groupshared int b;
+// CHECK: spirv.debug.opline.include-file-2.hlsl
+// CHECK: [[file2_code:%\d+]] = OpString "static int a;
+// CHECK: spirv.debug.opline.include-file-1.hlsl
+// CHECK: [[file1_code:%\d+]] = OpString "int function1() {
+// CHECK: [[main_code:%\d+]] = OpString "// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich-with-source
+
+// CHECK: {{%\d+}} = OpExtInst %void [[debugSet]] DebugSource {{%\d+}} [[file3_code]]
+// CHECK: {{%\d+}} = OpExtInst %void [[debugSet]] DebugSource {{%\d+}} [[file2_code]]
+// CHECK: {{%\d+}} = OpExtInst %void [[debugSet]] DebugSource {{%\d+}} [[file1_code]]
+// CHECK: {{%\d+}} = OpExtInst %void [[debugSet]] DebugSource {{%\d+}} [[main_code]]
+
+#include "spirv.debug.opline.include-file-1.hlsl"
+
+int callFunction1() {
+  return function1();
+}
+
+#include "spirv.debug.opline.include-file-2.hlsl"
+
+int callFunction2() {
+  return function2();
+}
+
+#include "spirv.debug.opline.include-file-3.hlsl"
+
+int callFunction3() {
+  CALL_FUNCTION_3;
+}
+
+void main() {
+  callFunction1();
+  callFunction2();
+  callFunction3();
+}

+ 36 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.function.hlsl

@@ -0,0 +1,36 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+// TODO: FlagIsPublic is shown as FlagIsProtected|FlagIsPrivate.
+
+// CHECK:             [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK:         [[fooName:%\d+]] = OpString "foo"
+// CHECK:        [[emptyStr:%\d+]] = OpString ""
+// CHECK:        [[mainName:%\d+]] = OpString "main"
+
+// CHECK:    [[int:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic {{%\d+}} %uint_32 Signed
+// CHECK:  [[float:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic {{%\d+}} %uint_32 Float
+
+// CHECK: [[fooFnType:%\d+]] = OpExtInst %void [[set]] DebugTypeFunction FlagIsProtected|FlagIsPrivate %void [[int]] [[float]]
+// CHECK:          [[source:%\d+]] = OpExtInst %void [[set]] DebugSource
+// CHECK: [[compilationUnit:%\d+]] = OpExtInst %void [[set]] DebugCompilationUnit
+
+// Check DebugFunction instructions
+//
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugFunction [[fooName]] [[fooFnType]] [[source]] 25 1 [[compilationUnit]] [[emptyStr]] FlagIsProtected|FlagIsPrivate 26 %foo
+
+// CHECK: [[float4:%\d+]] = OpExtInst %void [[set]] DebugTypeVector [[float]] 4
+// CHECK: [[mainFnType:%\d+]] = OpExtInst %void [[set]] DebugTypeFunction FlagIsProtected|FlagIsPrivate [[float4]] [[float4]]
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugFunction [[mainName]] [[mainFnType]] [[source]] 30 1 [[compilationUnit]] [[emptyStr]] FlagIsProtected|FlagIsPrivate 31 %src_main
+
+void foo(int x, float y)
+{
+  x = x + y;
+}
+
+float4 main(float4 color : COLOR) : SV_TARGET
+{
+  bool condition = false;
+  foo(1, color.x);
+  return color;
+}
+

+ 34 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.function.param.hlsl

@@ -0,0 +1,34 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+// TODO: FlagIsPublic is shown as FlagIsProtected|FlagIsPrivate.
+
+// CHECK:             [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK:         [[fooName:%\d+]] = OpString "foo"
+// CHECK:        [[emptyStr:%\d+]] = OpString ""
+// CHECK:               [[y:%\d+]] = OpString "y"
+// CHECK:               [[x:%\d+]] = OpString "x"
+// CHECK:        [[mainName:%\d+]] = OpString "main"
+// CHECK:           [[color:%\d+]] = OpString "color"
+
+// CHECK: [[int:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic {{%\d+}} %uint_32 Signed
+// CHECK: [[float:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic {{%\d+}} %uint_32 Float
+// CHECK: [[source:%\d+]] = OpExtInst %void [[set]] DebugSource
+// CHECK: [[foo:%\d+]] = OpExtInst %void [[set]] DebugFunction [[fooName]] {{%\d+}} [[source]] 23 1 {{%\d+}} [[emptyStr]] FlagIsProtected|FlagIsPrivate 24 %foo
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugLocalVariable [[y]] [[float]] [[source]] 23 23 [[foo]] FlagIsLocal 2
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugLocalVariable [[x]] [[int]] [[source]] 23 14 [[foo]] FlagIsLocal 1
+// CHECK: [[float4:%\d+]] = OpExtInst %void [[set]] DebugTypeVector [[float]] 4
+// CHECK: [[main:%\d+]] = OpExtInst %void [[set]] DebugFunction [[mainName]] {{%\d+}} [[source]] 28 1 {{%\d+}} [[emptyStr]] FlagIsProtected|FlagIsPrivate 29 %src_main
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugLocalVariable [[color]] [[float4]] [[source]] 28 20 [[main]] FlagIsLocal 1
+
+void foo(int x, float y)
+{
+  x = x + y;
+}
+
+float4 main(float4 color : COLOR) : SV_TARGET
+{
+  bool condition = false;
+  foo(1, color.x);
+  return color;
+}
+

+ 50 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.function.parent.hlsl

@@ -0,0 +1,50 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+// CHECK:      [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+
+// CHECK: rich.debug.function.parent.hlsl
+// CHECK: spirv.debug.opline.include-file-3.hlsl
+// CHECK: [[f3:%\d+]] = OpString "function3"
+// CHECK: spirv.debug.opline.include-file-2.hlsl
+// CHECK: [[f2:%\d+]] = OpString "function2"
+// CHECK: spirv.debug.opline.include-file-1.hlsl
+// CHECK: [[f1:%\d+]] = OpString "function1"
+
+
+#include "spirv.debug.opline.include-file-1.hlsl"
+
+int callFunction1() {
+  return function1();
+}
+
+#include "spirv.debug.opline.include-file-2.hlsl"
+
+int callFunction2() {
+  return function2();
+}
+
+#include "spirv.debug.opline.include-file-3.hlsl"
+
+int callFunction3() {
+  CALL_FUNCTION_3;
+}
+
+// CHECK: [[s3:%\d+]] = OpExtInst %void [[set]] DebugSource
+// CHECK: [[c3:%\d+]] = OpExtInst %void [[set]] DebugCompilationUnit 1 4 [[s3]] HLSL
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugFunction [[f3]] {{%\d+}} [[s3]] 3 1 [[c3]]
+
+// CHECK: [[s2:%\d+]] = OpExtInst %void [[set]] DebugSource
+// CHECK: [[c2:%\d+]] = OpExtInst %void [[set]] DebugCompilationUnit 1 4 [[s2]] HLSL
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugFunction [[f2]] {{%\d+}} [[s2]] 2 1 [[c2]]
+
+// CHECK: [[s1:%\d+]] = OpExtInst %void [[set]] DebugSource
+// CHECK: [[c1:%\d+]] = OpExtInst %void [[set]] DebugCompilationUnit 1 4 [[s1]] HLSL
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugFunction [[f1]] {{%\d+}} [[s1]] 1 1 [[c1]]
+
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugSource
+
+void main() {
+  callFunction1();
+  callFunction2();
+  callFunction3();
+}

+ 34 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.global-variable.hlsl

@@ -0,0 +1,34 @@
+// Run: %dxc -T ps_6_2 -E main -fspv-debug=rich -enable-16bit-types
+
+// CHECK:         [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK: [[varNameCond:%\d+]] = OpString "cond"
+// CHECK:    [[varNameC:%\d+]] = OpString "c"
+
+// CHECK: [[floatType:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic {{%\d+}} %uint_32 Float
+// CHECK: [[float4Type:%\d+]] = OpExtInst %void [[set]] DebugTypeVector [[floatType]] 4
+// CHECK:      [[source:%\d+]] = OpExtInst %void [[set]] DebugSource
+// CHECK: [[compileUnit:%\d+]] = OpExtInst %void [[set]] DebugCompilationUnit 1 4 [[source]] HLSL
+
+// CHECK:  [[boolType:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic {{%\d+}} %uint_32 Boolean
+
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugGlobalVariable [[varNameCond]] [[boolType]] [[source]] 18 13 [[compileUnit]] [[varNameCond]] %cond FlagIsDefinition
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugGlobalVariable [[varNameC]] [[float4Type]] [[source]] 17 15 [[compileUnit]] [[varNameC]] %c FlagIsDefinition
+
+static float4 c;
+static bool cond;
+
+float4 main(float4 color : COLOR) : SV_TARGET {
+  c = 0.xxxx;
+  cond = c.x == 0;
+
+  if (cond) {
+    int a = 2;
+    c = c + c;
+    {
+      uint b = 3;
+      c = c + c;
+    }
+  }
+
+  return color + c;
+}

+ 48 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.local-variable.hlsl

@@ -0,0 +1,48 @@
+// Run: %dxc -T ps_6_2 -E main -fspv-debug=rich -enable-16bit-types
+
+// CHECK:         [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK:    [[varNameB:%\d+]] = OpString "b"
+// CHECK:    [[varNameA:%\d+]] = OpString "a"
+// CHECK: [[varNameCond:%\d+]] = OpString "cond"
+// CHECK:    [[varNameC:%\d+]] = OpString "c"
+
+// CHECK:  [[uintType:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic {{%\d+}} %uint_32 Unsigned
+// CHECK: [[floatType:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic {{%\d+}} %uint_32 Float
+// CHECK: [[float4Type:%\d+]] = OpExtInst %void [[set]] DebugTypeVector [[floatType]] 4
+// CHECK:      [[source:%\d+]] = OpExtInst %void [[set]] DebugSource
+// CHECK: [[compileUnit:%\d+]] = OpExtInst %void [[set]] DebugCompilationUnit 1 4 [[source]] HLSL
+// CHECK:      [[main:%\d+]] = OpExtInst %void [[set]] DebugFunction {{%\d+}} {{%\d+}} [[source]] 29 1 [[compileUnit]] {{%\d+}} FlagIsProtected|FlagIsPrivate 30 %src_main
+
+// CHECK: [[mainFnLexBlock:%\d+]] = OpExtInst %void [[set]] DebugLexicalBlock [[source]] 30 1 [[main]]
+// CHECK: [[ifLexBlock:%\d+]] = OpExtInst %void [[set]] DebugLexicalBlock [[source]] 35 13 [[mainFnLexBlock]]
+// CHECK: [[tempLexBlock:%\d+]] = OpExtInst %void [[set]] DebugLexicalBlock [[source]] 38 5 [[ifLexBlock]]
+
+// CHECK:              {{%\d+}} = OpExtInst %void [[set]] DebugLocalVariable [[varNameB]] [[uintType]] [[source]] 39 12 [[tempLexBlock]] FlagIsLocal
+
+// CHECK:   [[intType:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic {{%\d+}} %uint_32 Signed
+// CHECK:            {{%\d+}} = OpExtInst %void [[set]] DebugLocalVariable [[varNameA]] [[intType]] [[source]] 36 9 [[ifLexBlock]] FlagIsLocal
+
+// CHECK:  [[boolType:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic {{%\d+}} %uint_32 Boolean
+// CHECK:                {{%\d+}} = OpExtInst %void [[set]] DebugLocalVariable [[varNameCond]] [[boolType]] [[source]] 32 8 [[mainFnLexBlock]] FlagIsLocal
+// CHECK:                {{%\d+}} = OpExtInst %void [[set]] DebugLocalVariable [[varNameC]] [[float4Type]] [[source]] 31 10 [[mainFnLexBlock]] FlagIsLocal
+
+float4 main(float4 color : COLOR) : SV_TARGET
+{
+  float4 c = 0.xxxx;
+  bool cond = c.x == 0;
+
+
+  if (cond) {
+    int a = 2;
+    c = c + c;
+    {
+      uint b = 3;
+      c = c + c;
+    }
+  }
+
+
+  return color + c;
+}
+
+

+ 56 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.member.function.param.hlsl

@@ -0,0 +1,56 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+struct foo {
+  int a;
+
+  void func0(float arg) {
+    b.x = arg;
+  }
+
+  float4 b;
+
+  int func1(int arg0, float arg1, bool arg2) {
+    a = arg0;
+    b.y = arg1;
+    if (arg2) return arg0;
+    return b.z;
+  }
+
+  bool c;
+};
+
+// CHECK: [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+
+// CHECK: [[fooName:%\d+]] = OpString "foo"
+// CHECK: [[func1:%\d+]] = OpString "foo.func1"
+// CHECK: [[arg2:%\d+]] = OpString "arg2"
+// CHECK: [[arg1:%\d+]] = OpString "arg1"
+// CHECK: [[arg0:%\d+]] = OpString "arg0"
+// CHECK: [[this:%\d+]] = OpString "this"
+// CHECK: [[func0:%\d+]] = OpString "foo.func0"
+// CHECK: [[arg:%\d+]] = OpString "arg"
+
+// CHECK: [[bool:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic {{%\d+}} %uint_32 Boolean
+// CHECK: [[foo:%\d+]] = OpExtInst %void [[set]] DebugTypeComposite [[fooName]] Structure {{%\d+}} 3 8
+
+// CHECK: [[float:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic {{%\d+}} %uint_32 Float
+// CHECK: [[int:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic {{%\d+}} %uint_32 Signed
+
+// CHECK: [[func1Type:%\d+]] = OpExtInst %void [[set]] DebugTypeFunction FlagIsProtected|FlagIsPrivate [[int]] [[foo]] [[int]] [[float]] [[bool]]
+// CHECK: [[f1:%\d+]] = OpExtInst %void [[set]] DebugFunction [[func1]] [[func1Type]] {{%\d+}} 12 3 [[foo]] {{%\d+}} FlagIsProtected|FlagIsPrivate 12 %foo_func1
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugLocalVariable [[arg2]] {{%\d+}} {{%\d+}} 12 40 [[f1]] FlagIsLocal 4
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugLocalVariable [[arg1]] {{%\d+}} {{%\d+}} 12 29 [[f1]] FlagIsLocal 3
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugLocalVariable [[arg0]] {{%\d+}} {{%\d+}} 12 17 [[f1]] FlagIsLocal 2
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugLocalVariable [[this]] [[foo]] {{%\d+}} 12 3 [[f1]] FlagArtificial|FlagObjectPointer 1
+// CHECK: [[func0Type:%\d+]] = OpExtInst %void [[set]] DebugTypeFunction FlagIsProtected|FlagIsPrivate %void [[foo]] [[float]]
+// CHECK: [[f0:%\d+]] = OpExtInst %void [[set]] DebugFunction [[func0]] [[func0Type]] {{%\d+}} 6 3 [[foo]] {{%\d+}} FlagIsProtected|FlagIsPrivate 6 %foo_func0
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugLocalVariable [[arg]] {{%\d+}} {{%\d+}} 6 20 [[f0]] FlagIsLocal 2
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugLocalVariable [[this]] [[foo]] {{%\d+}} 6 3 [[f0]] FlagArtificial|FlagObjectPointer 1
+
+float4 main(float4 color : COLOR) : SV_TARGET {
+  foo a;
+  a.func0(1);
+  a.func1(1, 1, 1);
+
+  return color;
+}

+ 43 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.member.function.without-call.hlsl

@@ -0,0 +1,43 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+struct foo {
+  int a;
+
+  void func0(float arg) {
+    b.x = arg;
+  }
+
+  float4 b;
+
+  int func1(int arg0, float arg1, bool arg2) {
+    a = arg0;
+    b.y = arg1;
+    if (arg2) return arg0;
+    return b.z;
+  }
+
+  bool c;
+};
+
+// CHECK: [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK: [[foo:%\d+]] = OpString "foo"
+// CHECK: [[c_name:%\d+]] = OpString "c"
+// CHECK: [[b_name:%\d+]] = OpString "b"
+// CHECK: [[a_name:%\d+]] = OpString "a"
+// CHECK: [[func1:%\d+]] = OpString "foo.func1"
+// CHECK: [[func0:%\d+]] = OpString "foo.func0"
+
+// CHECK: [[parent:%\d+]] = OpExtInst %void [[set]] DebugTypeComposite [[foo]] Structure {{%\d+}} 3 1 {{%\d+}} {{%\d+}} %uint_192 FlagIsProtected|FlagIsPrivate [[a:%\d+]] [[f0:%\d+]] [[b:%\d+]] [[f1:%\d+]] [[c:%\d+]]
+// CHECK: [[c]] = OpExtInst %void [[set]] DebugTypeMember [[c_name]]
+// CHECK: [[b]] = OpExtInst %void [[set]] DebugTypeMember [[b_name]]
+// CHECK: [[a]] = OpExtInst %void [[set]] DebugTypeMember [[a_name]]
+// CHECK: [[none:%\d+]] = OpExtInst %void [[set]] DebugInfoNone
+// CHECK: [[f1]] = OpExtInst %void [[set]] DebugFunction [[func1]] {{%\d+}} {{%\d+}} 12 3 [[parent]] {{%\d+}} FlagIsProtected|FlagIsPrivate 12 [[none]]
+// CHECK: [[f0]] = OpExtInst %void [[set]] DebugFunction [[func0]] {{%\d+}} {{%\d+}} 6 3 [[parent]] {{%\d+}} FlagIsProtected|FlagIsPrivate 6 %foo_func0
+
+float4 main(float4 color : COLOR) : SV_TARGET {
+  foo a;
+  a.func0(1);
+
+  return color;
+}

+ 33 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.rwtexture.hlsl

@@ -0,0 +1,33 @@
+// Run: %dxc -T vs_6_0 -E main -fspv-debug=rich
+
+//CHECK: [[name_2d_arr:%\d+]] = OpString "@type.2d.image.array"
+//CHECK: [[name_1d_arr:%\d+]] = OpString "@type.1d.image.array"
+//CHECK: [[name_3d:%\d+]] = OpString "@type.3d.image"
+//CHECK: [[name_1d:%\d+]] = OpString "@type.1d.image"
+
+//CHECK: [[2daf_comp:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugTypeComposite [[name_2d_arr]] Class [[src:%\d+]] 0 0 [[cu:%\d+]] {{%\d+}} [[info_none:%\d+]]
+//CHECK: [[tem_p6:%\d+]] = OpExtInst %void [[ext]] DebugTypeTemplateParameter
+//CHECK: [[2daf:%\d+]] = OpExtInst %void [[ext]] DebugTypeTemplate [[2daf_comp]] [[tem_p6]]
+//CHECK: OpExtInst %void [[ext]] DebugGlobalVariable {{%\d+}} [[2daf]] [[src]] {{\d+}} {{\d+}} [[cu]] {{%\d+}} %t8
+
+//CHECK: [[1dai_comp:%\d+]] = OpExtInst %void [[ext]] DebugTypeComposite [[name_1d_arr]] Class [[src]] 0 0 [[cu]] {{%\d+}} [[info_none]]
+//CHECK: [[tem_p3:%\d+]] = OpExtInst %void [[ext]] DebugTypeTemplateParameter
+//CHECK: [[1dai:%\d+]] = OpExtInst %void [[ext]] DebugTypeTemplate [[1dai_comp]] [[tem_p3]]
+//CHECK: OpExtInst %void [[ext]] DebugGlobalVariable {{%\d+}} [[1dai]] [[src]] {{\d+}} {{\d+}} [[cu]] {{%\d+}} %t5
+
+//CHECK: [[3df_comp:%\d+]] = OpExtInst %void [[ext]] DebugTypeComposite [[name_3d]] Class [[src]] 0 0 [[cu]] {{%\d+}} [[info_none]]
+//CHECK: [[tem_p2:%\d+]] = OpExtInst %void [[ext]] DebugTypeTemplateParameter
+//CHECK: [[3df:%\d+]] = OpExtInst %void [[ext]] DebugTypeTemplate [[3df_comp]] [[tem_p2]]
+//CHECK: OpExtInst %void [[ext]] DebugGlobalVariable {{%\d+}} [[3df]] [[src]] {{\d+}} {{\d+}} [[cu]] {{%\d+}} %t3
+
+//CHECK: [[1di_comp:%\d+]] = OpExtInst %void [[ext]] DebugTypeComposite [[name_1d]] Class [[src]] 0 0 [[cu]] {{%\d+}} [[info_none]]
+//CHECK: [[tem_p0:%\d+]] = OpExtInst %void [[ext]] DebugTypeTemplateParameter
+//CHECK: [[1di:%\d+]] = OpExtInst %void [[ext]] DebugTypeTemplate [[1di_comp]] [[tem_p0]]
+//CHECK: OpExtInst %void [[ext]] DebugGlobalVariable {{%\d+}} [[1di]] [[src]] {{\d+}} {{\d+}} [[cu]] {{%\d+}} %t1
+
+RWTexture1D   <int>    t1 ;
+RWTexture3D   <float3> t3 ;
+RWTexture1DArray<int>    t5;
+RWTexture2DArray<float4> t8;
+
+void main() {}

+ 16 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.sampler.hlsl

@@ -0,0 +1,16 @@
+// Run: %dxc -T vs_6_0 -E main -fspv-debug=rich
+
+//CHECK: [[name:%\d+]] = OpString "@type.sampler"
+//CHECK: [[info_none:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugInfoNone
+//CHECK: [[sampler:%\d+]] = OpExtInst %void [[ext]] DebugTypeComposite [[name]] Structure [[src:%\d+]] 0 0 [[cu:%\d+]] {{%\d+}} [[info_none]]
+
+//CHECK: OpExtInst %void [[ext]] DebugGlobalVariable {{%\d+}} [[sampler]] [[src]] {{\d+}} {{\d+}} [[cu]] {{%\d+}} %s3
+//CHECK: OpExtInst %void [[ext]] DebugGlobalVariable {{%\d+}} [[sampler]] [[src]] {{\d+}} {{\d+}} [[cu]] {{%\d+}} %s2
+//CHECK: OpExtInst %void [[ext]] DebugGlobalVariable {{%\d+}} [[sampler]] [[src]] {{\d+}} {{\d+}} [[cu]] {{%\d+}} %s1
+
+SamplerState           s1 : register(s1);
+SamplerComparisonState s2 : register(s2);
+sampler                s3 : register(s3);
+
+void main() {
+}

+ 13 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.sort.type.template.hlsl

@@ -0,0 +1,13 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+// CHECK: [[dbg_info_none:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugInfoNone
+// CHECK: [[ty:%\d+]] = OpExtInst %void [[ext]] DebugTypeComposite {{%\d+}} Class {{%\d+}} 0 0 {{%\d+}} {{%\d+}} [[dbg_info_none]]
+// CHECK: [[param:%\d+]] = OpExtInst %void [[ext]] DebugTypeTemplateParameter {{%\d+}} {{%\d+}} [[dbg_info_none]]
+// CHECK: OpExtInst %void [[ext]] DebugTypeTemplate [[ty]] [[param]]
+
+Texture2D<float4> tex : register(t0);
+
+float4 main(float4 pos : SV_Position) : SV_Target0
+{
+  return tex.Load(int3(pos.xy, 0));
+}

+ 68 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.structured-buffer.hlsl

@@ -0,0 +1,68 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+struct S {
+    float  a;
+    float3 b;
+    int2 c;
+};
+
+struct T {
+    float  a;
+    float3 b;
+    S      c;
+    int2   d;
+};
+
+StructuredBuffer<S> mySBuffer1 : register(t1);
+StructuredBuffer<T> mySBuffer2 : register(t2);
+
+RWStructuredBuffer<S> mySBuffer3 : register(u3);
+RWStructuredBuffer<T> mySBuffer4 : register(u4);
+
+// CHECK: [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK: [[T:%\d+]] = OpString "T"
+// CHECK: [[S:%\d+]] = OpString "S"
+// CHECK: [[RW_S:%\d+]] = OpString "@type.RWStructuredBuffer.S"
+// CHECK: [[param:%\d+]] = OpString "TemplateParam"
+// CHECK: [[inputBuffer:%\d+]] = OpString "inputBuffer"
+// CHECK: [[RW_T:%\d+]] = OpString "@type.RWStructuredBuffer.T"
+// CHECK: [[SB_T:%\d+]] = OpString "@type.StructuredBuffer.T"
+// CHECK: [[SB_S:%\d+]] = OpString "@type.StructuredBuffer.S"
+
+// CHECK: [[T_ty:%\d+]] = OpExtInst %void [[set]] DebugTypeComposite [[T]] Structure
+// CHECK: [[S_ty:%\d+]] = OpExtInst %void [[set]] DebugTypeComposite [[S]] Structure
+
+// CHECK: [[none:%\d+]] = OpExtInst %void [[set]] DebugInfoNone
+// CHECK: [[RW_S_ty:%\d+]] = OpExtInst %void [[set]] DebugTypeComposite [[RW_S]] Class {{%\d+}} 0 0 {{%\d+}} {{%\d+}} [[none]]
+// CHECK: [[param2:%\d+]] = OpExtInst %void [[set]] DebugTypeTemplateParameter [[param]] [[S_ty]]
+// CHECK: [[RW_S_temp:%\d+]] = OpExtInst %void [[set]] DebugTypeTemplate [[RW_S_ty]] [[param2]]
+
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugLocalVariable [[inputBuffer]] [[RW_S_temp]]
+
+// CHECK: [[RW_T_ty:%\d+]] = OpExtInst %void [[set]] DebugTypeComposite [[RW_T]] Class {{%\d+}} 0 0 {{%\d+}} {{%\d+}} [[none]]
+// CHECK: [[param3:%\d+]] = OpExtInst %void [[set]] DebugTypeTemplateParameter [[param]] [[T_ty]]
+// CHECK: [[RW_T_temp:%\d+]] = OpExtInst %void [[set]] DebugTypeTemplate [[RW_T_ty]] [[param3]]
+
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugGlobalVariable {{%\d+}} [[RW_T_temp]] {{%\d+}} {{\d+}} {{\d+}} {{%\d+}} {{%\d+}} %mySBuffer4
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugGlobalVariable {{%\d+}} [[RW_S_temp]] {{%\d+}} {{\d+}} {{\d+}} {{%\d+}} {{%\d+}} %mySBuffer3
+
+// CHECK: [[SB_T_ty:%\d+]] = OpExtInst %void [[set]] DebugTypeComposite [[SB_T]] Class {{%\d+}} 0 0 {{%\d+}} {{%\d+}} [[none]]
+// CHECK: [[param1:%\d+]] = OpExtInst %void [[set]] DebugTypeTemplateParameter [[param]] [[T_ty]]
+// CHECK: [[SB_T_temp:%\d+]] = OpExtInst %void [[set]] DebugTypeTemplate [[SB_T_ty]] [[param1]]
+
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugGlobalVariable {{%\d+}} [[SB_T_temp]] {{%\d+}} {{\d+}} {{\d+}} {{%\d+}} {{%\d+}} %mySBuffer2
+
+// CHECK: [[SB_S_ty:%\d+]] = OpExtInst %void [[set]] DebugTypeComposite [[SB_S]] Class {{%\d+}} 0 0 {{%\d+}} {{%\d+}} [[none]]
+// CHECK: [[param0:%\d+]] = OpExtInst %void [[set]] DebugTypeTemplateParameter [[param]] [[S_ty]]
+// CHECK: [[SB_S_temp:%\d+]] = OpExtInst %void [[set]] DebugTypeTemplate [[SB_S_ty]] [[param0]]
+
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugGlobalVariable {{%\d+}} [[SB_S_temp]] {{%\d+}} {{\d+}} {{\d+}} {{%\d+}} {{%\d+}} %mySBuffer1
+
+void foo(RWStructuredBuffer<S> inputBuffer) {
+  inputBuffer[0].a = 0;
+}
+
+float4 main() : SV_Target {
+    foo(mySBuffer3);
+    return 1.0;
+}

+ 33 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.switch.debugscope.hlsl

@@ -0,0 +1,33 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+float4 main(float2 inUV : TEXCOORD0) : SV_TARGET
+{
+  int x = int(floor(inUV.x / 0.25f));
+  float4 samplePos = float4(0, 0, 0, 1);
+  float2 uv = float2(inUV.x * 4.0f, (inUV.y - 1.0/3.0) * 3.0);
+  uv = 2.0 * float2(uv.x - float(x) * 1.0, uv.y) - 1.0;
+
+// CHECK:      OpSelectionMerge %switch_merge None
+// CHECK-NEXT: OpSwitch {{%\d+}} %switch_merge
+
+// OpBranch before a new OpLabel after OpSwitch causes a validation error.
+// CHECK-NOT:  DebugScope
+// CHECK-NOT:  OpBranch
+// CHECK-NEXT: %switch_0 = OpLabel
+
+  switch (x) {
+    case 0: // NEGATIVE_X
+      samplePos = float4(-1.0f, uv.y, uv.x, 1);
+      break;
+    case 1: // POSITIVE_Z
+      samplePos = float4(uv.x, uv.y, 1.0f, 1);
+      break;
+    case 2: // POSITIVE_X
+      samplePos = float4(1.0, uv.y, -uv.x, 1);
+      break;
+    case 3: // NEGATIVE_Z
+      samplePos = float4(-uv.x, uv.y, -1.0f, 1);
+      break;
+  }
+  return samplePos;
+}

+ 40 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.texture.hlsl

@@ -0,0 +1,40 @@
+// Run: %dxc -T vs_6_0 -E main -fspv-debug=rich
+
+//CHECK: [[name_2d_arr:%\d+]] = OpString "@type.2d.image.array"
+//CHECK: [[name_2d:%\d+]] = OpString "@type.2d.image"
+//CHECK: [[name_cb_arr:%\d+]] = OpString "@type.cube.image.array"
+
+//CHECK: [[info_none:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugInfoNone
+//CHECK: [[t3_comp:%\d+]] = OpExtInst %void [[ext]] DebugTypeComposite [[name_2d_arr]] Class [[src:%\d+]] 0 0 [[cu:%\d+]] {{%\d+}} [[info_none]]
+//CHECK: [[tem_p3:%\d+]] = OpExtInst %void [[ext]] DebugTypeTemplateParameter
+//CHECK: [[t3_ty:%\d+]] = OpExtInst %void [[ext]] DebugTypeTemplate [[t3_comp]] [[tem_p3]]
+//CHECK: OpExtInst %void [[ext]] DebugGlobalVariable {{%\d+}} [[t3_ty]] [[src]] {{\d+}} {{\d+}} [[cu]] {{%\d+}} %t3
+
+//CHECK: [[t2_comp:%\d+]] = OpExtInst %void [[ext]] DebugTypeComposite [[name_2d]] Class [[src]] 0 0 [[cu]] {{%\d+}} [[info_none]]
+//CHECK: [[tem_p2:%\d+]] = OpExtInst %void [[ext]] DebugTypeTemplateParameter
+//CHECK: [[t2_ty:%\d+]] = OpExtInst %void [[ext]] DebugTypeTemplate [[t2_comp]] [[tem_p2]]
+//CHECK: OpExtInst %void [[ext]] DebugGlobalVariable {{%\d+}} [[t2_ty]] [[src]] {{\d+}} {{\d+}} [[cu]] {{%\d+}} %t2
+
+//CHECK: [[t1_comp:%\d+]] = OpExtInst %void [[ext]] DebugTypeComposite [[name_cb_arr]] Class [[src]] 0 0 [[cu]] {{%\d+}} [[info_none]]
+//CHECK: [[tem_p1:%\d+]] = OpExtInst %void [[ext]] DebugTypeTemplateParameter
+//CHECK: [[t1_ty:%\d+]] = OpExtInst %void [[ext]] DebugTypeTemplate [[t1_comp]] [[tem_p1]]
+//CHECK: OpExtInst %void [[ext]] DebugGlobalVariable {{%\d+}} [[t1_ty]] [[src]] {{\d+}} {{\d+}} [[cu]] {{%\d+}} %t1
+
+//CHECK: [[t0_comp:%\d+]] = OpExtInst %void [[ext]] DebugTypeComposite [[name_2d]] Class [[src]] 0 0 [[cu]] {{%\d+}} [[info_none]]
+//CHECK: [[tem_p0:%\d+]] = OpExtInst %void [[ext]] DebugTypeTemplateParameter
+//CHECK: [[t0_ty:%\d+]] = OpExtInst %void [[ext]] DebugTypeTemplate [[t0_comp]] [[tem_p0]]
+//CHECK: OpExtInst %void [[ext]] DebugGlobalVariable {{%\d+}} [[t0_ty]] [[src]] {{\d+}} {{\d+}} [[cu]] {{%\d+}} %t0
+
+Texture2D   <int4>   t0 : register(t0);
+TextureCubeArray <float4> t1 : register(t1);
+Texture2DMS      <int3>   t2 : register(t2);
+
+struct S {
+    float a;
+    float b;
+};
+
+Texture2DArray<S> t3;
+
+void main() {
+}

+ 25 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.type.array-from-same-type.hlsl

@@ -0,0 +1,25 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+struct UBO
+{
+  float4x4 a;
+  float4x4 b[3];
+  float4 c;
+};
+
+cbuffer ubo : register(b0) { UBO ubo; }
+
+// CHECK:   [[bName:%\d+]] = OpString "b"
+// CHECK:   [[aName:%\d+]] = OpString "a"
+// CHECK: [[fooName:%\d+]] = OpString "foo"
+
+// CHECK: [[matf4v4_arr3:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugTypeArray [[dbg_f:%\d+]] %uint_3 %uint_4 %uint_4
+// CHECK: OpExtInst %void [[ext]] DebugTypeMember [[bName]] [[matf4v4_arr3]]
+// CHECK: [[matf4v4:%\d+]] = OpExtInst %void [[ext]] DebugTypeArray [[dbg_f]] %uint_4 %uint_4
+// CHECK: OpExtInst %void [[ext]] DebugTypeMember [[aName]] [[matf4v4]]
+// CHECK: OpExtInst %void [[ext]] DebugLocalVariable [[fooName]] [[matf4v4]]
+
+void main() {
+  float4x4 foo = ubo.a;
+  foo += ubo.b[0] * ubo.c[0];
+}

+ 36 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.type.array.hlsl

@@ -0,0 +1,36 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+// CHECK:       [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK:  [[boolName:%\d+]] = OpString "bool"
+// CHECK:     [[SName:%\d+]] = OpString "S"
+// CHECK:   [[intName:%\d+]] = OpString "int"
+// CHECK:  [[uintName:%\d+]] = OpString "uint"
+// CHECK: [[floatName:%\d+]] = OpString "float"
+// CHECK:           %uint_32 = OpConstant %uint 32
+
+// CHECK:   [[bool:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic [[boolName]] %uint_32 Boolean
+// CHECK: [[S:%\d+]] = OpExtInst %void [[set]] DebugTypeComposite [[SName]]
+// CHECK:   [[int:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic [[intName]] %uint_32 Signed
+// CHECK:  [[uint:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic [[uintName]] %uint_32 Unsigned
+// CHECK: [[float:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic [[floatName]] %uint_32 Float
+// CHECK:        {{%\d+}} = OpExtInst %void [[set]] DebugTypeArray [[S]] %uint_8
+// CHECK: [[boolv4:%\d+]] = OpExtInst %void [[set]] DebugTypeVector [[bool]] 4
+// CHECK:        {{%\d+}} = OpExtInst %void [[set]] DebugTypeArray [[boolv4]] %uint_7
+// CHECK:       {{%\d+}} = OpExtInst %void [[set]] DebugTypeArray [[float]] %uint_8 %uint_4
+// CHECK:       {{%\d+}} = OpExtInst %void [[set]] DebugTypeArray [[int]] %uint_8
+// CHECK:       {{%\d+}} = OpExtInst %void [[set]] DebugTypeArray [[uint]] %uint_4
+
+void main() {
+    const uint size = 4 * 3 - 4;
+
+    uint  x[4];
+    int   y[size];
+    float z[size][4];
+    bool4 v[7];
+
+    struct S {
+      uint a;
+      int b;
+      bool c;
+    } w[size];
+}

+ 11 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.type.bool.hlsl

@@ -0,0 +1,11 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+// CHECK:      [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK: [[typeName:%\d+]] = OpString "bool"
+
+float4 main(float4 color : COLOR) : SV_TARGET {
+  // CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugTypeBasic [[typeName]] %uint_32 Boolean
+  bool condition = false;
+  return color;
+}
+

+ 22 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.type.composite.before.function.hlsl

@@ -0,0 +1,22 @@
+// Run: %dxc -T vs_6_0 -E main -fspv-debug=rich
+
+// CHECK: [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK: [[out:%\d+]] = OpString "VS_OUTPUT"
+// CHECK: [[main:%\d+]] = OpString "main"
+
+// CHECK: [[VSOUT:%\d+]] = OpExtInst %void [[set]] DebugTypeComposite [[out]]
+// CHECK: [[ty:%\d+]] = OpExtInst %void [[set]] DebugTypeFunction FlagIsProtected|FlagIsPrivate [[VSOUT]]
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugFunction [[main]] [[ty]]
+
+struct VS_OUTPUT {
+  float4 pos : SV_POSITION;
+  float4 color : COLOR;
+};
+
+VS_OUTPUT main(float4 pos : POSITION,
+               float4 color : COLOR) {
+  VS_OUTPUT vout;
+  vout.pos = pos;
+  vout.color = color;
+  return vout;
+}

+ 15 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.type.composite.empty.hlsl

@@ -0,0 +1,15 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+struct foo {
+};
+
+// CHECK: [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK: [[foo:%\d+]] = OpString "foo"
+
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugTypeComposite [[foo]] Structure {{%\d+}} 3 8 {{%\d+}} {{%\d+}} %uint_0 FlagIsProtected|FlagIsPrivate
+
+float4 main(float4 color : COLOR) : SV_TARGET {
+  foo a;
+
+  return color;
+}

+ 51 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.type.composite.hlsl

@@ -0,0 +1,51 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+struct foo {
+  int a;
+
+  void func0(float arg) {
+    b.x = arg;
+  }
+
+  float4 b;
+
+  int func1(int arg0, float arg1, bool arg2) {
+    a = arg0;
+    b.y = arg1;
+    if (arg2) return arg0;
+    return b.z;
+  }
+
+  bool c;
+};
+
+// CHECK: [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK: [[bool_name:%\d+]] = OpString "bool"
+// CHECK: [[foo:%\d+]] = OpString "foo"
+// CHECK: [[c_name:%\d+]] = OpString "c"
+// CHECK: [[float_name:%\d+]] = OpString "float"
+// CHECK: [[b_name:%\d+]] = OpString "b"
+// CHECK: [[int_name:%\d+]] = OpString "int"
+// CHECK: [[a_name:%\d+]] = OpString "a"
+// CHECK: [[func1:%\d+]] = OpString "foo.func1"
+// CHECK: [[func0:%\d+]] = OpString "foo.func0"
+
+// CHECK: [[bool:%\d+]] = OpExtInst %void %1 DebugTypeBasic [[bool_name]] %uint_32 Boolean
+// CHECK: [[parent:%\d+]] = OpExtInst %void [[set]] DebugTypeComposite [[foo]] Structure {{%\d+}} 3 8 {{%\d+}} {{%\d+}} %uint_192 FlagIsProtected|FlagIsPrivate [[a:%\d+]] [[b:%\d+]] [[c:%\d+]] [[f0:%\d+]] [[f1:%\d+]]
+
+// CHECK: [[c]] = OpExtInst %void [[set]] DebugTypeMember [[c_name]] [[bool]] {{%\d+}} 19 8 [[parent]] %uint_160 %uint_32 FlagIsProtected|FlagIsPrivate
+// CHECK: [[float:%\d+]] = OpExtInst %void %1 DebugTypeBasic [[float_name]] %uint_32 Float
+// CHECK: [[v4f:%\d+]] = OpExtInst %void %1 DebugTypeVector [[float]] 4
+// CHECK: [[b]] = OpExtInst %void [[set]] DebugTypeMember [[b_name]] [[v4f]] {{%\d+}} 10 10 [[parent]] %uint_32 %uint_128 FlagIsProtected|FlagIsPrivate
+// CHECK: [[int:%\d+]] = OpExtInst %void %1 DebugTypeBasic [[int_name]] %uint_32 Signed
+// CHECK: [[a]] = OpExtInst %void [[set]] DebugTypeMember [[a_name]] [[int]] {{%\d+}} 4 7 [[parent]] %uint_0 %uint_32 FlagIsProtected|FlagIsPrivate
+// CHECK: [[f1]] = OpExtInst %void [[set]] DebugFunction [[func1]] {{%\d+}} {{%\d+}} 12 3 [[parent]] {{%\d+}} FlagIsProtected|FlagIsPrivate 12 %foo_func1
+// CHECK: [[f0]] = OpExtInst %void [[set]] DebugFunction [[func0]] {{%\d+}} {{%\d+}} 6 3 [[parent]] {{%\d+}} FlagIsProtected|FlagIsPrivate 6 %foo_func0
+
+float4 main(float4 color : COLOR) : SV_TARGET {
+  foo a;
+  a.func0(1);
+  a.func1(1, 1, 1);
+
+  return color;
+}

+ 16 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.type.float.hlsl

@@ -0,0 +1,16 @@
+// Run: %dxc -T ps_6_2 -E main -fspv-debug=rich -enable-16bit-types
+
+// CHECK:        [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK:  [[float64Name:%\d+]] = OpString "float64_t"
+// CHECK:    [[floatName:%\d+]] = OpString "float"
+// CHECK:  [[float16Name:%\d+]] = OpString "float16_t"
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugTypeBasic [[float64Name]] %uint_64 Float
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugTypeBasic [[floatName]] %uint_32 Float
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugTypeBasic [[float16Name]] %uint_16 Float
+
+float4 main(float4 color : COLOR) : SV_TARGET {
+  float a = 0;
+  float16_t b = 0;
+  float64_t c = 0;
+  return color;
+}

+ 28 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.type.function.hlsl

@@ -0,0 +1,28 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+// CHECK:    [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK:  [[int:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic {{%\d+}} %uint_32 Signed
+// CHECK:  [[float:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic {{%\d+}} %uint_32 Float
+//
+// Debug function type
+// TODO: FlagIsPublic (3u) is shown as FlagIsProtected|FlagIsPrivate.
+//
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugTypeFunction FlagIsProtected|FlagIsPrivate %void [[int]] [[float]]
+
+// CHECK: [[float4:%\d+]] = OpExtInst %void [[set]] DebugTypeVector [[float]] 4
+//
+// Debug function type
+// TODO: FlagIsPublic (3u) is shown as FlagIsProtected|FlagIsPrivate.
+//
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugTypeFunction FlagIsProtected|FlagIsPrivate [[float4]] [[float4]]
+
+void foo(int x, float y) {
+  x = x + y;
+}
+
+float4 main(float4 color : COLOR) : SV_TARGET {
+  bool condition = false;
+  foo(1, color.x);
+  return color;
+}
+

+ 26 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.type.int.hlsl

@@ -0,0 +1,26 @@
+// Run: %dxc -T ps_6_2 -E main -fspv-debug=rich -enable-16bit-types
+
+// CHECK:        [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK: [[uint64Name:%\d+]] = OpString "uint64_t"
+// CHECK:  [[int64Name:%\d+]] = OpString "int64_t"
+// CHECK: [[uint16Name:%\d+]] = OpString "uint16_t"
+// CHECK:  [[int16Name:%\d+]] = OpString "int16_t"
+// CHECK:   [[uintName:%\d+]] = OpString "uint"
+// CHECK:    [[intName:%\d+]] = OpString "int"
+// CHECK:            %uint_32 = OpConstant %uint 32
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugTypeBasic [[uint64Name]] %uint_64 Unsigned
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugTypeBasic [[int64Name]] %uint_64 Signed
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugTypeBasic [[uint16Name]] %uint_16 Unsigned
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugTypeBasic [[int16Name]] %uint_16 Signed
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugTypeBasic [[uintName]] %uint_32 Unsigned
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugTypeBasic [[intName]] %uint_32 Signed
+
+float4 main(float4 color : COLOR) : SV_TARGET {
+  int a = 0;
+  uint b = 1;
+  int16_t c = 0;
+  uint16_t d = 0;
+  int64_t e = 0;
+  uint64_t f = 0;
+  return color;
+}

+ 14 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.type.matrix.hlsl

@@ -0,0 +1,14 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+// NOTE: The current debug info extension (OpenCL.DebugInfo.100
+// Information Extended Instruction Set) does not support a matrix
+// type. To avoid a crash from matrix type, we temporarily emit a
+// debug array type for it. This test checks only that it runs
+// without a crash.
+
+// CHECK: [[float:%\d+]] = OpExtInst %void {{%\d+}} DebugTypeBasic {{%\d+}} %uint_32 Float
+// CHECK: {{%\d+}} = OpExtInst %void {{%\d+}} DebugTypeArray [[float]] %uint_3 %uint_4
+
+void main() {
+   float3x4 mat;
+}

+ 58 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.type.member.function.hlsl

@@ -0,0 +1,58 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
+
+struct base {
+  int p0;
+
+  void f0(float arg) {
+    p0 = arg;
+  }
+
+  float4 p1;
+
+  int f1(int arg0, float arg1, bool arg2) {
+    p0 = arg0;
+    p1.y = arg1;
+    if (arg2) return arg0;
+    return p1.z;
+  }
+
+  bool p2;
+};
+
+struct foo : base {
+  int a;
+
+  void func0(float arg) {
+    b.x = arg;
+  }
+
+  float4 b;
+
+  int func1(int arg0, float arg1, bool arg2) {
+    a = arg0;
+    b.y = arg1;
+    if (arg2) return arg0;
+    return b.z;
+  }
+
+  bool c;
+};
+
+// CHECK: [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+
+// CHECK: [[fooName:%\d+]] = OpString "foo"
+// CHECK: [[bool:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic {{%\d+}} %uint_32 Boolean
+// CHECK: [[foo:%\d+]] = OpExtInst %void %1 DebugTypeComposite [[fooName]] Structure {{%\d+}} 22 8 {{%\d+}} [[fooName]] %uint_192 FlagIsProtected|FlagIsPrivate
+// CHECK: [[float:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic {{%\d+}} %uint_32 Float
+// CHECK: [[int:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic {{%\d+}} %uint_32 Signed
+
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugTypeFunction FlagIsProtected|FlagIsPrivate [[int]] [[foo]] [[int]] [[float]] [[bool]]
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugTypeFunction FlagIsProtected|FlagIsPrivate %void [[foo]] [[float]]
+
+float4 main(float4 color : COLOR) : SV_TARGET {
+  foo a;
+  a.func0(1);
+  a.func1(1, 1, 1);
+
+  return color;
+}

+ 17 - 0
tools/clang/test/CodeGenSPIRV/rich.debug.type.vector.hlsl

@@ -0,0 +1,17 @@
+// Run: %dxc -T ps_6_2 -E main -fspv-debug=rich -enable-16bit-types
+
+// CHECK:        [[set:%\d+]] = OpExtInstImport "OpenCL.DebugInfo.100"
+// CHECK:    [[intName:%\d+]] = OpString "int"
+// CHECK:  [[floatName:%\d+]] = OpString "float"
+// CHECK:            %uint_32 = OpConstant %uint 32
+// CHECK: [[intType:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic [[intName]] %uint_32 Signed
+// CHECK:    [[int4:%\d+]] = OpExtInst %void [[set]] DebugTypeVector [[intType]] 4
+// CHECK: [[floatType:%\d+]] = OpExtInst %void [[set]] DebugTypeBasic [[floatName]] %uint_32 Float
+// CHECK:    [[float3:%\d+]] = OpExtInst %void [[set]] DebugTypeVector [[floatType]] 3
+
+float4 main(float4 color : COLOR) : SV_TARGET {
+  float3 b = 0.xxx;
+  int4 a = 0.xxxx;
+
+  return color;
+}

+ 0 - 2
tools/clang/test/CodeGenSPIRV/spirv.debug.ctrl.line.hlsl

@@ -6,8 +6,6 @@
 // CHECK:      OpSource HLSL 610 [[file]]
 // Have source code
 // CHECK:      float4 main(uint val
-// No tool
-// CHECK-NOT:  OpModuleProcessed
 // Have line
 // CHECK:      OpLine
 

+ 0 - 17
tools/clang/test/CodeGenSPIRV/spirv.debug.ctrl.source.hlsl

@@ -1,17 +0,0 @@
-// Run: %dxc -T ps_6_1 -E main -fspv-target-env=vulkan1.1 -fspv-debug=source
-
-// Have file path
-// CHECK:      [[file:%\d+]] = OpString
-// CHECK-SAME: spirv.debug.ctrl.source.hlsl
-// CHECK:      OpSource HLSL 610 [[file]]
-// Have source code
-// CHECK:      float4 main(uint val
-// No tool
-// CHECK-NOT: OpModuleProcessed
-// No line
-// CHECK-NOT: OpLine
-
-float4 main(uint val : A) : SV_Target {
-  uint a = reversebits(val);
-  return a;
-}

+ 2 - 1
tools/clang/test/CodeGenSPIRV/spirv.debug.o3.option.hlsl

@@ -11,7 +11,8 @@ struct VSOUT {
   float4 color : COLOR;
 };
 
-// CHECK:      OpLine [[file]] 15 1
+// TODO: After correctly propagate the line information in spirv-opt,
+//       add checking OpLine instructions.
 VSOUT main(float4 pos   : POSITION,
            float4 color : COLOR)
 {

+ 5 - 28
tools/clang/test/CodeGenSPIRV/spirv.debug.opline.entry.hlsl

@@ -3,39 +3,16 @@
 // CHECK:      [[file:%\d+]] = OpString
 // CHECK-SAME: spirv.debug.opline.entry.hlsl
 
-// CHECK:                          OpLine [[file]] 29 1
-// CHECK-NEXT:             %main = OpFunction %void None %16
-// CHECK-NEXT:          {{%\d+}} = OpLabel
-// CHECK-NEXT:                     OpLine [[file]] 29 20
-// CHECK-NEXT:      %param_var_a = OpVariable %_ptr_Function_v2float Function
-// CHECK-NEXT:                     OpLine [[file]] 30 20
-// CHECK-NEXT:      %param_var_b = OpVariable %_ptr_Function_v3float Function
-// CHECK-NEXT:                     OpLine [[file]] 31 20
-// CHECK-NEXT:      %param_var_c = OpVariable %_ptr_Function_v4float Function
-// CHECK-NEXT:                     OpLine [[file]] 29 20
-// CHECK-NEXT: [[texcoord:%\d+]] = OpLoad %v2float %in_var_TEXCOORD0
-// CHECK-NEXT:                     OpStore %param_var_a [[texcoord]]
-// CHECK-NEXT:                     OpLine [[file]] 30 20
-// CHECK-NEXT:   [[normal:%\d+]] = OpLoad %v3float %in_var_NORMAL
-// CHECK-NEXT:                     OpStore %param_var_b [[normal]]
-// CHECK-NEXT:                     OpLine [[file]] 31 20
-// CHECK-NEXT:    [[color:%\d+]] = OpLoad %v4float %in_var_COLOR
-// CHECK-NEXT:                     OpStore %param_var_c [[color]]
-// CHECK-NEXT:                     OpLine [[file]] 29 1
-// CHECK-NEXT:   [[result:%\d+]] = OpFunctionCall %v4float %src_main %param_var_a %param_var_b %param_var_c
-// CHECK-NEXT:                     OpLine [[file]] 31 33
-// CHECK-NEXT:                     OpStore %out_var_SV_Target [[result]]
-// CHECK-NEXT:                     OpReturn
 float4 main(float2 a : TEXCOORD0,
             float3 b : NORMAL,
             float4 c : COLOR) : SV_Target {
-// CHECK:                  OpLine [[file]] 29 1
-// CHECK-NEXT: %src_main = OpFunction %v4float None %29
-// CHECK-NEXT:             OpLine [[file]] 29 20
+// CHECK:                  OpLine [[file]] 6 1
+// CHECK-NEXT: %src_main = OpFunction %v4float None
+// CHECK-NEXT:             OpLine [[file]] 6 20
 // CHECK-NEXT:        %a = OpFunctionParameter %_ptr_Function_v2float
-// CHECK-NEXT:             OpLine [[file]] 30 20
+// CHECK-NEXT:             OpLine [[file]] 7 20
 // CHECK-NEXT:        %b = OpFunctionParameter %_ptr_Function_v3float
-// CHECK-NEXT:             OpLine [[file]] 31 20
+// CHECK-NEXT:             OpLine [[file]] 8 20
 // CHECK-NEXT:        %c = OpFunctionParameter %_ptr_Function_v4float
   float4 d = float4(a, b.xy + c.zw);
   return d;

+ 12 - 75
tools/clang/test/CodeGenSPIRV/spirv.debug.opline.function.hlsl

@@ -5,14 +5,12 @@
 
 void foo(in float4 a, out float3 b);
 
-// CHECK:              OpLine [[file]] 30 1
-// CHECK-NEXT: %main = OpFunction %void None
+// CHECK:                  OpLine [[file]] 28 1
+// CHECK-NEXT: %src_main = OpFunction %void None
 
 void bar(int a, in float b, inout bool2 c, const float3 d, out uint4 e) {
 }
 
-float4 getV4f(float x, int y, bool z);
-
 struct R {
   int a;
   void incr();
@@ -31,102 +29,41 @@ void main() {
   float4 v4f;
   float3 v3f;
 
-// CHECK:                     OpLine [[file]] 36 7
-// CHECK-NEXT: %param_var_a = OpVariable %_ptr_Function_v4float Function
   foo(v4f, v3f);
-// CHECK:                     OpLine [[file]] 39 14
-// CHECK-NEXT: %param_var_x = OpVariable %_ptr_Function_float Function
-  foo(getV4f(v4f.x,
-// CHECK:                     OpLine [[file]] 46 21
-// CHECK-NEXT: %param_var_x_0 = OpVariable %_ptr_Function_float Function
-// CHECK-NEXT:                OpLine [[file]] 46 28
-// CHECK-NEXT: %param_var_y = OpVariable %_ptr_Function_int Function
-// CHECK-NEXT:                OpLine [[file]] 46 35
-// CHECK-NEXT: %param_var_z = OpVariable %_ptr_Function_bool Function
-             getV4f(v4f.y, v4f.z, v4f.w).z,
-// CHECK:                     OpLine [[file]] 46 14
-// CHECK-NEXT: %param_var_y_0 = OpVariable %_ptr_Function_int Function
-// CHECK-NEXT:                OpLine [[file]] 51 14
-// CHECK-NEXT: %param_var_z_0 = OpVariable %_ptr_Function_bool Function
-             v3f.y),
-      v3f);
-// CHECK-NEXT:                OpLine [[file]] 39 7
-// CHECK-NEXT: %param_var_a_0 = OpVariable %_ptr_Function_v4float Function
-
   r[0].incr();
-  decr(r[0],
-// CHECK-NEXT:                OpLine [[file]] 62 13
-// CHECK-NEXT: %param_var_i = OpVariable %_ptr_Function_uint Function
-// CHECK-NEXT:                OpLine [[file]] 62 8
-// CHECK-NEXT: %param_var_b = OpVariable %_ptr_Function_R_0 Function
-       getR(1),
-       r[2],
-// CHECK-NEXT:                OpLine [[file]] 68 13
-// CHECK-NEXT: %param_var_i_0 = OpVariable %_ptr_Function_uint Function
-// CHECK-NEXT:                OpLine [[file]] 68 8
-// CHECK-NEXT: %param_var_d = OpVariable %_ptr_Function_R_0 Function
-       getR(3),
-// CHECK-NEXT:                OpLine [[file]] 73 13
-// CHECK-NEXT: %param_var_i_1 = OpVariable %_ptr_Function_uint Function
-// CHECK-NEXT:                OpLine [[file]] 73 8
-// CHECK-NEXT: %param_var_e = OpVariable %_ptr_Function_R_0 Function
-       getR(4));
+  decr(r[0], getR(1), r[2], getR(3), getR(4));
 
   rwsb[0].incr();
-
-  decr(rwsb[1],
-// CHECK-NEXT:                OpLine [[file]] 80 8
-// CHECK-NEXT: %param_var_b_0 = OpVariable %_ptr_Function_R_0 Function
-       rwsb[2],
-       rwsb[3],
-// CHECK-NEXT:                OpLine [[file]] 84 8
-// CHECK-NEXT: %param_var_d_0 = OpVariable %_ptr_Function_R_0 Function
-       rwsb[4],
-// CHECK-NEXT:                OpLine [[file]] 87 8
-// CHECK-NEXT: %param_var_e_0 = OpVariable %_ptr_Function_R_0 Function
-       rwsb[5]);
 }
 
-// CHECK:             OpLine [[file]] 96 1
+// CHECK:             OpLine [[file]] 45 1
 // CHECK-NEXT: %foo = OpFunction %void None
-// CHECK-NEXT:        OpLine [[file]] 96 20
+// CHECK-NEXT:        OpLine [[file]] 45 20
 // CHECK-NEXT:   %a = OpFunctionParameter %_ptr_Function_v4float
-// CHECK-NEXT:        OpLine [[file]] 96 34
+// CHECK-NEXT:        OpLine [[file]] 45 34
 // CHECK-NEXT:   %b = OpFunctionParameter %_ptr_Function_v3float
 void foo(in float4 a, out float3 b) {
   a = b.xxzz;
   b = a.yzw;
-// CHECK:                     OpLine [[file]] 103 7
-// CHECK-NEXT: %param_var_a_1 = OpVariable %_ptr_Function_int Function
-// CHECK-NEXT:                OpLine [[file]] 103 12
-// CHECK-NEXT: %param_var_b_1 = OpVariable %_ptr_Function_float Function
   bar(a.x, b.y, a.yz, b, a);
 }
 
-// CHECK:                     OpLine [[file]] 112 1
-// CHECK-NEXT:      %getV4f = OpFunction %v4float None
-// CHECK-NEXT:                OpLine [[file]] 112 21
-// CHECK-NEXT:           %x = OpFunctionParameter %_ptr_Function_float
-// CHECK-NEXT:                OpLine [[file]] 112 28
-// CHECK-NEXT:           %y = OpFunctionParameter %_ptr_Function_int
-float4 getV4f(float x, int y, bool z) { return float4(x, y, z, z); }
-
-// CHECK:                     OpLine [[file]] 117 1
+// CHECK:                     OpLine [[file]] 54 1
 // CHECK-NEXT:      %R_incr = OpFunction %void None
 // CHECK-NEXT:  %param_this = OpFunctionParameter %_ptr_Function_R_0
 void R::incr() { ++a; }
 
-// CHECK:                     OpLine [[file]] 123 1
+// CHECK:                     OpLine [[file]] 60 1
 // CHECK-NEXT:        %getR = OpFunction %R_0 None
-// CHECK-NEXT:                OpLine [[file]] 123 13
+// CHECK-NEXT:                OpLine [[file]] 60 13
 // CHECK-NEXT:           %i = OpFunctionParameter %_ptr_Function_uint
 R getR(uint i) { return r[i]; }
 
-// CHECK:                     OpLine [[file]] 131 1
+// CHECK:                     OpLine [[file]] 68 1
 // CHECK-NEXT:        %decr = OpFunction %void None
-// CHECK-NEXT:                OpLine [[file]] 131 19
+// CHECK-NEXT:                OpLine [[file]] 68 19
 // CHECK-NEXT:         %a_0 = OpFunctionParameter %_ptr_Function_R_0
-// CHECK-NEXT:                OpLine [[file]] 131 27
+// CHECK-NEXT:                OpLine [[file]] 68 27
 // CHECK-NEXT:         %b_0 = OpFunctionParameter %_ptr_Function_R_0
 void decr(inout R a, in R b, out R c, R d, const R e) { a.a--; }
 

+ 8 - 29
tools/clang/test/CodeGenSPIRV/spirv.debug.opline.include.hlsl

@@ -2,19 +2,19 @@
 
 // CHECK:      [[main:%\d+]] = OpString
 // CHECK-SAME: spirv.debug.opline.include.hlsl
+// CHECK-NEXT: OpSource HLSL 600 [[main]] "// Run: %dxc -T ps_6_0 -E main -Zi
+// CHECK:      [[file1:%\d+]] = OpString
+// CHECK-SAME: spirv.debug.opline.include-file-1.hlsl
+// CHECK-NEXT: OpSource HLSL 600 [[file1]] "int function1() {
 // CHECK:      [[file2:%\d+]] = OpString
 // CHECK-SAME: spirv.debug.opline.include-file-2.hlsl
+// CHECK-NEXT: OpSource HLSL 600 [[file2]] "static int a;
 // CHECK:      [[file3:%\d+]] = OpString
 // CHECK-SAME: spirv.debug.opline.include-file-3.hlsl
-// CHECK:      [[file1:%\d+]] = OpString
-// CHECK-SAME: spirv.debug.opline.include-file-1.hlsl
+// CHECK-NEXT: OpSource HLSL 600 [[file3]] "groupshared int b;
 
-// CHECK:              OpLine [[file2]] 1 12
-// CHECK-NEXT:    %a = OpVariable %_ptr_Private_int Private
-// CHECK:              OpLine [[file3]] 1 17
-// CHECK-NEXT:    %b = OpVariable %_ptr_Workgroup_int Workgroup
-// CHECK:              OpLine [[main]] 65 1
-// CHECK-NEXT: %main = OpFunction %void None
+// CHECK:                  OpLine [[main]] 65 1
+// CHECK-NEXT: %src_main = OpFunction %void None
 
 #include "spirv.debug.opline.include-file-1.hlsl"
 
@@ -90,27 +90,6 @@ void main() {
   callFunction3();
 }
 
-// CHECK:      OpLine [[main]] 21 1
-// CHECK-NEXT: %callFunction1 = OpFunction %int None
-// CHECK:      OpLine [[main]] 22 10
-// CHECK-NEXT: OpFunctionCall %int %function1
-// CHECK:      OpLine [[main]] 22 3
-// CHECK-NEXT: OpReturnValue
-
-// CHECK:      OpLine [[main]] 27 1
-// CHECK-NEXT: %callFunction2 = OpFunction %int None
-// CHECK:      OpLine [[main]] 42 10
-// CHECK-NEXT: OpFunctionCall %int %function2
-// CHECK:      OpLine [[main]] 42 3
-// CHECK-NEXT: OpReturnValue
-
-// CHECK:      OpLine [[main]] 47 1
-// CHECK-NEXT: %callFunction3 = OpFunction %int None
-// CHECK:      OpLine [[main]] 62 10
-// CHECK-NEXT: OpFunctionCall %int %function3
-// CHECK:      OpLine [[main]] 62 3
-// CHECK-NEXT: OpReturnValue
-
 // CHECK:      OpLine [[file1]] 1 1
 // CHECK-NEXT: %function1 = OpFunction %int None
 

+ 24 - 82
tools/clang/test/CodeGenSPIRV/spirv.debug.opline.variables.hlsl

@@ -3,93 +3,35 @@
 // CHECK:      [[file:%\d+]] = OpString
 // CHECK-SAME: spirv.debug.opline.variables.hlsl
 
-struct S {
-  float4 f;
-};
-
-// CHECK:                        OpLine [[file]] 12 32
-// CHECK-NEXT: %consume_v2bool = OpVariable %_ptr_Uniform_type_ConsumeStructuredBuffer_v2bool Uniform
-ConsumeStructuredBuffer<bool2> consume_v2bool;
-
-// CHECK:                        OpLine [[file]] 16 32
-// CHECK-NEXT: %append_v2float = OpVariable %_ptr_Uniform_type_AppendStructuredBuffer_v2float Uniform
-AppendStructuredBuffer<float2> append_v2float;
-
-// CHECK:                       OpLine [[file]] 20 19
-// CHECK-NEXT: %byte_addr_buf = OpVariable %_ptr_Uniform_type_ByteAddressBuffer Uniform
-ByteAddressBuffer byte_addr_buf;
-
-// CHECK:                    OpLine [[file]] 24 19
-// CHECK-NEXT: %rw_texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
-RWTexture2D<int3> rw_texture;
-
-// TODO(jaebaek): Check DeclResultIdMapper::create.*Var()
-//                we must emit "OpLine .." here.
-TextureBuffer<S> texture_buf;
-
-// CHECK:             OpLine [[file]] 32 14
-// CHECK-NEXT: %sam = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
-SamplerState sam;
-
-// CHECK:                     OpLine [[file]] 36 19
-// CHECK-NEXT: %float_array = OpVariable %_ptr_Workgroup__arr_float_uint_10 Workgroup
-groupshared float float_array[10];
-
-// CHECK:                     OpLine [[file]] 40 12
-// CHECK-NEXT:   %int_array = OpVariable %_ptr_Private__arr_int_uint_10 Private
-static int int_array[10];
-
-// "static" variables in functions must be defined first.
-// CHECK:                     OpLine [[file]] 61 16
-// CHECK-NEXT:           %c = OpVariable %_ptr_Private_v3bool Private
-// CHECK-NEXT: %init_done_c = OpVariable %_ptr_Private_bool Private %false
-
-bool3 test_function_variables() {
-// CHECK:                     OpLine [[file]] 50 9
-// CHECK-NEXT:         %a_0 = OpVariable %_ptr_Function_v3bool Function
-  bool3 a;
-
-// CHECK-NEXT:                OpLine [[file]] 54 22
-// CHECK-NEXT:         %b_0 = OpVariable %_ptr_Function_mat2v3float Function
-  row_major float2x3 b;
-
-// CHECK:                      OpLine [[file]] 61 20
-// CHECK-NEXT: [[init:%\d+]] = OpLoad %bool %init_done_c
-// CHECK-NEXT:                 OpSelectionMerge %if_init_done None
-// CHECK-NEXT:                 OpBranchConditional [[init]] %if_init_done %if_init_todo
-// CHECK-NEXT: %if_init_todo = OpLabel
-  static bool3 c = bool3(true, consume_v2bool.Consume());
-
-// CHECK:      %if_init_done = OpLabel
-
-  c = a && c;
-  return c;
+float test_function_variables() {
+// CHECK:                 OpLine [[file]] 9 22
+// CHECK-NEXT: {{%\d+}} = OpLoad %bool %init_done_foo
+  static float foo = 2.f;
+  return foo;
 }
 
-// CHECK:                     OpLine [[file]] 75 1
+// CHECK:                     OpLine [[file]] 19 1
 // CHECK-NEXT: %test_function_param = OpFunction %v2float None
-// CHECK-NEXT:                OpLine [[file]] 75 35
-// CHECK-NEXT:         %a_1 = OpFunctionParameter %_ptr_Function_v2float
-// CHECK-NEXT:                OpLine [[file]] 75 50
-// CHECK-NEXT:         %b_1 = OpFunctionParameter %_ptr_Function_v3bool
+// CHECK-NEXT:                OpLine [[file]] 19 35
+// CHECK-NEXT:           %a = OpFunctionParameter %_ptr_Function_v2float
+// CHECK-NEXT:                OpLine [[file]] 19 50
+// CHECK-NEXT:           %b = OpFunctionParameter %_ptr_Function_v3bool
 float2 test_function_param(float2 a, inout bool3 b,
-// CHECK-NEXT:                OpLine [[file]] 80 38
-// CHECK-NEXT:         %c_1 = OpFunctionParameter %_ptr_Function_int
-// CHECK-NEXT:                OpLine [[file]] 80 52
-// CHECK-NEXT:         %d_0 = OpFunctionParameter %_ptr_Function_v3float
-                           const int c, out float3 d,
-// CHECK-NEXT:                OpLine [[file]] 83 33
-// CHECK-NEXT:           %e = OpFunctionParameter %_ptr_Function_bool
-                           bool e) {
-// CHECK:                     OpLine [[file]] 86 9
-// CHECK-NEXT:           %f = OpVariable %_ptr_Function__arr_float_uint_2 Function
-  float f[2];
-  return a + d.xy + float2(f);
+// CHECK-NEXT:                OpLine [[file]] 24 38
+// CHECK-NEXT:           %c = OpFunctionParameter %_ptr_Function_int
+// CHECK-NEXT:                OpLine [[file]] 24 52
+// CHECK-NEXT:           %d = OpFunctionParameter %_ptr_Function_v3float
+                           const int c, out float3 d) {
+// CHECK:      OpLine [[file]] 27 9
+// CHECK-NEXT: OpStore %f
+  float f = a.x;
+  return a + d.xy + float2(f, a.y);
 }
 
 void main() {
-  bool a;
-  bool3 b = test_function_variables();
-  float3 c;
-  float2 d = test_function_param(float2(1, 0), b, 13, c, a);
+  float bar = test_function_variables();
+
+  bool3 param_b;
+  float3 param_d;
+  test_function_param(float2(1, 0), param_b, 13, param_d);
 }

+ 1 - 4
tools/clang/test/CodeGenSPIRV/spirv.debug.opsource.hlsl

@@ -2,10 +2,7 @@
 
 // CHECK:      [[str:%\d+]] = OpString
 // CHECK-SAME: spirv.debug.opsource.hlsl
-// CHECK:      OpSource HLSL 610 [[str]]
-
-// Make sure we have #line directive emitted by the preprocessor
-// CHECK-SAME: #line 1
+// CHECK:      OpSource HLSL 610 [[str]] "// Run: %dxc -T cs_6_1 -E main -Zi
 
 // Make sure we have the original source code
 // CHECK:      numthreads(8, 1, 1)

+ 1 - 0
tools/clang/unittests/SPIRV/CMakeLists.txt

@@ -14,6 +14,7 @@ add_clang_unittest(clang-spirv-tests
   SpirvContextTest.cpp
   SpirvTestOptions.cpp
   SpirvTypeTest.cpp
+  SpirvDebugInstructionTest.cpp
   SpirvConstantTest.cpp
   StringTest.cpp
   TestMain.cpp

+ 139 - 4
tools/clang/unittests/SPIRV/CodeGenSpirvTest.cpp

@@ -1625,10 +1625,6 @@ TEST_F(FileTest, SpirvDebugControlFile) {
   useVulkan1p1();
   runFileTest("spirv.debug.ctrl.file.hlsl");
 }
-TEST_F(FileTest, SpirvDebugControlSource) {
-  useVulkan1p1();
-  runFileTest("spirv.debug.ctrl.source.hlsl");
-}
 TEST_F(FileTest, SpirvDebugControlLine) {
   useVulkan1p1();
   runFileTest("spirv.debug.ctrl.line.hlsl");
@@ -2407,4 +2403,143 @@ TEST_F(FileTest, CompatibilityWithVk1p1) {
   runFileTest("sm6.wave.builtin.no-dup.vulkan1.2.hlsl");
 }
 
+// Tests for Rich Debug Information
+// TODO: change |runValidation| parameter back to 'true' once the following bug
+// has been fixed in SPIRV-Tools:
+// https://github.com/KhronosGroup/SPIRV-Tools/issues/3086
+const bool runValidationForRichDebugInfo = true;
+
+TEST_F(FileTest, RichDebugInfoDebugSource) {
+  runFileTest("rich.debug.debugsource.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoDebugCompilationUnit) {
+  runFileTest("rich.debug.debugcompilationunit.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoDebugLexicalBlock) {
+  runFileTest("rich.debug.debuglexicalblock.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoTypeBool) {
+  runFileTest("rich.debug.type.bool.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoTypeInt) {
+  runFileTest("rich.debug.type.int.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoTypeFloat) {
+  runFileTest("rich.debug.type.float.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoTypeVector) {
+  runFileTest("rich.debug.type.vector.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoTypeMatrix) {
+  runFileTest("rich.debug.type.matrix.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoTypeArray) {
+  runFileTest("rich.debug.type.array.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoTypeArrayFromSameType) {
+  runFileTest("rich.debug.type.array-from-same-type.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoTypeFunction) {
+  runFileTest("rich.debug.type.function.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoTypeMemberFunction) {
+  runFileTest("rich.debug.type.member.function.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoTypeCompositeBeforeFunction) {
+  runFileTest("rich.debug.type.composite.before.function.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoMemberFunctionParam) {
+  runFileTest("rich.debug.member.function.param.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, DISABLED_RichDebugInfoMemberFunctionWithoutCall) {
+  runFileTest("rich.debug.member.function.without-call.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoTypeComposite) {
+  runFileTest("rich.debug.type.composite.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoTypeCompositeEmpty) {
+  runFileTest("rich.debug.type.composite.empty.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoTypeStructuredBuffer) {
+  runFileTest("rich.debug.structured-buffer.hlsl", Expect::Success,
+              /*runValidation*/ false);
+}
+TEST_F(FileTest, RichDebugInfoLocalVariable) {
+  runFileTest("rich.debug.local-variable.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoGlobalVariable) {
+  runFileTest("rich.debug.global-variable.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoFunction) {
+  runFileTest("rich.debug.function.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoFunctionParent) {
+  runFileTest("rich.debug.function.parent.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoFunctionParam) {
+  runFileTest("rich.debug.function.param.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoDebugSourceMultiple) {
+  runFileTest("rich.debug.debugsource.multiple.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoDeclare) {
+  runFileTest("rich.debug.debugdeclare.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoDeclareWithoutInit) {
+  runFileTest("rich.debug.debugdeclare.without.init.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoScope) {
+  runFileTest("rich.debug.debugscope.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoTypeTexture) {
+  runFileTest("rich.debug.texture.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoTypeRWTexture) {
+  runFileTest("rich.debug.rwtexture.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoTypeSampler) {
+  runFileTest("rich.debug.sampler.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoCbuffer) {
+  runFileTest("rich.debug.cbuffer.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoSortTypeTemplate) {
+  runFileTest("rich.debug.sort.type.template.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+TEST_F(FileTest, RichDebugInfoSwitchDebugScope) {
+  runFileTest("rich.debug.switch.debugscope.hlsl", Expect::Success,
+              /*runValidation*/ runValidationForRichDebugInfo);
+}
+
 } // namespace

+ 44 - 0
tools/clang/unittests/SPIRV/SpirvDebugInstructionTest.cpp

@@ -0,0 +1,44 @@
+//===- unittests/SPIRV/SpirvDebugInstructionTest.cpp - test debug insts --===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "SpirvTestBase.h"
+#include "clang/SPIRV/SpirvBuilder.h"
+#include "clang/SPIRV/SpirvInstruction.h"
+#include "clang/SPIRV/SpirvType.h"
+
+using namespace clang::spirv;
+
+namespace {
+
+class SpirvDebugInstructionTest : public SpirvTestBase {
+public:
+  SpirvDebugInstructionTest()
+      : spirvBuilder(getAstContext(), getSpirvContext(), {}) {}
+  SpirvBuilder *GetSpirvBuilder() { return &spirvBuilder; }
+
+private:
+  SpirvBuilder spirvBuilder;
+};
+
+TEST_F(SpirvDebugInstructionTest, DynamicTypeCheckDebugInfoNone) {
+  SpirvInstruction *i = GetSpirvBuilder()->getOrCreateDebugInfoNone();
+  EXPECT_TRUE(llvm::isa<SpirvDebugInfoNone>(i));
+  EXPECT_TRUE(llvm::isa<SpirvDebugInstruction>(i));
+  EXPECT_TRUE(llvm::isa<SpirvInstruction>(i));
+}
+
+TEST_F(SpirvDebugInstructionTest, DynamicTypeCheckDebugTypeTemplateParameter) {
+  SpirvInstruction *i = new (getSpirvContext()) SpirvDebugTypeTemplateParameter(
+      "vtable check", nullptr, nullptr, nullptr, 0, 0);
+  EXPECT_TRUE(llvm::isa<SpirvDebugTypeTemplateParameter>(i));
+  EXPECT_TRUE(llvm::isa<SpirvDebugInstruction>(i));
+  EXPECT_TRUE(llvm::isa<SpirvInstruction>(i));
+}
+
+} // anonymous namespace

Some files were not shown because too many files changed in this diff