Skip to content

Commit 8b5f796

Browse files
spirv-val: Add ShaderDebugInfo EntryPoint (KhronosGroup#6691)
Part of KhronosGroup#6617 - Add proper `DebugNoLine` support - For things that point to the Entry point functions, print the functions out ``` error: 6: Local Size execution mode must not have a product of zero (X = 0, Y = 1, Z = 1). OpExecutionMode %2 LocalSize 0 1 1 --> a.comp:3:0 | 3 | void main() { | error: 5: [VUID-StandaloneSpirv-None-04633] OpEntryPoint Entry Point <id> '2[%2]'s function return type is not void. OpEntryPoint GLCompute %2 "main" --> a.comp:3:0 | 3 | void main() { | ```
1 parent 860c90a commit 8b5f796

3 files changed

Lines changed: 196 additions & 17 deletions

File tree

source/val/validation_state.cpp

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2188,19 +2188,24 @@ std::string ValidationState_t::InspectShaderDebugInfo(const Instruction& inst) {
21882188

21892189
std::ostringstream ss;
21902190
const Function* func = inst.function();
2191+
const spv::Op opcode = inst.opcode();
21912192
if (func != nullptr) {
2192-
if (inst.opcode() == spv::Op::OpVariable) {
2193+
if (opcode == spv::Op::OpVariable) {
21932194
InspectDebugLocalVariable(ss, *func, inst);
2194-
} else if (inst.opcode() == spv::Op::OpFunctionCall) {
2195-
InspectDebugFunctionDefinition(ss, inst);
2195+
} else if (opcode == spv::Op::OpFunctionCall) {
2196+
InspectFunctionCall(ss, inst);
21962197
} else {
21972198
// Currently a fall back for anything in a function
21982199
InspectDebugLine(ss, inst);
21992200
}
2200-
} else if (inst.opcode() == spv::Op::OpVariable) {
2201+
} else if (opcode == spv::Op::OpVariable) {
22012202
// Know are global because not in any function
22022203
// TODO - test with OpUntypedVariable as well
22032204
InspectDebugGlobalVariable(ss, inst);
2205+
} else if (opcode == spv::Op::OpExecutionMode ||
2206+
opcode == spv::Op::OpExecutionModeId ||
2207+
opcode == spv::Op::OpEntryPoint) {
2208+
InspectEntryPoint(ss, inst);
22042209
}
22052210

22062211
return ss.str();
@@ -2301,11 +2306,15 @@ void ValidationState_t::InspectDebugLine(std::ostringstream& ss,
23012306
}
23022307

23032308
if (prev->opcode() == spv::Op::OpExtInst &&
2304-
prev->GetOperandAs<uint32_t>(2) == set_id &&
2305-
prev->GetOperandAs<uint32_t>(3) ==
2306-
NonSemanticShaderDebugInfoDebugLine) {
2307-
debug_line_inst = prev;
2308-
break;
2309+
prev->GetOperandAs<uint32_t>(2) == set_id) {
2310+
const uint32_t ext_inst = prev->GetOperandAs<uint32_t>(3);
2311+
if (ext_inst == NonSemanticShaderDebugInfoDebugLine) {
2312+
debug_line_inst = prev;
2313+
break;
2314+
} else if (ext_inst == NonSemanticShaderDebugInfoDebugNoLine) {
2315+
// If we see a DebugNoLine first, this section has no valid line
2316+
break;
2317+
}
23092318
}
23102319
}
23112320

@@ -2400,22 +2409,43 @@ void ValidationState_t::InspectDebugLocalVariable(
24002409
PrintShaderDebugInfoSource(ss, *debug_source, source_info);
24012410
}
24022411

2403-
void ValidationState_t::InspectDebugFunctionDefinition(
2412+
void ValidationState_t::InspectFunctionCall(
24042413
std::ostringstream& ss, const Instruction& function_call_inst) {
24052414
// First print the caller, then print the callee if also found
24062415
InspectDebugLine(ss, function_call_inst);
24072416

2408-
const uint32_t set_id = ShaderDebugInfoSet();
2409-
const Instruction* debug_func_def = nullptr;
2410-
24112417
const uint32_t callee_function_id =
24122418
function_call_inst.GetOperandAs<uint32_t>(2);
24132419
const Instruction* function_inst = FindDef(callee_function_id);
2414-
if (!function_inst) return;
2420+
if (function_inst) {
2421+
InspectDebugFunctionDefinition(ss, *function_inst);
2422+
}
2423+
}
2424+
2425+
void ValidationState_t::InspectEntryPoint(std::ostringstream& ss,
2426+
const Instruction& inst) {
2427+
const Instruction* function_inst = nullptr;
2428+
if (inst.opcode() == spv::Op::OpExecutionMode ||
2429+
inst.opcode() == spv::Op::OpExecutionModeId) {
2430+
function_inst = FindDef(inst.GetOperandAs<uint32_t>(0));
2431+
} else if (inst.opcode() == spv::Op::OpEntryPoint) {
2432+
function_inst = FindDef(inst.GetOperandAs<uint32_t>(1));
2433+
}
2434+
2435+
if (function_inst) {
2436+
InspectDebugFunctionDefinition(ss, *function_inst);
2437+
}
2438+
}
2439+
2440+
void ValidationState_t::InspectDebugFunctionDefinition(
2441+
std::ostringstream& ss, const Instruction& function_inst) {
2442+
assert(function_inst.opcode() == spv::Op::OpFunction);
2443+
const uint32_t set_id = ShaderDebugInfoSet();
2444+
const Instruction* debug_func_def = nullptr;
24152445

24162446
// Loop through the Function block as the DebugFunctionDefinition needs to be
24172447
// inside it
2418-
size_t first_inst_id = (function_inst - &ordered_instructions()[0]) + 1;
2448+
size_t first_inst_id = (&function_inst - &ordered_instructions()[0]) + 1;
24192449
for (size_t i = first_inst_id + 1; i < ordered_instructions().size(); ++i) {
24202450
const Instruction& current_inst = ordered_instructions()[i];
24212451
if (current_inst.opcode() == spv::Op::OpFunctionEnd) {
@@ -2426,7 +2456,7 @@ void ValidationState_t::InspectDebugFunctionDefinition(
24262456
current_inst.GetOperandAs<uint32_t>(2) == set_id &&
24272457
current_inst.GetOperandAs<uint32_t>(3) ==
24282458
NonSemanticShaderDebugInfoDebugFunctionDefinition &&
2429-
current_inst.GetOperandAs<uint32_t>(5) == callee_function_id) {
2459+
current_inst.GetOperandAs<uint32_t>(5) == function_inst.id()) {
24302460
debug_func_def = &current_inst;
24312461
break;
24322462
}

source/val/validation_state.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1214,8 +1214,11 @@ class ValidationState_t {
12141214
const Instruction& inst);
12151215
void InspectDebugLocalVariable(std::ostringstream& ss, const Function& func,
12161216
const Instruction& inst);
1217+
void InspectFunctionCall(std::ostringstream& ss,
1218+
const Instruction& function_call_inst);
1219+
void InspectEntryPoint(std::ostringstream& ss, const Instruction& inst);
12171220
void InspectDebugFunctionDefinition(std::ostringstream& ss,
1218-
const Instruction& function_call_inst);
1221+
const Instruction& function_inst);
12191222
void PrintShaderDebugInfoSource(std::ostringstream& ss,
12201223
const Instruction& debug_source,
12211224
const DebugSourceInfo& source_info);

test/val/val_shader_debug_info_test.cpp

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,60 @@ void main() {
8383
|)"));
8484
}
8585

86+
TEST_F(ValidateShaderDebugInfo, DebugNoLine) {
87+
const std::string str = R"(
88+
OpCapability Shader
89+
OpExtension "SPV_KHR_non_semantic_info"
90+
%1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
91+
OpMemoryModel Logical GLSL450
92+
OpEntryPoint GLCompute %main "main"
93+
OpExecutionMode %main LocalSize 1 1 1
94+
%2 = OpString "a.comp"
95+
%19 = OpString "#version 450
96+
layout(set = 0, binding = 1, std430) buffer SSBO {
97+
vec4 data;
98+
};
99+
100+
void main() {
101+
data = vec4(0.0);
102+
}"
103+
OpDecorate %SSBO Block
104+
OpMemberDecorate %SSBO 0 Offset 0
105+
OpDecorate %_ Binding 1
106+
OpDecorate %_ DescriptorSet 0
107+
%void = OpTypeVoid
108+
%5 = OpTypeFunction %void
109+
%uint = OpTypeInt 32 0
110+
%uint_32 = OpConstant %uint 32
111+
%uint_0 = OpConstant %uint 0
112+
%18 = OpExtInst %void %1 DebugSource %2 %19
113+
%float = OpTypeFloat 32
114+
%v4float = OpTypeVector %float 4
115+
%SSBO = OpTypeStruct %v4float
116+
%_ptr_StorageBuffer_SSBO = OpTypePointer StorageBuffer %SSBO
117+
%uint_12 = OpConstant %uint 12
118+
%_ = OpVariable %_ptr_StorageBuffer_SSBO StorageBuffer
119+
%int = OpTypeInt 32 1
120+
%int_0 = OpConstant %int 0
121+
%float_0 = OpConstant %float 0
122+
%50 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
123+
%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
124+
%uint_7 = OpConstant %uint 7
125+
%main = OpFunction %void None %5
126+
%15 = OpLabel
127+
%54 = OpExtInst %void %1 DebugLine %18 %uint_7 %uint_7 %uint_0 %uint_0
128+
%55 = OpExtInst %void %1 DebugNoLine
129+
%53 = OpAccessChain %_ptr_StorageBuffer_v4float %_ %int_0 %int_0 %int_0
130+
%56 = OpExtInst %void %1 DebugLine %18 %uint_7 %uint_7 %uint_0 %uint_0
131+
OpStore %53 %50
132+
OpReturn
133+
OpFunctionEnd
134+
)";
135+
CompileSuccessfully(str.c_str(), SPV_ENV_VULKAN_1_1);
136+
EXPECT_NE(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
137+
EXPECT_THAT(getDiagnosticString(), Not(HasSubstr("a.comp")));
138+
}
139+
86140
TEST_F(ValidateShaderDebugInfo, DebugLineMultieLine) {
87141
const std::string str = R"(
88142
OpCapability Shader
@@ -794,6 +848,98 @@ void main() {
794848
|)"));
795849
}
796850

851+
TEST_F(ValidateShaderDebugInfo, ExecutionMode) {
852+
const std::string str = R"(
853+
OpCapability Shader
854+
OpExtension "SPV_KHR_non_semantic_info"
855+
%1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
856+
OpMemoryModel Logical GLSL450
857+
OpEntryPoint GLCompute %main "main"
858+
OpExecutionMode %main LocalSize 0 1 1
859+
%2 = OpString "a.comp"
860+
%8 = OpString "uint"
861+
%16 = OpString "main"
862+
%19 = OpString "#version 450
863+
864+
void main() {
865+
}"
866+
%void = OpTypeVoid
867+
%5 = OpTypeFunction %void
868+
%uint = OpTypeInt 32 0
869+
%uint_32 = OpConstant %uint 32
870+
%uint_6 = OpConstant %uint 6
871+
%uint_0 = OpConstant %uint 0
872+
%9 = OpExtInst %void %1 DebugTypeBasic %8 %uint_32 %uint_6 %uint_0
873+
%uint_3 = OpConstant %uint 3
874+
%6 = OpExtInst %void %1 DebugTypeFunction %uint_3 %void
875+
%18 = OpExtInst %void %1 DebugSource %2 %19
876+
%uint_1 = OpConstant %uint 1
877+
%uint_4 = OpConstant %uint 4
878+
%uint_2 = OpConstant %uint 2
879+
%20 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %18 %uint_2
880+
%17 = OpExtInst %void %1 DebugFunction %16 %6 %18 %uint_3 %uint_0 %20 %16 %uint_3 %uint_3
881+
%main = OpFunction %void None %5
882+
%15 = OpLabel
883+
%25 = OpExtInst %void %1 DebugScope %17
884+
%26 = OpExtInst %void %1 DebugLine %18 %uint_3 %uint_3 %uint_0 %uint_0
885+
%24 = OpExtInst %void %1 DebugFunctionDefinition %17 %main
886+
OpReturn
887+
OpFunctionEnd
888+
)";
889+
CompileSuccessfully(str.c_str(), SPV_ENV_VULKAN_1_3);
890+
EXPECT_NE(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
891+
EXPECT_THAT(getDiagnosticString(), HasSubstr(R"(--> a.comp:3:0
892+
|
893+
3 | void main() {
894+
|)"));
895+
}
896+
897+
TEST_F(ValidateShaderDebugInfo, EntryPoint) {
898+
const std::string str = R"(
899+
OpCapability Shader
900+
OpExtension "SPV_KHR_non_semantic_info"
901+
%1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
902+
OpMemoryModel Logical GLSL450
903+
OpEntryPoint GLCompute %main "main"
904+
OpExecutionMode %main LocalSize 1 1 1
905+
%2 = OpString "a.comp"
906+
%8 = OpString "uint"
907+
%16 = OpString "main"
908+
%19 = OpString "#version 450
909+
910+
void main() {
911+
}"
912+
%void = OpTypeVoid
913+
%5 = OpTypeFunction %void
914+
%uint = OpTypeInt 32 0
915+
%uint_32 = OpConstant %uint 32
916+
%uint_6 = OpConstant %uint 6
917+
%uint_0 = OpConstant %uint 0
918+
%9 = OpExtInst %void %1 DebugTypeBasic %8 %uint_32 %uint_6 %uint_0
919+
%uint_3 = OpConstant %uint 3
920+
%6 = OpExtInst %void %1 DebugTypeFunction %uint_3 %void
921+
%18 = OpExtInst %void %1 DebugSource %2 %19
922+
%uint_1 = OpConstant %uint 1
923+
%uint_4 = OpConstant %uint 4
924+
%uint_2 = OpConstant %uint 2
925+
%20 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %18 %uint_2
926+
%17 = OpExtInst %void %1 DebugFunction %16 %6 %18 %uint_3 %uint_0 %20 %16 %uint_3 %uint_3
927+
%main = OpFunction %uint None %5
928+
%15 = OpLabel
929+
%25 = OpExtInst %void %1 DebugScope %17
930+
%26 = OpExtInst %void %1 DebugLine %18 %uint_3 %uint_3 %uint_0 %uint_0
931+
%24 = OpExtInst %void %1 DebugFunctionDefinition %17 %main
932+
OpReturnValue %uint_1
933+
OpFunctionEnd
934+
)";
935+
CompileSuccessfully(str.c_str(), SPV_ENV_VULKAN_1_3);
936+
EXPECT_NE(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
937+
EXPECT_THAT(getDiagnosticString(), HasSubstr(R"(--> a.comp:3:0
938+
|
939+
3 | void main() {
940+
|)"));
941+
}
942+
797943
} // namespace
798944
} // namespace val
799945
} // namespace spvtools

0 commit comments

Comments
 (0)