https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/209774
Backport 1d4148821bf96bef23ea77952031e3e7bec26d3a Requested by: @lukel97 >From 688a29777d4b88339c129968a9cc9e9a0bffedef Mon Sep 17 00:00:00 2001 From: Mel Chen <[email protected]> Date: Wed, 15 Jul 2026 19:19:38 +0800 Subject: [PATCH] [VPlan] Fix nowrap flags for strided access pointers from SCEV (#209453) This patch addresses two things. First, the offset calculation (canonical IV * stride) should not reuse the NSW flag of the add recurrence. The NSW property from SCEV for the original scalar recurrence does not necessarily hold for the reconstructed multiplication using the vector canonical IV. The NUW flag, however, can still be safely propagated. Second, because vputils::getGEPFlagsForPtr currently doesn't support recipes other than VPInstruction, and to avoid relying on LLVM IR function (like calling stripPointerCasts()), we change VPVectorPointerRecipe's GEP flags to use the add recurrence's flags to prevent propagating unprovable GEP flags like inbounds. (cherry picked from commit 1d4148821bf96bef23ea77952031e3e7bec26d3a) --- llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp | 14 +++++++------- .../LoopVectorize/RISCV/strided-accesses-unroll.ll | 4 +--- .../LoopVectorize/RISCV/strided-accesses.ll | 10 +++++----- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp index 4da74c5146c52..f37d61f8464fa 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp @@ -7787,16 +7787,16 @@ void VPlanTransforms::convertToStridedAccesses(VPlan &Plan, auto *AddRecPtr = cast<SCEVAddRecExpr>(PtrSCEV); auto *Offset = Builder.createOverflowingOp( Instruction::Mul, {CanIV, StrideInBytes}, - {AddRecPtr->hasNoUnsignedWrap(), AddRecPtr->hasNoSignedWrap()}); - auto *BasePtr = Builder.createNoWrapPtrAdd( - StartVPV, Offset, - AddRecPtr->hasNoUnsignedWrap() ? GEPNoWrapFlags::noUnsignedWrap() - : GEPNoWrapFlags::none()); + {AddRecPtr->hasNoUnsignedWrap(), /*HasNSW=*/false}); + GEPNoWrapFlags NWFlags = AddRecPtr->hasNoUnsignedWrap() + ? GEPNoWrapFlags::noUnsignedWrap() + : GEPNoWrapFlags::none(); + VPValue *BasePtr = Builder.createNoWrapPtrAdd(StartVPV, Offset, NWFlags); // Create a new vector pointer for strided access. VPValue *NewPtr = Builder.createVectorPointer( - BasePtr, Type::getInt8Ty(Plan.getContext()), StrideInBytes, - Ptr->getGEPNoWrapFlags(), Ptr->getDebugLoc()); + BasePtr, Type::getInt8Ty(Plan.getContext()), StrideInBytes, NWFlags, + Ptr->getDebugLoc()); VPValue *Mask = LoadR->getMask(); if (!Mask) diff --git a/llvm/test/Transforms/LoopVectorize/RISCV/strided-accesses-unroll.ll b/llvm/test/Transforms/LoopVectorize/RISCV/strided-accesses-unroll.ll index c4727847d244f..8a53e298af869 100644 --- a/llvm/test/Transforms/LoopVectorize/RISCV/strided-accesses-unroll.ll +++ b/llvm/test/Transforms/LoopVectorize/RISCV/strided-accesses-unroll.ll @@ -1,8 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals none --filter-out-after "^scalar.ph" --version 6 ; RUN: opt < %s -S -p loop-vectorize -mtriple riscv64 -mattr=+v -force-vector-interleave=2 | FileCheck %s -; FIXME: the second part of the strided load's gep shouldn't have nuw. - define void @negative_stride_nuw(ptr noalias %src, ptr noalias %dst) { ; CHECK-LABEL: define void @negative_stride_nuw( ; CHECK-SAME: ptr noalias [[SRC:%.*]], ptr noalias [[DST:%.*]]) #[[ATTR0:[0-9]+]] { @@ -26,7 +24,7 @@ define void @negative_stride_nuw(ptr noalias %src, ptr noalias %dst) { ; CHECK-NEXT: [[TMP8:%.*]] = mul i64 [[INDEX]], -8 ; CHECK-NEXT: [[TMP9:%.*]] = getelementptr i8, ptr [[TMP7]], i64 [[TMP8]] ; CHECK-NEXT: [[TMP10:%.*]] = mul i64 [[TMP2]], -8 -; CHECK-NEXT: [[TMP11:%.*]] = getelementptr nuw i8, ptr [[TMP9]], i64 [[TMP10]] +; CHECK-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr [[TMP9]], i64 [[TMP10]] ; CHECK-NEXT: [[TMP12:%.*]] = call <vscale x 4 x i32> @llvm.experimental.vp.strided.load.nxv4i32.p0.i64(ptr align 4 [[TMP9]], i64 -8, <vscale x 4 x i1> splat (i1 true), i32 [[TMP6]]) ; CHECK-NEXT: [[TMP13:%.*]] = call <vscale x 4 x i32> @llvm.experimental.vp.strided.load.nxv4i32.p0.i64(ptr align 4 [[TMP11]], i64 -8, <vscale x 4 x i1> splat (i1 true), i32 [[TMP6]]) ; CHECK-NEXT: [[TMP14:%.*]] = getelementptr inbounds i32, ptr [[DST]], i64 [[INDEX]] diff --git a/llvm/test/Transforms/LoopVectorize/RISCV/strided-accesses.ll b/llvm/test/Transforms/LoopVectorize/RISCV/strided-accesses.ll index 673d26a02e036..1062ba477bdce 100644 --- a/llvm/test/Transforms/LoopVectorize/RISCV/strided-accesses.ll +++ b/llvm/test/Transforms/LoopVectorize/RISCV/strided-accesses.ll @@ -1262,13 +1262,13 @@ define void @double_stride_ptr_iv(ptr %p, ptr %p2, i64 %stride) { ; STRIDED-UF2-NEXT: br i1 [[CMP_N]], label %[[EXIT:.*]], label %[[SCALAR_PH]] ; STRIDED-UF2: [[SCALAR_PH]]: ; STRIDED-UF2-NEXT: [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], %[[MIDDLE_BLOCK]] ], [ 0, %[[ENTRY]] ], [ 0, %[[VECTOR_MEMCHECK]] ] -; STRIDED-UF2-NEXT: [[BC_RESUME_VAL16:%.*]] = phi ptr [ [[TMP11]], %[[MIDDLE_BLOCK]] ], [ [[P]], %[[ENTRY]] ], [ [[P]], %[[VECTOR_MEMCHECK]] ] -; STRIDED-UF2-NEXT: [[BC_RESUME_VAL17:%.*]] = phi ptr [ [[TMP12]], %[[MIDDLE_BLOCK]] ], [ [[P2]], %[[ENTRY]] ], [ [[P2]], %[[VECTOR_MEMCHECK]] ] +; STRIDED-UF2-NEXT: [[BC_RESUME_VAL15:%.*]] = phi ptr [ [[TMP11]], %[[MIDDLE_BLOCK]] ], [ [[P]], %[[ENTRY]] ], [ [[P]], %[[VECTOR_MEMCHECK]] ] +; STRIDED-UF2-NEXT: [[BC_RESUME_VAL16:%.*]] = phi ptr [ [[TMP12]], %[[MIDDLE_BLOCK]] ], [ [[P2]], %[[ENTRY]] ], [ [[P2]], %[[VECTOR_MEMCHECK]] ] ; STRIDED-UF2-NEXT: br label %[[LOOP:.*]] ; STRIDED-UF2: [[LOOP]]: ; STRIDED-UF2-NEXT: [[I:%.*]] = phi i64 [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ], [ [[NEXTI:%.*]], %[[LOOP]] ] -; STRIDED-UF2-NEXT: [[PTR:%.*]] = phi ptr [ [[BC_RESUME_VAL16]], %[[SCALAR_PH]] ], [ [[PTR_NEXT:%.*]], %[[LOOP]] ] -; STRIDED-UF2-NEXT: [[PTR2:%.*]] = phi ptr [ [[BC_RESUME_VAL17]], %[[SCALAR_PH]] ], [ [[PTR2_NEXT:%.*]], %[[LOOP]] ] +; STRIDED-UF2-NEXT: [[PTR:%.*]] = phi ptr [ [[BC_RESUME_VAL15]], %[[SCALAR_PH]] ], [ [[PTR_NEXT:%.*]], %[[LOOP]] ] +; STRIDED-UF2-NEXT: [[PTR2:%.*]] = phi ptr [ [[BC_RESUME_VAL16]], %[[SCALAR_PH]] ], [ [[PTR2_NEXT:%.*]], %[[LOOP]] ] ; STRIDED-UF2-NEXT: [[X0:%.*]] = load i32, ptr [[PTR]], align 4 ; STRIDED-UF2-NEXT: [[Y0:%.*]] = add i32 [[X0]], 1 ; STRIDED-UF2-NEXT: store i32 [[Y0]], ptr [[PTR2]], align 4 @@ -1356,7 +1356,7 @@ define void @constant_stride_reinterpret(ptr noalias %in, ptr noalias %out) { ; CHECK-UF2-NEXT: [[TMP5:%.*]] = shl nuw i64 [[INDEX]], 2 ; CHECK-UF2-NEXT: [[TMP6:%.*]] = getelementptr nuw i8, ptr [[IN]], i64 [[TMP5]] ; CHECK-UF2-NEXT: [[TMP7:%.*]] = mul i64 [[TMP3]], 4 -; CHECK-UF2-NEXT: [[TMP13:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP6]], i64 [[TMP7]] +; CHECK-UF2-NEXT: [[TMP13:%.*]] = getelementptr nuw i8, ptr [[TMP6]], i64 [[TMP7]] ; CHECK-UF2-NEXT: [[WIDE_MASKED_GATHER:%.*]] = call <vscale x 2 x i64> @llvm.experimental.vp.strided.load.nxv2i64.p0.i64(ptr align 8 [[TMP6]], i64 4, <vscale x 2 x i1> splat (i1 true), i32 [[TMP12]]) ; CHECK-UF2-NEXT: [[WIDE_MASKED_GATHER1:%.*]] = call <vscale x 2 x i64> @llvm.experimental.vp.strided.load.nxv2i64.p0.i64(ptr align 8 [[TMP13]], i64 4, <vscale x 2 x i1> splat (i1 true), i32 [[TMP12]]) ; CHECK-UF2-NEXT: [[TMP8:%.*]] = getelementptr inbounds nuw i64, ptr [[OUT]], i64 [[INDEX]] _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
