Index: llvm/include/llvm/IR/Function.h =================================================================== --- llvm/include/llvm/IR/Function.h +++ llvm/include/llvm/IR/Function.h @@ -62,6 +62,8 @@ class LLVM_EXTERNAL_VISIBILITY Function : public GlobalObject, public ilist_node { public: + uint64_t CallSiteInfoStackFwdGlobalOffset = 0; + using BasicBlockListType = SymbolTableList; // BasicBlock iterators... Index: llvm/include/llvm/MC/MachineLocation.h =================================================================== --- llvm/include/llvm/MC/MachineLocation.h +++ llvm/include/llvm/MC/MachineLocation.h @@ -23,6 +23,7 @@ private: bool IsRegister = false; ///< True if location is a register. unsigned Register = 0; ///< gcc/gdb register number. + uint64_t Offset = 0; public: enum : uint32_t { @@ -33,11 +34,12 @@ MachineLocation() = default; /// Create a direct register location. - explicit MachineLocation(unsigned R, bool Indirect = false) - : IsRegister(!Indirect), Register(R) {} + explicit MachineLocation(unsigned R, bool Indirect = false, uint64_t Offs = 0) + : IsRegister(!Indirect), Register(R), Offset(Offs) {} bool operator==(const MachineLocation &Other) const { - return IsRegister == Other.IsRegister && Register == Other.Register; + return IsRegister == Other.IsRegister && Register == Other.Register && + Offset == Other.Offset; } // Accessors. @@ -45,6 +47,9 @@ bool isIndirect() const { return !IsRegister; } bool isReg() const { return IsRegister; } unsigned getReg() const { return Register; } + + /// Offset for a register-indirect location. + uint64_t getOffset() const { return Offset; } void setIsRegister(bool Is) { IsRegister = Is; } void setRegister(unsigned R) { Register = R; } }; Index: llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -1230,12 +1230,13 @@ DIE &CallSiteDIE, SmallVector &Params) { for (const auto &Param : Params) { unsigned Register = Param.getRegister(); + uint64_t Offset = Param.getOffset(); auto CallSiteDieParam = DIE::get(DIEValueAllocator, getDwarf5OrGNUTag(dwarf::DW_TAG_call_site_parameter)); insertDIE(CallSiteDieParam); addAddress(*CallSiteDieParam, dwarf::DW_AT_location, - MachineLocation(Register)); + MachineLocation(Register, Offset ? true : false, Offset)); DIELoc *Loc = new (DIEValueAllocator) DIELoc; DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); @@ -1439,7 +1440,15 @@ if (Location.isIndirect()) DwarfExpr.setMemoryLocationKind(); + uint64_t Offset = Location.getOffset(); DIExpressionCursor Cursor({}); + if (Offset) { + DIExpression *DIExpr = + DIExpression::get(Asm->MF->getFunction().getContext(), + {dwarf::DW_OP_plus_uconst, Offset}); + Cursor = DIExpressionCursor(DIExpr); + } + const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo(); if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Location.getReg())) return; Index: llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -263,14 +263,19 @@ unsigned Register; ///< Parameter register at the callee entry point. DbgValueLoc Value; ///< Corresponding location for the parameter value at ///< the call site. + uint64_t Offset; + public: - DbgCallSiteParam(unsigned Reg, DbgValueLoc Val) - : Register(Reg), Value(Val) { + DbgCallSiteParam(unsigned Reg, DbgValueLoc Val, uint64_t Offs) + : Register(Reg), Value(Val), Offset(Offs) { assert(Reg && "Parameter register cannot be undef"); } + DbgCallSiteParam(unsigned Reg, DbgValueLoc Val) + : DbgCallSiteParam(Reg, Val, 0) {} unsigned getRegister() const { return Register; } DbgValueLoc getValue() const { return Value; } + uint64_t getOffset() const { return Offset; } }; /// Collection used for storing debug call site parameters. Index: llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -882,23 +882,67 @@ const auto &CalleesMap = MF->getCallSitesInfo(); auto CallFwdRegsInfo = CalleesMap.find(CallMI); - if (CallFwdRegsInfo == CalleesMap.end()) - return; + const auto &CalleesStackMap = MF->getCallSitesInfoStackFwd(); + auto CallFwdStackInfo = CalleesStackMap.find(CallMI); + bool CollectStackFwdParams = false; + uint64_t Offset; + const Function *F; + + auto CallMIMO = CallMI->getOperand(0); + if (CallMIMO.isGlobal()) { + F = dyn_cast(CallMIMO.getGlobal()); + Offset = F->CallSiteInfoStackFwdGlobalOffset; + + // Arguments passed on the stack. + if (CallFwdStackInfo != CalleesStackMap.end()) { + CollectStackFwdParams = true; + } + } const DIExpression *EmptyExpr = DIExpression::get(MF->getFunction().getContext(), {}); + // Arguments passed through the registers. + if (CallFwdRegsInfo != CalleesMap.end()) { + for (auto Param : IRParams) { + DICallSiteParam *DICSParam = cast(Param); + for (auto ArgReg : CallFwdRegsInfo->second) { + if (DICSParam->getArgNum() == ArgReg.ArgNo) { + auto DIExpr = DICSParam->getExpression(); + + // Currently covering only the case of constant arguments forwarding. + 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; + } + } + } + } + + if (!CollectStackFwdParams) + return; + for (auto Param : IRParams) { - auto DIParamVal = cast(Param); - for (auto ArgReg : CallFwdRegsInfo->second) { - if (DIParamVal->getArgNum() == ArgReg.ArgNo) { - auto DIExpr = DIParamVal->getExpression(); + DICallSiteParam *DICSParam = cast(Param); + for (auto ArgOff : CallFwdStackInfo->second) { + if (DICSParam->getArgNum() == ArgOff.ArgNo) { + auto DIExpr = DICSParam->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); + uint64_t TotalOffset = ArgOff.Offset + Offset; + uint64_t Value = DIExpr->getElement(1); + Register StackPtr = MF->getSubtarget() + .getTargetLowering() + ->getStackPointerRegisterToSaveRestore(); + unsigned int Reg = StackPtr.id(); + DbgValueLoc DbgLocVal(EmptyExpr, DbgValueLocEntry(Value)); + DbgCallSiteParam CSParam(Reg, DbgLocVal, TotalOffset); + Params.push_back(CSParam); ++NumCSParams; } break; Index: llvm/lib/CodeGen/PrologEpilogInserter.cpp =================================================================== --- llvm/lib/CodeGen/PrologEpilogInserter.cpp +++ llvm/lib/CodeGen/PrologEpilogInserter.cpp @@ -1129,6 +1129,7 @@ int64_t StackSize = Offset - LocalAreaOffset; MFI.setStackSize(StackSize); NumBytesStackSpace += StackSize; + (MF.getFunction()).CallSiteInfoStackFwdGlobalOffset = Offset; } /// insertPrologEpilogCode - Scan the function for modified callee saved Index: llvm/test/DebugInfo/X86/call-site-param-unused.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/call-site-param-unused.ll @@ -0,0 +1,110 @@ +; RUN: llc -emit-call-site-info -mtriple=x86_64-unknown-linux-gnu %s -filetype=obj -o - | llvm-dwarfdump - | FileCheck %s + +;; Compiled from source: +;; extern void fn1 (); +;; long int __attribute__((noinline)) fn2 +;; (long int x, long int y, long int z, long int q, long int w, long int e, long int r) +;; { +;; fn1(); +;; return 0; +;; } +;; int main() { +;; fn2(1,2,3,4,5,6,7); +;; return 0; +;; } +;; Using command: +;; clang -g -O2 test7.c -emit-llvm -S -o test7.ll + +; This test should verify that there is suitable DW_TAG_GNU_call_site_parameter for unused +; constant arguments that are marked as undef due to DeadArgumentElimination pass. +; It checks existence of DWARF tags for arguments that are passed through the registers +; and via the stack. +; CHECK: DW_TAG_GNU_call_site +; CHECK: DW_AT_abstract_origin ({{.*}} "fn2") +; CHECK: DW_TAG_GNU_call_site_parameter +; CHECK-NEXT: DW_AT_location (DW_OP_reg5 RDI) +; CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_lit1) +; CHECK: DW_AT_location (DW_OP_fbreg +16) +; CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_lit7) + +; ModuleID = 'test7.c' +source_filename = "test7.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: noinline nounwind uwtable +define dso_local i64 @fn2(i64 %x, i64 %y, i64 %z, i64 %q, i64 %w, i64 %e, i64 %r) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata i64 %x, metadata !12, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !19 + call void @llvm.dbg.value(metadata i64 %y, metadata !13, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !19 + call void @llvm.dbg.value(metadata i64 %z, metadata !14, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !19 + call void @llvm.dbg.value(metadata i64 %q, metadata !15, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !19 + call void @llvm.dbg.value(metadata i64 %w, metadata !16, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !19 + call void @llvm.dbg.value(metadata i64 %e, metadata !17, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !19 + call void @llvm.dbg.value(metadata i64 %r, metadata !18, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !19 + tail call void (...) @fn1() #4, !dbg !20 + ret i64 0, !dbg !21 +} + +declare !dbg !22 dso_local void @fn1(...) local_unnamed_addr #1 + +; Function Attrs: nounwind uwtable +define dso_local i32 @main() local_unnamed_addr #2 !dbg !26 { +entry: + %call = tail call i64 @fn2(i64 undef, i64 undef, i64 undef, i64 undef, i64 undef, i64 undef, i64 undef), !dbg !30 + ret i32 0, !dbg !39 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +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 = { "frame-pointer"="none" "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 #2 = { 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 #3 = { nofree nosync nounwind readnone speculatable willreturn } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 14.0.0 (https://github.com/milica-lazarevic/llvm-project.git 59bcfb05e4737f96d9cae8b56671041bf932f4ae)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test7.c", directory: "/home/syrmia/diplomski") +!2 = !{i32 7, !"Dwarf Version", i32 4} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"uwtable", i32 1} +!6 = !{!"clang version 14.0.0 (https://github.com/milica-lazarevic/llvm-project.git 59bcfb05e4737f96d9cae8b56671041bf932f4ae)"} +!7 = distinct !DISubprogram(name: "fn2", scope: !1, file: !1, line: 2, type: !8, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !10, !10, !10, !10, !10, !10, !10} +!10 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed) +!11 = !{!12, !13, !14, !15, !16, !17, !18} +!12 = !DILocalVariable(name: "x", arg: 1, scope: !7, file: !1, line: 2, type: !10) +!13 = !DILocalVariable(name: "y", arg: 2, scope: !7, file: !1, line: 2, type: !10) +!14 = !DILocalVariable(name: "z", arg: 3, scope: !7, file: !1, line: 2, type: !10) +!15 = !DILocalVariable(name: "q", arg: 4, scope: !7, file: !1, line: 2, type: !10) +!16 = !DILocalVariable(name: "w", arg: 5, scope: !7, file: !1, line: 2, type: !10) +!17 = !DILocalVariable(name: "e", arg: 6, scope: !7, file: !1, line: 2, type: !10) +!18 = !DILocalVariable(name: "r", arg: 7, scope: !7, file: !1, line: 2, type: !10) +!19 = !DILocation(line: 0, scope: !7) +!20 = !DILocation(line: 4, column: 3, scope: !7) +!21 = !DILocation(line: 5, column: 3, scope: !7) +!22 = !DISubprogram(name: "fn1", scope: !1, file: !1, line: 1, type: !23, spFlags: DISPFlagOptimized, retainedNodes: !25) +!23 = !DISubroutineType(types: !24) +!24 = !{null} +!25 = !{} +!26 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 7, type: !27, scopeLine: 7, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !25) +!27 = !DISubroutineType(types: !28) +!28 = !{!29} +!29 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!30 = !DILocation(line: 8, column: 3, scope: !26, params: !31) +!31 = !{!32, !33, !34, !35, !36, !37, !38} +!32 = !DICallSiteParam(argnum: 0, expr: !DIExpression(DW_OP_constu, 1, DW_OP_stack_value)) +!33 = !DICallSiteParam(argnum: 1, expr: !DIExpression(DW_OP_constu, 2, DW_OP_stack_value)) +!34 = !DICallSiteParam(argnum: 2, expr: !DIExpression(DW_OP_constu, 3, DW_OP_stack_value)) +!35 = !DICallSiteParam(argnum: 3, expr: !DIExpression(DW_OP_constu, 4, DW_OP_stack_value)) +!36 = !DICallSiteParam(argnum: 4, expr: !DIExpression(DW_OP_constu, 5, DW_OP_stack_value)) +!37 = !DICallSiteParam(argnum: 5, expr: !DIExpression(DW_OP_constu, 6, DW_OP_stack_value)) +!38 = !DICallSiteParam(argnum: 6, expr: !DIExpression(DW_OP_constu, 7, DW_OP_stack_value)) +!39 = !DILocation(line: 9, column: 3, scope: !26)