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.
65 lines
3.7 KiB
LLVM
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"}
|
|
;.
|