diff --git a/llpc/test/shaderdb/debug_info/FunctionCall.pipe b/llpc/test/shaderdb/debug_info/FunctionCall.pipe new file mode 100644 index 0000000000..f551e320eb --- /dev/null +++ b/llpc/test/shaderdb/debug_info/FunctionCall.pipe @@ -0,0 +1,153 @@ +; RUN: amdllpc -trim-debug-info=false -filetype=asm -o - -gfxip 11.0 %s | FileCheck -check-prefixes=NOTRIM %s +; RUN: amdllpc -trim-debug-info=true -filetype=asm -o - -gfxip 11.0 %s | FileCheck -check-prefixes=TRIM %s + +; Just a simple sanity check that the compiler ran through and produced *some* debug info +; NOTRIM: .loc 1 11 0 prologue_end + +; TRIM-NOT: .loc +; TRIM: s_endpgm + +[CsSpirv] +; Compiled with glslangValidator --target-env vulkan1.3 -gVS +; SPIR-V +; Version: 1.6 +; Generator: Khronos Glslang Reference Front End; 11 +; Bound: 88 +; Schema: 0 + OpCapability Shader + OpExtension "SPV_KHR_non_semantic_info" + %2 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" + %3 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %dst %gl_GlobalInvocationID + OpExecutionModeId %main LocalSizeId %uint_1 %uint_1 %uint_1 + %1 = OpString "simplified.comp" + %9 = OpString "uint" + %15 = OpString "main" + %18 = OpString "#version 460 + +layout(set = 0, binding = 0, r32ui) uniform uimage2D dst; + +uint BugFunction(uint val0) { + return val0; +} + +void main() { + uvec4 data = uvec4(BugFunction(0)); + imageStore(dst, ivec2(gl_GlobalInvocationID.xy), data); +} +" + %29 = OpString "BugFunction" + %35 = OpString "val0" + %53 = OpString "data" + %62 = OpString "type.2d.image" + %63 = OpString "@type.2d.image" + %68 = OpString "dst" + %76 = OpString "gl_GlobalInvocationID" + %82 = OpString "int" + OpName %main "main" + OpName %BugFunction_u1_ "BugFunction(u1;" + OpName %val0 "val0" + OpName %data "data" + OpName %param "param" + OpName %dst "dst" + OpName %gl_GlobalInvocationID "gl_GlobalInvocationID" + OpModuleProcessed "client vulkan100" + OpModuleProcessed "target-env spirv1.6" + OpModuleProcessed "target-env vulkan1.3" + OpModuleProcessed "entry-point main" + OpDecorate %dst DescriptorSet 0 + OpDecorate %dst Binding 0 + OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId + %void = OpTypeVoid + %5 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %uint_32 = OpConstant %uint 32 + %uint_6 = OpConstant %uint 6 + %uint_0 = OpConstant %uint 0 + %8 = OpExtInst %void %2 DebugTypeBasic %9 %uint_32 %uint_6 %uint_0 + %uint_3 = OpConstant %uint 3 + %6 = OpExtInst %void %2 DebugTypeFunction %uint_3 %void + %17 = OpExtInst %void %2 DebugSource %1 %18 + %uint_1 = OpConstant %uint 1 + %uint_4 = OpConstant %uint 4 + %uint_2 = OpConstant %uint 2 + %19 = OpExtInst %void %2 DebugCompilationUnit %uint_1 %uint_4 %17 %uint_2 + %16 = OpExtInst %void %2 DebugFunction %15 %6 %17 %uint_0 %uint_0 %19 %15 %uint_3 %uint_0 +%_ptr_Function_uint = OpTypePointer Function %uint + %25 = OpTypeFunction %uint %_ptr_Function_uint + %26 = OpExtInst %void %2 DebugTypeFunction %uint_3 %8 %8 + %30 = OpExtInst %void %2 DebugFunction %29 %26 %17 %uint_0 %uint_0 %19 %29 %uint_3 %uint_0 + %34 = OpExtInst %void %2 DebugLocalVariable %35 %8 %17 %uint_0 %uint_0 %30 %uint_4 %uint_1 + %37 = OpExtInst %void %2 DebugExpression + %uint_10 = OpConstant %uint 10 + %v4uint = OpTypeVector %uint 4 + %49 = OpExtInst %void %2 DebugTypeVector %8 %uint_4 +%_ptr_Function_v4uint = OpTypePointer Function %v4uint + %52 = OpExtInst %void %2 DebugLocalVariable %53 %49 %17 %uint_10 %uint_0 %16 %uint_4 + %uint_11 = OpConstant %uint 11 + %60 = OpTypeImage %uint 2D 0 0 0 2 R32ui + %64 = OpExtInst %void %2 DebugInfoNone + %61 = OpExtInst %void %2 DebugTypeComposite %62 %uint_0 %17 %uint_11 %uint_0 %19 %63 %64 %uint_3 +%_ptr_UniformConstant_60 = OpTypePointer UniformConstant %60 + %dst = OpVariable %_ptr_UniformConstant_60 UniformConstant + %uint_8 = OpConstant %uint 8 + %67 = OpExtInst %void %2 DebugGlobalVariable %68 %61 %17 %uint_11 %uint_0 %19 %68 %dst %uint_8 + %v3uint = OpTypeVector %uint 3 + %72 = OpExtInst %void %2 DebugTypeVector %8 %uint_3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint +%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input + %75 = OpExtInst %void %2 DebugGlobalVariable %76 %72 %17 %uint_11 %uint_0 %19 %76 %gl_GlobalInvocationID %uint_8 + %v2uint = OpTypeVector %uint 2 + %78 = OpExtInst %void %2 DebugTypeVector %8 %uint_2 + %int = OpTypeInt 32 1 + %83 = OpExtInst %void %2 DebugTypeBasic %82 %uint_32 %uint_4 %uint_0 + %v2int = OpTypeVector %int 2 + %85 = OpExtInst %void %2 DebugTypeVector %83 %uint_2 + OpLine %1 9 11 + %main = OpFunction %void None %5 + %23 = OpLabel + %data = OpVariable %_ptr_Function_v4uint Function + %param = OpVariable %_ptr_Function_uint Function + %44 = OpExtInst %void %2 DebugFunctionDefinition %16 %main + %45 = OpExtInst %void %2 DebugScope %16 + %46 = OpExtInst %void %2 DebugLine %17 %uint_10 %uint_10 %uint_0 %uint_0 + %54 = OpExtInst %void %2 DebugDeclare %52 %data %37 + OpStore %param %uint_0 + %56 = OpFunctionCall %uint %BugFunction_u1_ %param + %57 = OpCompositeConstruct %v4uint %56 %56 %56 %56 + OpStore %data %57 + %58 = OpExtInst %void %2 DebugLine %17 %uint_11 %uint_11 %uint_0 %uint_0 + %70 = OpLoad %60 %dst + %79 = OpLoad %v3uint %gl_GlobalInvocationID + %80 = OpVectorShuffle %v2uint %79 %79 0 1 + %86 = OpBitcast %v2int %80 + %87 = OpLoad %v4uint %data + OpImageWrite %70 %86 %87 ZeroExtend + OpReturn + OpFunctionEnd + OpLine %1 5 27 +%BugFunction_u1_ = OpFunction %uint None %25 + %val0 = OpFunctionParameter %_ptr_Function_uint + %31 = OpLabel + %32 = OpExtInst %void %2 DebugScope %30 + %33 = OpExtInst %void %2 DebugLine %17 %uint_0 %uint_0 %uint_0 %uint_0 + %36 = OpExtInst %void %2 DebugDeclare %34 %val0 %37 + %38 = OpExtInst %void %2 DebugFunctionDefinition %30 %BugFunction_u1_ + %39 = OpExtInst %void %2 DebugScope %30 + %40 = OpExtInst %void %2 DebugLine %17 %uint_6 %uint_6 %uint_0 %uint_0 + %41 = OpLoad %uint %val0 + OpReturnValue %41 + OpFunctionEnd + +[CsInfo] +entryPoint = main +userDataNode[0].visibility = 0xffffffff +userDataNode[0].type = DescriptorTableVaPtr +userDataNode[0].offsetInDwords = 0 +userDataNode[0].sizeInDwords = 1 +userDataNode[0].next[0].type = DescriptorImage +userDataNode[0].next[0].offsetInDwords = 0 +userDataNode[0].next[0].sizeInDwords = 8 +userDataNode[0].next[0].set = 0x00000000 +userDataNode[0].next[0].binding = 0 diff --git a/llpc/translator/lib/SPIRV/SPIRVToLLVMDbgTran.cpp b/llpc/translator/lib/SPIRV/SPIRVToLLVMDbgTran.cpp index e6d4713528..bf441cae9a 100644 --- a/llpc/translator/lib/SPIRV/SPIRVToLLVMDbgTran.cpp +++ b/llpc/translator/lib/SPIRV/SPIRVToLLVMDbgTran.cpp @@ -477,15 +477,11 @@ DINode *SPIRVToLLVMDbgTran::transFunction(const SPIRVExtInst *DebugInst) { SPIRVWord SPIRVDebugFlags = getConstant(Ops[FlagsIdx]); DINode::DIFlags Flags = mapToDIFlags(SPIRVDebugFlags); - // TODO: IsDefinition is always true for DebugFunction, but should be false - // for DebugFunctionDeclaration. - const bool IsDefinition = true; - bool IsOptimized = SPIRVDebugFlags & SPIRVDebug::FlagIsOptimized; bool IsLocal = SPIRVDebugFlags & SPIRVDebug::FlagIsLocal; - bool IsMainSubprogram = BM->getEntryPoint(Ops[FunctionIdIdx]) != nullptr; DISubprogram::DISPFlags SPFlags = - DISubprogram::toSPFlags(IsLocal, IsDefinition, IsOptimized, DISubprogram::SPFlagNonvirtual, IsMainSubprogram); + DISubprogram::toSPFlags(IsLocal, /*IsDefinition*/ true, IsOptimized, DISubprogram::SPFlagNonvirtual, + /*IsMainSubprogram*/ false); unsigned ScopeLine = getConstant(Ops[ScopeLineIdx]); @@ -504,26 +500,9 @@ DINode *SPIRVToLLVMDbgTran::transFunction(const SPIRVExtInst *DebugInst) { DINodeArray TParams = Builder.getOrCreateArray(Elts); llvm::DITemplateParameterArray TParamsArray = TParams.get(); - DISubprogram *DIS = nullptr; - if ((isa(Scope) || isa(Scope)) && !IsDefinition) - DIS = Builder.createMethod(Scope, Name, LinkageName, File, LineNo, Ty, 0, 0, nullptr, Flags, SPFlags, TParamsArray); - else - DIS = - Builder.createFunction(Scope, Name, LinkageName, File, LineNo, Ty, ScopeLine, Flags, SPFlags, TParamsArray, FD); + DISubprogram *DIS = + Builder.createFunction(Scope, Name, LinkageName, File, LineNo, Ty, ScopeLine, Flags, SPFlags, TParamsArray, FD); DebugInstCache[DebugInst] = DIS; - SPIRVId RealFuncId = Ops[FunctionIdIdx]; - FuncMap[RealFuncId] = DIS; - - // Function. - SPIRVEntry *E = BM->getEntry(Ops[FunctionIdIdx]); - if (E->getOpCode() == OpFunction) { - SPIRVFunction *BF = static_cast(E); - llvm::Function *F = SPIRVReader->transFunction(BF); - assert(F && "Translation of function failed!"); - if (!F->hasMetadata()) - F->setMetadata("dbg", DIS); - F->setSubprogram(DIS); - } return DIS; } @@ -887,12 +866,15 @@ Instruction *SPIRVToLLVMDbgTran::transDebugIntrinsic(const SPIRVExtInst *DebugIn case SPIRVDebug::NoScope: return nullptr; case SPIRVDebug::FunctionDefinition: { - using namespace SPIRVDebug::Operand::Function; - SPIRVExtInst *funcExt = BM->get(Ops[0]); - std::vector &args = funcExt->getArguments(); - assert(args.size() > FunctionIdIdx); - args[FunctionIdIdx] = Ops[1]; - transDebugInst(funcExt); + SPIRVExtInst *dbgDef = BM->get(Ops[0]); + SPIRVFunction *opDef = BM->get(Ops[1]); + DISubprogram *DIS = transDebugInst(dbgDef); + + FuncMap[opDef->getId()] = DIS; + + llvm::Function *F = SPIRVReader->transFunction(opDef); + assert(F && "Translation of function failed!"); + F->setSubprogram(DIS); return nullptr; } diff --git a/llpc/translator/lib/SPIRV/libSPIRV/SPIRV.debug.h b/llpc/translator/lib/SPIRV/libSPIRV/SPIRV.debug.h index 546517745f..c8b461a5f9 100644 --- a/llpc/translator/lib/SPIRV/libSPIRV/SPIRV.debug.h +++ b/llpc/translator/lib/SPIRV/libSPIRV/SPIRV.debug.h @@ -348,9 +348,8 @@ enum { LinkageNameIdx = 6, FlagsIdx = 7, ScopeLineIdx = 8, - FunctionIdIdx = 9, - DeclarationIdx = 10, - MinOperandCount = 10 + DeclarationIdx = 9, + MinOperandCount = 9 }; } diff --git a/llpc/translator/lib/SPIRV/libSPIRV/SPIRVInstruction.h b/llpc/translator/lib/SPIRV/libSPIRV/SPIRVInstruction.h index 20111fdbce..22af462ac5 100644 --- a/llpc/translator/lib/SPIRV/libSPIRV/SPIRVInstruction.h +++ b/llpc/translator/lib/SPIRV/libSPIRV/SPIRVInstruction.h @@ -1560,11 +1560,6 @@ class SPIRVExtInst : public SPIRVFunctionCallGeneric { SPIRVLine *line = Module->add(new SPIRVLine(Module, Args[0], dbgLn, dbgCol)); Module->setCurrentLine(line); } - // NonSemanticShaderDebugInfo100DebugFunction has one less argument than - // OpenCL.DebugInfo.100 DebugFunction - else if (ExtOpDebug == NonSemanticShaderDebugInfo100DebugFunction) { - Args.push_back(0); - } } } void validate() const override { diff --git a/llpc/util/llpcShaderModuleHelper.cpp b/llpc/util/llpcShaderModuleHelper.cpp index 330ad95500..56bd1f4232 100644 --- a/llpc/util/llpcShaderModuleHelper.cpp +++ b/llpc/util/llpcShaderModuleHelper.cpp @@ -254,10 +254,13 @@ unsigned ShaderModuleHelper::trimSpirvDebugInfo(const BinaryData *spvBin, llvm:: codeBuffer = codeBuffer.drop_front(sizeof(Vkgc::SpirvHeader) / wordSize); } + unsigned nonSemanticShaderDebug = ~0; + // Copy SPIR-V instructions while (codePos < end) { unsigned opCode = (codePos[0] & OpCodeMask); unsigned wordCount = (codePos[0] >> WordCountShift); + bool skip = false; switch (opCode) { case OpSource: case OpSourceContinued: @@ -266,12 +269,29 @@ unsigned ShaderModuleHelper::trimSpirvDebugInfo(const BinaryData *spvBin, llvm:: case OpLine: case OpNop: case OpNoLine: - case OpModuleProcessed: { - // Skip debug instructions + case OpModuleProcessed: + skip = true; + break; + case OpExtInstImport: { + unsigned id = codePos[1]; + const char *name = reinterpret_cast(&codePos[2]); + if (!strcmp(name, "NonSemantic.Shader.DebugInfo.100")) { + nonSemanticShaderDebug = id; + skip = true; + } break; } - default: { - // Copy other instructions + case OpExtInst: { + unsigned set = codePos[3]; + if (set == nonSemanticShaderDebug) + skip = true; + break; + } + default: + break; + } + + if (!skip) { if (writeCode) { assert(codePos + wordCount <= end); assert(wordCount <= codeBuffer.size()); @@ -279,8 +299,6 @@ unsigned ShaderModuleHelper::trimSpirvDebugInfo(const BinaryData *spvBin, llvm:: codeBuffer = codeBuffer.drop_front(wordCount); } totalSizeInWords += wordCount; - break; - } } codePos += wordCount;