Updated spirv-tools.

This commit is contained in:
Бранимир Караџић 2020-03-28 16:25:06 -07:00
parent eff6f13011
commit f334d0c1cb
15 changed files with 377 additions and 43 deletions

View File

@ -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:

View File

@ -1 +1 @@
"v2020.2-dev", "SPIRV-Tools v2020.2-dev 9897187ba975fbb16bbce48d1d45761bf27bfac1"
"v2020.3-dev", "SPIRV-Tools v2020.3-dev eff6f130119f3e6acbf81f8432c0912296d4dfdb"

View File

@ -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",
});

View File

@ -34,6 +34,11 @@ Function* Function::Clone(IRContext* ctx) const {
},
true);
for (const auto& i : debug_insts_in_header_) {
clone->AddDebugInstructionInHeader(
std::unique_ptr<Instruction>(i.Clone(ctx)));
}
clone->blocks_.reserve(blocks_.size());
for (const auto& b : blocks_) {
std::unique_ptr<BasicBlock> bb(b->Clone(ctx));
@ -79,6 +84,12 @@ bool Function::WhileEachInst(const std::function<bool(Instruction*)>& 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<bool(const Instruction*)>& 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<const BasicBlock*>(bb.get())->WhileEachInst(
f, run_on_debug_line_insts)) {

View File

@ -56,6 +56,8 @@ class Function {
// Appends a parameter to this function.
inline void AddParameter(std::unique_ptr<Instruction> p);
// Appends a debug instruction in function header to this function.
inline void AddDebugInstructionInHeader(std::unique_ptr<Instruction> p);
// Appends a basic block to this function.
inline void AddBasicBlock(std::unique_ptr<BasicBlock> b);
// Appends a basic block to this function at the position |ip|.
@ -151,6 +153,8 @@ class Function {
std::unique_ptr<Instruction> def_inst_;
// All parameters to this function.
std::vector<std::unique_ptr<Instruction>> 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<std::unique_ptr<BasicBlock>> blocks_;
// The OpFunctionEnd instruction.
@ -167,6 +171,11 @@ inline void Function::AddParameter(std::unique_ptr<Instruction> p) {
params_.emplace_back(std::move(p));
}
inline void Function::AddDebugInstructionInHeader(
std::unique_ptr<Instruction> p) {
debug_insts_in_header_.push_back(std::move(p));
}
inline void Function::AddBasicBlock(std::unique_ptr<BasicBlock> b) {
AddBasicBlock(std::move(b), end());
}

View File

@ -16,6 +16,7 @@
#include <initializer_list>
#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<Instruction>(),
@ -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<Instruction>&& 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<SpvOp>(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<uint32_t> 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<Instruction>(),
@ -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<uint32_t>{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<uint32_t>* 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<uint32_t> operands = {
(num_words << 16) | static_cast<uint16_t>(SpvOpExtInst),
type_id,
result_id,
ext_set,
static_cast<uint32_t>(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

View File

@ -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<uint32_t>* 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<Instruction> {
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> {
Instruction(IRContext* c, const spv_parsed_instruction_t& inst,
std::vector<Instruction>&& 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<Instruction> {
// 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<Instruction> {
// empty.
std::vector<Instruction> 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,

View File

@ -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_("<instruction>"),
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<SpvOp>(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<Instruction> 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));
}
}
}
}

View File

@ -78,6 +78,9 @@ class IrLoader {
std::unique_ptr<BasicBlock> block_;
// Line related debug instructions accumulated thus far.
std::vector<Instruction> dbg_line_info_;
// The last DebugScope information that IrLoader::AddInstruction() handled.
DebugScope last_dbg_scope_;
};
} // namespace opt

View File

@ -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",
});

View File

@ -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",

View File

@ -137,10 +137,27 @@ void Module::ToBinary(std::vector<uint32_t>* 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 {

View File

@ -17,6 +17,7 @@
#include <functional>
#include <memory>
#include <unordered_map>
#include <utility>
#include <vector>
@ -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<Function> 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<Instruction*> 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<Instruction> 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<Function> 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();
}

View File

@ -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<uint32_t> optimized_binary_with_nop;
context->module()->ToBinary(&optimized_binary_with_nop,
/* skip_nop = */ false);

View File

@ -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.