Add common enum for debug info instructions from either opencl or vulkan (#4377)

Co-authored-by: baldurk <baldurk@baldurk.org>
diff --git a/BUILD.bazel b/BUILD.bazel
index 145ef74..4075441 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -69,7 +69,7 @@
 
 generate_extinst_lang_headers("OpenCLDebugInfo100", CLDEBUGINFO100_GRAMMAR_JSON_FILE)
 
-generate_extinst_lang_headers("VulkanDebugInfo100", VKDEBUGINFO100_GRAMMAR_JSON_FILE)
+generate_extinst_lang_headers("NonSemanticVulkanDebugInfo100", VKDEBUGINFO100_GRAMMAR_JSON_FILE)
 
 py_binary(
     name = "generate_registry_tables",
@@ -107,7 +107,7 @@
         ":gen_enum_string_mapping",
         ":gen_extinst_lang_headers_DebugInfo",
         ":gen_extinst_lang_headers_OpenCLDebugInfo100",
-        ":gen_extinst_lang_headers_VulkanDebugInfo100",
+        ":gen_extinst_lang_headers_NonSemanticVulkanDebugInfo100",
         ":gen_glsl_tables_unified1",
         ":gen_opencl_tables_unified1",
         ":gen_registry_tables",
diff --git a/BUILD.gn b/BUILD.gn
index fb6d03f..270814f 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -416,6 +416,7 @@
     "source/binary.cpp",
     "source/binary.h",
     "source/cfa.h",
+    "source/common_debug_info.h",
     "source/diagnostic.cpp",
     "source/diagnostic.h",
     "source/disassemble.cpp",
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index 163505f..e4568e3 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -234,6 +234,7 @@
   ${CMAKE_CURRENT_SOURCE_DIR}/assembly_grammar.h
   ${CMAKE_CURRENT_SOURCE_DIR}/binary.h
   ${CMAKE_CURRENT_SOURCE_DIR}/cfa.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/common_debug_info.h
   ${CMAKE_CURRENT_SOURCE_DIR}/diagnostic.h
   ${CMAKE_CURRENT_SOURCE_DIR}/disassemble.h
   ${CMAKE_CURRENT_SOURCE_DIR}/enum_set.h
diff --git a/source/common_debug_info.h b/source/common_debug_info.h
new file mode 100644
index 0000000..0ae85aa
--- /dev/null
+++ b/source/common_debug_info.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2021 The Khronos Group Inc.
+// Copyright (c) 2021 Valve Corporation
+// Copyright (c) 2021 LunarG Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_COMMON_DEBUG_INFO_HEADER_H_
+#define SOURCE_COMMON_DEBUG_INFO_HEADER_H_
+
+// This enum defines the known common set of instructions that are the same
+// between OpenCL.DebugInfo.100 and NonSemantic.Vulkan.DebugInfo.100.
+// note that NonSemantic.DebugInfo.100 instructions can still have slightly
+// different encoding, as it does not use literals anywhere and only constants.
+enum CommonDebugInfoInstructions {
+  CommonDebugInfoDebugInfoNone = 0,
+  CommonDebugInfoDebugCompilationUnit = 1,
+  CommonDebugInfoDebugTypeBasic = 2,
+  CommonDebugInfoDebugTypePointer = 3,
+  CommonDebugInfoDebugTypeQualifier = 4,
+  CommonDebugInfoDebugTypeArray = 5,
+  CommonDebugInfoDebugTypeVector = 6,
+  CommonDebugInfoDebugTypedef = 7,
+  CommonDebugInfoDebugTypeFunction = 8,
+  CommonDebugInfoDebugTypeEnum = 9,
+  CommonDebugInfoDebugTypeComposite = 10,
+  CommonDebugInfoDebugTypeMember = 11,
+  CommonDebugInfoDebugTypeInheritance = 12,
+  CommonDebugInfoDebugTypePtrToMember = 13,
+  CommonDebugInfoDebugTypeTemplate = 14,
+  CommonDebugInfoDebugTypeTemplateParameter = 15,
+  CommonDebugInfoDebugTypeTemplateTemplateParameter = 16,
+  CommonDebugInfoDebugTypeTemplateParameterPack = 17,
+  CommonDebugInfoDebugGlobalVariable = 18,
+  CommonDebugInfoDebugFunctionDeclaration = 19,
+  CommonDebugInfoDebugFunction = 20,
+  CommonDebugInfoDebugLexicalBlock = 21,
+  CommonDebugInfoDebugLexicalBlockDiscriminator = 22,
+  CommonDebugInfoDebugScope = 23,
+  CommonDebugInfoDebugNoScope = 24,
+  CommonDebugInfoDebugInlinedAt = 25,
+  CommonDebugInfoDebugLocalVariable = 26,
+  CommonDebugInfoDebugInlinedVariable = 27,
+  CommonDebugInfoDebugDeclare = 28,
+  CommonDebugInfoDebugValue = 29,
+  CommonDebugInfoDebugOperation = 30,
+  CommonDebugInfoDebugExpression = 31,
+  CommonDebugInfoDebugMacroDef = 32,
+  CommonDebugInfoDebugMacroUndef = 33,
+  CommonDebugInfoDebugImportedEntity = 34,
+  CommonDebugInfoDebugSource = 35,
+  CommonDebugInfoInstructionsMax = 0x7ffffff
+};
+
+#endif  // SOURCE_COMMON_DEBUG_INFO_HEADER_H_
diff --git a/source/opt/feature_manager.cpp b/source/opt/feature_manager.cpp
index ad70c1e..db3abdd 100644
--- a/source/opt/feature_manager.cpp
+++ b/source/opt/feature_manager.cpp
@@ -80,6 +80,8 @@
   extinst_importid_GLSLstd450_ = module->GetExtInstImportId("GLSL.std.450");
   extinst_importid_OpenCL100DebugInfo_ =
       module->GetExtInstImportId("OpenCL.DebugInfo.100");
+  extinst_importid_Vulkan100DebugInfo_ =
+      module->GetExtInstImportId("NonSemantic.Vulkan.DebugInfo.100");
 }
 
 bool operator==(const FeatureManager& a, const FeatureManager& b) {
@@ -107,6 +109,11 @@
     return false;
   }
 
+  if (a.extinst_importid_Vulkan100DebugInfo_ !=
+      b.extinst_importid_Vulkan100DebugInfo_) {
+    return false;
+  }
+
   return true;
 }
 }  // namespace opt
