<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_NEW "
title="NEW - jump-threading creating dead loop, causing LazyValueInfo to recurse infinitely"
href="https://bugs.llvm.org/show_bug.cgi?id=33357">33357</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>jump-threading creating dead loop, causing LazyValueInfo to recurse infinitely
</td>
</tr>
<tr>
<th>Product</th>
<td>new-bugs
</td>
</tr>
<tr>
<th>Version</th>
<td>unspecified
</td>
</tr>
<tr>
<th>Hardware</th>
<td>PC
</td>
</tr>
<tr>
<th>OS</th>
<td>Linux
</td>
</tr>
<tr>
<th>Status</th>
<td>NEW
</td>
</tr>
<tr>
<th>Severity</th>
<td>enhancement
</td>
</tr>
<tr>
<th>Priority</th>
<td>P
</td>
</tr>
<tr>
<th>Component</th>
<td>new bugs
</td>
</tr>
<tr>
<th>Assignee</th>
<td>unassignedbugs@nondot.org
</td>
</tr>
<tr>
<th>Reporter</th>
<td>mikael.holmen@ericsson.com
</td>
</tr>
<tr>
<th>CC</th>
<td>llvm-bugs@lists.llvm.org
</td>
</tr></table>
<p>
<div>
<pre>Created <span class=""><a href="attachment.cgi?id=18592" name="attach_18592" title="reproducer">attachment 18592</a> <a href="attachment.cgi?id=18592&action=edit" title="reproducer">[details]</a></span>
reproducer
I've stumbled on a case where LazyValueInfo recurses infinitely and crashes due
to a rewrite done by jump-threading.
Reproduce with the following bugpoint reduced reproducer:
opt -S -Os -O1 -o - reduced.ll
I have so far failed to reproduce it when only invoking opt with
-jump-threading but I suppose it should be possible.
Short version of the problem:
-----------------------------
Should LavyValueInfo be able to handle
%0 = and i1 %0, %tobool5
placed in a loop that is dead due to a jump-threading rewrite, or shouldn't
jump-threading call LazyValueInfo on instructions in the dead loop at all?
Details:
-----------------------------
(bugpoint-reduced) Input to jump-threading:
define void @f4(i32 %p1) local_unnamed_addr #1 {
entry:
%cmp = icmp eq i32 %p1, 0
br i1 undef, label %if.end16, label %for.cond.preheader
for.cond.preheader: ; preds = %entry
%conv12 = trunc i32 %p1 to i16
br label %for.cond
for.cond: ; preds = %if.end,
%if.then14, %for.cond.preheader
%f.0.in = phi i1 [ %cmp, %for.cond.preheader ], [ %0, %if.then14 ], [ %0,
%if.end ]
%call4 = tail call i16 @f1()
%tobool5 = icmp ne i16 %call4, 0
%0 = and i1 %f.0.in, %tobool5
br i1 %0, label %if.then11, label %if.end
if.then11: ; preds = %for.cond
store i16 %conv12, i16* @a, align 1
br label %if.end
if.end: ; preds = %if.then11,
%for.cond
br i1 %cmp, label %for.cond, label %if.then14
if.then14: ; preds = %if.end
store i16 1, i16* @b, align 1
br label %for.cond
if.end16: ; preds = %entry
ret void
}
Then
entry:
%cmp = icmp eq i32 %p1, 0
br i1 undef, label %if.end16, label %for.cond.preheader
is quickly replaced with
entry:
%cmp = icmp eq i32 %p1, 0
br label %if.end16
due to the original condition being undef:
In block 'entry' folding undef terminator: br i1 undef, label %if.end16,
label %for.cond.preheader
The function now looks like:
define void @f4(i32 %p1) local_unnamed_addr #1 {
entry:
%cmp = icmp eq i32 %p1, 0
br label %if.end16
for.cond.preheader: ; No predecessors!
%conv12 = trunc i32 %p1 to i16
br label %for.cond
for.cond: ; preds = %if.end,
%if.then14, %for.cond.preheader
%f.0.in = phi i1 [ %cmp, %for.cond.preheader ], [ %0, %if.then14 ], [ %0,
%if.end ]
%call4 = tail call i16 @f1()
%tobool5 = icmp ne i16 %call4, 0
%0 = and i1 %f.0.in, %tobool5
br i1 %0, label %if.then11, label %if.end
if.then11: ; preds = %for.cond
store i16 %conv12, i16* @a, align 1
br label %if.end
if.end: ; preds = %if.then11,
%for.cond
br i1 %cmp, label %for.cond, label %if.then14
if.then14: ; preds = %if.end
store i16 1, i16* @b, align 1
br label %for.cond
if.end16: ; preds = %entry
ret void
}
Note that for.cond.preheader is dead, no predecessors anymore.
Jump-threading therefore removes it:
JT: Deleting dead block 'for.cond.preheader' with terminator: br label
%for.cond
and the edge from for.cond.preheader to for.cond is also removed, leaving
for.cond like:
for.cond: ; preds = %if.end, %if.then14
%call4 = tail call i16 @f1()
%tobool5 = icmp ne i16 %call4, 0
%0 = and i1 %0, %tobool5
br i1 %0, label %if.then11, label %if.end
Especially notice the instruction:
%0 = and i1 %0, %tobool5
Operand 1 of the instruction was previously the result of a phi node, but since
we removed the dead block the phi could be simplified and removed, and we now
have an instruction referencing itself.
This instruction is later examined by LazyValueInfo and we end up in:
static LVILatticeVal
getValueFromCondition(Value *Val, Value *Cond, bool isTrueDest,
DenseMap<Value*, LVILatticeVal> &Visited) {
auto I = Visited.find(Cond);
if (I != Visited.end())
return I->second;
auto Result = getValueFromConditionImpl(Val, Cond, isTrueDest, Visited);
Visited[Cond] = Result;
return Result;
}
For an "and", getValueFromConditionImpl in turn will call getValueFromCondition
on both its operands. Since operand 1 of it is the "and" itself, we have
infinite recursion.
getValueFromCondition does have a visited list, but instructions are only
inserted in that after the instruction has been fully examined, so it doesn't
help us in this case.
Who's to blame?</pre>
</div>
</p>
<hr>
<span>You are receiving this mail because:</span>
<ul>
<li>You are on the CC list for the bug.</li>
</ul>
</body>
</html>