Index: llvm/include/llvm/Transforms/Utils/Local.h =================================================================== --- llvm/include/llvm/Transforms/Utils/Local.h +++ llvm/include/llvm/Transforms/Utils/Local.h @@ -283,6 +283,9 @@ /// dbg.addr. TinyPtrVector FindDbgDeclareUses(Value *V); +/// Finds an entry value for the variable. +Value* findEntryValue(DIVariable *Var); + /// Finds the llvm.dbg.value intrinsics describing a value. void findDbgValues(SmallVectorImpl &DbgValues, Value *V); Index: llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -287,7 +287,8 @@ // a call site parameter expression and if that expression is just a register // location, emit it with addBReg and offset 0, because we should emit a DWARF // expression representing a value, rather than a location. - if (!isMemoryLocation() && !HasComplexExpression && + // FIXME: Simplify the statements regarding entry values. + if (!isMemoryLocation() && (!HasComplexExpression || isEntryValue()) && (!isParameterValue() || isEntryValue())) { for (auto &Reg : DwarfRegs) { if (Reg.DwarfRegNo >= 0) @@ -299,7 +300,7 @@ finalizeEntryValue(); if (isEntryValue() && !isIndirect() && !isParameterValue() && - DwarfVersion >= 4) + DwarfVersion >= 4 && !HasComplexExpression) emitOp(dwarf::DW_OP_stack_value); DwarfRegs.clear(); @@ -453,10 +454,6 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor, unsigned FragmentOffsetInBits) { - // Entry values can currently only cover the initial register location, - // and not any other parts of the following DWARF expression. - assert(!IsEmittingEntryValue && "Can't emit entry value around expression"); - // If we need to mask out a subregister, do it now, unless the next // operation would emit an OpPiece anyway. auto N = ExprCursor.peek(); @@ -509,7 +506,7 @@ return; } case dwarf::DW_OP_plus_uconst: - assert(!isRegisterLocation()); + assert(!isRegisterLocation() || isEntryValue()); emitOp(dwarf::DW_OP_plus_uconst); emitUnsigned(Op->getArg(0)); break; @@ -603,6 +600,9 @@ if (isImplicitLocation() && !isParameterValue()) // Turn this into an implicit location description. addStackValue(); + + if (IsEmittingEntryValue) + finalizeEntryValue(); } /// add masking operations to stencil out a subregister. Index: llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h =================================================================== --- llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h +++ llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h @@ -107,7 +107,8 @@ /// EmitDbgValue - Generate machine instruction for a dbg_value node. /// MachineInstr *EmitDbgValue(SDDbgValue *SD, - DenseMap &VRBaseMap); + DenseMap &VRBaseMap, + DenseMap *ValueMap = 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 *ValueMap) { MDNode *Var = SD->getVariable(); MDNode *Expr = SD->getExpression(); DebugLoc DL = SD->getDebugLoc(); @@ -706,11 +708,26 @@ SD->setIsEmitted(); if (SD->isInvalidated()) { + Register Reg = 0; + Value *EntryValue = nullptr; + + if (cast(Var)->isParameter()) + EntryValue = findEntryValue(cast(Var)); + + if (EntryValue && ValueMap) { + auto VMI = ValueMap->find(EntryValue); + if (VMI != ValueMap->end()) { + Reg = VMI->second; + 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); 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 &ValueMap) override; private: std::vector Sequence; @@ -759,7 +760,8 @@ } MachineBasicBlock* -ScheduleDAGLinearize::EmitSchedule(MachineBasicBlock::iterator &InsertPos) { +ScheduleDAGLinearize::EmitSchedule(MachineBasicBlock::iterator &InsertPos, + DenseMap &ValueMap) { 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 @@ -120,7 +120,8 @@ /// according to the order specified in Sequence. /// virtual MachineBasicBlock* - EmitSchedule(MachineBasicBlock::iterator &InsertPos); + EmitSchedule(MachineBasicBlock::iterator &InsertPos, + DenseMap &ValueMap); 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.ValueMap.find(V) == FuncInfo.ValueMap.end()) + FuncInfo.ValueMap[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->ValueMap); } // If the block was split, make sure we update any references that are used to Index: llvm/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/lib/IR/DebugInfoMetadata.cpp +++ llvm/lib/IR/DebugInfoMetadata.cpp @@ -1029,8 +1029,7 @@ // entry values of a simple register location. One reason for this is that // we currently can't calculate the size of the resulting DWARF block for // other expressions. - return I->get() == expr_op_begin()->get() && I->getArg(0) == 1 && - getNumElements() == 2; + return I->get() == expr_op_begin()->get() && I->getArg(0) == 1; } case dwarf::DW_OP_LLVM_convert: case dwarf::DW_OP_LLVM_tag_offset: @@ -1195,8 +1194,9 @@ if (EntryValue) { Ops.push_back(dwarf::DW_OP_LLVM_entry_value); // Add size info needed for entry value expression. - // Add plus one for target register operand. - Ops.push_back(Expr->getNumElements() + 1); + // It is always of size 1 at the moment, since we support + // simple register locations only. + Ops.push_back(1); } // If there are no ops to prepend, do not even add the DW_OP_stack_value. Index: llvm/lib/Transforms/Utils/Local.cpp =================================================================== --- llvm/lib/Transforms/Utils/Local.cpp +++ llvm/lib/Transforms/Utils/Local.cpp @@ -1593,6 +1593,30 @@ return DDIs; } +Value *llvm::findEntryValue(DIVariable *Var) { + // TODO: Find an entry value for local variables, + // if the local variable value can be expressed + // in terms of an entry value (of a parameter). + if (!cast(Var)->isParameter()) + return nullptr; + + LLVM_DEBUG(llvm::dbgs() << "Finding entry value for variable: "; + Var->dump();); + + if (auto *MDV = MetadataAsValue::get(Var->getContext(), Var)) { + LLVM_DEBUG(llvm::dbgs() << " mdv : "; MDV->dump();); + for (User *U : MDV->users()) { + LLVM_DEBUG(llvm::dbgs() << " user : "; U->dump();); + if (DbgValueInst *DVI = dyn_cast(U)) { + LLVM_DEBUG(llvm::dbgs() << " dbg.val: "; DVI->dump();); + return DVI->getValue(); + } + } + } + + return nullptr; +} + void llvm::findDbgValues(SmallVectorImpl &DbgValues, Value *V) { // This function is hot. Check whether the value has any metadata to avoid a // DenseMap lookup. 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)