Luke Lau b04cf3b0fd
[VPlan] Remove verifier check that EVL can only be used by VPInstruction with one use (#175502)
Fixes #175028

We have a VPlanVerifier assertion that a VPInstruction that uses EVL
only has one use. This used to hold until we implemented CSE, but now we
can run into the case where e.g. a multiply from an expanded
VPWidenPointerInductionRecipe gets cse'd, causing it to have multiple
uses:

    EMIT ir<%0> = WIDEN-POINTER-INDUCTION ir<%.pre3>, ir<6>, vp<%5>
    EMIT ir<%1> = WIDEN-POINTER-INDUCTION ir<%.pre>, ir<6>, vp<%5>
    EMIT-SCALAR vp<%5> = EXPLICIT-VECTOR-LENGTH vp<%avl>

    -->

    EMIT-SCALAR vp<%10> = EXPLICIT-VECTOR-LENGTH vp<%avl>
    EMIT vp<%11> = mul ir<6>, vp<%10>
    EMIT vp<%ptr.ind> = ptradd vp<%pointer.phi>, vp<%11>
    EMIT vp<%12> = mul ir<6>, vp<%10>
    EMIT vp<%ptr.ind>.1 = ptradd vp<%pointer.phi>.1, vp<%12>

    -->

    EMIT-SCALAR vp<%5> = EXPLICIT-VECTOR-LENGTH vp<%avl>
    EMIT vp<%6> = mul ir<6>, vp<%5>
    EMIT vp<%ptr.ind> = ptradd vp<%pointer.phi>, vp<%6>
    EMIT vp<%ptr.ind>.1 = ptradd vp<%pointer.phi>.1, vp<%6>

This removes the check, as I'm not sure it's that useful anymore now
that we have CSE. Coincidentally, this crash only happened on RV32
because RV64 requires zexting the EVL, which sidesteps a lot of the
checks to begin with.
2026-01-12 14:58:04 +00:00

65 lines
3.7 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt < %s -S -p loop-vectorize -mtriple riscv32 -mattr=+v | FileCheck %s
; The EVL here is used by two VPWidenPointerInductionRecipes which are then
; expanded to two muls. The muls are then CSE'd, so make sure the verifier
; doesn't complain if a user of EVL has multiple uses.
define i32 @widenpointerinduction_evl_cse(ptr noalias %p0, ptr noalias %p1) {
; CHECK-LABEL: define i32 @widenpointerinduction_evl_cse(
; CHECK-SAME: ptr noalias [[P0:%.*]], ptr noalias [[P1:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: br label %[[VECTOR_PH:.*]]
; CHECK: [[VECTOR_PH]]:
; CHECK-NEXT: [[BROADCAST_SPLATINSERT:%.*]] = insertelement <vscale x 4 x ptr> poison, ptr [[P0]], i64 0
; CHECK-NEXT: [[BROADCAST_SPLAT:%.*]] = shufflevector <vscale x 4 x ptr> [[BROADCAST_SPLATINSERT]], <vscale x 4 x ptr> poison, <vscale x 4 x i32> zeroinitializer
; CHECK-NEXT: [[BROADCAST_SPLATINSERT1:%.*]] = insertelement <vscale x 4 x ptr> poison, ptr [[P1]], i64 0
; CHECK-NEXT: [[BROADCAST_SPLAT2:%.*]] = shufflevector <vscale x 4 x ptr> [[BROADCAST_SPLATINSERT1]], <vscale x 4 x ptr> poison, <vscale x 4 x i32> zeroinitializer
; CHECK-NEXT: br label %[[VECTOR_BODY:.*]]
; CHECK: [[VECTOR_BODY]]:
; CHECK-NEXT: [[POINTER_PHI:%.*]] = phi ptr [ [[P0]], %[[VECTOR_PH]] ], [ [[PTR_IND:%.*]], %[[VECTOR_BODY]] ]
; CHECK-NEXT: [[POINTER_PHI3:%.*]] = phi ptr [ [[P1]], %[[VECTOR_PH]] ], [ [[PTR_IND5:%.*]], %[[VECTOR_BODY]] ]
; CHECK-NEXT: [[AVL:%.*]] = phi i32 [ 1024, %[[VECTOR_PH]] ], [ [[AVL_NEXT:%.*]], %[[VECTOR_BODY]] ]
; CHECK-NEXT: [[TMP0:%.*]] = call <vscale x 4 x i32> @llvm.stepvector.nxv4i32()
; CHECK-NEXT: [[TMP1:%.*]] = shl <vscale x 4 x i32> [[TMP0]], splat (i32 1)
; CHECK-NEXT: [[VECTOR_GEP:%.*]] = getelementptr i8, ptr [[POINTER_PHI3]], <vscale x 4 x i32> [[TMP1]]
; CHECK-NEXT: [[VECTOR_GEP4:%.*]] = getelementptr i8, ptr [[POINTER_PHI]], <vscale x 4 x i32> [[TMP1]]
; CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.experimental.get.vector.length.i32(i32 [[AVL]], i32 4, i1 true)
; CHECK-NEXT: call void @llvm.vp.scatter.nxv4p0.nxv4p0(<vscale x 4 x ptr> [[VECTOR_GEP4]], <vscale x 4 x ptr> align 4 [[BROADCAST_SPLAT]], <vscale x 4 x i1> splat (i1 true), i32 [[TMP2]])
; CHECK-NEXT: call void @llvm.vp.scatter.nxv4p0.nxv4p0(<vscale x 4 x ptr> [[VECTOR_GEP]], <vscale x 4 x ptr> align 4 [[BROADCAST_SPLAT2]], <vscale x 4 x i1> splat (i1 true), i32 [[TMP2]])
; CHECK-NEXT: [[AVL_NEXT]] = sub nuw i32 [[AVL]], [[TMP2]]
; CHECK-NEXT: [[TMP3:%.*]] = shl i32 [[TMP2]], 1
; CHECK-NEXT: [[PTR_IND]] = getelementptr i8, ptr [[POINTER_PHI]], i32 [[TMP3]]
; CHECK-NEXT: [[PTR_IND5]] = getelementptr i8, ptr [[POINTER_PHI3]], i32 [[TMP3]]
; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[AVL_NEXT]], 0
; CHECK-NEXT: br i1 [[TMP4]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]]
; CHECK: [[MIDDLE_BLOCK]]:
; CHECK-NEXT: br label %[[EXIT:.*]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret i32 0
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry], [ %iv.next, %loop ]
%x = phi ptr [ %p0, %entry ], [ %x.next, %loop ]
%y = phi ptr [ %p1, %entry ], [ %y.next, %loop ]
store ptr %x, ptr %p0
store ptr %y, ptr %p1
%iv.next = add i32 %iv, 1
%x.next = getelementptr i8, ptr %x, i32 2
%y.next = getelementptr i8, ptr %y, i32 2
%ec = icmp eq i32 %iv.next, 1024
br i1 %ec, label %exit, label %loop
exit:
ret i32 0
}
;.
; CHECK: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]], [[META2:![0-9]+]]}
; CHECK: [[META1]] = !{!"llvm.loop.isvectorized", i32 1}
; CHECK: [[META2]] = !{!"llvm.loop.unroll.runtime.disable"}
;.