Index: llvm/include/llvm/Transforms/Utils/DebugEntryValues.h =================================================================== --- llvm/include/llvm/Transforms/Utils/DebugEntryValues.h +++ llvm/include/llvm/Transforms/Utils/DebugEntryValues.h @@ -5,6 +5,7 @@ #include "llvm/Pass.h" namespace llvm { +void describeCallSiteParams(Function &F); void markEntryValues(Function &F); } // namespace llvm @@ -12,5 +13,10 @@ llvm::PreservedAnalyses run(llvm::Function &F, llvm::FunctionAnalysisManager &AM); }; +struct DebugEntryValuesCallSite + : public llvm::PassInfoMixin { + llvm::PreservedAnalyses run(llvm::Function &F, + llvm::FunctionAnalysisManager &AM); +}; #endif // LLVM_TRANSFORMS_UTILS_DEBUG_ENTRY_VALUES_H Index: llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -792,8 +792,9 @@ /// Try to interpret values loaded into registers that forward parameters /// for \p CallMI. Store parameters with interpreted value into \p Params. -static void collectCallSiteParameters(const MachineInstr *CallMI, - ParamSet &Params) { +static void +collectCallSiteParameters(const MachineInstr *CallMI, ParamSet &Params, + SmallVectorImpl &DescribedRegs) { const MachineFunction *MF = CallMI->getMF(); const auto &CalleesMap = MF->getCallSitesInfo(); auto CallFwdRegsInfo = CalleesMap.find(CallMI); @@ -821,6 +822,11 @@ (void)InsertedReg; } + // Do not emit CSInfo for registers that has already been described. + for (auto Reg : DescribedRegs) { + ForwardedRegWorklist.erase(Reg); + } + // Do not emit CSInfo for undef forwarding registers. for (auto &MO : CallMI->uses()) if (MO.isReg() && MO.isUndef()) @@ -868,6 +874,39 @@ } } +static void +collectCallSiteParametersIR(const MachineInstr *CallMI, ParamSet &Params, + DINodeArray IRParams, + SmallVectorImpl &DescribedRegs) { + const MachineFunction *MF = CallMI->getMF(); + const auto &CalleesMap = MF->getCallSitesInfo(); + auto CallFwdRegsInfo = CalleesMap.find(CallMI); + + if (CallFwdRegsInfo == CalleesMap.end()) + return; + + const DIExpression *EmptyExpr = + DIExpression::get(MF->getFunction().getContext(), {}); + + for (auto Param : IRParams) { + auto DIParamVal = cast(Param); + for (auto ArgReg : CallFwdRegsInfo->second) { + if (DIParamVal->getArgNum() == ArgReg.ArgNo) { + auto DIExpr = DIParamVal->getExpression(); + if (DIExpr->getElement(0) == dwarf::DW_OP_constu) { + DbgValueLoc DbgLocVal(EmptyExpr, + DbgValueLocEntry(DIExpr->getElement(1))); + DbgCallSiteParam CSParm(ArgReg.Reg, DbgLocVal); + Params.push_back(CSParm); + DescribedRegs.emplace_back(ArgReg.Reg); + ++NumCSParams; + } + break; + } + } + } +} + void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP, DwarfCompileUnit &CU, DIE &ScopeDIE, const MachineFunction &MF) { @@ -989,8 +1028,18 @@ // Optionally emit call-site-param debug info. if (emitDebugEntryValues()) { ParamSet Params; + auto DL = MI.getDebugLoc().get(); + DINodeArray IRParams; + if (DL) + IRParams = DL->getParameters(); + SmallVector DescribedRegs; + + // Try to interpret values of call site parameters, introduced on IR level. + if (IRParams) + collectCallSiteParametersIR(&MI, Params, IRParams, DescribedRegs); + // Try to interpret values of call site parameters. - collectCallSiteParameters(&MI, Params); + collectCallSiteParameters(&MI, Params, DescribedRegs); CU.constructCallSiteParmEntryDIEs(CallSiteDIE, Params); } } Index: llvm/lib/Passes/PassBuilderPipelines.cpp =================================================================== --- llvm/lib/Passes/PassBuilderPipelines.cpp +++ llvm/lib/Passes/PassBuilderPipelines.cpp @@ -918,6 +918,9 @@ // constants. MPM.addPass(createModuleToFunctionPassAdaptor(PromotePass())); + // Describe arguments on caller site. + MPM.addPass(createModuleToFunctionPassAdaptor(DebugEntryValuesCallSite())); + // Remove any dead arguments exposed by cleanups and constant folding // globals. MPM.addPass(DeadArgumentEliminationPass()); Index: llvm/lib/Passes/PassRegistry.def =================================================================== --- llvm/lib/Passes/PassRegistry.def +++ llvm/lib/Passes/PassRegistry.def @@ -250,6 +250,7 @@ FUNCTION_PASS("correlated-propagation", CorrelatedValuePropagationPass()) FUNCTION_PASS("dce", DCEPass()) FUNCTION_PASS("dbg-entry-values", DebugEntryValues()) +FUNCTION_PASS("dbg-entry-values-call-sites", DebugEntryValuesCallSite()) FUNCTION_PASS("dfa-jump-threading", DFAJumpThreadingPass()) FUNCTION_PASS("div-rem-pairs", DivRemPairsPass()) FUNCTION_PASS("dse", DSEPass()) Index: llvm/lib/Transforms/Utils/DebugEntryValues.cpp =================================================================== --- llvm/lib/Transforms/Utils/DebugEntryValues.cpp +++ llvm/lib/Transforms/Utils/DebugEntryValues.cpp @@ -9,6 +9,47 @@ using namespace llvm; +// Try to describe arguments passed to the function. +void llvm::describeCallSiteParams(Function &F) { + for (BasicBlock &B : F) + for (Instruction &I : B) { + auto *CI = dyn_cast(&I); + auto *IntrinsicCall = dyn_cast(&I); + if (!CI || CI->isDebugOrPseudoInst() || IntrinsicCall) + continue; + SmallVector Args; + size_t ArgNum = 0; + for (auto it = CI->arg_begin(); it != CI->arg_end(); it++) { + auto Arg = it->get(); + + // For now, we're supporting only constant arguments passing. + if (auto ArgumentConstant = dyn_cast(Arg)) { + if (ArgumentConstant->getBitWidth() > 64) + continue; + auto ConstVal = ArgumentConstant->getZExtValue(); + auto Expr = DIExpression::get( + Arg->getContext(), + {dwarf::DW_OP_constu, ConstVal, dwarf::DW_OP_stack_value}); + auto Param = DICallSiteParam::get(Arg->getContext(), ArgNum, Expr); + Args.push_back(Param); + } + ArgNum++; + } + if (Args.size() == 0) + continue; + DIBuilder *DIB = new DIBuilder(*F.getParent()); + DINodeArray Arguments = DIB->getOrCreateArray(Args); + auto DL = (CI->getDebugLoc()); + if (!DL) + continue; + + // Attach params field to DILocation of a call instruction. + CI->Instruction::setDebugLoc(DILocation::get( + F.getContext(), DL->getLine(), DL->getColumn(), DL->getScope(), + DL->getInlinedAt(), DL->isImplicitCode(), Arguments)); + } +} + void llvm::markEntryValues(Function &F) { auto SP = F.getSubprogram(); if (!SP) { @@ -98,6 +139,11 @@ markEntryValues(F); return PreservedAnalyses::all(); } +PreservedAnalyses DebugEntryValuesCallSite::run(Function &F, + FunctionAnalysisManager &AM) { + describeCallSiteParams(F); + return PreservedAnalyses::all(); +} namespace { struct DebugEntryValuesLegacyPass : public FunctionPass { @@ -112,6 +158,24 @@ }; // end of struct DebugEntryValuesLegacyPass } // end of anonymous namespace +namespace { +struct DebugEntryValuesCallSiteLegacyPass : public FunctionPass { + static char ID; + DebugEntryValuesCallSiteLegacyPass() : FunctionPass(ID) {} + + bool runOnFunction(Function &F) override { + describeCallSiteParams(F); + return false; + } + +}; // end of struct DebugEntryValuesLegacyPass +} // end of anonymous namespace + +char DebugEntryValuesCallSiteLegacyPass::ID = 0; + +static RegisterPass + DEV("dbg-entry-values-call-sites", "Collect call site parameter info"); + char DebugEntryValuesLegacyPass::ID = 0; static RegisterPass Index: llvm/test/Other/new-pm-defaults.ll =================================================================== --- llvm/test/Other/new-pm-defaults.ll +++ llvm/test/Other/new-pm-defaults.ll @@ -109,6 +109,7 @@ ; CHECK-O-NEXT: Running pass: CalledValuePropagationPass ; CHECK-O-NEXT: Running pass: GlobalOptPass ; CHECK-O-NEXT: Running pass: PromotePass +; CHECK-O-NEXT: Running pass: DebugEntryValuesCallSite ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass ; CHECK-O-NEXT: Running pass: DebugEntryValues ; CHECK-O-NEXT: Running pass: InstCombinePass Index: llvm/test/Other/new-pm-thinlto-defaults.ll =================================================================== --- llvm/test/Other/new-pm-thinlto-defaults.ll +++ llvm/test/Other/new-pm-thinlto-defaults.ll @@ -78,6 +78,7 @@ ; CHECK-O-NEXT: Running pass: CalledValuePropagationPass ; CHECK-O-NEXT: Running pass: GlobalOptPass ; CHECK-O-NEXT: Running pass: PromotePass +; CHECK-O-NEXT: Running pass: DebugEntryValuesCallSite ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass ; CHECK-O-NEXT: Running pass: DebugEntryValues ; CHECK-O-NEXT: Running pass: InstCombinePass Index: llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll =================================================================== --- llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll +++ llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll @@ -48,6 +48,7 @@ ; CHECK-O-NEXT: Running pass: CalledValuePropagationPass ; CHECK-O-NEXT: Running pass: GlobalOptPass ; CHECK-O-NEXT: Running pass: PromotePass +; CHECK-O-NEXT: Running pass: DebugEntryValuesCallSite ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass ; CHECK-O-NEXT: Running pass: DebugEntryValues ; CHECK-O-NEXT: Running pass: InstCombinePass Index: llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll =================================================================== --- llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll +++ llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll @@ -62,6 +62,7 @@ ; CHECK-O-NEXT: Running pass: CalledValuePropagationPass ; CHECK-O-NEXT: Running pass: GlobalOptPass ; CHECK-O-NEXT: Running pass: PromotePass +; CHECK-O-NEXT: Running pass: DebugEntryValuesCallSite ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass ; CHECK-O-NEXT: Running pass: DebugEntryValues ; CHECK-O-NEXT: Running pass: InstCombinePass Index: llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll =================================================================== --- llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll +++ llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll @@ -48,6 +48,7 @@ ; CHECK-O-NEXT: Running pass: CalledValuePropagationPass ; CHECK-O-NEXT: Running pass: GlobalOptPass ; CHECK-O-NEXT: Running pass: PromotePass +; CHECK-O-NEXT: Running pass: DebugEntryValuesCallSite ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass ; CHECK-O-NEXT: Running pass: DebugEntryValues ; CHECK-O-NEXT: Running pass: InstCombinePass Index: llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll =================================================================== --- llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll +++ llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll @@ -58,6 +58,7 @@ ; CHECK-O-NEXT: Running pass: CalledValuePropagationPass ; CHECK-O-NEXT: Running pass: GlobalOptPass ; CHECK-O-NEXT: Running pass: PromotePass +; CHECK-O-NEXT: Running pass: DebugEntryValuesCallSite ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass ; CHECK-O-NEXT: Running pass: DebugEntryValues ; CHECK-O-NEXT: Running pass: InstCombinePass Index: llvm/test/Transforms/DebugEntryValues/diloc-params.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/DebugEntryValues/diloc-params.ll @@ -0,0 +1,54 @@ +; RUN: opt -dbg-entry-values-call-sites -S < %s | FileCheck %s + +; Function Attrs: noinline nounwind uwtable +define dso_local i64 @fn1(i64 %0, i64 %1, i64 %2) local_unnamed_addr #0 !dbg !8 { + call void @llvm.dbg.value(metadata i64 %0, metadata !13, metadata !DIExpression()), !dbg !16 + call void @llvm.dbg.value(metadata i64 %1, metadata !14, metadata !DIExpression()), !dbg !16 + call void @llvm.dbg.value(metadata i64 %2, metadata !15, metadata !DIExpression()), !dbg !16 + ret i64 0, !dbg !17 +} + +; Function Attrs: noinline nounwind uwtable +define dso_local i64 @fn2() local_unnamed_addr #0 !dbg !18 { + %1 = call i64 @fn1(i64 1, i64 2, i64 3), !dbg !21 + ret i64 0, !dbg !22 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { noinline nounwind uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { nofree nosync nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 14.0.0 (https://github.com/llvm/llvm-project.git c2574e63ff71c1d3caea48cb6200c2422bd8f33d)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "testOriginal.c", directory: "/home/syrmia/diplomski/testF") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{i32 7, !"uwtable", i32 1} +!7 = !{!"clang version 14.0.0 (https://github.com/llvm/llvm-project.git c2574e63ff71c1d3caea48cb6200c2422bd8f33d)"} +!8 = distinct !DISubprogram(name: "fn1", scope: !1, file: !1, line: 2, type: !9, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12) +!9 = !DISubroutineType(types: !10) +!10 = !{!11, !11, !11, !11} +!11 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) +!12 = !{!13, !14, !15} +!13 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 2, type: !11) +!14 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !1, line: 2, type: !11) +!15 = !DILocalVariable(name: "c", arg: 3, scope: !8, file: !1, line: 2, type: !11) +!16 = !DILocation(line: 0, scope: !8) +!17 = !DILocation(line: 4, column: 3, scope: !8) +!18 = distinct !DISubprogram(name: "fn2", scope: !1, file: !1, line: 8, type: !19, scopeLine: 9, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!19 = !DISubroutineType(types: !20) +!20 = !{!11} +!21 = !DILocation(line: 10, column: 10, scope: !18) +; CHECK: !21 = !DILocation(line: 10, column: 10, scope: !18, params: !22) +; CHECK-NEXT: !22 = !{!23, !24, !25} +; CHECK-NEXT: !23 = !DICallSiteParam(argnum: 0, expr: !DIExpression(DW_OP_constu, 1, DW_OP_stack_value)) +; CHECK-NEXT: !24 = !DICallSiteParam(argnum: 1, expr: !DIExpression(DW_OP_constu, 2, DW_OP_stack_value)) +; CHECK-NEXT: !25 = !DICallSiteParam(argnum: 2, expr: !DIExpression(DW_OP_constu, 3, DW_OP_stack_value)) +!22 = !DILocation(line: 10, column: 3, scope: !18)