diff --git a/source/opt/feature_manager.h b/source/opt/feature_manager.h
index 66d1cba..4720c6d 100644
--- a/source/opt/feature_manager.h
+++ b/source/opt/feature_manager.h
@@ -55,6 +55,10 @@
     return extinst_importid_OpenCL100DebugInfo_;
   }
 
+  uint32_t GetExtInstImportId_Vulkan100DebugInfo() const {
+    return extinst_importid_Vulkan100DebugInfo_;
+  }
+
   friend bool operator==(const FeatureManager& a, const FeatureManager& b);
   friend bool operator!=(const FeatureManager& a, const FeatureManager& b) {
     return !(a == b);
@@ -92,6 +96,10 @@
   // Common OpenCL100DebugInfo external instruction import ids, cached
   // for performance.
   uint32_t extinst_importid_OpenCL100DebugInfo_ = 0;
+
+  // Common NonSemanticVulkan100DebugInfo external instruction import ids,
+  // cached for performance.
+  uint32_t extinst_importid_Vulkan100DebugInfo_ = 0;
 };
 
 }  // namespace opt
diff --git a/source/opt/instruction.cpp b/source/opt/instruction.cpp
index 1054a20..f93ad01 100644
--- a/source/opt/instruction.cpp
+++ b/source/opt/instruction.cpp
@@ -16,6 +16,7 @@
 
 #include <initializer_list>
 
+#include "NonSemanticVulkanDebugInfo100.h"
 #include "OpenCLDebugInfo100.h"
 #include "source/disassemble.h"
 #include "source/opt/fold.h"
@@ -32,7 +33,8 @@
 const uint32_t kPointerTypeStorageClassIndex = 0;
 const uint32_t kTypeImageSampledIndex = 5;
 
-// Constants for OpenCL.DebugInfo.100 extension instructions.
+// Constants for OpenCL.DebugInfo.100 / NonSemantic.Vulkan.DebugInfo.100
+// extension instructions.
 const uint32_t kExtInstSetIdInIdx = 0;
 const uint32_t kExtInstInstructionInIdx = 1;
 const uint32_t kDebugScopeNumWords = 7;
