Skip to content

Commit 4548962

Browse files
spirv-val: Print DebugLocalVariable in error message (KhronosGroup#6685)
next part of KhronosGroup#6617 will print ``` error: 42: Variables must have a function[7] storage class inside of a function %37 = OpVariable %_ptr_Function_uint Uniform --> a.comp:4:0 | 4 | uint x = 0; | ``` ... Next goal will be how to combine it so when you have an error on the `OpLoad`/`OpStore` it can print **both** the line the access occured and the variable declaration
1 parent 0bb5218 commit 4548962

3 files changed

Lines changed: 205 additions & 2 deletions

File tree

source/val/validation_state.cpp

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2187,8 +2187,13 @@ std::string ValidationState_t::InspectShaderDebugInfo(const Instruction& inst) {
21872187
}
21882188

21892189
std::ostringstream ss;
2190-
if (inst.function() != nullptr) {
2191-
InspectDebugLine(ss, inst);
2190+
const Function* func = inst.function();
2191+
if (func != nullptr) {
2192+
if (inst.opcode() == spv::Op::OpVariable) {
2193+
InspectDebugLocalVariable(ss, *func, inst);
2194+
} else {
2195+
InspectDebugLine(ss, inst);
2196+
}
21922197
} else if (inst.opcode() == spv::Op::OpVariable) {
21932198
// Know are global because not in any function
21942199
// TODO - test with OpUntypedVariable as well
@@ -2286,6 +2291,60 @@ void ValidationState_t::InspectDebugGlobalVariable(
22862291
column_start);
22872292
}
22882293

2294+
void ValidationState_t::InspectDebugLocalVariable(
2295+
std::ostringstream& ss, const Function& func,
2296+
const Instruction& variable_inst) {
2297+
const uint32_t set_id = ShaderDebugInfoSet();
2298+
const Instruction* debug_declare_inst = nullptr;
2299+
2300+
const Instruction* function_inst = FindDef(func.id());
2301+
// Loop through the Function block as the DebugDeclare needs to be inside it
2302+
size_t first_inst_id = (function_inst - &ordered_instructions()[0]) + 1;
2303+
for (size_t i = first_inst_id + 1; i < ordered_instructions().size(); ++i) {
2304+
const Instruction& current_inst = ordered_instructions()[i];
2305+
if (current_inst.opcode() == spv::Op::OpFunctionEnd) {
2306+
break; // we hit the next Funciton block
2307+
}
2308+
2309+
if (current_inst.opcode() == spv::Op::OpExtInst &&
2310+
current_inst.GetOperandAs<uint32_t>(2) == set_id &&
2311+
current_inst.GetOperandAs<uint32_t>(3) ==
2312+
NonSemanticShaderDebugInfoDebugDeclare &&
2313+
current_inst.GetOperandAs<uint32_t>(5) == variable_inst.id()) {
2314+
debug_declare_inst = &current_inst;
2315+
break;
2316+
}
2317+
}
2318+
2319+
if (!debug_declare_inst) return;
2320+
2321+
const Instruction* debug_local_variable =
2322+
FindDef(debug_declare_inst->GetOperandAs<uint32_t>(4));
2323+
if (!debug_local_variable ||
2324+
debug_local_variable->GetOperandAs<uint32_t>(3) !=
2325+
NonSemanticShaderDebugInfoDebugLocalVariable) {
2326+
return;
2327+
}
2328+
2329+
const Instruction* debug_source =
2330+
FindDef(debug_local_variable->GetOperandAs<uint32_t>(6));
2331+
if (!debug_source || debug_source->GetOperandAs<uint32_t>(3) !=
2332+
NonSemanticShaderDebugInfoDebugSource) {
2333+
return;
2334+
}
2335+
2336+
bool is_int32 = false, is_const_int32 = false;
2337+
uint32_t line_start = 0;
2338+
uint32_t column_start = 0;
2339+
std::tie(is_int32, is_const_int32, line_start) =
2340+
EvalInt32IfConst(debug_local_variable->word(8));
2341+
std::tie(is_int32, is_const_int32, column_start) =
2342+
EvalInt32IfConst(debug_local_variable->word(9));
2343+
2344+
PrintShaderDebugInfoSource(ss, *debug_source, line_start, line_start,
2345+
column_start);
2346+
}
2347+
22892348
void ValidationState_t::PrintShaderDebugInfoSource(
22902349
std::ostringstream& ss, const Instruction& debug_source,
22912350
uint32_t line_start, uint32_t line_end, uint32_t column_start) {

source/val/validation_state.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,8 @@ class ValidationState_t {
10101010
void InspectDebugLine(std::ostringstream& ss, const Instruction& inst);
10111011
void InspectDebugGlobalVariable(std::ostringstream& ss,
10121012
const Instruction& inst);
1013+
void InspectDebugLocalVariable(std::ostringstream& ss, const Function& func,
1014+
const Instruction& inst);
10131015
void PrintShaderDebugInfoSource(std::ostringstream& ss,
10141016
const Instruction& debug_source,
10151017
uint32_t line_start, uint32_t line_end,

test/val/val_shader_debug_info_test.cpp

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,148 @@ TEST_F(ValidateShaderDebugInfo, NoDebugGlobalVariable) {
363363
EXPECT_THAT(getDiagnosticString(), Not(HasSubstr("a.comp")));
364364
}
365365

366+
TEST_F(ValidateShaderDebugInfo, DebugLocalVariable) {
367+
const std::string str = R"(
368+
OpCapability Shader
369+
OpExtension "SPV_KHR_non_semantic_info"
370+
%1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
371+
OpMemoryModel Logical GLSL450
372+
OpEntryPoint GLCompute %main "main"
373+
OpExecutionMode %main LocalSize 1 1 1
374+
%2 = OpString "a.comp"
375+
%8 = OpString "uint"
376+
%16 = OpString "main"
377+
%19 = OpString "#version 450
378+
379+
void main() {
380+
uint x = 0;
381+
int y = int(x);
382+
}"
383+
%32 = OpString "x"
384+
%37 = OpString "int"
385+
%43 = OpString "y"
386+
%void = OpTypeVoid
387+
%5 = OpTypeFunction %void
388+
%uint = OpTypeInt 32 0
389+
%uint_32 = OpConstant %uint 32
390+
%uint_6 = OpConstant %uint 6
391+
%uint_0 = OpConstant %uint 0
392+
%9 = OpExtInst %void %1 DebugTypeBasic %8 %uint_32 %uint_6 %uint_0
393+
%uint_3 = OpConstant %uint 3
394+
%6 = OpExtInst %void %1 DebugTypeFunction %uint_3 %void
395+
%18 = OpExtInst %void %1 DebugSource %2 %19
396+
%uint_1 = OpConstant %uint 1
397+
%uint_4 = OpConstant %uint 4
398+
%uint_2 = OpConstant %uint 2
399+
%20 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %18 %uint_2
400+
%17 = OpExtInst %void %1 DebugFunction %16 %6 %18 %uint_3 %uint_0 %20 %16 %uint_3 %uint_3
401+
%_ptr_Function_uint = OpTypePointer Function %uint
402+
%uint_7 = OpConstant %uint 7
403+
%29 = OpExtInst %void %1 DebugTypePointer %9 %uint_7 %uint_0
404+
%31 = OpExtInst %void %1 DebugLocalVariable %32 %9 %18 %uint_4 %uint_0 %17 %uint_4
405+
%34 = OpExtInst %void %1 DebugExpression
406+
%int = OpTypeInt 32 1
407+
%38 = OpExtInst %void %1 DebugTypeBasic %37 %uint_32 %uint_4 %uint_0
408+
%_ptr_Function_int = OpTypePointer Function %int
409+
%40 = OpExtInst %void %1 DebugTypePointer %38 %uint_7 %uint_0
410+
%uint_5 = OpConstant %uint 5
411+
%42 = OpExtInst %void %1 DebugLocalVariable %43 %38 %18 %uint_5 %uint_0 %17 %uint_4
412+
%main = OpFunction %void None %5
413+
%15 = OpLabel
414+
%x = OpVariable %_ptr_Function_uint Uniform
415+
%y = OpVariable %_ptr_Function_int Function
416+
%25 = OpExtInst %void %1 DebugScope %17
417+
%26 = OpExtInst %void %1 DebugLine %18 %uint_3 %uint_3 %uint_0 %uint_0
418+
%24 = OpExtInst %void %1 DebugFunctionDefinition %17 %main
419+
%35 = OpExtInst %void %1 DebugLine %18 %uint_4 %uint_4 %uint_0 %uint_0
420+
%33 = OpExtInst %void %1 DebugDeclare %31 %x %34
421+
OpStore %x %uint_0
422+
%46 = OpExtInst %void %1 DebugLine %18 %uint_5 %uint_5 %uint_0 %uint_0
423+
%45 = OpExtInst %void %1 DebugDeclare %42 %y %34
424+
%47 = OpLoad %uint %x
425+
%48 = OpBitcast %int %47
426+
OpStore %y %48
427+
%49 = OpExtInst %void %1 DebugLine %18 %uint_6 %uint_6 %uint_0 %uint_0
428+
OpReturn
429+
OpFunctionEnd
430+
)";
431+
CompileSuccessfully(str.c_str(), SPV_ENV_VULKAN_1_3);
432+
EXPECT_NE(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
433+
EXPECT_THAT(getDiagnosticString(), HasSubstr(R"( --> a.comp:4:0
434+
|
435+
4 | uint x = 0;
436+
|)"));
437+
}
438+
439+
// Test if no DebugLocalVariable is found, things still work
440+
TEST_F(ValidateShaderDebugInfo, NoDebugLocalVariable) {
441+
const std::string str = R"(
442+
OpCapability Shader
443+
OpExtension "SPV_KHR_non_semantic_info"
444+
%1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
445+
OpMemoryModel Logical GLSL450
446+
OpEntryPoint GLCompute %main "main"
447+
OpExecutionMode %main LocalSize 1 1 1
448+
%2 = OpString "a.comp"
449+
%8 = OpString "uint"
450+
%16 = OpString "main"
451+
%19 = OpString "#version 450
452+
453+
void main() {
454+
uint x = 0;
455+
int y = int(x);
456+
}"
457+
%32 = OpString "x"
458+
%37 = OpString "int"
459+
%43 = OpString "y"
460+
%void = OpTypeVoid
461+
%5 = OpTypeFunction %void
462+
%uint = OpTypeInt 32 0
463+
%uint_32 = OpConstant %uint 32
464+
%uint_6 = OpConstant %uint 6
465+
%uint_0 = OpConstant %uint 0
466+
%9 = OpExtInst %void %1 DebugTypeBasic %8 %uint_32 %uint_6 %uint_0
467+
%uint_3 = OpConstant %uint 3
468+
%6 = OpExtInst %void %1 DebugTypeFunction %uint_3 %void
469+
%18 = OpExtInst %void %1 DebugSource %2 %19
470+
%uint_1 = OpConstant %uint 1
471+
%uint_4 = OpConstant %uint 4
472+
%uint_2 = OpConstant %uint 2
473+
%20 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %18 %uint_2
474+
%17 = OpExtInst %void %1 DebugFunction %16 %6 %18 %uint_3 %uint_0 %20 %16 %uint_3 %uint_3
475+
%_ptr_Function_uint = OpTypePointer Function %uint
476+
%uint_7 = OpConstant %uint 7
477+
%29 = OpExtInst %void %1 DebugTypePointer %9 %uint_7 %uint_0
478+
%31 = OpExtInst %void %1 DebugLocalVariable %32 %9 %18 %uint_4 %uint_0 %17 %uint_4
479+
%34 = OpExtInst %void %1 DebugExpression
480+
%int = OpTypeInt 32 1
481+
%38 = OpExtInst %void %1 DebugTypeBasic %37 %uint_32 %uint_4 %uint_0
482+
%_ptr_Function_int = OpTypePointer Function %int
483+
%40 = OpExtInst %void %1 DebugTypePointer %38 %uint_7 %uint_0
484+
%uint_5 = OpConstant %uint 5
485+
%42 = OpExtInst %void %1 DebugLocalVariable %43 %38 %18 %uint_5 %uint_0 %17 %uint_4
486+
%main = OpFunction %void None %5
487+
%15 = OpLabel
488+
%x = OpVariable %_ptr_Function_uint Uniform
489+
%y = OpVariable %_ptr_Function_int Function
490+
%25 = OpExtInst %void %1 DebugScope %17
491+
%26 = OpExtInst %void %1 DebugLine %18 %uint_3 %uint_3 %uint_0 %uint_0
492+
%24 = OpExtInst %void %1 DebugFunctionDefinition %17 %main
493+
%35 = OpExtInst %void %1 DebugLine %18 %uint_4 %uint_4 %uint_0 %uint_0
494+
OpStore %x %uint_0
495+
%46 = OpExtInst %void %1 DebugLine %18 %uint_5 %uint_5 %uint_0 %uint_0
496+
%47 = OpLoad %uint %x
497+
%48 = OpBitcast %int %47
498+
OpStore %y %48
499+
%49 = OpExtInst %void %1 DebugLine %18 %uint_6 %uint_6 %uint_0 %uint_0
500+
OpReturn
501+
OpFunctionEnd
502+
)";
503+
CompileSuccessfully(str.c_str(), SPV_ENV_VULKAN_1_3);
504+
EXPECT_NE(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
505+
EXPECT_THAT(getDiagnosticString(), Not(HasSubstr("a.comp")));
506+
}
507+
366508
} // namespace
367509
} // namespace val
368510
} // namespace spvtools

0 commit comments

Comments
 (0)