<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_CONFIRMED "
   title="CONFIRMED - [DebugInfo@O2][Dexter] Pointer variable location can be dropped despite being live"
   href="https://bugs.llvm.org/show_bug.cgi?id=39726">39726</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>[DebugInfo@O2][Dexter] Pointer variable location can be dropped despite being live
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>libraries
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>CONFIRMED
          </td>
        </tr>

        <tr>
          <th>Keywords</th>
          <td>wrong-debug
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>Scalar Optimizations
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>jeremy.morse.llvm@gmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>carlos.alberto.enciso@gmail.com, chackz0x12@gmail.com, greg.bedwell@sony.com, llvm-bugs@lists.llvm.org, paul.robinson@am.sony.com
          </td>
        </tr>

        <tr>
          <th>Blocks</th>
          <td>38754, 38768
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Spinning this out of <a class="bz_bug_link 
          bz_status_CONFIRMED "
   title="CONFIRMED - [DebugInfo@O2][Dexter] Illegal value appears in variable when conditional blocks folded"
   href="show_bug.cgi?id=38754">bug 38754</a>, this bug is about an unfortunate dropping of a
dbg.value when it's located in the "correct" place. In the code at the bottom
of this bug, the "qux" variable in "main" can have its location dropped,
preventing the developer seeing anything useful in the function. I've been
using llvm/clang r346686 with options "-O2 -g". The problem described below
only happens if you disable CodeGenPrepare's placeDbgValues method (which I'm
trying to eliminate). Alternately you can replicate this behaviour with other
clangs by:

  clang++ test.cpp -O2 -g -mllvm -stop-after=codegenprepare -c -o out.mir
  [Edit out.mir moving dbg.value for 'qux' to occur after inlined 
   constructor completes, after the merged store to the 'fgasdf' field]
  llc -start-after=codegenprepare out.mir -o out.s
  clang++ out.s -o a.out

In plain clang from trunk, in the code below the dbg.value for 'qux' is moved
to immediately after the call to 'new': it's emitted as a DBG_VALUE in the
first BB, and its lifetime extended across the body of the whole function.

Without placeDbgValues, however, the dbg.value for 'qux' stays in its original
location after the constructor call, and due to some curious behaviours the SSA
register it's applied to is never used. The DBG_VALUE for qux is never emitted
because it appears a dead value if it's left in the "correct" location.

The reason why this happens is easy to explain (see below), there are sane
reasons why. This bug however is about the fact that the combined behaviours
leads to an (IMHO) unacceptable outcome, where a pointer variable of
significant interest to the developer (and which is in a live register the
~whole function) has debug info dropped.

Here's the IR for main (with correctly placed dbg.value) with comments where
I've omitted code:
  ; Call to allocate "qux"
  %3 = tail call i8* @_Znwm(i64 4) #7
  ; The constructor for class foo is inlined, including a conditional
  ; jump between BBs because of the if-condition, finishing with a write
  ; to fgasdf:
  %13 = bitcast i8* %3 to %class.foo*
  %14 = bitcast i8* %3 to i32*
  store i32 %12, i32* %14, align 4
  ; The constructor complete, we make the dbg.value call for "qux"
  call void @llvm.dbg.value(metadata i8* %3, metadata !28, [blah])
  ; The body for 'spoons' and the printf call are performed using SSA
  ; registers and no further loads/stores, finally:
  tail call void @_ZN3foo9loldeleteEPS_(%class.foo* nonnull %13)
  ret i32 0

The dbg.value is applied to an SSA variable of type "i8*", but everything else
after that instruction either doesn't touch the allocated object, or uses the
pointer SSA-reg that's been cast to "%class.foo*", i.e. %13. In combination
with the fact that the dbg.value is no longer in the basic block where %3 is
defined, SelectionDAG then drops the DBG_VALUE. This scenario is avoided if we
were to:
 * Not having a jump-forcing conditional in the constructor
 * Not inline anything
 * Call delete directly rather then calling a static method to delete
   (the delete operation appears to consume an i8*)

To summarise, if we leave the dbg.value for "qux" in the code below in the
correct location (after the constructor), then by accident we end up dropping
it. It seems obvious that there should be a way around this, either by
something looking further through casts, or the dbg.value being applied to the
"correctly" (TM) typed SSA-reg-pointer. I think this might be a fairly general
problem though, of the form:
 * Lots of code inlined into a function
 * All the inlined code GEPs or casts pointers to various elements of
   data structures
 * After a certain point in the function, all the base pointers to the
   relevant data structures appear to go out of liveness, not because 
   they're dead but because subsequent code refers to the memory with a
   different type.

(This is important because placeDbgValues must die IMHO, so this bug will
eventually present to an end user). The code is below; I've scattered noinline
to emulate function calls that don't get inlined while keeping it
single-source.

--------8<--------
#include <stdio.h>

__attribute__((noinline)) int rand() {
  volatile int foo = 4;
  return foo;
}

class foo {
public:
  int fgasdf;
  foo(int i) {
    if (rand() == 4)
      fgasdf = rand() * i;
    else
      fgasdf = rand() / i;
  }

  int spoons(int u) {
    return fgasdf * u + rand();
  }

  __attribute__((noinline)) static void loldelete(foo *go) {
    delete go;
  }
};

int main(int argc, char **argv) {
  foo *qux = new foo(argc);
  int bees = qux->spoons(argc);
  printf("%d\n", bees);
  foo::loldelete(qux);
  return 0;
}
-------->8--------</pre>
        </div>
      </p>

        <div id="referenced">
          <hr style="border: 1px dashed #969696">
          <b>Referenced Bugs:</b>
          <ul>
              <li>
                [<a class="bz_bug_link 
          bz_status_CONFIRMED "
   title="CONFIRMED - [DebugInfo@O2][Dexter] Illegal value appears in variable when conditional blocks folded"
   href="https://bugs.llvm.org/show_bug.cgi?id=38754">Bug 38754</a>] [DebugInfo@O2][Dexter] Illegal value appears in variable when conditional blocks folded
              </li>
              <li>
                [<a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - [meta][DebugInfo] Umbrella bug for poor debug experiences"
   href="https://bugs.llvm.org/show_bug.cgi?id=38768">Bug 38768</a>] [meta][DebugInfo] Umbrella bug for poor debug experiences
              </li>
          </ul>
        </div>
        <br>

      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>