[llvm-bugs] [Bug 49688] New: WRONG code CFGOpt? InstCombine?

via llvm-bugs llvm-bugs at lists.llvm.org
Mon Mar 22 16:01:22 PDT 2021


https://bugs.llvm.org/show_bug.cgi?id=49688

            Bug ID: 49688
           Summary: WRONG code CFGOpt? InstCombine?
           Product: libraries
           Version: trunk
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P
         Component: Scalar Optimizations
          Assignee: unassignedbugs at nondot.org
          Reporter: paulsson at linux.vnet.ibm.com
                CC: llvm-bugs at lists.llvm.org

Created attachment 24682
  --> https://bugs.llvm.org/attachment.cgi?id=24682&action=edit
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
}

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20210322/fe9d67c7/attachment-0001.html>


More information about the llvm-bugs mailing list