Open patrick-rivos opened 5 months ago
Partially cleaned up testcase:
target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"
define i32 @main() #0 {
entry:
%sext.0 = sext i16 0 to i32
br label %loop.preheader
loop.preheader: ; preds = %loop.preheader, %entry
%iv.i = phi i64 [ %iv.next.i, %loop.preheader ], [ 0, %entry ]
%phi.0 = phi i8 [ %or.0, %loop.preheader ], [ 0, %entry ]
%max.0 = tail call i32 @llvm.smax.i32(i32 0, i32 %sext.0)
%cmp = icmp eq i32 %max.0, 0
%zext.true = zext i1 %cmp to i32
%0 = lshr i32 %zext.true, 1
%1 = trunc i32 %0 to i8
%or.0 = or i8 %phi.0, %1
%iv.next.i = add i64 %iv.i, 1
%cmp.us.i = icmp slt i64 %iv.i, 1
br i1 %cmp.us.i, label %loop.preheader, label %loop.exit
loop.exit: ; preds = %loop.preheader
store i8 %or.0, ptr null, align 1
ret i32 0
}
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.smax.i32(i32, i32) #1
attributes #0 = { "target-features"="+64bit,+v" }
Basic analysis:
The issue is caused by:
https://github.com/llvm/llvm-project/blob/39bfdb7f33f7f53ab662c5cea25129c45a9b4c11/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp#L1074-L1076
when %sext.0 = sext i16 0 to i32
is the only unaccounted for MinBWs entry.
Op->getLiveInIRValue()
returns a Constant i32 0
, so the dynamic cast to Instruction returns a null pointer which does not exist in MinBWs.
I think the Constant is an optimized sext i16 0 to i32
so I'll try to find where the constant comes from next.
Alright I think I understand everything that's going on here
Using this testcase:
target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
define i32 @main() #1 {
entry:
%zext.0 = zext i8 0 to i64
br label %loop
loop: ; preds = %loop, %entry
%phi.0 = phi i64 [ %incrementor, %loop ], [ 0, %entry ]
%incrementor = add i64 %phi.0, 1
%max.0 = tail call i64 @llvm.umax.i64(i64 %zext.0, i64 0)
%cmp.0 = icmp ne i64 %max.0, 0
%zext.1 = zext i1 %cmp.0 to i64
%trunc.0 = trunc i64 %zext.1 to i32
%shl.0 = shl i32 %trunc.0, 8 ; Truncate and shift to make all bits dead
%trunc.1 = trunc i32 %shl.0 to i8
%exitcond6 = icmp ne i64 %phi.0, 16
br i1 %exitcond6, label %loop, label %loop.exit
loop.exit: ; preds = %loop
store i8 %trunc.1, ptr null, align 1
ret i32 0
}
attributes #1 = { "target-features"="+v" }
computeMinimumValueSizes operates on a region, but a chain terminated with one instruction outside the bounds of the region is still considered valid. This compounded with weirdness with WIDEN-CALL causes issues in truncateToMinimalBitwidths where this range is considered:
<x1> vector loop: {
vector.body:
EMIT vp<%2> = CANONICAL-INDUCTION ir<0>, vp<%3>
WIDEN-INDUCTION %phi.0 = phi %incrementor, 0, ir<1>
CLONE ir<%incrementor> = add ir<%phi.0>, ir<1>
WIDEN-CALL ir<%max.0> = call @llvm.umax.i64(ir<%zext.0>, ir<0>) (using vector intrinsic)
WIDEN ir<%cmp.0> = icmp ne ir<%max.0>, ir<0>
WIDEN-CAST ir<%zext.1> = zext ir<%cmp.0> to i64
WIDEN-CAST ir<%trunc.0> = trunc ir<%zext.1> to i32
WIDEN ir<%shl.0> = shl ir<%trunc.0>, ir<8>
WIDEN-CAST ir<%trunc.1> = trunc ir<%shl.0> to i8
CLONE ir<%exitcond6> = icmp ne ir<%phi.0>, ir<16>
Successor(s):
:
Successor(s): vector.latch
vector.latch:
EMIT vp<%3> = add nuw vp<%2>, vp<%0>
EMIT branch-on-count vp<%3>, vp<%1>
No successors
}
Successor(s): middle.block
The MinBWs are:
%cmp.0 = icmp ne i64 %max.0, 0 Size: 1
%zext.0 = zext i8 0 to i64 Size: 1
comp.0 is found easily but zext.0 isn't in the region. Normally chains outside the region are handled by this which pulls in arguments.
We don't consider WIDEN-CALL since it doesn't have an entry in MinBW (and isn't allowed). It doesn't have an entry since the function call uses a ptr which cannot be truncated so that op fails to truncate.
DemandedBits understands a subset of all intrinsics while VPlanAnalysis doesn't handle any of them (for the pointer reason).
This can be fixed by ignoring the call function pointer argument for all intrinsic cases that DemandedBits handles.
VPWidenCallRecipe also needs a way to specify a new return type when executed so I added getResultType and setResultType methods.
I'll submit a PR soon.
Reduced LLVM IR:
Backtrace:
Godbolt: https://godbolt.org/z/6TxWGMz6e
Assert: https://github.com/llvm/llvm-project/blob/c403a478076a16172d9b50e16c288b0d360f42ce/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp#L1061-L1063
Found via fuzzer.