Index: llvm/include/llvm/CodeGen/FunctionLoweringInfo.h =================================================================== --- llvm/include/llvm/CodeGen/FunctionLoweringInfo.h +++ llvm/include/llvm/CodeGen/FunctionLoweringInfo.h @@ -77,6 +77,9 @@ /// cross-basic-block values. DenseMap ValueMap; + /// A mapping from the argument values to their virtual registers. + DenseMap ArgValueMap; + /// VirtReg2Value map is needed by the Divergence Analysis driven /// instruction selection. It is reverted ValueMap. It is computed /// in lazy style - on demand. It is used to get the Value corresponding Index: llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h =================================================================== --- llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h +++ llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h @@ -106,8 +106,9 @@ /// EmitDbgValue - Generate machine instruction for a dbg_value node. /// - MachineInstr *EmitDbgValue(SDDbgValue *SD, - DenseMap &VRBaseMap); + MachineInstr * + EmitDbgValue(SDDbgValue *SD, DenseMap &VRBaseMap, + DenseMap *ArgValueMap = nullptr); /// Generate machine instruction for a dbg_label node. MachineInstr *EmitDbgLabel(SDDbgLabel *SD); Index: llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp +++ llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp @@ -30,6 +30,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/Utils/Local.h" using namespace llvm; #define DEBUG_TYPE "instr-emitter" @@ -696,7 +697,8 @@ /// MachineInstr * InstrEmitter::EmitDbgValue(SDDbgValue *SD, - DenseMap &VRBaseMap) { + DenseMap &VRBaseMap, + DenseMap *ArgValueMap) { MDNode *Var = SD->getVariable(); MDNode *Expr = SD->getExpression(); DebugLoc DL = SD->getDebugLoc(); @@ -706,11 +708,28 @@ SD->setIsEmitted(); if (SD->isInvalidated()) { + Register Reg = 0; + Value *EntryValue = nullptr; + + // It the node has been invalidated, try to salvage the value + // if an entry value is available for the variable. Entry values + // act as backups here, and it will end up in an expression with + // a DW_OP_entry_value. + if (cast(Var)->isParameter()) + EntryValue = + findEntryValue(cast(Var), MF->getFunction()); + + if (EntryValue && ArgValueMap) { + if ((Reg = ArgValueMap->lookup(EntryValue))) + Expr = DIExpression::prepend(cast(Expr), + DIExpression::EntryValue); + } + // An invalidated SDNode must generate an undef DBG_VALUE: although the // original value is no longer computed, earlier DBG_VALUEs live ranges // must not leak into later code. auto MIB = BuildMI(*MF, DL, TII->get(TargetOpcode::DBG_VALUE)); - MIB.addReg(0U); + MIB.addReg(Reg, RegState::Debug); MIB.addReg(0U, RegState::Debug); MIB.addMetadata(Var); MIB.addMetadata(Expr); Index: llvm/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp +++ llvm/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp @@ -647,7 +647,8 @@ void Schedule() override; MachineBasicBlock * - EmitSchedule(MachineBasicBlock::iterator &InsertPos) override; + EmitSchedule(MachineBasicBlock::iterator &InsertPos, + DenseMap & /*ArgValueMap*/) override; private: std::vector Sequence; @@ -758,8 +759,9 @@ ScheduleNode(DAG->getRoot().getNode()); } -MachineBasicBlock* -ScheduleDAGLinearize::EmitSchedule(MachineBasicBlock::iterator &InsertPos) { +MachineBasicBlock *ScheduleDAGLinearize::EmitSchedule( + MachineBasicBlock::iterator &InsertPos, + DenseMap & /*ArgValueMap*/) { InstrEmitter Emitter(BB, InsertPos); DenseMap VRBaseMap; Index: llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.h =================================================================== --- llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.h +++ llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.h @@ -119,8 +119,9 @@ /// EmitSchedule - Insert MachineInstrs into the MachineBasicBlock /// according to the order specified in Sequence. /// - virtual MachineBasicBlock* - EmitSchedule(MachineBasicBlock::iterator &InsertPos); + virtual MachineBasicBlock * + EmitSchedule(MachineBasicBlock::iterator &InsertPos, + DenseMap &ArgValueMap); void dumpNode(const SUnit &SU) const override; void dump() const override; Index: llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp +++ llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp @@ -828,7 +828,8 @@ /// point. ScheduleDAGSDNodes holds a BB pointer for convenience, but this does /// not necessarily refer to returned BB. The emitter may split blocks. MachineBasicBlock *ScheduleDAGSDNodes:: -EmitSchedule(MachineBasicBlock::iterator &InsertPos) { +EmitSchedule(MachineBasicBlock::iterator &InsertPos, + DenseMap &ValueMap) { InstrEmitter Emitter(BB, InsertPos); DenseMap VRBaseMap; DenseMap CopyVRBaseMap; @@ -967,7 +968,7 @@ if ((*DI)->isEmitted()) continue; - MachineInstr *DbgMI = Emitter.EmitDbgValue(*DI, VRBaseMap); + MachineInstr *DbgMI = Emitter.EmitDbgValue(*DI, VRBaseMap, &ValueMap); if (DbgMI) { if (!LastOrder) // Insert to start of the BB (after PHIs). Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5470,6 +5470,11 @@ Op = MachineOperand::CreateReg(Reg, false); IsIndirect = IsDbgDeclare; } + + // Map the register into the Value, so it can be used for debug + // info recovering. + if (FuncInfo.ArgValueMap.find(V) == FuncInfo.ArgValueMap.end()) + FuncInfo.ArgValueMap[V] = Reg; } if (!Op && N.getNode()) { Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -970,7 +970,8 @@ // FuncInfo->InsertPt is passed by reference and set to the end of the // scheduled instructions. - LastMBB = FuncInfo->MBB = Scheduler->EmitSchedule(FuncInfo->InsertPt); + LastMBB = FuncInfo->MBB = + Scheduler->EmitSchedule(FuncInfo->InsertPt, FuncInfo->ArgValueMap); } // If the block was split, make sure we update any references that are used to Index: llvm/test/DebugInfo/X86/entry-values-for-isel-invalidated-nodes.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/entry-values-for-isel-invalidated-nodes.ll @@ -0,0 +1,61 @@ +; RUN: llc < %s -O2 -stop-before=finalize-isel | FileCheck %s +; RUN: llc -O2 %s -o %t -filetype=obj +; RUN: llvm-dwarfdump %t | FileCheck %s --check-prefix=CHECK-DWARFDUMP + +; C producer: +; void f1(int); +; void f2(int i) { +; f1(1); +; i = i + 5; +; f1(3); +; } +; $ clang -g -O2 test.c -S -emit-llvm + +; CHECK: DBG_VALUE $edi, $noreg, !{{.*}}, !DIExpression() +; CHECK: DBG_VALUE $edi, $noreg, !{{.*}}, !DIExpression(DW_OP_LLVM_entry_value, 1, DW_OP_plus_uconst, 5, DW_OP_stack_value) + +; CHECK-DWARFDUMP: DW_OP_GNU_entry_value(DW_OP_reg5 RDI), DW_OP_stack_value +; CHECK-DWARFDUMP: DW_OP_GNU_entry_value(DW_OP_reg5 RDI), DW_OP_constu 0xffffffff, DW_OP_and, DW_OP_plus_uconst 0x5, DW_OP_stack_value + +; ModuleID = 'test.c' +source_filename = "test.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: nounwind uwtable +define dso_local void @f2(i32 %i) local_unnamed_addr !dbg !7 { +entry: + call void @llvm.dbg.value(metadata i32 %i, metadata !12, metadata !DIExpression()), !dbg !13 + tail call void @f1(i32 1), !dbg !14 + call void @llvm.dbg.value(metadata i32 %i, metadata !12, metadata !DIExpression(DW_OP_plus_uconst, 5, DW_OP_stack_value)), !dbg !13 + tail call void @f1(i32 3), !dbg !15 + ret void, !dbg !16 +} + +declare !dbg !17 dso_local void @f1(i32) local_unnamed_addr + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/dir") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 12.0.0"} +!7 = distinct !DISubprogram(name: "f2", scope: !1, file: !1, line: 2, type: !8, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{null, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DILocalVariable(name: "i", arg: 1, scope: !7, file: !1, line: 2, type: !10) +!13 = !DILocation(line: 0, scope: !7) +!14 = !DILocation(line: 3, column: 3, scope: !7) +!15 = !DILocation(line: 5, column: 3, scope: !7) +!16 = !DILocation(line: 6, column: 1, scope: !7) +!17 = !DISubprogram(name: "f1", scope: !1, file: !1, line: 1, type: !8, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)