Handle conflict between debug info and existing validation rule (#3104)

* Allow OpExtInst for DebugInfo between secion 9 and 10

Fixes #3086

* Handle spirv-opt errors on DebugInfo Ext

* Add IR Loader test

* Fix ir loader bug

* Handle DebugFunction/DebugTypeMember forward reference

* Add test cases (forward reference to function)

* Support old DebugInfo extension

* Validate local debug info out of function
This commit is contained in:
Jaebaek Seo 2020-01-23 17:04:30 -05:00 коммит произвёл David Neto
Родитель b97057e7f7
Коммит dd37d73c5e
21 изменённых файлов: 1371 добавлений и 5 удалений

Просмотреть файл

@ -239,7 +239,8 @@ $(1)/$(2).h : \
--extinst-grammar=$(3) \
--extinst-output-base=$(1)/$(2)
@echo "[$(TARGET_ARCH_ABI)] Generate language specific header for $(2): headers <= grammar"
$(LOCAL_PATH)/source/ext_inst.cpp: $(1)/$(2).h
$(foreach F,$(SPVTOOLS_SRC_FILES) $(SPVTOOLS_OPT_SRC_FILES),$(LOCAL_PATH)/$F ) \
: $(1)/$(2).h
endef
# We generate language-specific headers for DebugInfo and OpenCL.DebugInfo.100
$(eval $(call gen_spvtools_lang_headers,$(SPVTOOLS_OUT_PATH),DebugInfo,$(SPV_DEBUGINFO_GRAMMAR)))

Просмотреть файл

@ -138,6 +138,14 @@ bool spvExtInstIsNonSemantic(const spv_ext_inst_type_t type) {
return false;
}
bool spvExtInstIsDebugInfo(const spv_ext_inst_type_t type) {
if (type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 ||
type == SPV_EXT_INST_TYPE_DEBUGINFO) {
return true;
}
return false;
}
spv_result_t spvExtInstTableNameLookup(const spv_ext_inst_table table,
const spv_ext_inst_type_t type,
const char* name,

Просмотреть файл

@ -24,6 +24,9 @@ spv_ext_inst_type_t spvExtInstImportTypeGet(const char* name);
// Returns true if the extended instruction set is non-semantic
bool spvExtInstIsNonSemantic(const spv_ext_inst_type_t type);
// Returns true if the extended instruction set is debug info
bool spvExtInstIsDebugInfo(const spv_ext_inst_type_t type);
// Finds the named extented instruction of the given type in the given extended
// instruction table. On success, returns SPV_SUCCESS and writes a handle of
// the instruction entry into *entry.

Просмотреть файл

@ -324,6 +324,11 @@ spv_result_t MergeModules(const MessageConsumer& consumer,
linked_module->AddDebug3Inst(
std::unique_ptr<Instruction>(inst.Clone(linked_context)));
for (const auto& module : input_modules)
for (const auto& inst : module->ext_inst_debuginfo())
linked_module->AddExtInstDebugInfo(
std::unique_ptr<Instruction>(inst.Clone(linked_context)));
// If the generated module uses SPIR-V 1.1 or higher, add an
// OpModuleProcessed instruction about the linking step.
if (linked_module->version() >= 0x10100) {

Просмотреть файл

@ -19,6 +19,8 @@
#include <algorithm>
#include "DebugInfo.h"
#include "OpenCLDebugInfo100.h"
#include "source/macro.h"
#include "source/spirv_constant.h"
#include "source/spirv_target_env.h"
@ -512,3 +514,37 @@ std::function<bool(unsigned)> spvOperandCanBeForwardDeclaredFunction(
}
return out;
}
std::function<bool(unsigned)> spvDbgInfoExtOperandCanBeForwardDeclaredFunction(
spv_ext_inst_type_t ext_type, uint32_t key) {
// 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.
std::function<bool(unsigned index)> out;
if (ext_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) {
switch (OpenCLDebugInfo100Instructions(key)) {
case OpenCLDebugInfo100DebugFunction:
out = [](unsigned index) { return index == 13; };
break;
case OpenCLDebugInfo100DebugTypeComposite:
out = [](unsigned index) { return index >= 13; };
break;
default:
out = [](unsigned) { return false; };
break;
}
} else {
switch (DebugInfoInstructions(key)) {
case DebugInfoDebugFunction:
out = [](unsigned index) { return index == 13; };
break;
case DebugInfoDebugTypeComposite:
out = [](unsigned index) { return index >= 12; };
break;
default:
out = [](unsigned) { return false; };
break;
}
}
return out;
}

Просмотреть файл

@ -141,4 +141,11 @@ bool spvIsInIdType(spv_operand_type_t type);
std::function<bool(unsigned)> spvOperandCanBeForwardDeclaredFunction(
SpvOp opcode);
// Takes the instruction key of a debug info extension instruction
// and returns a function object that will return true if the index
// of the operand can be forward declared. This function will
// used in the SSA validation stage of the pipeline
std::function<bool(unsigned)> spvDbgInfoExtOperandCanBeForwardDeclaredFunction(
spv_ext_inst_type_t ext_type, uint32_t key);
#endif // SOURCE_OPERAND_H_

Просмотреть файл

@ -988,6 +988,10 @@ void InstrumentPass::InitializeInstrument() {
(void)i;
++module_offset;
}
for (auto& i : module->ext_inst_debuginfo()) {
(void)i;
++module_offset;
}
for (auto& i : module->annotations()) {
(void)i;
++module_offset;

Просмотреть файл

@ -187,6 +187,14 @@ class IRContext {
inline IteratorRange<Module::inst_iterator> debugs3();
inline IteratorRange<Module::const_inst_iterator> debugs3() const;
// Iterators for debug info instructions (excluding OpLine & OpNoLine)
// contained in this module. These are OpExtInst for OpenCL.DebugInfo.100
// or DebugInfo extension placed between section 9 and 10.
inline Module::inst_iterator ext_inst_debuginfo_begin();
inline Module::inst_iterator ext_inst_debuginfo_end();
inline IteratorRange<Module::inst_iterator> ext_inst_debuginfo();
inline IteratorRange<Module::const_inst_iterator> ext_inst_debuginfo() const;
// Add |capability| to the module, if it is not already enabled.
inline void AddCapability(SpvCapability capability);
@ -215,6 +223,8 @@ class IRContext {
// Appends a debug 3 instruction (OpModuleProcessed) to this module.
// This is due to decision by the SPIR Working Group, pending publication.
inline void AddDebug3Inst(std::unique_ptr<Instruction>&& d);
// Appends a OpExtInst for DebugInfo to this module.
inline void AddExtInstDebugInfo(std::unique_ptr<Instruction>&& d);
// Appends an annotation instruction to this module.
inline void AddAnnotationInst(std::unique_ptr<Instruction>&& a);
// Appends a type-declaration instruction to this module.
@ -925,6 +935,23 @@ IteratorRange<Module::const_inst_iterator> IRContext::debugs3() const {
return ((const Module*)module_.get())->debugs3();
}
Module::inst_iterator IRContext::ext_inst_debuginfo_begin() {
return module()->ext_inst_debuginfo_begin();
}
Module::inst_iterator IRContext::ext_inst_debuginfo_end() {
return module()->ext_inst_debuginfo_end();
}
IteratorRange<Module::inst_iterator> IRContext::ext_inst_debuginfo() {
return module()->ext_inst_debuginfo();
}
IteratorRange<Module::const_inst_iterator> IRContext::ext_inst_debuginfo()
const {
return ((const Module*)module_.get())->ext_inst_debuginfo();
}
void IRContext::AddCapability(SpvCapability capability) {
if (!get_feature_mgr()->HasCapability(capability)) {
std::unique_ptr<Instruction> capability_inst(new Instruction(
@ -1018,6 +1045,10 @@ void IRContext::AddDebug3Inst(std::unique_ptr<Instruction>&& d) {
module()->AddDebug3Inst(std::move(d));
}
void IRContext::AddExtInstDebugInfo(std::unique_ptr<Instruction>&& d) {
module()->AddExtInstDebugInfo(std::move(d));
}
void IRContext::AddAnnotationInst(std::unique_ptr<Instruction>&& a) {
if (AreAnalysesValid(kAnalysisDecorations)) {
get_decoration_mgr()->AddDecoration(a.get());

Просмотреть файл

@ -16,6 +16,8 @@
#include <utility>
#include "DebugInfo.h"
#include "OpenCLDebugInfo100.h"
#include "source/ext_inst.h"
#include "source/opt/log.h"
#include "source/opt/reflect.h"
@ -118,6 +120,9 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) {
(opcode == SpvOpExtInst &&
spvExtInstIsNonSemantic(inst->ext_inst_type))) {
module_->AddGlobalValue(std::move(spv_inst));
} else if (opcode == SpvOpExtInst &&
spvExtInstIsDebugInfo(inst->ext_inst_type)) {
module_->AddExtInstDebugInfo(std::move(spv_inst));
} else {
Errorf(consumer_, src, loc,
"Unhandled inst type (opcode: %d) found outside function "
@ -136,6 +141,39 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) {
}
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) {
Errorf(consumer_, src, loc,
"Debug info extension instruction other than DebugScope, "
"DebugNoScope, DebugDeclare, and DebugValue found inside "
"function",
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) {
Errorf(consumer_, src, loc,
"Debug info extension instruction other than DebugScope, "
"DebugNoScope, DebugDeclare, and DebugValue found inside "
"function",
opcode);
return false;
}
}
}
block_->AddInstruction(std::move(spv_inst));
}
}

Просмотреть файл

@ -95,6 +95,7 @@ void Module::ForEachInst(const std::function<void(Instruction*)>& f,
DELEGATE(debugs1_);
DELEGATE(debugs2_);
DELEGATE(debugs3_);
DELEGATE(ext_inst_debuginfo_);
DELEGATE(annotations_);
DELEGATE(types_values_);
for (auto& i : functions_) i->ForEachInst(f, run_on_debug_line_insts);
@ -117,6 +118,7 @@ void Module::ForEachInst(const std::function<void(const Instruction*)>& f,
for (auto& i : debugs3_) DELEGATE(i);
for (auto& i : annotations_) DELEGATE(i);
for (auto& i : types_values_) DELEGATE(i);
for (auto& i : ext_inst_debuginfo_) DELEGATE(i);
for (auto& i : functions_) {
static_cast<const Function*>(i.get())->ForEachInst(f,
run_on_debug_line_insts);

Просмотреть файл

@ -102,6 +102,10 @@ class Module {
// This is due to decision by the SPIR Working Group, pending publication.
inline void AddDebug3Inst(std::unique_ptr<Instruction> d);
// Appends a debug info extension (OpenCL.DebugInfo.100 or DebugInfo)
// instruction to this module.
inline void AddExtInstDebugInfo(std::unique_ptr<Instruction> d);
// Appends an annotation instruction to this module.
inline void AddAnnotationInst(std::unique_ptr<Instruction> a);
@ -182,6 +186,14 @@ class Module {
inline IteratorRange<inst_iterator> debugs3();
inline IteratorRange<const_inst_iterator> debugs3() const;
// Iterators for debug info instructions (excluding OpLine & OpNoLine)
// contained in this module. These are OpExtInst for OpenCL.DebugInfo.100
// or DebugInfo extension placed between section 9 and 10.
inline inst_iterator ext_inst_debuginfo_begin();
inline inst_iterator ext_inst_debuginfo_end();
inline IteratorRange<inst_iterator> ext_inst_debuginfo();
inline IteratorRange<const_inst_iterator> ext_inst_debuginfo() const;
// Iterators for entry point instructions contained in this module
inline IteratorRange<inst_iterator> entry_points();
inline IteratorRange<const_inst_iterator> entry_points() const;
@ -274,6 +286,7 @@ class Module {
InstructionList debugs1_;
InstructionList debugs2_;
InstructionList debugs3_;
InstructionList ext_inst_debuginfo_;
InstructionList annotations_;
// Type declarations, constants, and global variable declarations.
InstructionList types_values_;
@ -323,6 +336,10 @@ inline void Module::AddDebug3Inst(std::unique_ptr<Instruction> d) {
debugs3_.push_back(std::move(d));
}
inline void Module::AddExtInstDebugInfo(std::unique_ptr<Instruction> d) {
ext_inst_debuginfo_.push_back(std::move(d));
}
inline void Module::AddAnnotationInst(std::unique_ptr<Instruction> a) {
annotations_.push_back(std::move(a));
}
@ -403,6 +420,22 @@ inline IteratorRange<Module::const_inst_iterator> Module::debugs3() const {
return make_range(debugs3_.begin(), debugs3_.end());
}
inline Module::inst_iterator Module::ext_inst_debuginfo_begin() {
return ext_inst_debuginfo_.begin();
}
inline Module::inst_iterator Module::ext_inst_debuginfo_end() {
return ext_inst_debuginfo_.end();
}
inline IteratorRange<Module::inst_iterator> Module::ext_inst_debuginfo() {
return make_range(ext_inst_debuginfo_.begin(), ext_inst_debuginfo_.end());
}
inline IteratorRange<Module::const_inst_iterator> Module::ext_inst_debuginfo()
const {
return make_range(ext_inst_debuginfo_.begin(), ext_inst_debuginfo_.end());
}
inline IteratorRange<Module::inst_iterator> Module::entry_points() {
return make_range(entry_points_.begin(), entry_points_.end());
}

Просмотреть файл

@ -75,6 +75,7 @@ Pass::Status StripDebugInfoPass::Process() {
for (auto& dbg : context()->debugs2()) to_kill.push_back(&dbg);
for (auto& dbg : context()->debugs3()) to_kill.push_back(&dbg);
for (auto& dbg : context()->ext_inst_debuginfo()) to_kill.push_back(&dbg);
// OpName must come first, since they may refer to other debug instructions.
// If they are after the instructions that refer to, then they will be killed

Просмотреть файл

@ -77,6 +77,7 @@ Pass::Status StripReflectInfoPass::Process() {
for (auto& dbg : context()->debugs1()) to_remove.push_back(&dbg);
for (auto& dbg : context()->debugs2()) to_remove.push_back(&dbg);
for (auto& dbg : context()->debugs3()) to_remove.push_back(&dbg);
for (auto& dbg : context()->ext_inst_debuginfo()) to_remove.push_back(&dbg);
// remove any extended inst imports that are non semantic
std::unordered_set<uint32_t> non_semantic_sets;

Просмотреть файл

@ -52,6 +52,13 @@ RemoveUnreferencedInstructionReductionOpportunityFinder::
result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
}
for (auto& inst : context->module()->ext_inst_debuginfo()) {
if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
continue;
}
result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
}
for (auto& inst : context->module()->types_values()) {
if (context->get_def_use_mgr()->NumUsers(&inst) > 0) {
continue;

Просмотреть файл

@ -91,6 +91,12 @@ class Instruction {
spvExtInstIsNonSemantic(inst_.ext_inst_type);
}
/// True if this is an OpExtInst for debug info extension.
bool IsDebugInfo() const {
return opcode() == SpvOp::SpvOpExtInst &&
spvExtInstIsDebugInfo(inst_.ext_inst_type);
}
// Casts the words belonging to the operand under |index| to |T| and returns.
template <typename T>
T GetOperandAs(size_t index) const {

Просмотреть файл

@ -54,6 +54,16 @@ spv_result_t ValidateAdjacency(ValidationState_t& _) {
adjacency_status =
adjacency_status == IN_NEW_FUNCTION ? IN_ENTRY_BLOCK : PHI_VALID;
break;
case SpvOpExtInst:
// If it is a debug info instruction, we do not change the status to
// allow debug info instructions before OpVariable in a function.
// TODO(https://gitlab.khronos.org/spirv/SPIR-V/issues/533): We need
// to discuss the location of DebugScope, DebugNoScope, DebugDeclare,
// and DebugValue.
if (!spvExtInstIsDebugInfo(inst.ext_inst_type())) {
adjacency_status = PHI_AND_VAR_INVALID;
}
break;
case SpvOpPhi:
if (adjacency_status != PHI_VALID) {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)

Просмотреть файл

@ -88,7 +88,7 @@ spv_result_t ValidateFunction(ValidationState_t& _, const Instruction* inst) {
const auto* use = pair.first;
if (std::find(acceptable.begin(), acceptable.end(), use->opcode()) ==
acceptable.end() &&
!use->IsNonSemantic()) {
!use->IsNonSemantic() && !use->IsDebugInfo()) {
return _.diag(SPV_ERROR_INVALID_ID, use)
<< "Invalid use of function result id " << _.getIdName(inst->id())
<< ".";

Просмотреть файл

@ -131,7 +131,11 @@ spv_result_t CheckIdDefinitionDominateUse(ValidationState_t& _) {
// instruction operand's ID can be forward referenced.
spv_result_t IdPass(ValidationState_t& _, Instruction* inst) {
auto can_have_forward_declared_ids =
spvOperandCanBeForwardDeclaredFunction(inst->opcode());
inst->opcode() == SpvOpExtInst &&
spvExtInstIsDebugInfo(inst->ext_inst_type())
? spvDbgInfoExtOperandCanBeForwardDeclaredFunction(
inst->ext_inst_type(), inst->word(4))
: spvOperandCanBeForwardDeclaredFunction(inst->opcode());
// Keep track of a result id defined by this instruction. 0 means it
// does not define an id.

Просмотреть файл

@ -14,15 +14,16 @@
// Source code for logical layout validation as described in section 2.4
#include "source/val/validate.h"
#include <cassert>
#include "DebugInfo.h"
#include "OpenCLDebugInfo100.h"
#include "source/diagnostic.h"
#include "source/opcode.h"
#include "source/operand.h"
#include "source/val/function.h"
#include "source/val/instruction.h"
#include "source/val/validate.h"
#include "source/val/validation_state.h"
namespace spvtools {
@ -46,6 +47,53 @@ spv_result_t ModuleScopedInstructions(ValidationState_t& _,
<< "Non-semantic OpExtInst must not appear before types "
<< "section";
}
} else if (spvExtInstIsDebugInfo(inst->ext_inst_type())) {
const uint32_t ext_inst_index = inst->word(4);
bool local_debug_info = false;
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) {
local_debug_info = true;
}
} 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) {
local_debug_info = true;
}
}
if (local_debug_info) {
if (_.in_function_body() == false) {
// DebugScope, DebugNoScope, DebugDeclare, DebugValue must
// appear in a function body.
return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
<< "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
<< "of debug info extension must appear in a function "
<< "body";
}
} else {
// Debug info extinst opcodes other than DebugScope, DebugNoScope,
// DebugDeclare, DebugValue must be placed between section 9 (types,
// constants, global variables) and section 10 (function
// declarations).
if (_.current_layout_section() < kLayoutTypes ||
_.current_layout_section() >= kLayoutFunctionDeclarations) {
return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
<< "Debug info extension instructions other than "
<< "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
<< "must appear between section 9 (types, constants, "
<< "global variables) and section 10 (function "
<< "declarations)";
}
}
} else {
// otherwise they must be used in a block
if (_.current_layout_section() < kLayoutFunctionDefinitions) {
@ -182,6 +230,53 @@ spv_result_t FunctionScopedInstructions(ValidationState_t& _,
<< "Non-semantic OpExtInst within function definition must "
"appear in a block";
}
} else if (spvExtInstIsDebugInfo(inst->ext_inst_type())) {
const uint32_t ext_inst_index = inst->word(4);
bool local_debug_info = false;
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) {
local_debug_info = true;
}
} 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) {
local_debug_info = true;
}
}
if (local_debug_info) {
if (_.in_function_body() == false) {
// DebugScope, DebugNoScope, DebugDeclare, DebugValue must
// appear in a function body.
return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
<< "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
<< "of debug info extension must appear in a function "
<< "body";
}
} else {
// Debug info extinst opcodes other than DebugScope, DebugNoScope,
// DebugDeclare, DebugValue must be placed between section 9 (types,
// constants, global variables) and section 10 (function
// declarations).
if (_.current_layout_section() < kLayoutTypes ||
_.current_layout_section() >= kLayoutFunctionDeclarations) {
return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
<< "Debug info extension instructions other than "
<< "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
<< "must appear between section 9 (types, constants, "
<< "global variables) and section 10 (function "
<< "declarations)";
}
}
} else {
// otherwise they must be used in a block
if (_.in_block() == false) {

Просмотреть файл

@ -129,6 +129,621 @@ TEST(IrBuilder, KeepLineDebugInfo) {
// clang-format on
}
TEST(IrBuilder, ConsumeDebugInfoInst) {
// /* HLSL */
//
// struct VS_OUTPUT {
// float4 pos : SV_POSITION;
// float4 color : COLOR;
// };
//
// VS_OUTPUT main(float4 pos : POSITION,
// float4 color : COLOR) {
// VS_OUTPUT vout;
// vout.pos = pos;
// vout.color = color;
// return vout;
// }
DoRoundTripCheck(R"(OpCapability Shader
%1 = OpExtInstImport "OpenCL.DebugInfo.100"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main" %pos %color %gl_Position %out_var_COLOR
%7 = OpString "simple_vs.hlsl"
%8 = OpString "#line 1 \"simple_vs.hlsl\"
struct VS_OUTPUT {
float4 pos : SV_POSITION;
float4 color : COLOR;
};
VS_OUTPUT main(float4 pos : POSITION,
float4 color : COLOR) {
VS_OUTPUT vout;
vout.pos = pos;
vout.color = color;
return vout;
}
"
OpSource HLSL 600 %7 "#line 1 \"simple_vs.hlsl\"
struct VS_OUTPUT {
float4 pos : SV_POSITION;
float4 color : COLOR;
};
VS_OUTPUT main(float4 pos : POSITION,
float4 color : COLOR) {
VS_OUTPUT vout;
vout.pos = pos;
vout.color = color;
return vout;
}
"
%9 = OpString "struct VS_OUTPUT"
%10 = OpString "float"
%11 = OpString "pos : SV_POSITION"
%12 = OpString "color : COLOR"
%13 = OpString "VS_OUTPUT"
%14 = OpString "main"
%15 = OpString "VS_OUTPUT_main_v4f_v4f"
%16 = OpString "pos : POSITION"
%17 = OpString "color : COLOR"
%18 = OpString "vout"
OpName %out_var_COLOR "out.var.COLOR"
OpName %main "main"
OpName %VS_OUTPUT "VS_OUTPUT"
OpMemberName %VS_OUTPUT 0 "pos"
OpMemberName %VS_OUTPUT 1 "color"
OpName %pos "pos"
OpName %color "color"
OpName %vout "vout"
OpDecorate %gl_Position BuiltIn Position
OpDecorate %pos Location 0
OpDecorate %color Location 1
OpDecorate %out_var_COLOR Location 0
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%int_1 = OpConstant %int 1
%int_32 = OpConstant %int 32
%int_128 = OpConstant %int 128
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Input_v4float = OpTypePointer Input %v4float
%_ptr_Output_v4float = OpTypePointer Output %v4float
%void = OpTypeVoid
%31 = OpTypeFunction %void
%_ptr_Function_v4float = OpTypePointer Function %v4float
%VS_OUTPUT = OpTypeStruct %v4float %v4float
%_ptr_Function_VS_OUTPUT = OpTypePointer Function %VS_OUTPUT
OpLine %7 6 23
%pos = OpVariable %_ptr_Input_v4float Input
OpLine %7 7 23
%color = OpVariable %_ptr_Input_v4float Input
OpLine %7 2 16
%gl_Position = OpVariable %_ptr_Output_v4float Output
OpLine %7 3 18
%out_var_COLOR = OpVariable %_ptr_Output_v4float Output
%34 = OpExtInst %void %1 DebugSource %7 %8
%35 = OpExtInst %void %1 DebugCompilationUnit 2 4 %34 HLSL
%36 = OpExtInst %void %1 DebugTypeComposite %9 Structure %34 1 1 %35 %13 %int_128 FlagIsProtected|FlagIsPrivate %37 %38
%39 = OpExtInst %void %1 DebugTypeBasic %10 %int_32 Float
%40 = OpExtInst %void %1 DebugTypeVector %39 4
%37 = OpExtInst %void %1 DebugTypeMember %11 %40 %34 2 3 %36 %int_0 %int_128 FlagIsProtected|FlagIsPrivate
%38 = OpExtInst %void %1 DebugTypeMember %12 %40 %34 3 3 %36 %int_128 %int_128 FlagIsProtected|FlagIsPrivate
%41 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %36 %40 %40
%42 = OpExtInst %void %1 DebugExpression
%43 = OpExtInst %void %1 DebugFunction %14 %41 %34 6 1 %35 %15 FlagIsProtected|FlagIsPrivate 7 %main
%44 = OpExtInst %void %1 DebugLocalVariable %16 %40 %34 6 16 %43 FlagIsLocal 0
%45 = OpExtInst %void %1 DebugLocalVariable %17 %40 %34 7 16 %43 FlagIsLocal 1
%46 = OpExtInst %void %1 DebugLocalVariable %18 %36 %34 8 3 %43 FlagIsLocal
%47 = OpExtInst %void %1 DebugDeclare %44 %pos %42
%48 = OpExtInst %void %1 DebugDeclare %45 %color %42
OpLine %7 6 1
%main = OpFunction %void None %31
%49 = OpLabel
%50 = OpExtInst %void %1 DebugScope %43
OpLine %7 8 13
%vout = OpVariable %_ptr_Function_VS_OUTPUT Function
%51 = OpExtInst %void %1 DebugDeclare %46 %vout %42
OpLine %7 9 14
%52 = OpLoad %v4float %pos
OpLine %7 9 3
%53 = OpAccessChain %_ptr_Function_v4float %vout %int_0
%54 = OpExtInst %void %1 DebugValue %46 %53 %42 %int_0
OpStore %53 %52
OpLine %7 10 16
%55 = OpLoad %v4float %color
OpLine %7 10 3
%56 = OpAccessChain %_ptr_Function_v4float %vout %int_1
%57 = OpExtInst %void %1 DebugValue %46 %56 %42 %int_1
OpStore %56 %55
OpLine %7 11 10
%58 = OpLoad %VS_OUTPUT %vout
OpLine %7 11 3
%59 = OpCompositeExtract %v4float %58 0
OpStore %gl_Position %59
%60 = OpCompositeExtract %v4float %58 1
OpStore %out_var_COLOR %60
OpReturn
OpFunctionEnd
)");
}
TEST(IrBuilder, ConsumeDebugInfoLexicalScopeInst) {
// /* HLSL */
//
// float4 func2(float arg2) { // func2_block
// return float4(arg2, 0, 0, 0);
// }
//
// float4 func1(float arg1) { // func1_block
// if (arg1 > 1) { // if_true_block
// return float4(0, 0, 0, 0);
// }
// return func2(arg1); // if_merge_block
// }
//
// float4 main(float pos : POSITION) : SV_POSITION { // main
// return func1(pos);
// }
DoRoundTripCheck(R"(OpCapability Shader
%1 = OpExtInstImport "OpenCL.DebugInfo.100"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main" %pos %gl_Position
%5 = OpString "block/block.hlsl"
%6 = OpString "#line 1 \"block/block.hlsl\"
float4 func2(float arg2) {
return float4(arg2, 0, 0, 0);
}
float4 func1(float arg1) {
if (arg1 > 1) {
return float4(0, 0, 0, 0);
}
return func2(arg1);
}
float4 main(float pos : POSITION) : SV_POSITION {
return func1(pos);
}
"
OpSource HLSL 600 %5 "#line 1 \"block/block.hlsl\"
float4 func2(float arg2) {
return float4(arg2, 0, 0, 0);
}
float4 func1(float arg1) {
if (arg1 > 1) {
return float4(0, 0, 0, 0);
}
return func2(arg1);
}
float4 main(float pos : POSITION) : SV_POSITION {
return func1(pos);
}
"
%7 = OpString "float"
%8 = OpString "main"
%9 = OpString "v4f_main_f"
%10 = OpString "v4f_func1_f"
%11 = OpString "v4f_func2_f"
%12 = OpString "pos : POSITION"
%13 = OpString "func1"
%14 = OpString "func2"
OpName %main "main"
OpName %pos "pos"
OpName %bb_entry "bb.entry"
OpName %param_var_arg1 "param.var.arg1"
OpName %func1 "func1"
OpName %arg1 "arg1"
OpName %bb_entry_0 "bb.entry"
OpName %param_var_arg2 "param.var.arg2"
OpName %if_true "if.true"
OpName %if_merge "if.merge"
OpName %func2 "func2"
OpName %arg2 "arg2"
OpName %bb_entry_1 "bb.entry"
OpDecorate %gl_Position BuiltIn Position
OpDecorate %pos Location 0
%float = OpTypeFloat 32
%int = OpTypeInt 32 1
%float_1 = OpConstant %float 1
%float_0 = OpConstant %float 0
%int_32 = OpConstant %int 32
%v4float = OpTypeVector %float 4
%32 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
%_ptr_Input_float = OpTypePointer Input %float
%_ptr_Output_v4float = OpTypePointer Output %v4float
%void = OpTypeVoid
%36 = OpTypeFunction %void
%_ptr_Function_float = OpTypePointer Function %float
%38 = OpTypeFunction %v4float %_ptr_Function_float
%bool = OpTypeBool
OpLine %5 12 25
%pos = OpVariable %_ptr_Input_float Input
OpLine %5 12 37
%gl_Position = OpVariable %_ptr_Output_v4float Output
%40 = OpExtInst %void %1 DebugSource %5 %6
%41 = OpExtInst %void %1 DebugCompilationUnit 2 4 %40 HLSL
%42 = OpExtInst %void %1 DebugTypeBasic %7 %int_32 Float
%43 = OpExtInst %void %1 DebugTypeVector %42 4
%44 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %42
%45 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %42
%46 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %42
%47 = OpExtInst %void %1 DebugFunction %8 %44 %40 12 1 %41 %9 FlagIsProtected|FlagIsPrivate 13 %main
%48 = OpExtInst %void %1 DebugFunction %13 %45 %40 5 1 %41 %10 FlagIsProtected|FlagIsPrivate 13 %func1
%49 = OpExtInst %void %1 DebugFunction %14 %46 %40 1 1 %41 %11 FlagIsProtected|FlagIsPrivate 13 %func2
%50 = OpExtInst %void %1 DebugLexicalBlock %40 6 17 %48
%51 = OpExtInst %void %1 DebugLexicalBlock %40 9 3 %48
OpLine %5 12 1
%main = OpFunction %void None %36
%bb_entry = OpLabel
%52 = OpExtInst %void %1 DebugScope %47
OpLine %5 13 16
%param_var_arg1 = OpVariable %_ptr_Function_float Function
%53 = OpLoad %float %pos
OpStore %param_var_arg1 %53
OpLine %5 13 10
%54 = OpFunctionCall %v4float %func1 %param_var_arg1
OpLine %5 13 3
OpStore %gl_Position %54
OpReturn
OpFunctionEnd
OpLine %5 5 1
%func1 = OpFunction %v4float None %38
OpLine %5 5 20
%arg1 = OpFunctionParameter %_ptr_Function_float
%bb_entry_0 = OpLabel
%55 = OpExtInst %void %1 DebugScope %48
OpLine %5 9 16
%param_var_arg2 = OpVariable %_ptr_Function_float Function
OpLine %5 6 7
%56 = OpLoad %float %arg1
OpLine %5 6 12
%57 = OpFOrdGreaterThan %bool %56 %float_1
OpLine %5 6 17
OpSelectionMerge %if_merge None
OpBranchConditional %57 %if_true %if_merge
%if_true = OpLabel
%58 = OpExtInst %void %1 DebugScope %50
OpLine %5 7 5
OpReturnValue %32
%if_merge = OpLabel
%59 = OpExtInst %void %1 DebugScope %51
OpLine %5 9 16
%60 = OpLoad %float %arg1
OpStore %param_var_arg2 %60
OpLine %5 9 10
%61 = OpFunctionCall %v4float %func2 %param_var_arg2
OpLine %5 9 3
OpReturnValue %61
OpFunctionEnd
OpLine %5 1 1
%func2 = OpFunction %v4float None %38
OpLine %5 1 20
%arg2 = OpFunctionParameter %_ptr_Function_float
%bb_entry_1 = OpLabel
%62 = OpExtInst %void %1 DebugScope %49
OpLine %5 2 17
%63 = OpLoad %float %arg2
%64 = OpCompositeConstruct %v4float %63 %float_0 %float_0 %float_0
OpLine %5 2 3
OpReturnValue %64
OpFunctionEnd
)");
}
TEST(IrBuilder, ConsumeDebugInlinedAt) {
// /* HLSL */
//
// float4 func2(float arg2) { // func2_block
// return float4(arg2, 0, 0, 0);
// }
//
// float4 func1(float arg1) { // func1_block
// if (arg1 > 1) { // if_true_block
// return float4(0, 0, 0, 0);
// }
// return func2(arg1); // if_merge_block
// }
//
// float4 main(float pos : POSITION) : SV_POSITION { // main
// return func1(pos);
// }
//
// TODO(https://gitlab.khronos.org/spirv/SPIR-V/issues/533): In the following
// SPIRV code, we use DebugInfoNone to reference opted-out function from
// DebugFunction similar to opted-out global variable for DebugGlobalVariable,
// but this is not a part of the spec yet. We are still in discussion and we
// must correct it if our decision is different.
DoRoundTripCheck(R"(OpCapability Shader
%1 = OpExtInstImport "OpenCL.DebugInfo.100"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main" %pos %gl_Position
%5 = OpString "block/block.hlsl"
%6 = OpString "#line 1 \"block/block.hlsl\"
float4 func2(float arg2) {
return float4(arg2, 0, 0, 0);
}
float4 func1(float arg1) {
if (arg1 > 1) {
return float4(0, 0, 0, 0);
}
return func2(arg1);
}
float4 main(float pos : POSITION) : SV_POSITION {
return func1(pos);
}
"
OpSource HLSL 600 %5 "#line 1 \"block/block.hlsl\"
float4 func2(float arg2) {
return float4(arg2, 0, 0, 0);
}
float4 func1(float arg1) {
if (arg1 > 1) {
return float4(0, 0, 0, 0);
}
return func2(arg1);
}
float4 main(float pos : POSITION) : SV_POSITION {
return func1(pos);
}
"
%7 = OpString "float"
%8 = OpString "main"
%9 = OpString "v4f_main_f"
%10 = OpString "v4f_func1_f"
%11 = OpString "v4f_func2_f"
%12 = OpString "pos : POSITION"
%13 = OpString "func1"
%14 = OpString "func2"
OpName %main "main"
OpName %pos "pos"
OpName %bb_entry "bb.entry"
OpName %if_true "if.true"
OpName %if_merge "if.merge"
OpDecorate %gl_Position BuiltIn Position
OpDecorate %pos Location 0
%float = OpTypeFloat 32
%int = OpTypeInt 32 1
%float_1 = OpConstant %float 1
%float_0 = OpConstant %float 0
%int_32 = OpConstant %int 32
%v4float = OpTypeVector %float 4
%24 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
%_ptr_Input_float = OpTypePointer Input %float
%_ptr_Output_v4float = OpTypePointer Output %v4float
%void = OpTypeVoid
%28 = OpTypeFunction %void
%_ptr_Function_float = OpTypePointer Function %float
%30 = OpTypeFunction %v4float %_ptr_Function_float
%bool = OpTypeBool
OpLine %5 12 25
%pos = OpVariable %_ptr_Input_float Input
OpLine %5 12 37
%gl_Position = OpVariable %_ptr_Output_v4float Output
%32 = OpExtInst %void %1 DebugInfoNone
%33 = OpExtInst %void %1 DebugSource %5 %6
%34 = OpExtInst %void %1 DebugCompilationUnit 2 4 %33 HLSL
%35 = OpExtInst %void %1 DebugTypeBasic %7 %int_32 Float
%36 = OpExtInst %void %1 DebugTypeVector %35 4
%37 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %36 %35
%38 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %36 %35
%39 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %36 %35
%40 = OpExtInst %void %1 DebugFunction %8 %37 %33 12 1 %34 %9 FlagIsProtected|FlagIsPrivate 13 %main
%41 = OpExtInst %void %1 DebugFunction %13 %38 %33 5 1 %34 %10 FlagIsProtected|FlagIsPrivate 13 %32
%42 = OpExtInst %void %1 DebugFunction %14 %39 %33 1 1 %34 %11 FlagIsProtected|FlagIsPrivate 13 %32
%43 = OpExtInst %void %1 DebugLexicalBlock %33 12 49 %40
%44 = OpExtInst %void %1 DebugLexicalBlock %33 5 26 %41
%45 = OpExtInst %void %1 DebugLexicalBlock %33 1 26 %42
%46 = OpExtInst %void %1 DebugLexicalBlock %33 6 17 %44
%47 = OpExtInst %void %1 DebugLexicalBlock %33 9 3 %44
%48 = OpExtInst %void %1 DebugInlinedAt 9 %47
%49 = OpExtInst %void %1 DebugInlinedAt 13 %43
%50 = OpExtInst %void %1 DebugInlinedAt 13 %43 %48
OpLine %5 12 1
%main = OpFunction %void None %28
%bb_entry = OpLabel
%51 = OpExtInst %void %1 DebugScope %44 %49
OpLine %5 6 7
%52 = OpLoad %float %pos
OpLine %5 6 12
%53 = OpFOrdGreaterThan %bool %52 %float_1
OpLine %5 6 17
OpSelectionMerge %if_merge None
OpBranchConditional %53 %if_true %if_merge
%if_true = OpLabel
%54 = OpExtInst %void %1 DebugScope %46 %49
OpLine %5 7 5
OpStore %gl_Position %24
OpReturn
%if_merge = OpLabel
%55 = OpExtInst %void %1 DebugScope %45 %50
OpLine %5 2 17
%56 = OpLoad %float %pos
OpLine %5 2 10
%57 = OpCompositeConstruct %v4float %56 %float_0 %float_0 %float_0
%58 = OpExtInst %void %1 DebugScope %43
OpLine %5 13 3
OpStore %gl_Position %57
OpReturn
OpFunctionEnd
)");
}
TEST(IrBuilder, DebugInfoInstInFunctionOutOfBlock) {
// /* HLSL */
//
// float4 func2(float arg2) { // func2_block
// return float4(arg2, 0, 0, 0);
// }
//
// float4 func1(float arg1) { // func1_block
// if (arg1 > 1) { // if_true_block
// return float4(0, 0, 0, 0);
// }
// return func2(arg1); // if_merge_block
// }
//
// float4 main(float pos : POSITION) : SV_POSITION { // main
// return func1(pos);
// }
const std::string text = R"(OpCapability Shader
%1 = OpExtInstImport "OpenCL.DebugInfo.100"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main" %pos %gl_Position
%5 = OpString "block/block.hlsl"
%6 = OpString "#line 1 \"block/block.hlsl\"
float4 func2(float arg2) {
return float4(arg2, 0, 0, 0);
}
float4 func1(float arg1) {
if (arg1 > 1) {
return float4(0, 0, 0, 0);
}
return func2(arg1);
}
float4 main(float pos : POSITION) : SV_POSITION {
return func1(pos);
}
"
OpSource HLSL 600 %5 "#line 1 \"block/block.hlsl\"
float4 func2(float arg2) {
return float4(arg2, 0, 0, 0);
}
float4 func1(float arg1) {
if (arg1 > 1) {
return float4(0, 0, 0, 0);
}
return func2(arg1);
}
float4 main(float pos : POSITION) : SV_POSITION {
return func1(pos);
}
"
%7 = OpString "float"
%8 = OpString "main"
%9 = OpString "v4f_main_f"
%10 = OpString "v4f_func1_f"
%11 = OpString "v4f_func2_f"
%12 = OpString "pos : POSITION"
%13 = OpString "func1"
%14 = OpString "func2"
OpName %main "main"
OpName %pos "pos"
OpName %bb_entry "bb.entry"
OpName %param_var_arg1 "param.var.arg1"
OpName %func1 "func1"
OpName %arg1 "arg1"
OpName %bb_entry_0 "bb.entry"
OpName %param_var_arg2 "param.var.arg2"
OpName %if_true "if.true"
OpName %if_merge "if.merge"
OpName %func2 "func2"
OpName %arg2 "arg2"
OpName %bb_entry_1 "bb.entry"
OpDecorate %gl_Position BuiltIn Position
OpDecorate %pos Location 0
%float = OpTypeFloat 32
%int = OpTypeInt 32 1
%float_1 = OpConstant %float 1
%float_0 = OpConstant %float 0
%int_32 = OpConstant %int 32
%v4float = OpTypeVector %float 4
%32 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
%_ptr_Input_float = OpTypePointer Input %float
%_ptr_Output_v4float = OpTypePointer Output %v4float
%void = OpTypeVoid
%36 = OpTypeFunction %void
%_ptr_Function_float = OpTypePointer Function %float
%38 = OpTypeFunction %v4float %_ptr_Function_float
%bool = OpTypeBool
OpLine %5 12 25
%pos = OpVariable %_ptr_Input_float Input
OpLine %5 12 37
%gl_Position = OpVariable %_ptr_Output_v4float Output
%40 = OpExtInst %void %1 DebugSource %5 %6
%41 = OpExtInst %void %1 DebugCompilationUnit 2 4 %40 HLSL
%42 = OpExtInst %void %1 DebugTypeBasic %7 %int_32 Float
%43 = OpExtInst %void %1 DebugTypeVector %42 4
%44 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %42
%45 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %42
%46 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %42
%47 = OpExtInst %void %1 DebugFunction %8 %44 %40 12 1 %41 %9 FlagIsProtected|FlagIsPrivate 13 %main
%48 = OpExtInst %void %1 DebugFunction %13 %45 %40 5 1 %41 %10 FlagIsProtected|FlagIsPrivate 13 %func1
%49 = OpExtInst %void %1 DebugFunction %14 %46 %40 1 1 %41 %11 FlagIsProtected|FlagIsPrivate 13 %func2
%50 = OpExtInst %void %1 DebugLexicalBlock %40 6 17 %48
%51 = OpExtInst %void %1 DebugLexicalBlock %40 9 3 %48
OpLine %5 12 1
%main = OpFunction %void None %36
%52 = OpExtInst %void %1 DebugScope %47
%bb_entry = OpLabel
OpLine %5 13 16
%param_var_arg1 = OpVariable %_ptr_Function_float Function
%53 = OpLoad %float %pos
OpStore %param_var_arg1 %53
OpLine %5 13 10
%54 = OpFunctionCall %v4float %func1 %param_var_arg1
OpLine %5 13 3
OpStore %gl_Position %54
OpReturn
OpFunctionEnd
OpLine %5 5 1
%func1 = OpFunction %v4float None %38
OpLine %5 5 20
%arg1 = OpFunctionParameter %_ptr_Function_float
%bb_entry_0 = OpLabel
%55 = OpExtInst %void %1 DebugScope %48
OpLine %5 9 16
%param_var_arg2 = OpVariable %_ptr_Function_float Function
OpLine %5 6 7
%56 = OpLoad %float %arg1
OpLine %5 6 12
%57 = OpFOrdGreaterThan %bool %56 %float_1
OpLine %5 6 17
OpSelectionMerge %if_merge None
OpBranchConditional %57 %if_true %if_merge
%if_true = OpLabel
%58 = OpExtInst %void %1 DebugScope %50
OpLine %5 7 5
OpReturnValue %32
%if_merge = OpLabel
%59 = OpExtInst %void %1 DebugScope %51
OpLine %5 9 16
%60 = OpLoad %float %arg1
OpStore %param_var_arg2 %60
OpLine %5 9 10
%61 = OpFunctionCall %v4float %func2 %param_var_arg2
OpLine %5 9 3
OpReturnValue %61
OpFunctionEnd
OpLine %5 1 1
%func2 = OpFunction %v4float None %38
OpLine %5 1 20
%arg2 = OpFunctionParameter %_ptr_Function_float
%bb_entry_1 = OpLabel
%62 = OpExtInst %void %1 DebugScope %49
OpLine %5 2 17
%63 = OpLoad %float %arg2
%64 = OpCompositeConstruct %v4float %63 %float_0 %float_0 %float_0
OpLine %5 2 3
OpReturnValue %64
OpFunctionEnd
)";
SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
std::unique_ptr<IRContext> context =
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text);
ASSERT_EQ(nullptr, context);
}
TEST(IrBuilder, LocalGlobalVariables) {
// #version 310 es
//

Просмотреть файл

@ -33,6 +33,9 @@ using ::testing::HasSubstr;
using ::testing::Not;
using ValidateExtInst = spvtest::ValidateBase<bool>;
using ValidateOldDebugInfo = spvtest::ValidateBase<std::string>;
using ValidateOpenCL100DebugInfo = spvtest::ValidateBase<std::string>;
using ValidateLocalDebugInfoOutOfFunction = spvtest::ValidateBase<std::string>;
using ValidateGlslStd450SqrtLike = spvtest::ValidateBase<std::string>;
using ValidateGlslStd450FMinLike = spvtest::ValidateBase<std::string>;
using ValidateGlslStd450FClampLike = spvtest::ValidateBase<std::string>;
@ -460,6 +463,462 @@ OpFunctionEnd)";
return ss.str();
}
std::string GenerateShaderCodeForDebugInfo(
const std::string& op_string_instructions,
const std::string& op_const_instructions,
const std::string& debug_instructions_before_main, const std::string& body,
const std::string& capabilities_and_extensions = "",
const std::string& execution_model = "Fragment") {
std::ostringstream ss;
ss << R"(
OpCapability Shader
OpCapability Float16
OpCapability Float64
OpCapability Int16
OpCapability Int64
)";
ss << capabilities_and_extensions;
ss << "%extinst = OpExtInstImport \"GLSL.std.450\"\n";
ss << "OpMemoryModel Logical GLSL450\n";
ss << "OpEntryPoint " << execution_model << " %main \"main\""
<< " %f32_output"
<< " %f32vec2_output"
<< " %u32_output"
<< " %u32vec2_output"
<< " %u64_output"
<< " %f32_input"
<< " %f32vec2_input"
<< " %u32_input"
<< " %u32vec2_input"
<< " %u64_input"
<< "\n";
if (execution_model == "Fragment") {
ss << "OpExecutionMode %main OriginUpperLeft\n";
}
ss << op_string_instructions;
ss << R"(
%void = OpTypeVoid
%func = OpTypeFunction %void
%bool = OpTypeBool
%f16 = OpTypeFloat 16
%f32 = OpTypeFloat 32
%f64 = OpTypeFloat 64
%u32 = OpTypeInt 32 0
%s32 = OpTypeInt 32 1
%u64 = OpTypeInt 64 0
%s64 = OpTypeInt 64 1
%u16 = OpTypeInt 16 0
%s16 = OpTypeInt 16 1
%f32vec2 = OpTypeVector %f32 2
%f32vec3 = OpTypeVector %f32 3
%f32vec4 = OpTypeVector %f32 4
%f64vec2 = OpTypeVector %f64 2
%f64vec3 = OpTypeVector %f64 3
%f64vec4 = OpTypeVector %f64 4
%u32vec2 = OpTypeVector %u32 2
%u32vec3 = OpTypeVector %u32 3
%s32vec2 = OpTypeVector %s32 2
%u32vec4 = OpTypeVector %u32 4
%s32vec4 = OpTypeVector %s32 4
%u64vec2 = OpTypeVector %u64 2
%s64vec2 = OpTypeVector %s64 2
%f64mat22 = OpTypeMatrix %f64vec2 2
%f32mat22 = OpTypeMatrix %f32vec2 2
%f32mat23 = OpTypeMatrix %f32vec2 3
%f32mat32 = OpTypeMatrix %f32vec3 2
%f32mat33 = OpTypeMatrix %f32vec3 3
%f32_0 = OpConstant %f32 0
%f32_1 = OpConstant %f32 1
%f32_2 = OpConstant %f32 2
%f32_3 = OpConstant %f32 3
%f32_4 = OpConstant %f32 4
%f32_h = OpConstant %f32 0.5
%f32vec2_01 = OpConstantComposite %f32vec2 %f32_0 %f32_1
%f32vec2_12 = OpConstantComposite %f32vec2 %f32_1 %f32_2
%f32vec3_012 = OpConstantComposite %f32vec3 %f32_0 %f32_1 %f32_2
%f32vec3_123 = OpConstantComposite %f32vec3 %f32_1 %f32_2 %f32_3
%f32vec4_0123 = OpConstantComposite %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3
%f32vec4_1234 = OpConstantComposite %f32vec4 %f32_1 %f32_2 %f32_3 %f32_4
%f64_0 = OpConstant %f64 0
%f64_1 = OpConstant %f64 1
%f64_2 = OpConstant %f64 2
%f64_3 = OpConstant %f64 3
%f64vec2_01 = OpConstantComposite %f64vec2 %f64_0 %f64_1
%f64vec3_012 = OpConstantComposite %f64vec3 %f64_0 %f64_1 %f64_2
%f64vec4_0123 = OpConstantComposite %f64vec4 %f64_0 %f64_1 %f64_2 %f64_3
%f16_0 = OpConstant %f16 0
%f16_1 = OpConstant %f16 1
%f16_h = OpConstant %f16 0.5
%u32_0 = OpConstant %u32 0
%u32_1 = OpConstant %u32 1
%u32_2 = OpConstant %u32 2
%u32_3 = OpConstant %u32 3
%s32_0 = OpConstant %s32 0
%s32_1 = OpConstant %s32 1
%s32_2 = OpConstant %s32 2
%s32_3 = OpConstant %s32 3
%u64_0 = OpConstant %u64 0
%u64_1 = OpConstant %u64 1
%u64_2 = OpConstant %u64 2
%u64_3 = OpConstant %u64 3
%s64_0 = OpConstant %s64 0
%s64_1 = OpConstant %s64 1
%s64_2 = OpConstant %s64 2
%s64_3 = OpConstant %s64 3
)";
ss << op_const_instructions;
ss << R"(
%s32vec2_01 = OpConstantComposite %s32vec2 %s32_0 %s32_1
%u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1
%s32vec2_12 = OpConstantComposite %s32vec2 %s32_1 %s32_2
%u32vec2_12 = OpConstantComposite %u32vec2 %u32_1 %u32_2
%s32vec4_0123 = OpConstantComposite %s32vec4 %s32_0 %s32_1 %s32_2 %s32_3
%u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3
%s64vec2_01 = OpConstantComposite %s64vec2 %s64_0 %s64_1
%u64vec2_01 = OpConstantComposite %u64vec2 %u64_0 %u64_1
%f32mat22_1212 = OpConstantComposite %f32mat22 %f32vec2_12 %f32vec2_12
%f32mat23_121212 = OpConstantComposite %f32mat23 %f32vec2_12 %f32vec2_12 %f32vec2_12
%f32_ptr_output = OpTypePointer Output %f32
%f32vec2_ptr_output = OpTypePointer Output %f32vec2
%u32_ptr_output = OpTypePointer Output %u32
%u32vec2_ptr_output = OpTypePointer Output %u32vec2
%u64_ptr_output = OpTypePointer Output %u64
%f32_output = OpVariable %f32_ptr_output Output
%f32vec2_output = OpVariable %f32vec2_ptr_output Output
%u32_output = OpVariable %u32_ptr_output Output
%u32vec2_output = OpVariable %u32vec2_ptr_output Output
%u64_output = OpVariable %u64_ptr_output Output
%f32_ptr_input = OpTypePointer Input %f32
%f32vec2_ptr_input = OpTypePointer Input %f32vec2
%u32_ptr_input = OpTypePointer Input %u32
%u32vec2_ptr_input = OpTypePointer Input %u32vec2
%u64_ptr_input = OpTypePointer Input %u64
%f32_ptr_function = OpTypePointer Function %f32
%f32_input = OpVariable %f32_ptr_input Input
%f32vec2_input = OpVariable %f32vec2_ptr_input Input
%u32_input = OpVariable %u32_ptr_input Input
%u32vec2_input = OpVariable %u32vec2_ptr_input Input
%u64_input = OpVariable %u64_ptr_input Input
%u32_ptr_function = OpTypePointer Function %u32
%struct_f16_u16 = OpTypeStruct %f16 %u16
%struct_f32_f32 = OpTypeStruct %f32 %f32
%struct_f32_f32_f32 = OpTypeStruct %f32 %f32 %f32
%struct_f32_u32 = OpTypeStruct %f32 %u32
%struct_f32_u32_f32 = OpTypeStruct %f32 %u32 %f32
%struct_u32_f32 = OpTypeStruct %u32 %f32
%struct_u32_u32 = OpTypeStruct %u32 %u32
%struct_f32_f64 = OpTypeStruct %f32 %f64
%struct_f32vec2_f32vec2 = OpTypeStruct %f32vec2 %f32vec2
%struct_f32vec2_u32vec2 = OpTypeStruct %f32vec2 %u32vec2
)";
ss << debug_instructions_before_main;
ss << R"(
%main = OpFunction %void None %func
%main_entry = OpLabel
)";
ss << body;
ss << R"(
OpReturn
OpFunctionEnd)";
return ss.str();
}
TEST_F(ValidateOldDebugInfo, UseDebugInstructionOutOfFunction) {
const std::string src = R"(
%code = OpString "main() {}"
)";
const std::string dbg_inst = R"(
%cu = OpExtInst %void %DbgExt DebugCompilationUnit %code 1 1
)";
const std::string extension = R"(
%DbgExt = OpExtInstImport "DebugInfo"
)";
CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "",
extension, "Vertex"));
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateOpenCL100DebugInfo, UseDebugInstructionOutOfFunction) {
const std::string src = R"(
%src = OpString "simple.hlsl"
%code = OpString "main() {}"
)";
const std::string dbg_inst = R"(
%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code
)";
const std::string extension = R"(
%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100"
)";
CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "",
extension, "Vertex"));
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateOpenCL100DebugInfo, DebugSourceInFunction) {
const std::string src = R"(
%src = OpString "simple.hlsl"
%code = OpString "main() {}"
)";
const std::string dbg_inst = R"(
%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code
)";
const std::string extension = R"(
%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100"
)";
CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", "", dbg_inst,
extension, "Vertex"));
ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Debug info extension instructions other than DebugScope, "
"DebugNoScope, DebugDeclare, DebugValue must appear between "
"section 9 (types, constants, global variables) and section 10 "
"(function declarations)"));
}
TEST_P(ValidateLocalDebugInfoOutOfFunction, OpenCLDebugInfo100DebugScope) {
const std::string src = R"(
%src = OpString "simple.hlsl"
%code = OpString "void main() {}"
%void_name = OpString "void"
%main_name = OpString "main"
%main_linkage_name = OpString "v_main"
%int_name = OpString "int"
%foo_name = OpString "foo"
)";
const std::string dbg_inst_header = R"(
%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code
%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL
%void_info = OpExtInst %void %DbgExt DebugTypeBasic %void_name %u32_0 Unspecified
%int_info = OpExtInst %void %DbgExt DebugTypeBasic %int_name %u32_0 Signed
%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void_info %void_info
%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_linkage_name FlagIsPublic 1 %main
%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %int_info %dbg_src 1 1 %main_info FlagIsLocal
%expr = OpExtInst %void %DbgExt DebugExpression
)";
const std::string body = R"(
%foo = OpVariable %u32_ptr_function Function
%foo_val = OpLoad %u32 %foo
)";
const std::string extension = R"(
%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100"
)";
CompileSuccessfully(GenerateShaderCodeForDebugInfo(
src, "", dbg_inst_header + GetParam(), body, extension, "Vertex"));
ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("DebugScope, DebugNoScope, DebugDeclare, DebugValue "
"of debug info extension must appear in a function "
"body"));
}
INSTANTIATE_TEST_SUITE_P(
AllLocalDebugInfo, ValidateLocalDebugInfoOutOfFunction,
::testing::ValuesIn(std::vector<std::string>{
"%main_scope = OpExtInst %void %DbgExt DebugScope %main_info",
"%no_scope = OpExtInst %void %DbgExt DebugNoScope",
}));
TEST_F(ValidateOpenCL100DebugInfo, DebugFunctionForwardReference) {
const std::string src = R"(
%src = OpString "simple.hlsl"
%code = OpString "void main() {}"
%void_name = OpString "void"
%main_name = OpString "main"
%main_linkage_name = OpString "v_main"
)";
const std::string dbg_inst_header = R"(
%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code
%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL
%void_info = OpExtInst %void %DbgExt DebugTypeBasic %void_name %u32_0 Unspecified
%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void_info %void_info
%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_linkage_name FlagIsPublic 1 %main
)";
const std::string body = R"(
%main_scope = OpExtInst %void %DbgExt DebugScope %main_info
)";
const std::string extension = R"(
%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100"
)";
CompileSuccessfully(GenerateShaderCodeForDebugInfo(
src, "", dbg_inst_header, body, extension, "Vertex"));
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateOpenCL100DebugInfo, DebugScopeBeforeOpVariableInFunction) {
const std::string src = R"(
%src = OpString "simple.hlsl"
%code = OpString "float4 main(float arg) {
float foo;
return float4(0, 0, 0, 0);
}
"
%float_name = OpString "float"
%main_name = OpString "main"
%main_linkage_name = OpString "v4f_main_f"
)";
const std::string size_const = R"(
%int_32 = OpConstant %u32 32
)";
const std::string dbg_inst_header = R"(
%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code
%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL
%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float
%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4
%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %v4float_info %float_info
%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %main
)";
const std::string body = R"(
%main_scope = OpExtInst %void %DbgExt DebugScope %main_info
%foo = OpVariable %f32_ptr_function Function
)";
const std::string extension = R"(
%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100"
)";
CompileSuccessfully(GenerateShaderCodeForDebugInfo(
src, size_const, dbg_inst_header, body, extension, "Vertex"));
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateOpenCL100DebugInfo, DebugTypeCompositeForwardReference) {
const std::string src = R"(
%src = OpString "simple.hlsl"
%code = OpString "struct VS_OUTPUT {
float4 pos : SV_POSITION;
float4 color : COLOR;
};
main() {}
"
%VS_OUTPUT_name = OpString "struct VS_OUTPUT"
%float_name = OpString "float"
%VS_OUTPUT_pos_name = OpString "pos : SV_POSITION"
%VS_OUTPUT_color_name = OpString "color : COLOR"
%VS_OUTPUT_linkage_name = OpString "VS_OUTPUT"
)";
const std::string size_const = R"(
%int_32 = OpConstant %u32 32
%int_128 = OpConstant %u32 128
)";
const std::string dbg_inst_header = R"(
%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code
%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL
%VS_OUTPUT_info = OpExtInst %void %DbgExt DebugTypeComposite %VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %VS_OUTPUT_color_info
%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float
%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4
%VS_OUTPUT_pos_info = OpExtInst %void %DbgExt DebugTypeMember %VS_OUTPUT_pos_name %v4float_info %dbg_src 2 3 %VS_OUTPUT_info %u32_0 %int_128 FlagIsPublic
%VS_OUTPUT_color_info = OpExtInst %void %DbgExt DebugTypeMember %VS_OUTPUT_color_name %v4float_info %dbg_src 3 3 %VS_OUTPUT_info %int_128 %int_128 FlagIsPublic
)";
const std::string extension = R"(
%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100"
)";
CompileSuccessfully(GenerateShaderCodeForDebugInfo(
src, size_const, dbg_inst_header, "", extension, "Vertex"));
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateOpenCL100DebugInfo, DebugTypeCompositeMissingReference) {
const std::string src = R"(
%src = OpString "simple.hlsl"
%code = OpString "struct VS_OUTPUT {
float4 pos : SV_POSITION;
float4 color : COLOR;
};
main() {}
"
%VS_OUTPUT_name = OpString "struct VS_OUTPUT"
%float_name = OpString "float"
%VS_OUTPUT_pos_name = OpString "pos : SV_POSITION"
%VS_OUTPUT_color_name = OpString "color : COLOR"
%VS_OUTPUT_linkage_name = OpString "VS_OUTPUT"
)";
const std::string size_const = R"(
%int_32 = OpConstant %u32 32
%int_128 = OpConstant %u32 128
)";
const std::string dbg_inst_header = R"(
%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code
%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL
%VS_OUTPUT_info = OpExtInst %void %DbgExt DebugTypeComposite %VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %VS_OUTPUT_color_info
%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float
%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4
%VS_OUTPUT_pos_info = OpExtInst %void %DbgExt DebugTypeMember %VS_OUTPUT_pos_name %v4float_info %dbg_src 2 3 %VS_OUTPUT_info %u32_0 %int_128 FlagIsPublic
)";
const std::string extension = R"(
%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100"
)";
CompileSuccessfully(GenerateShaderCodeForDebugInfo(
src, size_const, dbg_inst_header, "", extension, "Vertex"));
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("forward referenced IDs have not been defined"));
}
TEST_P(ValidateGlslStd450SqrtLike, Success) {
const std::string ext_inst_name = GetParam();
std::ostringstream ss;