| 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