[opt] Miscompilation in `loop-flatten` due to improper invalidation of SCEV Analysis
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
test.ll
```llvm
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
define void @zext_i8(i8 %N, ptr %A) {
entry:
%cmp20.not = icmp eq i8 %N, 0
br i1 %cmp20.not, label %common.ret, label %for.cond1.preheader.us
for.cond1.preheader.us: ; preds = %for.cond1.for.inc7_crit_edge.us, %entry
%i.021.us = phi i8 [ %inc8.us, %for.cond1.for.inc7_crit_edge.us ], [ 0, %entry ]
br label %for.body3.us
for.body3.us: ; preds = %for.body3.us, %for.cond1.preheader.us
%j.019.us = phi i8 [ 0, %for.cond1.preheader.us ], [ %inc.us, %for.body3.us ]
%mul.us = mul i8 %i.021.us, %N
%add.us = add i8 %j.019.us, %mul.us
%idxprom.us = zext i8 %add.us to i64
%arrayidx.us = getelementptr [2 x i8], ptr %A, i64 %idxprom.us
store i16 1, ptr %arrayidx.us, align 2
%inc.us = add i8 %j.019.us, 1
%cmp2.us = icmp ult i8 %inc.us, %N
br i1 %cmp2.us, label %for.body3.us, label %for.cond1.for.inc7_crit_edge.us
for.cond1.for.inc7_crit_edge.us: ; preds = %for.body3.us
%inc8.us = add i8 %i.021.us, 1
%cmp.us = icmp ult i8 %inc8.us, %N
br i1 %cmp.us, label %for.cond1.preheader.us, label %common.ret
common.ret: ; preds = %for.cond1.for.inc7_crit_edge.us, %entry
ret void
}
```
Reproduce:
```
opt -passes="module(cgscc(function(loop(loop-flatten)))),module(cgscc(function(lower-expect))),function(loop-vectorize)" \
--force-vector-width=4 --force-vector-interleave=3 test.ll -S -o \
stale.ll
opt -passes="module(cgscc(function(loop(loop-flatten)))),module(cgscc(function(invalidate))),module(cgscc(function(lower-expect))),function(loop-vectorize)" \
--force-vector-width=4 --force-vector-interleave=3 test.ll -S -o \
fresh.ll
diff fresh.ll stale.ll
```
```diff
16c16
< br i1 %min.iters.check, label %scalar.ph, label %vector.scevcheck
---
> br i1 %min.iters.check, label %scalar.ph, label %vector.ph
18,23c18
< vector.scevcheck: ; preds = %for.cond1.preheader.us.preheader
< %2 = add nsw i64 %flatten.tripcount, -1
< %3 = icmp ugt i64 %2, 255
< br i1 %3, label %scalar.ph, label %vector.ph
<
< vector.ph: ; preds = %vector.scevcheck
---
> vector.ph: ; preds = %for.cond1.preheader.us.preheader
30,34c25,31
< %4 = trunc i64 %index to i8
< %5 = zext i8 %4 to i64
< %6 = getelementptr [2 x i8], ptr %A, i64 %5
< %7 = getelementptr i16, ptr %6, i64 4
< %8 = getelementptr i16, ptr %6, i64 8
---
> %2 = trunc i64 %index to i8
> %3 = zext i8 %2 to i64
> %4 = getelementptr [2 x i8], ptr %A, i64 %3
> %5 = getelementptr i16, ptr %4, i64 4
> %6 = getelementptr i16, ptr %4, i64 8
> store <4 x i16> splat (i16 1), ptr %4, align 2
> store <4 x i16> splat (i16 1), ptr %5, align 2
36,37d32
< store <4 x i16> splat (i16 1), ptr %7, align 2
< store <4 x i16> splat (i16 1), ptr %8, align 2
39,40c34,35
< %9 = icmp eq i64 %index.next, %n.vec
< br i1 %9, label %middle.block, label %vector.body, !llvm.loop !0
---
> %7 = icmp eq i64 %index.next, %n.vec
> br i1 %7, label %middle.block, label %vector.body, !llvm.loop !0
46,47c41,42
< scalar.ph: ; preds = %vector.scevcheck, %for.cond1.preheader.us.preheader, %middle.block
< %bc.resume.val = phi i64 [ %n.vec, %middle.block ], [ 0, %for.cond1.preheader.us.preheader ], [ 0, %vector.scevcheck ]
---
> scalar.ph: ; preds = %for.cond1.preheader.us.preheader, %middle.block
> %bc.resume.val = phi i64 [ %n.vec, %middle.block ], [ 0, %for.cond1.preheader.us.preheader ]
57,60c52,55
< %10 = trunc nuw i64 %indvar1 to i8
< %mul.us = mul i8 %10, %N
< %11 = trunc nuw i64 %indvar to i8
< %add.us = add i8 %11, %mul.us
---
> %8 = trunc nuw i64 %indvar1 to i8
> %mul.us = mul i8 %8, %N
> %9 = trunc nuw i64 %indvar to i8
> %add.us = add i8 %9, %mul.us
80,84d74
< ; Function Attrs: nocallback nocreateundeforpoison nofree nosync nounwind speculatable willreturn memory(none)
< declare { i8, i1 } @llvm.umul.with.overflow.i8(i8, i8) #0
<
< attributes #0 = { nocallback nocreateundeforpoison nofree nosync nounwind speculatable willreturn memory(none) }
<
88c78
< !3 = distinct !{!3, !1}
---
> !3 = distinct !{!3, !2, !1}
stevegustaman@b86a552ca51b:/shared/llvm-fuzzing/clangs/llvm-project-repo/repro/optonly$ cmp stale.ll fresh.ll
stale.ll fresh.ll differ: char 625, line 16
stevegustaman@b86a552ca51b:/shared/llvm-fuzzing/clangs/llvm-project-repo/repro/optonly$ diff fresh.ll stale.ll
16c16
< br i1 %min.iters.check, label %scalar.ph, label %vector.scevcheck
---
> br i1 %min.iters.check, label %scalar.ph, label %vector.ph
18,23c18
< vector.scevcheck: ; preds = %for.cond1.preheader.us.preheader
< %2 = add nsw i64 %flatten.tripcount, -1
< %3 = icmp ugt i64 %2, 255
< br i1 %3, label %scalar.ph, label %vector.ph
<
< vector.ph: ; preds = %vector.scevcheck
---
> vector.ph: ; preds = %for.cond1.preheader.us.preheader
30,34c25,31
< %4 = trunc i64 %index to i8
< %5 = zext i8 %4 to i64
< %6 = getelementptr [2 x i8], ptr %A, i64 %5
< %7 = getelementptr i16, ptr %6, i64 4
< %8 = getelementptr i16, ptr %6, i64 8
---
> %2 = trunc i64 %index to i8
> %3 = zext i8 %2 to i64
> %4 = getelementptr [2 x i8], ptr %A, i64 %3
> %5 = getelementptr i16, ptr %4, i64 4
> %6 = getelementptr i16, ptr %4, i64 8
> store <4 x i16> splat (i16 1), ptr %4, align 2
> store <4 x i16> splat (i16 1), ptr %5, align 2
36,37d32
< store <4 x i16> splat (i16 1), ptr %7, align 2
< store <4 x i16> splat (i16 1), ptr %8, align 2
39,40c34,35
< %9 = icmp eq i64 %index.next, %n.vec
< br i1 %9, label %middle.block, label %vector.body, !llvm.loop !0
---
> %7 = icmp eq i64 %index.next, %n.vec
> br i1 %7, label %middle.block, label %vector.body, !llvm.loop !0
46,47c41,42
< scalar.ph: ; preds = %vector.scevcheck, %for.cond1.preheader.us.preheader, %middle.block
< %bc.resume.val = phi i64 [ %n.vec, %middle.block ], [ 0, %for.cond1.preheader.us.preheader ], [ 0, %vector.scevcheck ]
---
> scalar.ph: ; preds = %for.cond1.preheader.us.preheader, %middle.block
> %bc.resume.val = phi i64 [ %n.vec, %middle.block ], [ 0, %for.cond1.preheader.us.preheader ]
57,60c52,55
< %10 = trunc nuw i64 %indvar1 to i8
< %mul.us = mul i8 %10, %N
< %11 = trunc nuw i64 %indvar to i8
< %add.us = add i8 %11, %mul.us
---
> %8 = trunc nuw i64 %indvar1 to i8
> %mul.us = mul i8 %8, %N
> %9 = trunc nuw i64 %indvar to i8
> %add.us = add i8 %9, %mul.us
80,84d74
< ; Function Attrs: nocallback nocreateundeforpoison nofree nosync nounwind speculatable willreturn memory(none)
< declare { i8, i1 } @llvm.umul.with.overflow.i8(i8, i8) #0
<
< attributes #0 = { nocallback nocreateundeforpoison nofree nosync nounwind speculatable willreturn memory(none) }
<
88c78
< !3 = distinct !{!3, !1}
---
> !3 = distinct !{!3, !2, !1}
```
Looks like `loop-flatten` pass failed to invalidate SCEV properly. Adding the invalidation `invalidate` (as in `fresh.ll`) fixes the issue.
Contributor guide
Assessment
This issue has not been assessed yet.