Issue 97600
Summary [LICM] Miscompilation caused by wrong AA result
Labels miscompilation, loopoptim, llvm:optimizations, TBAA, llvm:analysis
Assignees
Reporter dtcxzyw
    Reproducer: https://godbolt.org/z/Y1vvbndf8
```
@c = dso_local global i32 0, align 4
@d = dso_local local_unnamed_addr global ptr @c, align 8

define i32 @main() {
entry:
  br label %for.cond

for.cond: ; preds = %f.exit.split, %entry
  %b.0 = phi i32 [ 0, %entry ], [ %inc6, %f.exit.split ]
  %cmp = icmp ult i32 %b.0, 2
  br i1 %cmp, label %for.cond1.preheader, label %for.cond.cleanup

for.cond1.preheader:                              ; preds = %for.cond
  br label %for.cond1

for.cond.cleanup: ; preds = %for.cond
  %0 = load i32, ptr @c, align 4, !tbaa !13
  ret i32 %0

for.cond1: ; preds = %for.cond1, %for.cond1.preheader
  %i.0 = phi i32 [ %inc, %for.cond1 ], [ 0, %for.cond1.preheader ]
  %cmp2 = icmp ult i32 %i.0, 2
  %inc = add nuw nsw i32 %i.0, 1
  br i1 %cmp2, label %for.cond1, label %for.body.i.preheader, !llvm.loop !17

for.body.i.preheader:                             ; preds = %for.cond1
  %cmp2.lcssa = phi i1 [ %cmp2, %for.cond1 ]
  %1 = xor i1 %cmp2.lcssa, true
  %2 = bitcast i1 %1 to <1 x i1>
  %3 = call <1 x ptr> @llvm.masked.load.v1p0.p0(ptr @d, i32 8, <1 x i1> %2, <1 x ptr> poison), !tbaa !9
  %4 = bitcast <1 x ptr> %3 to ptr
  store i32 0, ptr @c, align 4, !tbaa !13
  %5 = load i32, ptr %4, align 4, !tbaa !13
 %tobool1.not.i = icmp ne i32 %5, 0
  %tobool1.not.i.fr = freeze i1 %tobool1.not.i
  br i1 %tobool1.not.i.fr, label %f.exit.split, label %for.body.i.preheader.split

for.body.i.preheader.split: ; preds = %for.body.i.preheader
  br label %for.body.i

for.body.i:                                       ; preds = %for.body.i.preheader.split, %for.body.i
  %n.04.i = phi i8 [ %add.i, %for.body.i ], [ -66, %for.body.i.preheader.split ]
  %add.i = add nsw i8 %n.04.i, 1
  %tobool.not.i = icmp eq i8 %add.i, 0
  br i1 %tobool.not.i, label %f.exit, label %for.body.i, !llvm.loop !15

f.exit:                                           ; preds = %for.body.i
  br label %f.exit.split

f.exit.split: ; preds = %for.body.i.preheader, %f.exit
  store i32 7, ptr %4, align 4, !tbaa !13
  %inc6 = add nuw nsw i32 %b.0, 1
  br label %for.cond, !llvm.loop !18
}

!9 = !{!10, !10, i64 0}
!10 = !{!"any pointer", !11, i64 0}
!11 = !{!"omnipotent char", !12, i64 0}
!12 = !{!"Simple C/C++ TBAA"}
!13 = !{!14, !14, i64 0}
!14 = !{!"int", !11, i64 0}
!15 = distinct !{!15, !16}
!16 = !{!"llvm.loop.mustprogress"}
!17 = distinct !{!17, !16}
!18 = distinct !{!18, !16}
```
After LICM:
```
source_filename = "/app/example.ll"

define i32 @main() {
entry:
  br label %for.cond

for.cond:                                         ; preds = %f.exit.split, %entry
  %0 = phi i32 [ poison, %entry ], [ 0, %f.exit.split ]
  %b.0 = phi i32 [ 0, %entry ], [ %inc6, %f.exit.split ]
  %cmp = icmp ult i32 %b.0, 2
  br i1 %cmp, label %for.cond1.preheader, label %for.cond.cleanup

for.cond1.preheader: ; preds = %for.cond
  br label %for.cond1

for.cond.cleanup:                                 ; preds = %for.cond
  %.lcssa = phi i32 [ %0, %for.cond ]
  store i32 %.lcssa, ptr @c, align 4, !tbaa !0
  %1 = load i32, ptr @c, align 4, !tbaa !0
 ret i32 %1

for.cond1:                                        ; preds = %for.cond1, %for.cond1.preheader
  %i.0 = phi i32 [ %inc, %for.cond1 ], [ 0, %for.cond1.preheader ]
  %cmp2 = icmp ult i32 %i.0, 2
  %inc = add nuw nsw i32 %i.0, 1
  br i1 %cmp2, label %for.cond1, label %for.body.i.preheader, !llvm.loop !4

for.body.i.preheader: ; preds = %for.cond1
  %cmp2.lcssa = phi i1 [ %cmp2, %for.cond1 ]
  %2 = xor i1 %cmp2.lcssa, true
  %3 = bitcast i1 %2 to <1 x i1>
  %4 = call <1 x ptr> @llvm.masked.load.v1p0.p0(ptr @d, i32 8, <1 x i1> %3, <1 x ptr> poison), !tbaa !6
  %5 = bitcast <1 x ptr> %4 to ptr
 %6 = load i32, ptr %5, align 4, !tbaa !0
  %tobool1.not.i = icmp ne i32 %6, 0
  %tobool1.not.i.fr = freeze i1 %tobool1.not.i
  br i1 %tobool1.not.i.fr, label %f.exit.split, label %for.body.i.preheader.split

for.body.i.preheader.split: ; preds = %for.body.i.preheader
  br label %for.body.i

for.body.i:                                       ; preds = %for.body.i, %for.body.i.preheader.split
  %n.04.i = phi i8 [ %add.i, %for.body.i ], [ -66, %for.body.i.preheader.split ]
  %add.i = add nsw i8 %n.04.i, 1
  %tobool.not.i = icmp eq i8 %add.i, 0
  br i1 %tobool.not.i, label %f.exit, label %for.body.i, !llvm.loop !8

f.exit: ; preds = %for.body.i
  br label %f.exit.split

f.exit.split:                                     ; preds = %f.exit, %for.body.i.preheader
  store i32 7, ptr %5, align 4, !tbaa !0
  %inc6 = add nuw nsw i32 %b.0, 1
  br label %for.cond, !llvm.loop !9
}

declare <1 x ptr> @llvm.masked.load.v1p0.p0(ptr nocapture, i32 immarg, <1 x i1>, <1 x ptr>) #0

attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: read) }

!0 = !{!1, !1, i64 0}
!1 = !{!"int", !2, i64 0}
!2 = !{!"omnipotent char", !3, i64 0}
!3 = !{!"Simple C/C++ TBAA"}
!4 = distinct !{!4, !5}
!5 = !{!"llvm.loop.mustprogress"}
!6 = !{!7, !7, i64 0}
!7 = !{!"any pointer", !2, i64 0}
!8 = distinct !{!8, !5}
!9 = distinct !{!9, !5}
```
```
> lli test.ll
> echo $?
7
> bin/opt -passes=licm test.ll -S -o out.ll
> lli out.ll
> echo $?
0
```
`store i32 7, ptr %5, align 4, !tbaa !0` may write something to `@c`. So this transform is incorrect.

Related patch: https://github.com/llvm/llvm-project/pull/96878
Original C code (needs x86 +cf or riscv +zicldst):
```
#include "csmith.h"
uint32_t c = 0;
int32_t *d = &c;
void f(int32_t *o) {
  uint8_t n;
  for (n = 190; n; n += 1) {
    *o = 0;
    if (*d)
      break;
 }
}
int main() {
  for (int b = 0; b <= 1; b++) {
    uint64_t j[2];
    int i;
    for (i = 0; i < 2; i++)
      j[i] = 1;
 f(&c);
    safe_add_func_int32_t_s_s(0, j[1]);
    *d = 7;
  }
 printf("%d\n", c);
  return 0;
}
```

cc @nikic @fhahn @KanRobert 

_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to