<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] Register Coalescing makes variable assignments appear too early"
href="https://bugs.llvm.org/show_bug.cgi?id=40010">40010</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>[DebugInfo@O2] Register Coalescing makes variable assignments appear too early
</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>chackz0x12@gmail.com, dblaikie@gmail.com, greg.bedwell@sony.com, international.phantom@gmail.com, llvm-bugs@lists.llvm.org, paul.robinson@am.sony.com
</td>
</tr>
<tr>
<th>Blocks</th>
<td>38754
</td>
</tr></table>
<p>
<div>
<pre>With trunk r348754 and the code below, the register coalescing pass combines
the "foo" and "bar" SSA variables into one virtual register, but points the
corresponding DBG_VALUE at the wrong value. Command line is "llc
-start-after=codegenprepare -stop-after=simple-register-coalescing", and the
heavily contrived code:
-------->8--------
declare void @llvm.dbg.value(metadata, metadata, metadata)
define i32 @test(i32* %pin) {
entry:
br label %start
start:
%foo = phi i32 [0, %entry], [%bar, %start]
%baz = load i32, i32* %pin, align 1
%qux = xor i32 %baz, 1234
%bar = add i32 %qux, %foo
call void @llvm.dbg.value(metadata i32 %foo, metadata !1, metadata
!DIExpression()), !dbg !6
%cmp = icmp ugt i32 %bar, 1000000
br i1 %cmp, label %leave, label %start
leave:
ret i32 %bar
}
!llvm.module.flags = !{!4}
!llvm.dbg.cu = !{!2}
!1 = !DILocalVariable(name: "bees", scope: !5, type: null)
!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer:
"beards", isOptimized: true, runtimeVersion: 4, emissionKind: FullDebug)
!3 = !DIFile(filename: "bees.cpp", directory: "")
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = distinct !DISubprogram(name: "nope", scope: !2, file: !3, line: 1, unit:
!2)
!6 = !DILocation(line: 0, scope: !5)
--------8<--------
The loop here is loading some integers, xoring and accumulating them, then
breaking out after a large value is reached. %foo is the phi for the
accumulator, and %bar the value for the next iteration. The dbg.value points a
DILocalVariable at %foo half way through the loop body.
Register coalescing correctly spots that %foo and %bar can share the same
register (being the accumulator), and combines them, transforming this X86:
-------->8--------
%0:gr32 = COPY %7:gr32
%8:gr32 = MOV32rm %2:gr64, 1, $noreg, 0, $noreg :: (load 4 from %ir.pin, align
1)
%5:gr32 = COPY %8:gr32
%5:gr32 = XOR32rr %5:gr32(tied-def 0), %4:gr32, implicit-def dead $eflags
%1:gr32 = COPY %0:gr32
%1:gr32 = ADD32rr %1:gr32(tied-def 0), %5:gr32, implicit-def dead $eflags
DBG_VALUE %0:gr32, $noreg, !"bees", !DIExpression(), debug-location !5;
bees.cpp:0 line no:0
CMP32ri %1:gr32, 1000001, implicit-def $eflags
%7:gr32 = COPY %1:gr32
JB_1 %bb.1, implicit killed $eflags
JMP_1 %bb.2
--------8<--------
Into:
-------->8--------
%5:gr32 = MOV32rm %2, 1, $noreg, 0, $noreg :: (load 4 from %ir.pin...)
%5:gr32 = XOR32rr %5, %4, implicit-def dead $eflags
%7:gr32 = ADD32rr %7, %5, implicit-def dead $eflags
DBG_VALUE %7, $noreg, !3, !DIExpression(), debug-location !5
CMP32ri %7, 1000001, implicit-def $eflags
JB_1 %bb.1, implicit killed $eflags
JMP_1 %bb.2
--------8<--------
Note that the DBG_VALUE now points at what was %bar, the next accumulator value
of the loop, where previously it referred to the current value in %foo. A
developer would expect the DBG_VALUE to have the value of %foo for the
remainder of the loop, but due to this transform, they get the value of %bar.
The coalescing is a totally valid optimisation but leads to the value of %foo
being dead for the second half of the loop body. IMHO the correct action of
register coalescing would have been to mark the DBG_VALUE as undef: once %0 and
%7 are coalesced and %7 modified, there's no way to recover the original
valuation of %0.
While this is currently observable from vanilla trunk with the given command
line, codegenprepare messes with the location of the dbg.value, so this isn't a
fault that one would observe from a frontend I believe.
Given that the two registers have to be connected by a COPY, this isn't going
to lead to a completely unexpected value appearing to the debugger in a
variable. However, making values appear before their time is reporting a false
state to the developer.</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>
</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>