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(DILocalVariable *Var, Function &F); + /// 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(); @@ -509,7 +510,7 @@ return; } case dwarf::DW_OP_plus_uconst: - assert(!isRegisterLocation()); + assert(!isRegisterLocation() || isEntryValue()); emitOp(dwarf::DW_OP_plus_uconst); emitUnsigned(Op->getArg(0)); break; @@ -540,7 +541,7 @@ emitOp(dwarf::DW_OP_deref); break; case dwarf::DW_OP_constu: - assert(!isRegisterLocation()); + assert(!isRegisterLocation() || isEntryValue()); emitConstu(Op->getArg(0)); break; case dwarf::DW_OP_LLVM_convert: { 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,47 @@ return DDIs; } +Value *llvm::findEntryValue(DILocalVariable *Var, Function &F) { + // Skip empty functions. + if (F.empty()) + return nullptr; + + // 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();); + + BasicBlock &EntryBB = *(F.begin()); + for (auto &I : EntryBB) { + LLVM_DEBUG(llvm::dbgs() << " Investigating: "; I.dump();); + if (DbgValueInst *DVI = dyn_cast(&I)) { + if (DVI->getVariable() != Var) + continue; + + // TODO: Add support for variables with pre-existing elements. + if (DVI->getExpression()->getNumElements() > 0) + return nullptr; + + // Do not consider variables from inlined functions. + if (DVI->getDebugLoc()->getInlinedAt()) + return nullptr; + + auto V = DVI->getValue(); + if (isa(V)) + return nullptr; + + LLVM_DEBUG(llvm::dbgs() << " Found: "; V->dump();); + return V; + } + } + + 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/Verifier/diexpression-valid-entry-value.ll =================================================================== --- llvm/test/Verifier/diexpression-valid-entry-value.ll +++ llvm/test/Verifier/diexpression-valid-entry-value.ll @@ -1,5 +1,7 @@ ; RUN: opt -S < %s 2>&1 | FileCheck %s -!named = !{!0} +!named = !{!0, !1, !2} ; CHECK-NOT: invalid expression !0 = !DIExpression(DW_OP_LLVM_entry_value, 1) +!1 = !DIExpression(DW_OP_LLVM_entry_value, 1, DW_OP_plus_uconst, 3, DW_OP_stack_value) +!2 = !DIExpression(DW_OP_LLVM_entry_value, 1, DW_OP_constu, 9, DW_OP_minus, DW_OP_stack_value) Index: llvm/unittests/Transforms/Utils/LocalTest.cpp =================================================================== --- llvm/unittests/Transforms/Utils/LocalTest.cpp +++ llvm/unittests/Transforms/Utils/LocalTest.cpp @@ -582,6 +582,70 @@ verifyDebugValuesAreSalvaged(); } +TEST(Local, FindEntryValue) { + LLVMContext Ctx; + + std::unique_ptr M = parseIR(Ctx, + R"( + define internal void @foo(i32 %i, i64 %p.0, i64 %p.1, i32 %j, i32 %k) !dbg !4 { + entry: + call void @llvm.dbg.value(metadata i32 %i, metadata !8, metadata !DIExpression()), !dbg !6 + call void @llvm.dbg.value(metadata i64 %p.0, metadata !9, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 64)), !dbg !6 + call void @llvm.dbg.value(metadata i64 %p.1, metadata !9, metadata !DIExpression(DW_OP_LLVM_fragment, 64, 64)), !dbg !6 + call void @llvm.dbg.value(metadata i32 %j, metadata !15, metadata !DIExpression()), !dbg !16 + call void @llvm.dbg.value(metadata i32 undef, metadata !17, metadata !DIExpression()), !dbg !6 + ret void, !dbg !6 + } + + ; Function Attrs: nounwind readnone speculatable willreturn + declare void @llvm.dbg.value(metadata, metadata, metadata) + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!3} + + !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + !1 = !DIFile(filename: "test.ll", directory: "/") + !2 = !{} + !3 = !{i32 2, !"Debug Info Version", i32 3} + !4 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !5, isLocal: true, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, retainedNodes: !7) + !5 = !DISubroutineType(types: !2) + !6 = !DILocation(line: 1, column: 1, scope: !4) + !7 = !{!8, !9, !15, !17} + !8 = !DILocalVariable(name: "i", arg: 1, scope: !4, file: !1, line: 2) + !9 = !DILocalVariable(name: "p", arg: 2, scope: !4, file: !1, line: 5, type: !10) + !10 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !1, line: 1, size: 128, elements: !11) + !11 = !{!12, !14} + !12 = !DIDerivedType(tag: DW_TAG_member, name: "one", scope: !10, file: !1, line: 2, baseType: !13, size: 64) + !13 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed) + !14 = !DIDerivedType(tag: DW_TAG_member, name: "two", scope: !10, file: !1, line: 3, baseType: !13, size: 64, offset: 64) + !15 = !DILocalVariable(name: "j", arg: 3, scope: !4, file: !1, line: 2) + !16 = !DILocation(line: 1, column: 1, scope: !4, inlinedAt: !6) + !17 = !DILocalVariable(name: "k", arg: 4, scope: !4, file: !1, line: 2) + + )"); + + auto &F = *cast(M->getNamedValue("foo")); + auto SP = F.getSubprogram(); + auto ParamI = SP->getRetainedNodes()[0]; + auto EntryValue = findEntryValue(cast(ParamI), F); + ASSERT_TRUE(EntryValue != nullptr); + + auto ParamP = SP->getRetainedNodes()[1]; + auto EntryValue2 = findEntryValue(cast(ParamP), F); + // Avoid fragmented entry values. + ASSERT_TRUE(EntryValue2 == nullptr); + + auto ParamJ = SP->getRetainedNodes()[2]; + auto EntryValue3 = findEntryValue(cast(ParamJ), F); + // Avoid inlined parameters. + ASSERT_TRUE(EntryValue3 == nullptr); + + auto ParamK = SP->getRetainedNodes()[3]; + auto EntryValue4 = findEntryValue(cast(ParamK), F); + // Return nullptr for undefs. + ASSERT_TRUE(EntryValue4 == nullptr); +} + TEST(Local, ChangeToUnreachable) { LLVMContext Ctx;