From f334d0c1cbb86b2bf1223d830c1bcf5143e545ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=80=D0=B0=D0=BD=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D0=B0=D1=80=D0=B0=D1=9F=D0=B8=D1=9B?= Date: Sat, 28 Mar 2020 16:25:06 -0700 Subject: [PATCH] Updated spirv-tools. --- 3rdparty/spirv-tools/CHANGES | 31 +++- .../include/generated/build-version.inc | 2 +- .../opt/aggressive_dead_code_elim_pass.cpp | 1 + 3rdparty/spirv-tools/source/opt/function.cpp | 17 +++ 3rdparty/spirv-tools/source/opt/function.h | 9 ++ .../spirv-tools/source/opt/instruction.cpp | 106 ++++++++++++- 3rdparty/spirv-tools/source/opt/instruction.h | 60 +++++++- 3rdparty/spirv-tools/source/opt/ir_loader.cpp | 140 ++++++++++++++---- 3rdparty/spirv-tools/source/opt/ir_loader.h | 3 + .../opt/local_access_chain_convert_pass.cpp | 1 + .../opt/local_single_block_elim_pass.cpp | 1 + 3rdparty/spirv-tools/source/opt/module.cpp | 21 ++- 3rdparty/spirv-tools/source/opt/module.h | 12 +- 3rdparty/spirv-tools/source/opt/optimizer.cpp | 7 +- .../spirv-tools/source/val/validate_cfg.cpp | 9 ++ 15 files changed, 377 insertions(+), 43 deletions(-) diff --git a/3rdparty/spirv-tools/CHANGES b/3rdparty/spirv-tools/CHANGES index 48c93a4d6..fe6641ecf 100644 --- a/3rdparty/spirv-tools/CHANGES +++ b/3rdparty/spirv-tools/CHANGES @@ -1,7 +1,34 @@ Revision history for SPIRV-Tools -v2020.2-dev 2020-02-03 - - Start v2020.2-dev +v2020.3-dev 2020-03-26 + - Start v2020.3-dev + +v2020.2 2020-03-26 + - General: + - Support extended instructions in the vscode language server + - Make spvOpcodeString part of the public API (#3174) + - Added guide to writing a spirv-fuzz fuzzer pass (#3190) + - Add support for KHR_ray_{query,tracing} extensions (#3235) + - Optimizer + - Debug Printf support (#3215) + - Add data structure for DebugScope, DebugDeclare in spirv-opt (#3183) + - Fix identification of Vulkan images and buffers (#3253) + - Validator + - Add support for SPV_AMD_shader_image_load_store_lod (#3186) + - Add validation rules for OpenCL.DebugInfo.100 extension (#3133) + - Adding WebGPU specific Workgroup scope rule (#3204) + - Disallow phis of images, samplers and sampled images (#3246) + - Reduce + - Fuzz + - Fuzzer passes to add local and global variables (#3175) + - Add fuzzer passes to add loads/stores (#3176) + - Fuzzer pass to add function calls (#3178) + - Fuzzer pass that adds access chains (#3182) + - Fuzzer pass to add equation instructions (#3202) + - Add swap commutable operands transformation (#3205) + - Add fuzzer pass to permute function parameters (#3212) + - Allow OpPhi operand to be replaced with a composite synonym (#3221) + - Linker v2020.1 2020-02-03 - General: diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index a8359bf32..4c169271b 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2020.2-dev", "SPIRV-Tools v2020.2-dev 9897187ba975fbb16bbce48d1d45761bf27bfac1" +"v2020.3-dev", "SPIRV-Tools v2020.3-dev eff6f130119f3e6acbf81f8432c0912296d4dfdb" diff --git a/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp b/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp index 2cdf5fff4..db2b67b92 100644 --- a/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp @@ -931,6 +931,7 @@ void AggressiveDCEPass::InitExtensions() { "SPV_NV_shading_rate", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", + "SPV_KHR_ray_tracing", "SPV_EXT_fragment_invocation_density", "SPV_EXT_physical_storage_buffer", }); diff --git a/3rdparty/spirv-tools/source/opt/function.cpp b/3rdparty/spirv-tools/source/opt/function.cpp index efda68b78..5d50f37c6 100644 --- a/3rdparty/spirv-tools/source/opt/function.cpp +++ b/3rdparty/spirv-tools/source/opt/function.cpp @@ -34,6 +34,11 @@ Function* Function::Clone(IRContext* ctx) const { }, true); + for (const auto& i : debug_insts_in_header_) { + clone->AddDebugInstructionInHeader( + std::unique_ptr(i.Clone(ctx))); + } + clone->blocks_.reserve(blocks_.size()); for (const auto& b : blocks_) { std::unique_ptr bb(b->Clone(ctx)); @@ -79,6 +84,12 @@ bool Function::WhileEachInst(const std::function& f, } } + for (auto& di : debug_insts_in_header_) { + if (!di.WhileEachInst(f, run_on_debug_line_insts)) { + return false; + } + } + for (auto& bb : blocks_) { if (!bb->WhileEachInst(f, run_on_debug_line_insts)) { return false; @@ -106,6 +117,12 @@ bool Function::WhileEachInst(const std::function& f, } } + for (const auto& di : debug_insts_in_header_) { + if (!di.WhileEachInst(f, run_on_debug_line_insts)) { + return false; + } + } + for (const auto& bb : blocks_) { if (!static_cast(bb.get())->WhileEachInst( f, run_on_debug_line_insts)) { diff --git a/3rdparty/spirv-tools/source/opt/function.h b/3rdparty/spirv-tools/source/opt/function.h index 390856823..f208d8e4d 100644 --- a/3rdparty/spirv-tools/source/opt/function.h +++ b/3rdparty/spirv-tools/source/opt/function.h @@ -56,6 +56,8 @@ class Function { // Appends a parameter to this function. inline void AddParameter(std::unique_ptr p); + // Appends a debug instruction in function header to this function. + inline void AddDebugInstructionInHeader(std::unique_ptr p); // Appends a basic block to this function. inline void AddBasicBlock(std::unique_ptr b); // Appends a basic block to this function at the position |ip|. @@ -151,6 +153,8 @@ class Function { std::unique_ptr def_inst_; // All parameters to this function. std::vector> params_; + // All debug instructions in this function's header. + InstructionList debug_insts_in_header_; // All basic blocks inside this function in specification order std::vector> blocks_; // The OpFunctionEnd instruction. @@ -167,6 +171,11 @@ inline void Function::AddParameter(std::unique_ptr p) { params_.emplace_back(std::move(p)); } +inline void Function::AddDebugInstructionInHeader( + std::unique_ptr p) { + debug_insts_in_header_.push_back(std::move(p)); +} + inline void Function::AddBasicBlock(std::unique_ptr b) { AddBasicBlock(std::move(b), end()); } diff --git a/3rdparty/spirv-tools/source/opt/instruction.cpp b/3rdparty/spirv-tools/source/opt/instruction.cpp index 49f91426d..3ce38a9a7 100644 --- a/3rdparty/spirv-tools/source/opt/instruction.cpp +++ b/3rdparty/spirv-tools/source/opt/instruction.cpp @@ -16,6 +16,7 @@ #include +#include "OpenCLDebugInfo100.h" #include "source/disassemble.h" #include "source/opt/fold.h" #include "source/opt/ir_context.h" @@ -30,6 +31,11 @@ const uint32_t kTypeImageDimIndex = 1; const uint32_t kLoadBaseIndex = 0; const uint32_t kVariableStorageClassIndex = 0; const uint32_t kTypeImageSampledIndex = 5; + +// Constants for OpenCL.DebugInfo.100 extension instructions. +const uint32_t kDebugScopeNumWords = 7; +const uint32_t kDebugScopeNumWordsWithoutInlinedAt = 6; +const uint32_t kDebugNoScopeNumWords = 5; } // namespace Instruction::Instruction(IRContext* c) @@ -38,7 +44,8 @@ Instruction::Instruction(IRContext* c) opcode_(SpvOpNop), has_type_id_(false), has_result_id_(false), - unique_id_(c->TakeNextUniqueId()) {} + unique_id_(c->TakeNextUniqueId()), + dbg_scope_(kNoDebugScope, kNoInlinedAt) {} Instruction::Instruction(IRContext* c, SpvOp op) : utils::IntrusiveNodeBase(), @@ -46,7 +53,8 @@ Instruction::Instruction(IRContext* c, SpvOp op) opcode_(op), has_type_id_(false), has_result_id_(false), - unique_id_(c->TakeNextUniqueId()) {} + unique_id_(c->TakeNextUniqueId()), + dbg_scope_(kNoDebugScope, kNoInlinedAt) {} Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst, std::vector&& dbg_line) @@ -55,7 +63,8 @@ Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst, has_type_id_(inst.type_id != 0), has_result_id_(inst.result_id != 0), unique_id_(c->TakeNextUniqueId()), - dbg_line_insts_(std::move(dbg_line)) { + dbg_line_insts_(std::move(dbg_line)), + dbg_scope_(kNoDebugScope, kNoInlinedAt) { assert((!IsDebugLineInst(opcode_) || dbg_line.empty()) && "Op(No)Line attaching to Op(No)Line found"); for (uint32_t i = 0; i < inst.num_operands; ++i) { @@ -67,6 +76,23 @@ Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst, } } +Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst, + const DebugScope& dbg_scope) + : context_(c), + opcode_(static_cast(inst.opcode)), + has_type_id_(inst.type_id != 0), + has_result_id_(inst.result_id != 0), + unique_id_(c->TakeNextUniqueId()), + dbg_scope_(dbg_scope) { + for (uint32_t i = 0; i < inst.num_operands; ++i) { + const auto& current_payload = inst.operands[i]; + std::vector words( + inst.words + current_payload.offset, + inst.words + current_payload.offset + current_payload.num_words); + operands_.emplace_back(current_payload.type, std::move(words)); + } +} + Instruction::Instruction(IRContext* c, SpvOp op, uint32_t ty_id, uint32_t res_id, const OperandList& in_operands) : utils::IntrusiveNodeBase(), @@ -75,7 +101,8 @@ Instruction::Instruction(IRContext* c, SpvOp op, uint32_t ty_id, has_type_id_(ty_id != 0), has_result_id_(res_id != 0), unique_id_(c->TakeNextUniqueId()), - operands_() { + operands_(), + dbg_scope_(kNoDebugScope, kNoInlinedAt) { if (has_type_id_) { operands_.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_TYPE_ID, std::initializer_list{ty_id}); @@ -94,7 +121,12 @@ Instruction::Instruction(Instruction&& that) has_result_id_(that.has_result_id_), unique_id_(that.unique_id_), operands_(std::move(that.operands_)), - dbg_line_insts_(std::move(that.dbg_line_insts_)) {} + dbg_line_insts_(std::move(that.dbg_line_insts_)), + dbg_scope_(that.dbg_scope_) { + for (auto& i : dbg_line_insts_) { + i.dbg_scope_ = that.dbg_scope_; + } +} Instruction& Instruction::operator=(Instruction&& that) { opcode_ = that.opcode_; @@ -103,6 +135,7 @@ Instruction& Instruction::operator=(Instruction&& that) { unique_id_ = that.unique_id_; operands_ = std::move(that.operands_); dbg_line_insts_ = std::move(that.dbg_line_insts_); + dbg_scope_ = that.dbg_scope_; return *this; } @@ -114,6 +147,7 @@ Instruction* Instruction::Clone(IRContext* c) const { clone->unique_id_ = c->TakeNextUniqueId(); clone->operands_ = operands_; clone->dbg_line_insts_ = dbg_line_insts_; + clone->dbg_scope_ = dbg_scope_; return clone; } @@ -198,6 +232,14 @@ bool Instruction::IsVulkanStorageImage() const { Instruction* base_type = context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1)); + + // Unpack the optional layer of arraying. + if (base_type->opcode() == SpvOpTypeArray || + base_type->opcode() == SpvOpTypeRuntimeArray) { + base_type = context()->get_def_use_mgr()->GetDef( + base_type->GetSingleWordInOperand(0)); + } + if (base_type->opcode() != SpvOpTypeImage) { return false; } @@ -224,6 +266,14 @@ bool Instruction::IsVulkanSampledImage() const { Instruction* base_type = context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1)); + + // Unpack the optional layer of arraying. + if (base_type->opcode() == SpvOpTypeArray || + base_type->opcode() == SpvOpTypeRuntimeArray) { + base_type = context()->get_def_use_mgr()->GetDef( + base_type->GetSingleWordInOperand(0)); + } + if (base_type->opcode() != SpvOpTypeImage) { return false; } @@ -250,6 +300,14 @@ bool Instruction::IsVulkanStorageTexelBuffer() const { Instruction* base_type = context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1)); + + // Unpack the optional layer of arraying. + if (base_type->opcode() == SpvOpTypeArray || + base_type->opcode() == SpvOpTypeRuntimeArray) { + base_type = context()->get_def_use_mgr()->GetDef( + base_type->GetSingleWordInOperand(0)); + } + if (base_type->opcode() != SpvOpTypeImage) { return false; } @@ -273,6 +331,13 @@ bool Instruction::IsVulkanStorageBuffer() const { Instruction* base_type = context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1)); + // Unpack the optional layer of arraying. + if (base_type->opcode() == SpvOpTypeArray || + base_type->opcode() == SpvOpTypeRuntimeArray) { + base_type = context()->get_def_use_mgr()->GetDef( + base_type->GetSingleWordInOperand(0)); + } + if (base_type->opcode() != SpvOpTypeStruct) { return false; } @@ -306,6 +371,14 @@ bool Instruction::IsVulkanUniformBuffer() const { Instruction* base_type = context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1)); + + // Unpack the optional layer of arraying. + if (base_type->opcode() == SpvOpTypeArray || + base_type->opcode() == SpvOpTypeRuntimeArray) { + base_type = context()->get_def_use_mgr()->GetDef( + base_type->GetSingleWordInOperand(0)); + } + if (base_type->opcode() != SpvOpTypeStruct) { return false; } @@ -735,5 +808,28 @@ bool Instruction::IsOpcodeSafeToDelete() const { } } +void DebugScope::ToBinary(uint32_t type_id, uint32_t result_id, + uint32_t ext_set, + std::vector* binary) const { + uint32_t num_words = kDebugScopeNumWords; + OpenCLDebugInfo100Instructions dbg_opcode = OpenCLDebugInfo100DebugScope; + if (GetLexicalScope() == kNoDebugScope) { + num_words = kDebugNoScopeNumWords; + dbg_opcode = OpenCLDebugInfo100DebugNoScope; + } else if (GetInlinedAt() == kNoInlinedAt) { + num_words = kDebugScopeNumWordsWithoutInlinedAt; + } + std::vector operands = { + (num_words << 16) | static_cast(SpvOpExtInst), + type_id, + result_id, + ext_set, + static_cast(dbg_opcode), + }; + binary->insert(binary->end(), operands.begin(), operands.end()); + if (GetLexicalScope() != kNoDebugScope) binary->push_back(GetLexicalScope()); + if (GetInlinedAt() != kNoInlinedAt) binary->push_back(GetInlinedAt()); +} + } // namespace opt } // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/instruction.h b/3rdparty/spirv-tools/source/opt/instruction.h index 63dfa8773..a3342c616 100644 --- a/3rdparty/spirv-tools/source/opt/instruction.h +++ b/3rdparty/spirv-tools/source/opt/instruction.h @@ -32,6 +32,9 @@ #include "source/opt/reflect.h" #include "spirv-tools/libspirv.h" +const uint32_t kNoDebugScope = 0; +const uint32_t kNoInlinedAt = 0; + namespace spvtools { namespace opt { @@ -100,6 +103,44 @@ inline bool operator!=(const Operand& o1, const Operand& o2) { return !(o1 == o2); } +// This structure is used to represent a DebugScope instruction from +// the OpenCL.100.DebugInfo extened instruction set. Note that we can +// ignore the result id of DebugScope instruction because it is not +// used for anything. We do not keep it to reduce the size of +// structure. +// TODO: Let validator check that the result id is not used anywhere. +class DebugScope { + public: + DebugScope(uint32_t lexical_scope, uint32_t inlined_at) + : lexical_scope_(lexical_scope), inlined_at_(inlined_at) {} + + inline bool operator!=(const DebugScope& d) const { + return lexical_scope_ != d.lexical_scope_ || inlined_at_ != d.inlined_at_; + } + + // Accessor functions for |lexical_scope_|. + uint32_t GetLexicalScope() const { return lexical_scope_; } + void SetLexicalScope(uint32_t scope) { lexical_scope_ = scope; } + + // Accessor functions for |inlined_at_|. + uint32_t GetInlinedAt() const { return inlined_at_; } + void SetInlinedAt(uint32_t at) { inlined_at_ = at; } + + // Pushes the binary segments for this DebugScope instruction into + // the back of *|binary|. + void ToBinary(uint32_t type_id, uint32_t result_id, uint32_t ext_set, + std::vector* binary) const; + + private: + // The result id of the lexical scope in which this debug scope is + // contained. The value is kNoDebugScope if there is no scope. + uint32_t lexical_scope_; + + // The result id of DebugInlinedAt if instruction in this debug scope + // is inlined. The value is kNoInlinedAt if it is not inlined. + uint32_t inlined_at_; +}; + // A SPIR-V instruction. It contains the opcode and any additional logical // operand, including the result id (if any) and result type id (if any). It // may also contain line-related debug instruction (OpLine, OpNoLine) directly @@ -120,7 +161,8 @@ class Instruction : public utils::IntrusiveNodeBase { opcode_(SpvOpNop), has_type_id_(false), has_result_id_(false), - unique_id_(0) {} + unique_id_(0), + dbg_scope_(kNoDebugScope, kNoInlinedAt) {} // Creates a default OpNop instruction. Instruction(IRContext*); @@ -134,6 +176,9 @@ class Instruction : public utils::IntrusiveNodeBase { Instruction(IRContext* c, const spv_parsed_instruction_t& inst, std::vector&& dbg_line = {}); + Instruction(IRContext* c, const spv_parsed_instruction_t& inst, + const DebugScope& dbg_scope); + // Creates an instruction with the given opcode |op|, type id: |ty_id|, // result id: |res_id| and input operands: |in_operands|. Instruction(IRContext* c, SpvOp op, uint32_t ty_id, uint32_t res_id, @@ -230,6 +275,9 @@ class Instruction : public utils::IntrusiveNodeBase { // Sets the result id inline void SetResultId(uint32_t res_id); inline bool HasResultId() const { return has_result_id_; } + // Sets DebugScope. + inline void SetDebugScope(const DebugScope& scope); + inline const DebugScope& GetDebugScope() const { return dbg_scope_; } // Remove the |index|-th operand void RemoveOperand(uint32_t index) { operands_.erase(operands_.begin() + index); @@ -482,6 +530,9 @@ class Instruction : public utils::IntrusiveNodeBase { // empty. std::vector dbg_line_insts_; + // DebugScope that wraps this instruction. + DebugScope dbg_scope_; + friend InstructionList; }; @@ -553,6 +604,13 @@ inline void Instruction::SetResultId(uint32_t res_id) { operands_[ridx].words = {res_id}; } +inline void Instruction::SetDebugScope(const DebugScope& scope) { + dbg_scope_ = scope; + for (auto& i : dbg_line_insts_) { + i.dbg_scope_ = scope; + } +} + inline void Instruction::SetResultType(uint32_t ty_id) { // TODO(dsinclair): Allow setting a type id if there wasn't one // previously. Need to make room in the operands_ array to place the result, diff --git a/3rdparty/spirv-tools/source/opt/ir_loader.cpp b/3rdparty/spirv-tools/source/opt/ir_loader.cpp index 836012f17..fcde0797b 100644 --- a/3rdparty/spirv-tools/source/opt/ir_loader.cpp +++ b/3rdparty/spirv-tools/source/opt/ir_loader.cpp @@ -23,6 +23,10 @@ #include "source/opt/reflect.h" #include "source/util/make_unique.h" +static const uint32_t kExtInstSetIndex = 4; +static const uint32_t kLexicalScopeIndex = 5; +static const uint32_t kInlinedAtIndex = 6; + namespace spvtools { namespace opt { @@ -30,16 +34,60 @@ IrLoader::IrLoader(const MessageConsumer& consumer, Module* m) : consumer_(consumer), module_(m), source_(""), - inst_index_(0) {} + inst_index_(0), + last_dbg_scope_(kNoDebugScope, kNoInlinedAt) {} bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { ++inst_index_; const auto opcode = static_cast(inst->opcode); if (IsDebugLineInst(opcode)) { - dbg_line_info_.push_back(Instruction(module()->context(), *inst)); + dbg_line_info_.push_back( + Instruction(module()->context(), *inst, last_dbg_scope_)); return true; } + // If it is a DebugScope or DebugNoScope of debug extension, we do not + // create a new instruction, but simply keep the information in + // struct DebugScope. + if (opcode == SpvOpExtInst && spvExtInstIsDebugInfo(inst->ext_inst_type)) { + const uint32_t ext_inst_index = inst->words[kExtInstSetIndex]; + if (inst->ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) { + const OpenCLDebugInfo100Instructions ext_inst_key = + OpenCLDebugInfo100Instructions(ext_inst_index); + if (ext_inst_key == OpenCLDebugInfo100DebugScope) { + uint32_t inlined_at = 0; + if (inst->num_words > kInlinedAtIndex) + inlined_at = inst->words[kInlinedAtIndex]; + last_dbg_scope_ = + DebugScope(inst->words[kLexicalScopeIndex], inlined_at); + module()->SetContainsDebugScope(); + return true; + } + if (ext_inst_key == OpenCLDebugInfo100DebugNoScope) { + last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt); + module()->SetContainsDebugScope(); + return true; + } + } else { + const DebugInfoInstructions ext_inst_key = + DebugInfoInstructions(ext_inst_index); + if (ext_inst_key == DebugInfoDebugScope) { + uint32_t inlined_at = 0; + if (inst->num_words > kInlinedAtIndex) + inlined_at = inst->words[kInlinedAtIndex]; + last_dbg_scope_ = + DebugScope(inst->words[kLexicalScopeIndex], inlined_at); + module()->SetContainsDebugScope(); + return true; + } + if (ext_inst_key == DebugInfoDebugNoScope) { + last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt); + module()->SetContainsDebugScope(); + return true; + } + } + } + std::unique_ptr spv_inst( new Instruction(module()->context(), *inst, std::move(dbg_line_info_))); dbg_line_info_.clear(); @@ -90,6 +138,7 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { block_->AddInstruction(std::move(spv_inst)); function_->AddBasicBlock(std::move(block_)); block_ = nullptr; + last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt); } else { if (function_ == nullptr) { // Outside function definition SPIRV_ASSERT(consumer_, block_ == nullptr); @@ -131,26 +180,32 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { return false; } } else { - if (block_ == nullptr) { // Inside function but outside blocks - if (opcode != SpvOpFunctionParameter) { - Errorf(consumer_, src, loc, - "Non-OpFunctionParameter (opcode: %d) found inside " - "function but outside basic block", - opcode); - return false; - } - function_->AddParameter(std::move(spv_inst)); - } else { - if (opcode == SpvOpExtInst && - spvExtInstIsDebugInfo(inst->ext_inst_type)) { - const uint32_t ext_inst_index = inst->words[4]; - if (inst->ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) { - const OpenCLDebugInfo100Instructions ext_inst_key = - OpenCLDebugInfo100Instructions(ext_inst_index); - if (ext_inst_key != OpenCLDebugInfo100DebugScope && - ext_inst_key != OpenCLDebugInfo100DebugNoScope && - ext_inst_key != OpenCLDebugInfo100DebugDeclare && - ext_inst_key != OpenCLDebugInfo100DebugValue) { + if (opcode == SpvOpLoopMerge || opcode == SpvOpSelectionMerge) + last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt); + if (last_dbg_scope_.GetLexicalScope() != kNoDebugScope) + spv_inst->SetDebugScope(last_dbg_scope_); + if (opcode == SpvOpExtInst && + spvExtInstIsDebugInfo(inst->ext_inst_type)) { + const uint32_t ext_inst_index = inst->words[kExtInstSetIndex]; + if (inst->ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) { + const OpenCLDebugInfo100Instructions ext_inst_key = + OpenCLDebugInfo100Instructions(ext_inst_index); + switch (ext_inst_key) { + case OpenCLDebugInfo100DebugDeclare: { + if (block_ == nullptr) // Inside function but outside blocks + function_->AddDebugInstructionInHeader(std::move(spv_inst)); + else + block_->AddInstruction(std::move(spv_inst)); + break; + } + case OpenCLDebugInfo100DebugValue: { + if (block_ == nullptr) // Inside function but outside blocks + function_->AddDebugInstructionInHeader(std::move(spv_inst)); + else + block_->AddInstruction(std::move(spv_inst)); + break; + } + default: { Errorf(consumer_, src, loc, "Debug info extension instruction other than DebugScope, " "DebugNoScope, DebugDeclare, and DebugValue found inside " @@ -158,13 +213,26 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { opcode); return false; } - } else { - const DebugInfoInstructions ext_inst_key = - DebugInfoInstructions(ext_inst_index); - if (ext_inst_key != DebugInfoDebugScope && - ext_inst_key != DebugInfoDebugNoScope && - ext_inst_key != DebugInfoDebugDeclare && - ext_inst_key != DebugInfoDebugValue) { + } + } else { + const DebugInfoInstructions ext_inst_key = + DebugInfoInstructions(ext_inst_index); + switch (ext_inst_key) { + case DebugInfoDebugDeclare: { + if (block_ == nullptr) // Inside function but outside blocks + function_->AddDebugInstructionInHeader(std::move(spv_inst)); + else + block_->AddInstruction(std::move(spv_inst)); + break; + } + case DebugInfoDebugValue: { + if (block_ == nullptr) // Inside function but outside blocks + function_->AddDebugInstructionInHeader(std::move(spv_inst)); + else + block_->AddInstruction(std::move(spv_inst)); + break; + } + default: { Errorf(consumer_, src, loc, "Debug info extension instruction other than DebugScope, " "DebugNoScope, DebugDeclare, and DebugValue found inside " @@ -174,7 +242,19 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { } } } - block_->AddInstruction(std::move(spv_inst)); + } else { + if (block_ == nullptr) { // Inside function but outside blocks + if (opcode != SpvOpFunctionParameter) { + Errorf(consumer_, src, loc, + "Non-OpFunctionParameter (opcode: %d) found inside " + "function but outside basic block", + opcode); + return false; + } + function_->AddParameter(std::move(spv_inst)); + } else { + block_->AddInstruction(std::move(spv_inst)); + } } } } diff --git a/3rdparty/spirv-tools/source/opt/ir_loader.h b/3rdparty/spirv-tools/source/opt/ir_loader.h index 940d7b0db..507992150 100644 --- a/3rdparty/spirv-tools/source/opt/ir_loader.h +++ b/3rdparty/spirv-tools/source/opt/ir_loader.h @@ -78,6 +78,9 @@ class IrLoader { std::unique_ptr block_; // Line related debug instructions accumulated thus far. std::vector dbg_line_info_; + + // The last DebugScope information that IrLoader::AddInstruction() handled. + DebugScope last_dbg_scope_; }; } // namespace opt diff --git a/3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.cpp b/3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.cpp index a8cf94b04..0afe79858 100644 --- a/3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.cpp @@ -379,6 +379,7 @@ void LocalAccessChainConvertPass::InitExtensions() { "SPV_NV_shading_rate", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", + "SPV_KHR_ray_tracing", "SPV_KHR_ray_query", "SPV_EXT_fragment_invocation_density", }); diff --git a/3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.cpp b/3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.cpp index c66271ef0..b5435bb7a 100644 --- a/3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.cpp @@ -256,6 +256,7 @@ void LocalSingleBlockLoadStoreElimPass::InitExtensions() { "SPV_NV_shading_rate", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", + "SPV_KHR_ray_tracing", "SPV_KHR_ray_query", "SPV_EXT_fragment_invocation_density", "SPV_EXT_physical_storage_buffer", diff --git a/3rdparty/spirv-tools/source/opt/module.cpp b/3rdparty/spirv-tools/source/opt/module.cpp index 4403894d8..2959d3d9f 100644 --- a/3rdparty/spirv-tools/source/opt/module.cpp +++ b/3rdparty/spirv-tools/source/opt/module.cpp @@ -137,10 +137,27 @@ void Module::ToBinary(std::vector* binary, bool skip_nop) const { binary->push_back(header_.bound); binary->push_back(header_.reserved); - auto write_inst = [binary, skip_nop](const Instruction* i) { - if (!(skip_nop && i->IsNop())) i->ToBinaryWithoutAttachedDebugInsts(binary); + size_t bound_idx = binary->size() - 2; + DebugScope last_scope(kNoDebugScope, kNoInlinedAt); + auto write_inst = [binary, skip_nop, &last_scope, + this](const Instruction* i) { + 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); + last_scope = scope; + } + + i->ToBinaryWithoutAttachedDebugInsts(binary); + } }; ForEachInst(write_inst, true); + + // We create new instructions for DebugScope. The bound must be updated. + binary->data()[bound_idx] = header_.bound; } uint32_t Module::ComputeIdBound() const { diff --git a/3rdparty/spirv-tools/source/opt/module.h b/3rdparty/spirv-tools/source/opt/module.h index fc53d35a1..2c96f0295 100644 --- a/3rdparty/spirv-tools/source/opt/module.h +++ b/3rdparty/spirv-tools/source/opt/module.h @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -48,7 +49,7 @@ class Module { using const_inst_iterator = InstructionList::const_iterator; // Creates an empty module with zero'd header. - Module() : header_({}) {} + Module() : header_({}), contains_debug_scope_(false) {} // Sets the header to the given |header|. void SetHeader(const ModuleHeader& header) { header_ = header; } @@ -118,6 +119,10 @@ class Module { // Appends a function to this module. inline void AddFunction(std::unique_ptr f); + // Sets |contains_debug_scope_| as true. + inline void SetContainsDebugScope(); + inline bool ContainsDebugScope() { return contains_debug_scope_; } + // Returns a vector of pointers to type-declaration instructions in this // module. std::vector GetTypes(); @@ -295,6 +300,9 @@ class Module { // If the module ends with Op*Line instruction, they will not be attached to // any instruction. We record them here, so they will not be lost. std::vector trailing_dbg_line_info_; + + // This module contains DebugScope or DebugNoScope. + bool contains_debug_scope_; }; // Pretty-prints |module| to |str|. Returns |str|. @@ -356,6 +364,8 @@ inline void Module::AddFunction(std::unique_ptr f) { functions_.emplace_back(std::move(f)); } +inline void Module::SetContainsDebugScope() { contains_debug_scope_ = true; } + inline Module::inst_iterator Module::capability_begin() { return capabilities_.begin(); } diff --git a/3rdparty/spirv-tools/source/opt/optimizer.cpp b/3rdparty/spirv-tools/source/opt/optimizer.cpp index 6e271f538..0a937e857 100644 --- a/3rdparty/spirv-tools/source/opt/optimizer.cpp +++ b/3rdparty/spirv-tools/source/opt/optimizer.cpp @@ -569,7 +569,12 @@ bool Optimizer::Run(const uint32_t* original_binary, } #ifndef NDEBUG - if (status == opt::Pass::Status::SuccessWithoutChange) { + // We do not keep the result id of DebugScope in struct DebugScope. + // Instead, we assign random ids for them, which results in sanity + // check failures. We want to skip the sanity check when the module + // contains DebugScope instructions. + if (status == opt::Pass::Status::SuccessWithoutChange && + !context->module()->ContainsDebugScope()) { std::vector optimized_binary_with_nop; context->module()->ToBinary(&optimized_binary_with_nop, /* skip_nop = */ false); diff --git a/3rdparty/spirv-tools/source/val/validate_cfg.cpp b/3rdparty/spirv-tools/source/val/validate_cfg.cpp index f3019d17f..1c279f654 100644 --- a/3rdparty/spirv-tools/source/val/validate_cfg.cpp +++ b/3rdparty/spirv-tools/source/val/validate_cfg.cpp @@ -62,6 +62,15 @@ spv_result_t ValidatePhi(ValidationState_t& _, const Instruction* inst) { } } + if (!_.options()->before_hlsl_legalization) { + if (type_opcode == SpvOpTypeSampledImage || + (_.HasCapability(SpvCapabilityShader) && + (type_opcode == SpvOpTypeImage || type_opcode == SpvOpTypeSampler))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Result type cannot be Op" << spvOpcodeString(type_opcode); + } + } + // Create a uniqued vector of predecessor ids for comparison against // incoming values. OpBranchConditional %cond %label %label produces two // predecessors in the CFG.