[llvm] r208506 - DebugInfo: Include lexical scopes in inlined subroutines.

David Blaikie dblaikie at gmail.com
Mon May 12 17:01:09 PDT 2014


On Mon, May 12, 2014 at 4:55 PM, David Blaikie <dblaikie at gmail.com> wrote:
> On Mon, May 12, 2014 at 4:51 PM, Alexey Samsonov <samsonov at google.com> wrote:
>> Looks like this change breaks debug info under certain conditions. Here's a
>> reproducer (sorry, but I wasn't able to quickly generate one without gtest):
>>
>> $ cat tmp/dbginfo/inl.cc
>> #include "gtest/gtest.h"
>> #include <stdio.h>
>>
>> void test(char x) {
>>   if (x)
>>     printf("good\n");
>> }
>>
>> TEST(Foo, foo) {
>>   char *x = new char[8];
>>   fprintf(stderr, "x: %p\n", x);
>>   test(x[1]);
>> }
>>
>> $ ./bin/clang++ -std=c++11 -O2 -gline-tables-only -D__STDC_LIMIT_MACROS
>> -D__STDC_CONSTANT_MACROS -I /llvm_build/include -I
>> /llvm/utils/unittest/googletest/include -I /llvm/include
>> /llvm_build/lib/libgtest_main.a llvm_build/lib/libgtest.a
>> /llvm_build/lib/libLLVMSupport.a -lcurses -lpthread -ldl tmp/dbginfo/inl.cc
>>
>> invocation of test() gets inlined in Foo_foo_Test::TestBody(). However,
>> there is no sign of DW_TAG_inlined_subroutine in the debug info:
>>
>> $ readelf -wi a.out
>> <...>
>>  <1><46>: Abbrev Number: 3 (DW_TAG_subprogram)
>>     <47>   DW_AT_name        : (indirect string, offset: 0x83): TestBody
>>     <4b>   DW_AT_decl_file   : 2
>>     <4c>   DW_AT_decl_line   : 9
>>     <4d>   DW_AT_external    : 1
>>     <4d>   DW_AT_accessibility: 1       (public)
>>     <4e>   DW_AT_low_pc      : 0x457b50
>>     <56>   DW_AT_high_pc     : 0x37
>>     <5a>   DW_AT_frame_base  : 1 byte block: 57         (DW_OP_reg7 (rsp))
>>     <5c>   Unknown AT value: 3fe7: 1
>>  <1><5c>: Abbrev Number: 4 (DW_TAG_subprogram)
>>     <5d>   DW_AT_name        : (indirect string, offset: 0x8c): Setup
>> <...>
>>
>> This happens both for "-g" and for "-gline-tables-only". Any idea why this
>> might happen?
>
> Nope, not off-hand. Do you have a preprocessed source file that
> demonstrates the issue?

Reproduced this using the various command line flags given in your
reproduction pointing to LLVM source/build tree. Reverted this patch
(r208642) while I investigate.

Thanks for the reproduction.

- Dave

>
> - David
>
>>
>> On Sun, May 11, 2014 at 11:12 AM, David Blaikie <dblaikie at gmail.com> wrote:
>>>
>>> Author: dblaikie
>>> Date: Sun May 11 13:12:17 2014
>>> New Revision: 208506
>>>
>>> URL: http://llvm.org/viewvc/llvm-project?rev=208506&view=rev
>>> Log:
>>> DebugInfo: Include lexical scopes in inlined subroutines.
>>>
>>> Added:
>>>     llvm/trunk/test/DebugInfo/inline-scopes.ll
>>> Modified:
>>>     llvm/trunk/include/llvm/ADT/STLExtras.h
>>>     llvm/trunk/include/llvm/CodeGen/LexicalScopes.h
>>>     llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
>>>     llvm/trunk/lib/CodeGen/LexicalScopes.cpp
>>>
>>> Modified: llvm/trunk/include/llvm/ADT/STLExtras.h
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/STLExtras.h?rev=208506&r1=208505&r2=208506&view=diff
>>>
>>> ==============================================================================
>>> --- llvm/trunk/include/llvm/ADT/STLExtras.h (original)
>>> +++ llvm/trunk/include/llvm/ADT/STLExtras.h Sun May 11 13:12:17 2014
>>> @@ -530,6 +530,13 @@ make_unique(size_t n) {
>>>
>>>  #endif
>>>
>>> +template<typename First, typename Second>
>>> +struct pair_hash {
>>> +  size_t operator()(const std::pair<First, Second> &P) const {
>>> +    return std::hash<First>()(P.first) * 31 +
>>> std::hash<Second>()(P.second);
>>> +  }
>>> +};
>>> +
>>>  } // End llvm namespace
>>>
>>>  #endif
>>>
>>> Modified: llvm/trunk/include/llvm/CodeGen/LexicalScopes.h
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/LexicalScopes.h?rev=208506&r1=208505&r2=208506&view=diff
>>>
>>> ==============================================================================
>>> --- llvm/trunk/include/llvm/CodeGen/LexicalScopes.h (original)
>>> +++ llvm/trunk/include/llvm/CodeGen/LexicalScopes.h Sun May 11 13:12:17
>>> 2014
>>> @@ -21,6 +21,7 @@
>>>  #include "llvm/ADT/DenseMap.h"
>>>  #include "llvm/ADT/SmallPtrSet.h"
>>>  #include "llvm/ADT/SmallVector.h"
>>> +#include "llvm/ADT/STLExtras.h"
>>>  #include "llvm/IR/DebugLoc.h"
>>>  #include "llvm/IR/Metadata.h"
>>>  #include "llvm/IR/ValueHandle.h"
>>> @@ -185,9 +186,7 @@ public:
>>>
>>>    /// findInlinedScope - Find an inlined scope for the given DebugLoc or
>>> return
>>>    /// NULL.
>>> -  LexicalScope *findInlinedScope(DebugLoc DL) {
>>> -    return InlinedLexicalScopeMap.lookup(DL);
>>> -  }
>>> +  LexicalScope *findInlinedScope(DebugLoc DL);
>>>
>>>    /// findLexicalScope - Find regular lexical scope or return null.
>>>    LexicalScope *findLexicalScope(const MDNode *N) {
>>> @@ -230,7 +229,9 @@ private:
>>>
>>>    /// InlinedLexicalScopeMap - Tracks inlined function scopes in current
>>>    /// function.
>>> -  DenseMap<DebugLoc, LexicalScope *> InlinedLexicalScopeMap;
>>> +  std::unordered_map<std::pair<const MDNode *, const MDNode *>,
>>> LexicalScope,
>>> +                     pair_hash<const MDNode *, const MDNode *>>
>>> +  InlinedLexicalScopeMap;
>>>
>>>    /// AbstractScopeMap - These scopes are  not included LexicalScopeMap.
>>>    // Use an unordered_map to ensure value pointer validity over
>>> insertion.
>>>
>>> Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp?rev=208506&r1=208505&r2=208506&view=diff
>>>
>>> ==============================================================================
>>> --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp (original)
>>> +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp Sun May 11 13:12:17
>>> 2014
>>> @@ -621,7 +621,7 @@ std::unique_ptr<DIE> DwarfDebug::constru
>>>    // avoid creating un-used children then removing them later when we
>>> find out
>>>    // the scope DIE is null.
>>>    std::unique_ptr<DIE> ScopeDIE;
>>> -  if (Scope->getInlinedAt()) {
>>> +  if (DS.getContext() && DS.isSubprogram()) {
>>>      ScopeDIE = constructInlinedScopeDIE(TheCU, Scope);
>>>      if (!ScopeDIE)
>>>        return nullptr;
>>> @@ -1212,10 +1212,12 @@ DwarfDebug::collectVariableInfo(SmallPtr
>>>      if (DV.getTag() == dwarf::DW_TAG_arg_variable &&
>>>          DISubprogram(DV.getContext()).describes(CurFn->getFunction()))
>>>        Scope = LScopes.getCurrentFunctionScope();
>>> -    else if (MDNode *IA = DV.getInlinedAt())
>>> -      Scope = LScopes.findInlinedScope(DebugLoc::getFromDILocation(IA));
>>> -    else
>>> -      Scope = LScopes.findLexicalScope(cast<MDNode>(DV->getOperand(1)));
>>> +    else if (MDNode *IA = DV.getInlinedAt()) {
>>> +      DebugLoc DL = DebugLoc::getFromDILocation(IA);
>>> +      Scope = LScopes.findInlinedScope(DebugLoc::get(
>>> +          DL.getLine(), DL.getCol(), DV.getContext(), IA));
>>> +    } else
>>> +      Scope = LScopes.findLexicalScope(DV.getContext());
>>>      // If variable scope is not found then skip this variable.
>>>      if (!Scope)
>>>        continue;
>>>
>>> Modified: llvm/trunk/lib/CodeGen/LexicalScopes.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/LexicalScopes.cpp?rev=208506&r1=208505&r2=208506&view=diff
>>>
>>> ==============================================================================
>>> --- llvm/trunk/lib/CodeGen/LexicalScopes.cpp (original)
>>> +++ llvm/trunk/lib/CodeGen/LexicalScopes.cpp Sun May 11 13:12:17 2014
>>> @@ -104,6 +104,14 @@ void LexicalScopes::extractLexicalScopes
>>>    }
>>>  }
>>>
>>> +LexicalScope *LexicalScopes::findInlinedScope(DebugLoc DL) {
>>> +  MDNode *Scope = nullptr;
>>> +  MDNode *IA = nullptr;
>>> +  DL.getScopeAndInlinedAt(Scope, IA, MF->getFunction()->getContext());
>>> +  auto I = InlinedLexicalScopeMap.find(std::make_pair(Scope, IA));
>>> +  return I != InlinedLexicalScopeMap.end() ? &I->second : nullptr;
>>> +}
>>> +
>>>  /// findLexicalScope - Find lexical scope, either regular or inlined, for
>>> the
>>>  /// given DebugLoc. Return NULL if not found.
>>>  LexicalScope *LexicalScopes::findLexicalScope(DebugLoc DL) {
>>> @@ -119,8 +127,10 @@ LexicalScope *LexicalScopes::findLexical
>>>    if (D.isLexicalBlockFile())
>>>      Scope = DILexicalBlockFile(Scope).getScope();
>>>
>>> -  if (IA)
>>> -    return
>>> InlinedLexicalScopeMap.lookup(DebugLoc::getFromDILocation(IA));
>>> +  if (IA) {
>>> +    auto I = InlinedLexicalScopeMap.find(std::make_pair(Scope, IA));
>>> +    return I != InlinedLexicalScopeMap.end() ? &I->second : nullptr;
>>> +  }
>>>    return findLexicalScope(Scope);
>>>  }
>>>
>>> @@ -170,21 +180,27 @@ LexicalScope *LexicalScopes::getOrCreate
>>>  }
>>>
>>>  /// getOrCreateInlinedScope - Find or create an inlined lexical scope.
>>> -LexicalScope *LexicalScopes::getOrCreateInlinedScope(MDNode *Scope,
>>> +LexicalScope *LexicalScopes::getOrCreateInlinedScope(MDNode *ScopeNode,
>>>                                                       MDNode *InlinedAt) {
>>> -  auto I = LexicalScopeMap.find(InlinedAt);
>>> -  if (I != LexicalScopeMap.end())
>>> +  std::pair<const MDNode*, const MDNode*> P(ScopeNode, InlinedAt);
>>> +  auto I = InlinedLexicalScopeMap.find(P);
>>> +  if (I != InlinedLexicalScopeMap.end())
>>>      return &I->second;
>>>
>>> -  DebugLoc InlinedLoc = DebugLoc::getFromDILocation(InlinedAt);
>>> +  LexicalScope *Parent;
>>> +  DILexicalBlock Scope(ScopeNode);
>>> +  if (Scope.isLexicalBlock()) {
>>> +    DILexicalBlock PB(Scope.getContext());
>>> +    Parent = getOrCreateInlinedScope(PB, InlinedAt);
>>> +  } else
>>> +    Parent =
>>> getOrCreateLexicalScope(DebugLoc::getFromDILocation(InlinedAt));
>>> +
>>>    // FIXME: Use forward_as_tuple instead of make_tuple, once MSVC2012
>>>    // compatibility is no longer required.
>>> -  I = LexicalScopeMap.emplace(
>>> -                          std::piecewise_construct,
>>> std::make_tuple(InlinedAt),
>>> -
>>> std::make_tuple(getOrCreateLexicalScope(InlinedLoc),
>>> -                                          DIDescriptor(Scope), InlinedAt,
>>> -                                          false)).first;
>>> -  InlinedLexicalScopeMap[InlinedLoc] = &I->second;
>>> +  I = InlinedLexicalScopeMap.emplace(std::piecewise_construct,
>>> +                                     std::make_tuple(P),
>>> +                                     std::make_tuple(Parent, Scope,
>>> InlinedAt,
>>> +                                                     false)).first;
>>>    return &I->second;
>>>  }
>>>
>>>
>>> Added: llvm/trunk/test/DebugInfo/inline-scopes.ll
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/inline-scopes.ll?rev=208506&view=auto
>>>
>>> ==============================================================================
>>> --- llvm/trunk/test/DebugInfo/inline-scopes.ll (added)
>>> +++ llvm/trunk/test/DebugInfo/inline-scopes.ll Sun May 11 13:12:17 2014
>>> @@ -0,0 +1,83 @@
>>> +; REQUIRES: object-emission
>>> +
>>> +; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump
>>> -debug-dump=info - | FileCheck %s
>>> +
>>> +; bool f1();
>>> +; inline __attribute__((always_inline))
>>> +; int f() {
>>> +;   if (bool b = f1())
>>> +;     return 1;
>>> +;   return 2;
>>> +; }
>>> +;
>>> +; int main() {
>>> +;   f();
>>> +; }
>>> +
>>> +; Ensure that lexical_blocks within inlined_subroutines are
>>> preserved/emitted.
>>> +; CHECK: DW_TAG_inlined_subroutine
>>> +; CHECK-NOT: DW_TAG
>>> +; CHECK: DW_TAG_lexical_block
>>> +; CHECK: DW_TAG_variable
>>> +
>>> +; Function Attrs: uwtable
>>> +define i32 @main() #0 {
>>> +entry:
>>> +  %retval.i = alloca i32, align 4
>>> +  %b.i = alloca i8, align 1
>>> +  call void @llvm.dbg.declare(metadata !{i8* %b.i}, metadata !13), !dbg
>>> !16
>>> +  %call.i = call zeroext i1 @_Z2f1v(), !dbg !16
>>> +  %frombool.i = zext i1 %call.i to i8, !dbg !16
>>> +  store i8 %frombool.i, i8* %b.i, align 1, !dbg !16
>>> +  %0 = load i8* %b.i, align 1, !dbg !16
>>> +  %tobool.i = trunc i8 %0 to i1, !dbg !16
>>> +  br i1 %tobool.i, label %if.then.i, label %if.end.i, !dbg !16
>>> +
>>> +if.then.i:                                        ; preds = %entry
>>> +  store i32 1, i32* %retval.i, !dbg !18
>>> +  br label %_Z1fv.exit, !dbg !18
>>> +
>>> +if.end.i:                                         ; preds = %entry
>>> +  store i32 2, i32* %retval.i, !dbg !19
>>> +  br label %_Z1fv.exit, !dbg !19
>>> +
>>> +_Z1fv.exit:                                       ; preds = %if.then.i,
>>> %if.end.i
>>> +  %1 = load i32* %retval.i, !dbg !20
>>> +  ret i32 0, !dbg !21
>>> +}
>>> +
>>> +; Function Attrs: nounwind readnone
>>> +declare void @llvm.dbg.declare(metadata, metadata) #1
>>> +
>>> +declare zeroext i1 @_Z2f1v() #2
>>> +
>>> +attributes #0 = { uwtable "less-precise-fpmad"="false"
>>> "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"
>>> "no-infs-fp-math"="false" "no-nans-fp-math"="false"
>>> "stack-protector-buffer-size"="8" "unsafe-fp-math"="false"
>>> "use-soft-float"="false" }
>>> +attributes #1 = { nounwind readnone }
>>> +attributes #2 = { "less-precise-fpmad"="false"
>>> "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"
>>> "no-infs-fp-math"="false" "no-nans-fp-math"="false"
>>> "stack-protector-buffer-size"="8" "unsafe-fp-math"="false"
>>> "use-soft-float"="false" }
>>> +
>>> +!llvm.dbg.cu = !{!0}
>>> +!llvm.module.flags = !{!10, !11}
>>> +!llvm.ident = !{!12}
>>> +
>>> +!0 = metadata !{i32 786449, metadata !1, i32 4, metadata !"clang version
>>> 3.5.0 ", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata
>>> !3, metadata !2, metadata !2, metadata !"", i32 1} ; [ DW_TAG_compile_unit ]
>>> [/tmp/dbginfo/inline-scopes.cpp] [DW_LANG_C_plus_plus]
>>> +!1 = metadata !{metadata !"inline-scopes.cpp", metadata !"/tmp/dbginfo"}
>>> +!2 = metadata !{}
>>> +!3 = metadata !{metadata !4, metadata !9}
>>> +!4 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"main",
>>> metadata !"main", metadata !"", i32 9, metadata !6, i1 false, i1 true, i32
>>> 0, i32 0, null, i32 256, i1 false, i32 ()* @main, null, null, metadata !2,
>>> i32 9} ; [ DW_TAG_subprogram ] [line 9] [def] [main]
>>> +!5 = metadata !{i32 786473, metadata !1}          ; [ DW_TAG_file_type ]
>>> [/tmp/dbginfo/inline-scopes.cpp]
>>> +!6 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64
>>> 0, i64 0, i32 0, null, metadata !7, i32 0, null, null, null} ; [
>>> DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
>>> +!7 = metadata !{metadata !8}
>>> +!8 = metadata !{i32 786468, null, null, metadata !"int", i32 0, i64 32,
>>> i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32,
>>> align 32, offset 0, enc DW_ATE_signed]
>>> +!9 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"f",
>>> metadata !"f", metadata !"_Z1fv", i32 3, metadata !6, i1 false, i1 true, i32
>>> 0, i32 0, null, i32 256, i1 false, null, null, null, metadata !2, i32 3} ; [
>>> DW_TAG_subprogram ] [line 3] [def] [f]
>>> +!10 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
>>> +!11 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
>>> +!12 = metadata !{metadata !"clang version 3.5.0 "}
>>> +!13 = metadata !{i32 786688, metadata !14, metadata !"b", metadata !5,
>>> i32 4, metadata !15, i32 0, i32 0} ; [ DW_TAG_auto_variable ] [b] [line 4]
>>> +!14 = metadata !{i32 786443, metadata !1, metadata !9, i32 4, i32 0, i32
>>> 0, i32 0} ; [ DW_TAG_lexical_block ] [/tmp/dbginfo/inline-scopes.cpp]
>>> +!15 = metadata !{i32 786468, null, null, metadata !"bool", i32 0, i64 8,
>>> i64 8, i64 0, i32 0, i32 2} ; [ DW_TAG_base_type ] [bool] [line 0, size 8,
>>> align 8, offset 0, enc DW_ATE_boolean]
>>> +!16 = metadata !{i32 4, i32 0, metadata !14, metadata !17}
>>> +!17 = metadata !{i32 10, i32 0, metadata !4, null}
>>> +!18 = metadata !{i32 5, i32 0, metadata !14, metadata !17}
>>> +!19 = metadata !{i32 6, i32 0, metadata !9, metadata !17}
>>> +!20 = metadata !{i32 7, i32 0, metadata !9, metadata !17}
>>> +!21 = metadata !{i32 11, i32 0, metadata !4, null}
>>>
>>>
>>> _______________________________________________
>>> llvm-commits mailing list
>>> llvm-commits at cs.uiuc.edu
>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>>
>>
>>
>>
>> --
>> Alexey Samsonov, Mountain View, CA



More information about the llvm-commits mailing list