<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 - WRONG code CFGOpt? InstCombine?"
href="https://bugs.llvm.org/show_bug.cgi?id=49688">49688</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>WRONG code CFGOpt? InstCombine?
</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>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>paulsson@linux.vnet.ibm.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=24682" name="attach_24682" title="reduced testcase">attachment 24682</a> <a href="attachment.cgi?id=24682&action=edit" title="reduced testcase">[details]</a></span>
reduced testcase
This program (wrong0.i):
static int *a;
int b, d;
int *c = &b;
int main() {
int e[3] = {2, 1, -2139220656};
a = &e[0];
d = (e[2] < 0) || (e[2] > (7 >> e[2]));
*c = d;
printf("%d\n", b);
}
I beleive the right-shift with a known negative value is undefined, but since
the first expression is always true, the program as a whole is still
well-defined, or?
Since e[2] is always less than 0, I would expect the second expression (after
the '||') to never be evaluated. However, SimplifyCFGPass does not understand
that the first expression is always true and so merges them so that they are
always both executed. I wonder why this is allowed...?
%1 = load i32, i32* %arrayidx1, align 4, !tbaa !6
%cmp = icmp slt i32 %1, 0
%shr = ashr i32 7, %1
%cmp4 = icmp sgt i32 %1, %shr
%2 = select i1 %cmp, i1 true, i1 %cmp4
Then InstCombine decides to remove the first check against less than zero:
%arrayidx1 = getelementptr inbounds [3 x i32], [3 x i32]* %e, i64 0, i64 2
%1 = load i32, i32* %arrayidx1, align 4, !tbaa !6
%shr = lshr i32 7, %1
%2 = icmp ugt i32 %1, %shr
%lor.ext = zext i1 %2 to i32
store i32 %lor.ext, i32* @d, align 4, !tbaa !6
So it seems that the user has written a well-defined program, but the compiler
has failed to realize this through the known constants.
clang -march=arch13 -O1 wrong0.i -o a.out -w; ./a.out
1
clang -march=arch13 -O2 wrong0.i -o a.out -w; ./a.out
0
clang -march=arch13 -O2 wrong0.i -o a.out -mllvm -enable-gvn-memdep=false -w;
./a.out
1
clang -march=arch13 -O2 wrong0.i -o a.out -mllvm -memssa-check-limit=0 -w;
./a.out
0
The store of '0' to @d is then later produced by GVN:
*** IR Dump After MergedLoadStoreMotionPass ***
; Function Attrs: nofree nounwind
define dso_local signext i32 @main() local_unnamed_addr #0 {
entry:
%e = alloca [3 x i32], align 4
%0 = bitcast [3 x i32]* %e to i8*
call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %0) #2
call void @llvm.memcpy.p0i8.p0i8.i64(i8* noundef nonnull align 4
dereferenceable(12) %0, i8* noundef nonnull align 4 dereferenceable(12) bitcast
([3 x i32]* @__const.main.e to i8*), i64 12, i1 false)
%arrayidx = getelementptr inbounds [3 x i32], [3 x i32]* %e, i64 0, i64 0
store i32* %arrayidx, i32** @a, align 8, !tbaa !2
%arrayidx1 = getelementptr inbounds [3 x i32], [3 x i32]* %e, i64 0, i64 2
%1 = load i32, i32* %arrayidx1, align 4, !tbaa !6
%shr = lshr i32 7, %1
%2 = icmp ugt i32 %1, %shr
%lor.ext = zext i1 %2 to i32
store i32 %lor.ext, i32* @d, align 4, !tbaa !6
%3 = load i32*, i32** @c, align 8, !tbaa !2
store i32 %lor.ext, i32* %3, align 4, !tbaa !6
%4 = load i32, i32* @b, align 4, !tbaa !6
%call = call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1)
getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i32 signext
%4)
call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %0) #2
ret i32 0
}
*** IR Dump After GVN ***
; Function Attrs: nofree nounwind
define dso_local signext i32 @main() local_unnamed_addr #0 {
entry:
%e = alloca [3 x i32], align 4
%0 = bitcast [3 x i32]* %e to i8*
call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %0) #2
call void @llvm.memcpy.p0i8.p0i8.i64(i8* noundef nonnull align 4
dereferenceable(12) %0, i8* noundef nonnull align 4 dereferenceable(12) bitcast
([3 x i32]* @__const.main.e to i8*), i64 12, i1 false)
%arrayidx = getelementptr inbounds [3 x i32], [3 x i32]* %e, i64 0, i64 0
store i32* %arrayidx, i32** @a, align 8, !tbaa !2
%arrayidx1 = getelementptr inbounds [3 x i32], [3 x i32]* %e, i64 0, i64 2
store i32 0, i32* @d, align 4, !tbaa !6
%1 = load i32*, i32** @c, align 8, !tbaa !2
store i32 0, i32* %1, align 4, !tbaa !6
%2 = load i32, i32* @b, align 4, !tbaa !6
%call = call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1)
getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i32 signext
%2)
call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %0) #2
ret i32 0
}</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>