[PATCH] D11180: Fixed debug info generation for function static variables, typedef, and records

Amjad Aboud via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 11 04:39:26 PDT 2015


aaboud added a comment.

Thanks David for your comments. I tried to answer all of them.
Hopefully, the answers are clear.

Also, I agreed to fix some code according to your comments, but I prefer to hear your reply on the other comments before I upload a new patch.


================
Comment at: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp:340-341
@@ +339,4 @@
+    if (!includeMinimalInlineScopes()) {
+      auto LocalDeclNodeRangeForScope = DD->findLocalDeclNodesForScope(DS);
+      for (const auto &DI : LocalDeclNodeRangeForScope) {
+        if (auto *IE = dyn_cast<DIImportedEntity>(DI.second))
----------------
dblaikie wrote:
> Could probably just roll the local variable into the for loop header.
I will.
I just thought that "findLocalDeclNodesForScope()" function is not cheap, and was not sure that calling it in the "for" loop header is guaranteed to happen once.
If you think that it will not be a performance issue, I will move it to the "for" loop header.

================
Comment at: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp:342-343
@@ +341,4 @@
+      for (const auto &DI : LocalDeclNodeRangeForScope) {
+        if (auto *IE = dyn_cast<DIImportedEntity>(DI.second))
+          Children.push_back(constructImportedEntityDIE(IE));
+        else if (RegularScope) {
----------------
dblaikie wrote:
> Should we be adding imported entity DIEs in inlined or abstract definitions? Not sure... I suppose maybe.
> 
> What does it mean not to add the types and static variables to these cases? (if we inline away all uses of a function - won't we lose the local types and static variables & the user won't be able to print/interact with them?)
First of all, notice that we agreed to keep the current behavior of how types/static variables are handled.
Right now, we are emitting them only in the original function (the one that did not get inline, regardless if it has a code or not), the only difference is that we used to emit them always in the function scope, and this patch assure emitting them in the right lexical scope.
We will discuss how to improve that in a separate thread once we are done with this patch.

Imported entries however, are correctly supported (also with inline) and they will always be added to the lexical scope, no matter if it is inline, abstract or regular scope. Thus, there is no need to change that.
If you ask me, once we handle the abstract/concrete static variable, we will end up emitting them too in all kind of lexical scopes.

================
Comment at: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp:351-352
@@ +350,4 @@
+                getOrCreateGlobalVariableDIE(GV, /* SkipContext */ true));
+          }
+          else if (auto *RT = dyn_cast<DIType>(DI.second)) {
+            if (getDIE(RT))
----------------
dblaikie wrote:
> Formatting (run clang-format over your change?)
I will do before I upload a new patch.

================
Comment at: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp:353-355
@@ +352,5 @@
+          else if (auto *RT = dyn_cast<DIType>(DI.second)) {
+            if (getDIE(RT))
+              // Type was already created, nothing to do.
+              continue;
+            Children.push_back(getOrCreateTypeDIE(RT, /* SkipContext */ true));
----------------
dblaikie wrote:
> Doesn't "getOrCreateTypeDIE" already do the getDIE check? (that would be implied by the "get" part of "get or create" in the name, I would hope)
True, however, if the getDIE in the getOrCreateTypeDIE returns an entry we will not know that and will end up adding this entry twice to the parent scope. This could happen, because types might be created bottom-up and added to the lexical block before handling the lexical scope itself (top-down). This is not the case for static variables, they will never be created bottom-up, that is why we have only an assertion there.
This is why we need to check "getDIE" for types separately before calling "getOrCreateTypeDIE()" function.

If we can differ creating types till all lexical scopes are created, this will prevent the above case for types, but it is not trivial thing to do.

Another thing, which I thought to discuss later with the abstract/concrete static variables, is to emit the type in all kind of lexical scope (inline, abstract, regular). However, we need to discuss it separately as type entry might not be small like the imported entry.

================
Comment at: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp:377-389
@@ -353,4 +376,15 @@
     }
-    ScopeDIE = constructLexicalScopeDIE(Scope);
-    assert(ScopeDIE && "Scope DIE should not be null.");
+    // Lexical block of non-inline function is stored in the lexical scope map.
+    if (RegularScope)
+      ScopeDIE = getDIE(DS);
+    if (ScopeDIE) {
+      // Mapped lexical scope should be already attached to its parent scope.
+      assert(ScopeDIE->getParent() && "Scope DIE was not attached to parent.");
+      AddScopeDieToFinalChildren = false;
+    } else {
+      ScopeDIE = constructLexicalScopeDIE(Scope);
+      assert(ScopeDIE && "Scope DIE should not be null.");
+      if (RegularScope)
+        insertDIE(Scope->getScopeNode(), ScopeDIE);
+    }
   }
----------------
dblaikie wrote:
> I'm somewhat confused about what this code is about/for. Could you help explain it further?
Let's start from the lines that was not changed (385-386), these are clear, we are creating a new lexical scope.
And if we know that it is a regular lexical scope, we want to add it to the scope map (387-388).

However, because now we are adding regular lexical scope to the map, we want to make sure we do not have this lexical block already created.
It could be created already in case we created a type that belongs to this lexical scope (or to one of its children scopes), as I said before types are not differed till all lexical block are created!
So, we want to check in the map for the lexical scope (379) but only for regular scope (378).
And if we find the lexical scope in the map, this means that it was already added to its parent scope (380-383), so we mark that flag to prevent adding it twice to the parent scope (396-397).

When we discuss the abstract/concrete static variables and differing type creation, we might find a way to prevent this.
But for now, we will need this code.

================
Comment at: lib/CodeGen/AsmPrinter/DwarfUnit.cpp:742-743
@@ +741,4 @@
+  if (!ContextDIE && !SkipContext) {
+    // Can reach this point when the parent scope is a lexical block.
+    // Which was not created yet, or that does not contain code, create it.
+    assert(isa<DILexicalBlockBase>(Context) && "Expected lexical block scope");
----------------
dblaikie wrote:
> When do we do this while not skipping context?
> 
> (also - creating a lexical block that doesn't contain any code may be rather useless - the debugger will never be at a location inside that scope, so it may be difficult to access the variables, etc, there if the debugger implements correct scoping rules... - but I'm not sure. What do other compilers do here?)
We do that because for some reason LLVM decide to emit debug info for functions that has no code (see the test PR24008.ll below).
even though the static member function "Run()" has no code and even when it was inline there is no instructions related to it, LLVM decided at endModule to create entry for this function, but it is a method, so it end up creating the class Bar type, which happens to be defined inside a lexical block that has no code!

If it was not a type, I would agree with you and say we should not be doing that, but type entries are needed to complete other entries, and we should emit them even if the parent scope of these types has no code.

GCC does that too, in his own way with his own gaps (if you ask me)...I still did not see a compiler that does this perfectly, hopefully we can eventually make LLVM do that the best.

================
Comment at: test/DebugInfo/X86/lexical-block-inline.ll:20
@@ +19,3 @@
+;; This test was generated by running following command:
+;; clang -cc1 -O2 -g -emit-llvm foo.cpp 
+;; Where foo.cpp
----------------
dblaikie wrote:
> Rather than using -O2 which changes a bunch of other stuff in the debug info too, it would be preferable to use no optimizations and add __attribute__((alwaysinline)) (or is it forceinline? I always forget the name) to the function that must be inlined.
I am not sure if this will work.
But I can run clang with -O0, then run inline/always-inline pass using opt if this sounds better to get less noise from other passes.
I will then comment that in the test description.


Repository:
  rL LLVM

http://reviews.llvm.org/D11180





More information about the llvm-commits mailing list