<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 - [InstCombine] Incorrect folding of LShr into select instruction"
href="https://bugs.llvm.org/show_bug.cgi?id=48353">48353</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>[InstCombine] Incorrect folding of LShr into select instruction
</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>NEW
</td>
</tr>
<tr>
<th>Severity</th>
<td>enhancement
</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>congzhecao@gmail.com
</td>
</tr>
<tr>
<th>CC</th>
<td>llvm-bugs@lists.llvm.org
</td>
</tr></table>
<p>
<div>
<pre>The IR that exposes this bug is as follows.
; ModuleID = 'test.c'
@m = common dso_local local_unnamed_addr global i32 0, align 4
define dso_local i32 @test() local_unnamed_addr #1 {
entry:
call fastcc void @foo(i32 51)
ret i32 0
}
define internal fastcc void @foo(i32 %aj) {
entry:
%cmp.i = icmp sgt i32 %aj, 1
%shr.i = select i1 %cmp.i, i32 0, i32 %aj
%cond.i1 = lshr i32 3, %shr.i
%conv.i = trunc i32 %cond.i1 to i8
%0 = and i8 %conv.i, 1
%cmp4 = icmp ugt i8 %0, 0
%conv5 = zext i1 %cmp4 to i32
store i32 %conv5, i32* @m
ret void
}
Note that at compile time we know the argument of foo() is %aj = 51 thus
"%shr.i = select i1 %cmp.i, i32 0, i32 %aj" will result in 0 and hence LShr
instruction that follows is correct, not resulting in a poison value.
When running "opt -instcombine test.ll -S", the following IR is generated.
Specifically, "%aj.op = lshr i32 3, %aj" is generated which result in a poison
value since %aj is actually greater than 32.
@m = common dso_local local_unnamed_addr global i32 0, align 4
define dso_local i32 @test() local_unnamed_addr #1 {
entry:
call fastcc void @foo(i32 51)
ret i32 0
}
define internal fastcc void @o(i32 %aj) {
entry:
%cmp.i = icmp sgt i32 %aj, 1
%aj.op = lshr i32 3, %aj
%.op2 = and i32 %aj.op, 1
%cmp.i3 = zext i1 %cmp.i to i32
%conv55 = or i32 %.op2, %cmp.i3
store i32 %conv55, i32* @m, align 4
ret void
}
************************
The cause is that during InstCombine, we fold
%shr.i = select i1 %cmp.i, i32 0, i32 %aj
%cond.i1 = lshr i32 3, %shr.i
into
%aj.op = lshr i32 3, %aj
%cond.i1 = select i1 %cmp.i, i32 3, i32 %aj.op,
thus generating the incorrect LShr instruction "%aj.op = lshr i32 3, %aj".
****************************
Our proposed fix:
In function InstCombiner::FoldOpIntoSelect() from
Transforms/InstCombine/InstructionCombining.cpp, add the following check such
that we only fold LShr into select when both the true value and the false value
are known to be constants.
// If op is a LShr instruction, we can only fold into select when both TV
// and FV are known to be constants, otherwise they may be evaluated to be
// greater than the width of the first operand of LShr, resulting in for
// example:
// LShr i32 X Y where Y > 32,
// which is not suppose to be generated.
if (Op.getOpcode() == Instruction::LShr &&
!(isa<Constant>(TV) && isa<Constant>(FV))) {
return nullptr;
}</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>