@@ -618,6 +620,49 @@
       GetSingleWordInOperand(kExtInstInstructionInIdx));
 }
 
+NonSemanticVulkanDebugInfo100Instructions Instruction::GetVulkan100DebugOpcode()
+    const {
+  if (opcode() != SpvOpExtInst) {
+    return NonSemanticVulkanDebugInfo100InstructionsMax;
+  }
+
+  if (!context()->get_feature_mgr()->GetExtInstImportId_Vulkan100DebugInfo()) {
+    return NonSemanticVulkanDebugInfo100InstructionsMax;
+  }
+
+  if (GetSingleWordInOperand(kExtInstSetIdInIdx) !=
+      context()->get_feature_mgr()->GetExtInstImportId_Vulkan100DebugInfo()) {
+    return NonSemanticVulkanDebugInfo100InstructionsMax;
+  }
+
+  return NonSemanticVulkanDebugInfo100Instructions(
+      GetSingleWordInOperand(kExtInstInstructionInIdx));
+}
+
+CommonDebugInfoInstructions Instruction::GetCommonDebugOpcode() const {
+  if (opcode() != SpvOpExtInst) {
+    return CommonDebugInfoInstructionsMax;
+  }
+
+  const uint32_t opencl_set_id =
+      context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo();
+  const uint32_t vulkan_set_id =
+      context()->get_feature_mgr()->GetExtInstImportId_Vulkan100DebugInfo();
+
+  if (!opencl_set_id && !vulkan_set_id) {
+    return CommonDebugInfoInstructionsMax;
+  }
+
+  const uint32_t used_set_id = GetSingleWordInOperand(kExtInstSetIdInIdx);
+
+  if (used_set_id != opencl_set_id && used_set_id != vulkan_set_id) {
+    return CommonDebugInfoInstructionsMax;
+  }
+
+  return CommonDebugInfoInstructions(
+      GetSingleWordInOperand(kExtInstInstructionInIdx));
+}
+
 bool Instruction::IsValidBaseImage() const {
   uint32_t tid = type_id();
   if (tid == 0) {
diff --git a/source/opt/instruction.h b/source/opt/instruction.h
index 3e557dd..7cdfc44 100644
--- a/source/opt/instruction.h
+++ b/source/opt/instruction.h
@@ -22,7 +22,9 @@
 #include <utility>
 #include <vector>
 
+#include "NonSemanticVulkanDebugInfo100.h"
 #include "OpenCLDebugInfo100.h"
+#include "source/common_debug_info.h"
 #include "source/latest_version_glsl_std_450_header.h"
 #include "source/latest_version_spirv_header.h"
 #include "source/opcode.h"
@@ -550,10 +552,28 @@
   // OpenCLDebugInfo100InstructionsMax.
   OpenCLDebugInfo100Instructions GetOpenCL100DebugOpcode() const;
 
+  // Returns debug opcode of a NonSemantic.Vulkan.DebugInfo.100 instruction. If
+  // it is not a NonSemantic.Vulkan.DebugInfo.100 instruction, just returns
+  // NonSemanticVulkanDebugInfo100InstructionsMax.
+  NonSemanticVulkanDebugInfo100Instructions GetVulkan100DebugOpcode() const;
+
+  // Returns debug opcode of an OpenCL.100.DebugInfo or
+  // NonSemantic.Vulkan.DebugInfo.100 instruction. Since these overlap, we
+  // return the OpenCLDebugInfo code
+  CommonDebugInfoInstructions GetCommonDebugOpcode() const;
+
   // Returns true if it is an OpenCL.DebugInfo.100 instruction.
   bool IsOpenCL100DebugInstr() const {
     return GetOpenCL100DebugOpcode() != OpenCLDebugInfo100InstructionsMax;
   }
+  // Returns true if it is a NonSemantic.Vulkan.DebugInfo.100 instruction.
+  bool IsVulkan100DebugInstr() const {
+    return GetVulkan100DebugOpcode() !=
+           NonSemanticVulkanDebugInfo100InstructionsMax;
+  }
+  bool IsCommonDebugInstr() const {
+    return GetCommonDebugOpcode() != CommonDebugInfoInstructionsMax;
+  }
 
   // Returns true if this instructions a non-semantic instruction.
   bool IsNonSemanticInstruction() const;