浏览代码

Updated spirv-tools.

Бранимир Караџић 4 年之前
父节点
当前提交
e67311db7e

+ 1 - 1
3rdparty/spirv-tools/include/generated/build-version.inc

@@ -1 +1 @@
-"v2021.3-dev", "SPIRV-Tools v2021.3-dev 13e61006818199bd11c1f6f0148d1258d8200375"
+"v2021.3-dev", "SPIRV-Tools v2021.3-dev 25ef0e5c8566c2abe88852e3b72e0facccbbbcb9"

文件差异内容过多而无法显示
+ 2 - 0
3rdparty/spirv-tools/include/generated/enum_string_mapping.inc


+ 1 - 0
3rdparty/spirv-tools/include/generated/extension_enum.inc

@@ -44,6 +44,7 @@ kSPV_INTEL_kernel_attributes,
 kSPV_INTEL_long_constant_composite,
 kSPV_INTEL_loop_fuse,
 kSPV_INTEL_media_block_io,
+kSPV_INTEL_optnone,
 kSPV_INTEL_shader_integer_functions2,
 kSPV_INTEL_subgroups,
 kSPV_INTEL_unstructured_loop_controls,

+ 4 - 1
3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc

@@ -156,6 +156,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_INTEL_kernel_attributes
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_long_constant_composite[] = {spvtools::Extension::kSPV_INTEL_long_constant_composite};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_loop_fuse[] = {spvtools::Extension::kSPV_INTEL_loop_fuse};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_media_block_io[] = {spvtools::Extension::kSPV_INTEL_media_block_io};
+static const spvtools::Extension pygen_variable_exts_SPV_INTEL_optnone[] = {spvtools::Extension::kSPV_INTEL_optnone};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_shader_integer_functions2[] = {spvtools::Extension::kSPV_INTEL_shader_integer_functions2};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_subgroups[] = {spvtools::Extension::kSPV_INTEL_subgroups};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_unstructured_loop_controls[] = {spvtools::Extension::kSPV_INTEL_unstructured_loop_controls};
@@ -270,7 +271,8 @@ static const spv_operand_desc_t pygen_variable_FunctionControlEntries[] = {
   {"Inline", 0x0001, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
   {"DontInline", 0x0002, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
   {"Pure", 0x0004, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
-  {"Const", 0x0008, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}
+  {"Const", 0x0008, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
+  {"OptNoneINTEL", 0x10000, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}
 };
 
 static const spv_operand_desc_t pygen_variable_MemorySemanticsEntries[] = {
@@ -1118,6 +1120,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
   {"AtomicFloat32AddEXT", 6033, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_shader_atomic_float_add, {}, 0xffffffffu, 0xffffffffu},
   {"AtomicFloat64AddEXT", 6034, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_shader_atomic_float_add, {}, 0xffffffffu, 0xffffffffu},
   {"LongConstantCompositeINTEL", 6089, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_long_constant_composite, {}, 0xffffffffu, 0xffffffffu},
+  {"OptNoneINTEL", 6094, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_optnone, {}, 0xffffffffu, 0xffffffffu},
   {"AtomicFloat16AddEXT", 6095, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_shader_atomic_float16_add, {}, 0xffffffffu, 0xffffffffu},
   {"DebugInfoModuleINTEL", 6114, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_debug_module, {}, 0xffffffffu, 0xffffffffu}
 };

+ 48 - 0
3rdparty/spirv-tools/include/spirv-tools/linter.hpp

@@ -0,0 +1,48 @@
+// Copyright (c) 2021 Google LLC.
+//
+// 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 INCLUDE_SPIRV_TOOLS_LINTER_HPP_
+#define INCLUDE_SPIRV_TOOLS_LINTER_HPP_
+
+#include "libspirv.hpp"
+
+namespace spvtools {
+
+// C++ interface for SPIR-V linting functionalities. It wraps the context
+// (including target environment and the corresponding SPIR-V grammar) and
+// provides a method for linting.
+//
+// Instances of this class provides basic thread-safety guarantee.
+class Linter {
+ public:
+  explicit Linter(spv_target_env env);
+
+  ~Linter();
+
+  // Sets the message consumer to the given |consumer|. The |consumer| will be
+  // invoked once for each message communicated from the library.
+  void SetMessageConsumer(MessageConsumer consumer);
+
+  // Returns a reference to the registered message consumer.
+  const MessageConsumer& consumer() const;
+
+  bool Run(const uint32_t* binary, size_t binary_size);
+
+ private:
+  struct Impl;
+  std::unique_ptr<Impl> impl_;
+};
+}  // namespace spvtools
+
+#endif  // INCLUDE_SPIRV_TOOLS_LINTER_HPP_

+ 51 - 0
3rdparty/spirv-tools/source/lint/linter.cpp

@@ -0,0 +1,51 @@
+// Copyright (c) 2021 Google LLC.
+//
+// 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.
+
+#include "spirv-tools/linter.hpp"
+
+namespace spvtools {
+
+struct Linter::Impl {
+  explicit Impl(spv_target_env env) : target_env(env) {
+    message_consumer = [](spv_message_level_t /*level*/, const char* /*source*/,
+                          const spv_position_t& /*position*/,
+                          const char* /*message*/) {};
+  }
+
+  spv_target_env target_env;         // Target environment.
+  MessageConsumer message_consumer;  // Message consumer.
+};
+
+Linter::Linter(spv_target_env env) : impl_(new Impl(env)) {}
+
+Linter::~Linter() {}
+
+void Linter::SetMessageConsumer(MessageConsumer consumer) {
+  impl_->message_consumer = consumer;
+}
+
+const MessageConsumer& Linter::consumer() const {
+  return impl_->message_consumer;
+}
+
+bool Linter::Run(const uint32_t* binary, size_t binary_size) {
+  (void)binary;
+  (void)binary_size;
+
+  consumer()(SPV_MSG_INFO, "", {0, 0, 0}, "Hello, world!");
+
+  return true;
+}
+
+}  // namespace spvtools

+ 6 - 0
3rdparty/spirv-tools/source/operand.cpp

@@ -578,6 +578,12 @@ std::function<bool(unsigned)> spvOperandCanBeForwardDeclaredFunction(
 
 std::function<bool(unsigned)> spvDbgInfoExtOperandCanBeForwardDeclaredFunction(
     spv_ext_inst_type_t ext_type, uint32_t key) {
+  // The Vulkan debug info extended instruction set is non-semantic so allows no
+  // forward references ever.
+  if (ext_type == SPV_EXT_INST_TYPE_NONSEMANTIC_VULKAN_DEBUGINFO_100) {
+    return [](unsigned) { return false; };
+  }
+
   // TODO(https://gitlab.khronos.org/spirv/SPIR-V/issues/532): Forward
   // references for debug info instructions are still in discussion. We must
   // update the following lines of code when we conclude the spec.

+ 156 - 0
3rdparty/spirv-tools/source/opt/control_dependence.cpp

@@ -0,0 +1,156 @@
+// Copyright (c) 2021 Google LLC.
+//
+// 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.
+
+#include "source/opt/control_dependence.h"
+
+#include <cassert>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "source/opt/basic_block.h"
+#include "source/opt/cfg.h"
+#include "source/opt/dominator_analysis.h"
+#include "source/opt/function.h"
+#include "source/opt/instruction.h"
+#include "spirv/unified1/spirv.h"
+
+// Computes the control dependence graph (CDG) using the algorithm in Cytron
+// 1991, "Efficiently Computing Static Single Assignment Form and the Control
+// Dependence Graph." It relies on the fact that the control dependence sources
+// (blocks on which a block is control dependent) are exactly the post-dominance
+// frontier for that block. The explanation and proofs are given in Section 6 of
+// that paper.
+// Link: https://www.cs.utexas.edu/~pingali/CS380C/2010/papers/ssaCytron.pdf
+//
+// The algorithm in Section 4.2 of the same paper is used to construct the
+// dominance frontier. It uses the post-dominance tree, which is available in
+// the IR context.
+
+namespace spvtools {
+namespace opt {
+constexpr uint32_t ControlDependenceAnalysis::kPseudoEntryBlock;
+
+uint32_t ControlDependence::GetConditionID(const CFG& cfg) const {
+  if (source_bb_id() == 0) {
+    // Entry dependence; return 0.
+    return 0;
+  }
+  const BasicBlock* source_bb = cfg.block(source_bb_id());
+  const Instruction* branch = source_bb->terminator();
+  assert((branch->opcode() == SpvOpBranchConditional ||
+          branch->opcode() == SpvOpSwitch) &&
+         "invalid control dependence; last instruction must be conditional "
+         "branch or switch");
+  return branch->GetSingleWordInOperand(0);
+}
+
+bool ControlDependence::operator<(const ControlDependence& other) const {
+  return std::tie(source_bb_id_, target_bb_id_, branch_target_bb_id_) <
+         std::tie(other.source_bb_id_, other.target_bb_id_,
+                  other.branch_target_bb_id_);
+}
+
+bool ControlDependence::operator==(const ControlDependence& other) const {
+  return std::tie(source_bb_id_, target_bb_id_, branch_target_bb_id_) ==
+         std::tie(other.source_bb_id_, other.target_bb_id_,
+                  other.branch_target_bb_id_);
+}
+
+std::ostream& operator<<(std::ostream& os, const ControlDependence& dep) {
+  os << dep.source_bb_id() << "->" << dep.target_bb_id();
+  if (dep.branch_target_bb_id() != dep.target_bb_id()) {
+    os << " through " << dep.branch_target_bb_id();
+  }
+  return os;
+}
+
+void ControlDependenceAnalysis::ComputePostDominanceFrontiers(
+    const CFG& cfg, const PostDominatorAnalysis& pdom) {
+  // Compute post-dominance frontiers (reverse graph).
+  // The dominance frontier for a block X is equal to (Equation 4)
+  //   DF_local(X) U { B in DF_up(Z) | X = ipdom(Z) }
+  //   (ipdom(Z) is the immediate post-dominator of Z.)
+  // where
+  //   DF_local(X) = { Y | X -> Y in CFG, X does not strictly post-dominate Y }
+  //     represents the contribution of X's predecessors to the DF, and
+  //   DF_up(Z) = { Y | Y in DF(Z), ipdom(Z) does not strictly post-dominate Y }
+  //     (note: ipdom(Z) = X.)
+  //     represents the contribution of a block to its immediate post-
+  //     dominator's DF.
+  // This is computed in one pass through a post-order traversal of the
+  // post-dominator tree.
+
+  // Assert that there is a block other than the pseudo exit in the pdom tree,
+  // as we need one to get the function entry point (as the pseudo exit is not
+  // actually part of the function.)
+  assert(!cfg.IsPseudoExitBlock(pdom.GetDomTree().post_begin()->bb_));
+  Function* function = pdom.GetDomTree().post_begin()->bb_->GetParent();
+  uint32_t function_entry = function->entry()->id();
+  // Explicitly initialize pseudo-entry block, as it doesn't depend on anything,
+  // so it won't be initialized in the following loop.
+  reverse_nodes_[kPseudoEntryBlock] = {};
+  for (auto it = pdom.GetDomTree().post_cbegin();
+       it != pdom.GetDomTree().post_cend(); ++it) {
+    ComputePostDominanceFrontierForNode(cfg, pdom, function_entry, *it);
+  }
+}
+
+void ControlDependenceAnalysis::ComputePostDominanceFrontierForNode(
+    const CFG& cfg, const PostDominatorAnalysis& pdom, uint32_t function_entry,
+    const DominatorTreeNode& pdom_node) {
+  const uint32_t label = pdom_node.id();
+  ControlDependenceList& edges = reverse_nodes_[label];
+  for (uint32_t pred : cfg.preds(label)) {
+    if (!pdom.StrictlyDominates(label, pred)) {
+      edges.push_back(ControlDependence(pred, label));
+    }
+  }
+  if (label == function_entry) {
+    // Add edge from pseudo-entry to entry.
+    // In CDG construction, an edge is added from entry to exit, so only the
+    // exit node can post-dominate entry.
+    edges.push_back(ControlDependence(kPseudoEntryBlock, label));
+  }
+  for (DominatorTreeNode* child : pdom_node) {
+    // Note: iterate dependences by value, as we need a copy.
+    for (const ControlDependence& dep : reverse_nodes_[child->id()]) {
+      // Special-case pseudo-entry, as above.
+      if (dep.source_bb_id() == kPseudoEntryBlock ||
+          !pdom.StrictlyDominates(label, dep.source_bb_id())) {
+        edges.push_back(ControlDependence(dep.source_bb_id(), label,
+                                          dep.branch_target_bb_id()));
+      }
+    }
+  }
+}
+
+void ControlDependenceAnalysis::ComputeControlDependenceGraph(
+    const CFG& cfg, const PostDominatorAnalysis& pdom) {
+  ComputePostDominanceFrontiers(cfg, pdom);
+  ComputeForwardGraphFromReverse();
+}
+
+void ControlDependenceAnalysis::ComputeForwardGraphFromReverse() {
+  for (const auto& entry : reverse_nodes_) {
+    // Ensure an entry is created for each node.
+    forward_nodes_[entry.first];
+    for (const ControlDependence& dep : entry.second) {
+      forward_nodes_[dep.source_bb_id()].push_back(dep);
+    }
+  }
+}
+
+}  // namespace opt
+}  // namespace spvtools

+ 197 - 0
3rdparty/spirv-tools/source/opt/control_dependence.h

@@ -0,0 +1,197 @@
+// Copyright (c) 2021 Google LLC.
+//
+// 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_OPT_CONTROL_DEPENDENCE_H_
+#define SOURCE_OPT_CONTROL_DEPENDENCE_H_
+
+#include <algorithm>
+#include <cstdint>
+#include <functional>
+#include <ostream>
+#include <unordered_map>
+#include <vector>
+
+#include "source/opt/cfg.h"
+#include "source/opt/dominator_analysis.h"
+
+namespace spvtools {
+namespace opt {
+
+class ControlDependence {
+ public:
+  // The label of the source of this dependence, i.e. the block on which the
+  // target is dependent on.
+  // A |source_bb_id| of 0 represents an "entry" dependence, meaning that the
+  // execution of |target_bb_id| is only dependent on entry to the function.
+  uint32_t source_bb_id() const { return source_bb_id_; }
+  // The label of the target of this dependence, i.e. the block which is
+  // dependent on the source.
+  uint32_t target_bb_id() const { return target_bb_id_; }
+  // The label of the target of the *branch* for this dependence.
+  // Equal to the ID of the entry block for entry dependences.
+  //
+  // For example, for the partial CFG pictured below:
+  // 1 ---> 2 ---> 4 ---> 6
+  //  \      \            ^
+  //   \-> 3  \-> 5 -----/
+  // Block 6 is control dependent on block 1, but this dependence comes from the
+  // branch 1 -> 2, so in this case the branch target ID would be 2.
+  uint32_t branch_target_bb_id() const { return branch_target_bb_id_; }
+
+  // Create a direct control dependence from BB ID |source| to |target|.
+  ControlDependence(uint32_t source, uint32_t target)
+      : source_bb_id_(source),
+        target_bb_id_(target),
+        branch_target_bb_id_(target) {}
+  // Create a control dependence from BB ID |source| to |target| through the
+  // branch from |source| to |branch_target|.
+  ControlDependence(uint32_t source, uint32_t target, uint32_t branch_target)
+      : source_bb_id_(source),
+        target_bb_id_(target),
+        branch_target_bb_id_(branch_target) {}
+
+  // Gets the ID of the conditional value for the branch corresponding to this
+  // control dependence. This is the first input operand for both
+  // OpConditionalBranch and OpSwitch.
+  // Returns 0 for entry dependences.
+  uint32_t GetConditionID(const CFG& cfg) const;
+
+  bool operator==(const ControlDependence& other) const;
+  bool operator!=(const ControlDependence& other) const {
+    return !(*this == other);
+  }
+
+  // Comparison operators, ordered lexicographically. Total ordering.
+  bool operator<(const ControlDependence& other) const;
+  bool operator>(const ControlDependence& other) const { return other < *this; }
+  bool operator<=(const ControlDependence& other) const {
+    return !(*this > other);
+  }
+  bool operator>=(const ControlDependence& other) const {
+    return !(*this < other);
+  }
+
+ private:
+  uint32_t source_bb_id_;
+  uint32_t target_bb_id_;
+  uint32_t branch_target_bb_id_;
+};
+
+// Prints |dep| to |os| in a human-readable way. For example,
+//   1->2           (target_bb_id = branch_target_bb_id = 2)
+//   3->4 through 5 (target_bb_id = 4, branch_target_bb_id = 5)
+std::ostream& operator<<(std::ostream& os, const ControlDependence& dep);
+
+// Represents the control dependence graph. A basic block is control dependent
+// on another if the result of that block (e.g. the condition of a conditional
+// branch) influences whether it is executed or not. More formally, a block A is
+// control dependent on B iff:
+// 1. there exists a path from A to the exit node that does *not* go through B
+//    (i.e., A does not postdominate B), and
+// 2. there exists a path B -> b_1 -> ... -> b_n -> A such that A post-dominates
+//    all nodes b_i.
+class ControlDependenceAnalysis {
+ public:
+  // Map basic block labels to control dependencies/dependents.
+  // Not guaranteed to be in any particular order.
+  using ControlDependenceList = std::vector<ControlDependence>;
+  using ControlDependenceListMap =
+      std::unordered_map<uint32_t, ControlDependenceList>;
+
+  // 0, the label number for the pseudo entry block.
+  // All control dependences on the pseudo entry block are of type kEntry, and
+  // vice versa.
+  static constexpr uint32_t kPseudoEntryBlock = 0;
+
+  // Build the control dependence graph for the given control flow graph |cfg|
+  // and corresponding post-dominator analysis |pdom|.
+  void ComputeControlDependenceGraph(const CFG& cfg,
+                                     const PostDominatorAnalysis& pdom);
+
+  // Get the list of the nodes that depend on a block.
+  // Return value is not guaranteed to be in any particular order.
+  const ControlDependenceList& GetDependenceTargets(uint32_t block) const {
+    return forward_nodes_.at(block);
+  }
+
+  // Get the list of the nodes on which a block depends on.
+  // Return value is not guaranteed to be in any particular order.
+  const ControlDependenceList& GetDependenceSources(uint32_t block) const {
+    return reverse_nodes_.at(block);
+  }
+
+  // Runs the function |f| on each block label in the CDG. If any iteration
+  // returns false, immediately stops iteration and returns false. Otherwise
+  // returns true. Nodes are iterated in some undefined order, including the
+  // pseudo-entry block.
+  bool WhileEachBlockLabel(std::function<bool(uint32_t)> f) const {
+    for (const auto& entry : forward_nodes_) {
+      if (!f(entry.first)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  // Runs the function |f| on each block label in the CDG. Nodes are iterated in
+  // some undefined order, including the pseudo-entry block.
+  void ForEachBlockLabel(std::function<void(uint32_t)> f) const {
+    WhileEachBlockLabel([&f](uint32_t label) {
+      f(label);
+      return true;
+    });
+  }
+
+  // Returns true if the block |id| exists in the control dependence graph.
+  // This can be false even if the block exists in the function when it is part
+  // of an infinite loop, since it is not part of the post-dominator tree.
+  bool HasBlock(uint32_t id) const { return forward_nodes_.count(id) > 0; }
+
+  // Returns true if block |a| is dependent on block |b|.
+  bool IsDependent(uint32_t a, uint32_t b) const {
+    if (!HasBlock(a)) return false;
+    // BBs tend to have more dependents (targets) than they are dependent on
+    // (sources), so search sources.
+    const ControlDependenceList& a_sources = GetDependenceSources(a);
+    return std::find_if(a_sources.begin(), a_sources.end(),
+                        [b](const ControlDependence& dep) {
+                          return dep.source_bb_id() == b;
+                        }) != a_sources.end();
+  }
+
+ private:
+  // Computes the post-dominance frontiers (i.e. the reverse CDG) for each node
+  // in the post-dominator tree. Only modifies reverse_nodes_; forward_nodes_ is
+  // not modified.
+  void ComputePostDominanceFrontiers(const CFG& cfg,
+                                     const PostDominatorAnalysis& pdom);
+  // Computes the post-dominance frontier for a specific node |pdom_node| in the
+  // post-dominator tree. Result is placed in reverse_nodes_[pdom_node.id()].
+  void ComputePostDominanceFrontierForNode(const CFG& cfg,
+                                           const PostDominatorAnalysis& pdom,
+                                           uint32_t function_entry,
+                                           const DominatorTreeNode& pdom_node);
+
+  // Computes the forward graph (forward_nodes_) from the reverse graph
+  // (reverse_nodes_).
+  void ComputeForwardGraphFromReverse();
+
+  ControlDependenceListMap forward_nodes_;
+  ControlDependenceListMap reverse_nodes_;
+};
+
+}  // namespace opt
+}  // namespace spvtools
+
+#endif  // SOURCE_OPT_CONTROL_DEPENDENCE_H_

+ 8 - 0
3rdparty/spirv-tools/source/opt/inline_pass.cpp

@@ -403,6 +403,14 @@ bool InlinePass::InlineEntryBlock(
       callee2caller, inlined_at_ctx, new_blk_ptr, callee_first_block);
 
   while (callee_inst_itr != callee_first_block->end()) {
+    // Don't inline function definition links, the calling function is not a
+    // definition.
+    if (callee_inst_itr->GetVulkan100DebugOpcode() ==
+        NonSemanticVulkanDebugInfo100DebugFunctionDefinition) {
+      ++callee_inst_itr;
+      continue;
+    }
+
     if (!InlineSingleInstruction(
             callee2caller, new_blk_ptr->get(), &*callee_inst_itr,
             context()->get_debug_info_mgr()->BuildDebugInlinedAtChain(

+ 30 - 0
3rdparty/spirv-tools/source/opt/ir_loader.cpp

@@ -17,6 +17,7 @@
 #include <utility>
 
 #include "DebugInfo.h"
+#include "NonSemanticVulkanDebugInfo100.h"
 #include "OpenCLDebugInfo100.h"
 #include "source/ext_inst.h"
 #include "source/opt/log.h"
@@ -232,6 +233,35 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) {
                 block_->AddInstruction(std::move(spv_inst));
               break;
             }
+            default: {
+              Errorf(consumer_, src, loc,
+                     "Debug info extension instruction other than DebugScope, "
+                     "DebugNoScope, DebugFunctionDefinition, DebugDeclare, and "
+                     "DebugValue found inside function",
+                     opcode);
+              return false;
+            }
+          }
+        } else if (inst->ext_inst_type ==
+                   SPV_EXT_INST_TYPE_NONSEMANTIC_VULKAN_DEBUGINFO_100) {
+          const NonSemanticVulkanDebugInfo100Instructions ext_inst_key =
+              NonSemanticVulkanDebugInfo100Instructions(ext_inst_index);
+          switch (ext_inst_key) {
+            case NonSemanticVulkanDebugInfo100DebugDeclare:
+            case NonSemanticVulkanDebugInfo100DebugValue:
+            case NonSemanticVulkanDebugInfo100DebugScope:
+            case NonSemanticVulkanDebugInfo100DebugNoScope:
+            case NonSemanticVulkanDebugInfo100DebugFunctionDefinition: {
+              if (block_ == nullptr) {  // Inside function but outside blocks
+                Errorf(consumer_, src, loc,
+                       "Debug info extension instruction found inside function "
+                       "but outside block",
+                       opcode);
+              } else {
+                block_->AddInstruction(std::move(spv_inst));
+              }
+              break;
+            }
             default: {
               Errorf(consumer_, src, loc,
                      "Debug info extension instruction other than DebugScope, "

+ 23 - 5
3rdparty/spirv-tools/source/opt/module.cpp

@@ -145,8 +145,10 @@ void Module::ToBinary(std::vector<uint32_t>* binary, bool skip_nop) const {
   DebugScope last_scope(kNoDebugScope, kNoInlinedAt);
   const Instruction* last_line_inst = nullptr;
   bool between_merge_and_branch = false;
+  bool between_label_and_phi_var = false;
   auto write_inst = [binary, skip_nop, &last_scope, &last_line_inst,
-                     &between_merge_and_branch, this](const Instruction* i) {
+                     &between_merge_and_branch, &between_label_and_phi_var,
+                     this](const Instruction* i) {
     // Skip emitting line instructions between merge and branch instructions.
     auto opcode = i->opcode();
     if (between_merge_and_branch &&
@@ -175,13 +177,29 @@ void Module::ToBinary(std::vector<uint32_t>* binary, bool skip_nop) const {
         last_line_inst = nullptr;
       }
     }
+
+    if (opcode == SpvOpLabel) {
+      between_label_and_phi_var = true;
+    } else if (opcode != SpvOpVariable && opcode != SpvOpPhi &&
+               opcode != SpvOpLine && opcode != SpvOpNoLine) {
+      between_label_and_phi_var = false;
+    }
+
     if (!(skip_nop && i->IsNop())) {
       const auto& scope = i->GetDebugScope();
       if (scope != last_scope) {
-        // Emit DebugScope |scope| to |binary|.
-        auto dbg_inst = ext_inst_debuginfo_.begin();
-        scope.ToBinary(dbg_inst->type_id(), context()->TakeNextId(),
-                       dbg_inst->GetSingleWordOperand(2), binary);
+        // Can only emit nonsemantic instructions after all phi instructions
+        // in a block so don't emit scope instructions before phi instructions
+        // for Vulkan.NonSemantic.DebugInfo.100.
+        if (!between_label_and_phi_var ||
+            context()
+                ->get_feature_mgr()
+                ->GetExtInstImportId_OpenCL100DebugInfo()) {
+          // Emit DebugScope |scope| to |binary|.
+          auto dbg_inst = ext_inst_debuginfo_.begin();
+          scope.ToBinary(dbg_inst->type_id(), context()->TakeNextId(),
+                         dbg_inst->GetSingleWordOperand(2), binary);
+        }
         last_scope = scope;
       }
 

+ 17 - 11
3rdparty/spirv-tools/source/val/validate_decorations.cpp

@@ -549,17 +549,23 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
       // limitation to this check if the array size is a spec constant or is a
       // runtime array then we will only check a single element. This means
       // some improper straddles might be missed.
-      for (uint32_t i = 0; i < num_elements; ++i) {
-        uint32_t next_offset = i * array_stride + offset;
-        if (SpvOpTypeStruct == element_inst->opcode() &&
-            SPV_SUCCESS != (recursive_status = checkLayout(
-                                typeId, storage_class_str, decoration_str,
-                                blockRules, scalar_block_layout,
-                                next_offset, constraints, vstate)))
-          return recursive_status;
-        // If offsets accumulate up to a 16-byte multiple stop checking since
-        // it will just repeat.
-        if (i > 0 && (next_offset % 16 == 0)) break;
+      if (SpvOpTypeStruct == element_inst->opcode()) {
+        std::vector<bool> seen(16, false);
+        for (uint32_t i = 0; i < num_elements; ++i) {
+          uint32_t next_offset = i * array_stride + offset;
+          // Stop checking if offsets repeat in terms of 16-byte multiples.
+          if (seen[next_offset % 16]) {
+            break;
+          }
+
+          if (SPV_SUCCESS !=
+              (recursive_status = checkLayout(
+                   typeId, storage_class_str, decoration_str, blockRules,
+                   scalar_block_layout, next_offset, constraints, vstate)))
+            return recursive_status;
+
+          seen[next_offset % 16] = true;
+        }
       }
 
       // Proceed to the element in case it is an array.

+ 1 - 1
3rdparty/spirv-tools/source/val/validate_extensions.cpp

@@ -812,7 +812,7 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
         for (uint32_t operand_index = 4; operand_index < num_operands;
              ++operand_index) {
           const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
-          if (!_.IsIntScalarOrVectorType(operand_type)) {
+          if (!operand_type || !_.IsIntScalarOrVectorType(operand_type)) {
             return _.diag(SPV_ERROR_INVALID_DATA, inst)
                    << ext_inst_name() << ": "
                    << "expected all operands to be int scalars or vectors";

部分文件因为文件数量过多而无法显示