[LoopVectorize] Miscompile with FindIV reduction used in expression
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
```llvm
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
@a = global [72 x i32] [i32 0, i32 42, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0]
define i32 @f(ptr %a, i32 %n) #0 {
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
%rdx = phi i32 [ -1, %entry ], [ %sel, %loop ]
%gep = getelementptr inbounds i32, ptr %a, i32 %iv
%l = load i32, ptr %gep, align 4
%c = icmp eq i32 %l, 42
%expr = mul i32 %iv, 4
%sel = select i1 %c, i32 %expr, i32 %rdx
%iv.next = add nuw nsw i32 %iv, 1
%ec = icmp eq i32 %iv.next, %n
br i1 %ec, label %done, label %loop
done:
ret i32 %sel
}
define i32 @main() {
%r = call i32 @f(ptr @a, i32 72)
ret i32 %r
}
attributes #0 = { "target-features"="+avx512f" }
```
llubi returns 4 before loop-vectorize and 16 after.
Disclosure: Found by AI. It provided this analysis:
`VPlanTransforms::optimizeFindIVReductions` can rewrite a FindLastIV reduction that
selects an *expression of the IV* (e.g. `mul %iv, 4`) into a reduction over the raw IV,
sinking the expression into the middle block. Epilogue vectorization must then be
disabled, because the main loop's reduction result is in "expression domain" while the
epilogue vector loop reduces raw IV values. The guard that detects this
(`hasUnsupportedHeaderPhiRecipe`) tests whether `ComputeReductionResult` has any
**non-`VPInstruction`** user. `optimizeFindIVReductions` sinks a `VPWidenRecipe` (which
satisfies the guard), but the later `simplifyRecipe` run folds `mul X, PowerOf2` into a
freshly created `Instruction::Shl` **`VPInstruction`** — after which the guard no longer
fires, epilogue vectorization is enabled, and the epilogue loop is seeded with a value
from the wrong domain. Result: wrong value returned at runtime.
Contributor guide
Research direction
Start by running the supplied LLVM IR reproducer with llubi before and after loop-vectorize, confirming the returned values are 4 and 16. Read VPlanTransforms::optimizeFindIVReductions, hasUnsupportedHeaderPhiRecipe, and simplifyRecipe to trace the reduction and epilogue decisions. Done means the optimized reproducer returns the same correct value as the unvectorized case.
Written by the indexing model from the issue text.
Assessment
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100