[llvm] 690b0b0 - [LV] Add initial costs for VPInstructionWithType::computeCost (#198291)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 10 03:17:54 PDT 2026


Author: David Sherwood
Date: 2026-06-10T11:17:50+01:00
New Revision: 690b0b0c63125aaf6b517df9d528789bb8c9c08a

URL: https://github.com/llvm/llvm-project/commit/690b0b0c63125aaf6b517df9d528789bb8c9c08a
DIFF: https://github.com/llvm/llvm-project/commit/690b0b0c63125aaf6b517df9d528789bb8c9c08a.diff

LOG: [LV] Add initial costs for VPInstructionWithType::computeCost (#198291)

I noticed this was previously always returning a cost of 0
due to fear of triggering the (now deleted) legacy/vplan
cost model assert. Since the assert has now been removed
this should be safe to implement properly. I haven't
filled in the costs for all types yet, since there is
currently no way to expose those code paths. I suspect
for things like VPInstruction::StepVector the recipe is
always in the vector preheader and we never ask for its
cost.

Added: 
    

Modified: 
    llvm/lib/Transforms/Vectorize/VPlan.h
    llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
    llvm/test/Transforms/LoopVectorize/RISCV/force-vect-msg.ll
    llvm/test/Transforms/LoopVectorize/RISCV/gather-scatter-cost.ll
    llvm/test/Transforms/LoopVectorize/RISCV/tail-folding-gather-scatter.ll
    llvm/test/Transforms/LoopVectorize/cast-costs.ll
    llvm/test/Transforms/LoopVectorize/vscale-cost.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 83475129cdebf..3903c84d2dfa3 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -1581,10 +1581,7 @@ class VPInstructionWithType : public VPInstruction {
 
   /// Return the cost of this VPInstruction.
   InstructionCost computeCost(ElementCount VF,
-                              VPCostContext &Ctx) const override {
-    // TODO: Compute accurate cost after retiring the legacy cost model.
-    return 0;
-  }
+                              VPCostContext &Ctx) const override;
 
   Type *getResultType() const { return getScalarType(); }
 

diff  --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index f78651cf8de6c..f1d6153f62c79 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -1790,6 +1790,31 @@ void VPInstruction::printRecipe(raw_ostream &O, const Twine &Indent,
 }
 #endif
 
+InstructionCost VPInstructionWithType::computeCost(ElementCount VF,
+                                                   VPCostContext &Ctx) const {
+  // NOTE: At the moment it seems only possible to expose this path for
+  // the trunc, zext and sext opcodes. However, isScalarCast also covers
+  // int<>fp conversions, bitcasts, ptr<>int conversions, etc.
+  if (Instruction::isCast(getOpcode()))
+    return getCostForRecipeWithOpcode(getOpcode(), ElementCount::getFixed(1),
+                                      Ctx);
+
+  switch (getOpcode()) {
+  case VPInstruction::VScale: {
+    Type *Ty = this->getScalarType();
+    ArrayRef<Type *> Tys;
+    IntrinsicCostAttributes Attrs(Intrinsic::vscale, Ty, Tys);
+    return Ctx.TTI.getIntrinsicInstrCost(Attrs, Ctx.CostKind);
+  }
+  default:
+    // Although VPInstructionWithType is also used for
+    // VPInstruction::StepVector and VPInstruction::WideIVStep it isn't
+    // currently possible to expose cases where the cost is queried.
+    llvm_unreachable("Unhandled opcode");
+  }
+  return 0;
+}
+
 void VPInstructionWithType::execute(VPTransformState &State) {
   Type *ResultTy = getResultType();
   if (Instruction::isCast(getOpcode())) {

diff  --git a/llvm/test/Transforms/LoopVectorize/RISCV/force-vect-msg.ll b/llvm/test/Transforms/LoopVectorize/RISCV/force-vect-msg.ll
index b6d41337678bd..f4be7b5490d7f 100644
--- a/llvm/test/Transforms/LoopVectorize/RISCV/force-vect-msg.ll
+++ b/llvm/test/Transforms/LoopVectorize/RISCV/force-vect-msg.ll
@@ -3,8 +3,8 @@
 
 ; CHECK: LV: Loop hints: force=enabled
 ; CHECK: LV: Scalar loop costs: 4.
-; ChosenFactor.Cost is 9, but the real cost will be divided by the width, which is 2.2.
-; CHECK: Cost for VF vscale x 2: 9
+; ChosenFactor.Cost is 11, but the real cost will be divided by the width, which is 2.8
+; CHECK: Cost for VF vscale x 2: 11
 ; Regardless of force vectorization or not, this loop will eventually be vectorized because of the cost model.
 ; Therefore, the following message does not need to be printed even if vectorization is explicitly forced in the metadata.
 ; CHECK-NOT: LV: Vectorization seems to be not beneficial, but was forced by a user.

diff  --git a/llvm/test/Transforms/LoopVectorize/RISCV/gather-scatter-cost.ll b/llvm/test/Transforms/LoopVectorize/RISCV/gather-scatter-cost.ll
index 07205354ac300..666e073ac5dd6 100644
--- a/llvm/test/Transforms/LoopVectorize/RISCV/gather-scatter-cost.ll
+++ b/llvm/test/Transforms/LoopVectorize/RISCV/gather-scatter-cost.ll
@@ -92,55 +92,30 @@ exit:
 }
 
 define void @predicated_strided_store(ptr %start) {
-; RVA23-LABEL: @predicated_strided_store(
-; RVA23-NEXT:  entry:
-; RVA23-NEXT:    br label [[VECTOR_PH:%.*]]
-; RVA23:       vector.ph:
-; RVA23-NEXT:    [[TMP0:%.*]] = call <vscale x 8 x i64> @llvm.stepvector.nxv8i64()
-; RVA23-NEXT:    br label [[VECTOR_BODY:%.*]]
-; RVA23:       vector.body:
-; RVA23-NEXT:    [[VEC_IND:%.*]] = phi <vscale x 8 x i64> [ [[TMP0]], [[VECTOR_PH]] ], [ [[VEC_IND_NEXT:%.*]], [[VECTOR_BODY]] ]
-; RVA23-NEXT:    [[AVL:%.*]] = phi i64 [ 586, [[VECTOR_PH]] ], [ [[AVL_NEXT:%.*]], [[VECTOR_BODY]] ]
-; RVA23-NEXT:    [[TMP2:%.*]] = call i32 @llvm.experimental.get.vector.length.i64(i64 [[AVL]], i32 8, i1 true)
-; RVA23-NEXT:    [[TMP3:%.*]] = zext i32 [[TMP2]] to i64
-; RVA23-NEXT:    [[BROADCAST_SPLATINSERT:%.*]] = insertelement <vscale x 8 x i64> poison, i64 [[TMP3]], i64 0
-; RVA23-NEXT:    [[BROADCAST_SPLAT:%.*]] = shufflevector <vscale x 8 x i64> [[BROADCAST_SPLATINSERT]], <vscale x 8 x i64> poison, <vscale x 8 x i32> zeroinitializer
-; RVA23-NEXT:    [[TMP4:%.*]] = mul <vscale x 8 x i64> [[VEC_IND]], splat (i64 7)
-; RVA23-NEXT:    [[TMP5:%.*]] = getelementptr i8, ptr [[START:%.*]], <vscale x 8 x i64> [[TMP4]]
-; RVA23-NEXT:    call void @llvm.vp.scatter.nxv8i8.nxv8p0(<vscale x 8 x i8> zeroinitializer, <vscale x 8 x ptr> align 1 [[TMP5]], <vscale x 8 x i1> splat (i1 true), i32 [[TMP2]])
-; RVA23-NEXT:    [[AVL_NEXT]] = sub nuw i64 [[AVL]], [[TMP3]]
-; RVA23-NEXT:    [[VEC_IND_NEXT]] = add <vscale x 8 x i64> [[VEC_IND]], [[BROADCAST_SPLAT]]
-; RVA23-NEXT:    [[TMP7:%.*]] = icmp eq i64 [[AVL_NEXT]], 0
-; RVA23-NEXT:    br i1 [[TMP7]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP9:![0-9]+]]
-; RVA23:       middle.block:
-; RVA23-NEXT:    br label [[LOOP:%.*]]
-; RVA23:       exit:
-; RVA23-NEXT:    ret void
-;
-; RVA23ZVL1024B-LABEL: @predicated_strided_store(
-; RVA23ZVL1024B-NEXT:  entry:
-; RVA23ZVL1024B-NEXT:    br label [[VECTOR_PH:%.*]]
-; RVA23ZVL1024B:       vector.ph:
-; RVA23ZVL1024B-NEXT:    [[TMP0:%.*]] = call <vscale x 2 x i64> @llvm.stepvector.nxv2i64()
-; RVA23ZVL1024B-NEXT:    br label [[VECTOR_BODY:%.*]]
-; RVA23ZVL1024B:       vector.body:
-; RVA23ZVL1024B-NEXT:    [[VEC_IND:%.*]] = phi <vscale x 2 x i64> [ [[TMP0]], [[VECTOR_PH]] ], [ [[VEC_IND_NEXT:%.*]], [[VECTOR_BODY]] ]
-; RVA23ZVL1024B-NEXT:    [[AVL:%.*]] = phi i64 [ 586, [[VECTOR_PH]] ], [ [[AVL_NEXT:%.*]], [[VECTOR_BODY]] ]
-; RVA23ZVL1024B-NEXT:    [[TMP2:%.*]] = call i32 @llvm.experimental.get.vector.length.i64(i64 [[AVL]], i32 2, i1 true)
-; RVA23ZVL1024B-NEXT:    [[TMP3:%.*]] = zext i32 [[TMP2]] to i64
-; RVA23ZVL1024B-NEXT:    [[BROADCAST_SPLATINSERT:%.*]] = insertelement <vscale x 2 x i64> poison, i64 [[TMP3]], i64 0
-; RVA23ZVL1024B-NEXT:    [[BROADCAST_SPLAT:%.*]] = shufflevector <vscale x 2 x i64> [[BROADCAST_SPLATINSERT]], <vscale x 2 x i64> poison, <vscale x 2 x i32> zeroinitializer
-; RVA23ZVL1024B-NEXT:    [[TMP4:%.*]] = mul <vscale x 2 x i64> [[VEC_IND]], splat (i64 7)
-; RVA23ZVL1024B-NEXT:    [[TMP5:%.*]] = getelementptr i8, ptr [[START:%.*]], <vscale x 2 x i64> [[TMP4]]
-; RVA23ZVL1024B-NEXT:    call void @llvm.vp.scatter.nxv2i8.nxv2p0(<vscale x 2 x i8> zeroinitializer, <vscale x 2 x ptr> align 1 [[TMP5]], <vscale x 2 x i1> splat (i1 true), i32 [[TMP2]])
-; RVA23ZVL1024B-NEXT:    [[AVL_NEXT]] = sub nuw i64 [[AVL]], [[TMP3]]
-; RVA23ZVL1024B-NEXT:    [[VEC_IND_NEXT]] = add <vscale x 2 x i64> [[VEC_IND]], [[BROADCAST_SPLAT]]
-; RVA23ZVL1024B-NEXT:    [[TMP7:%.*]] = icmp eq i64 [[AVL_NEXT]], 0
-; RVA23ZVL1024B-NEXT:    br i1 [[TMP7]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP9:![0-9]+]]
-; RVA23ZVL1024B:       middle.block:
-; RVA23ZVL1024B-NEXT:    br label [[LOOP:%.*]]
-; RVA23ZVL1024B:       exit:
-; RVA23ZVL1024B-NEXT:    ret void
+; CHECK-LABEL: @predicated_strided_store(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[VECTOR_PH:%.*]]
+; CHECK:       vector.ph:
+; CHECK-NEXT:    [[TMP0:%.*]] = call <vscale x 8 x i64> @llvm.stepvector.nxv8i64()
+; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
+; CHECK:       vector.body:
+; CHECK-NEXT:    [[VEC_IND:%.*]] = phi <vscale x 8 x i64> [ [[TMP0]], [[VECTOR_PH]] ], [ [[VEC_IND_NEXT:%.*]], [[VECTOR_BODY]] ]
+; CHECK-NEXT:    [[AVL:%.*]] = phi i64 [ 586, [[VECTOR_PH]] ], [ [[AVL_NEXT:%.*]], [[VECTOR_BODY]] ]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.experimental.get.vector.length.i64(i64 [[AVL]], i32 8, i1 true)
+; CHECK-NEXT:    [[TMP2:%.*]] = zext i32 [[TMP1]] to i64
+; CHECK-NEXT:    [[BROADCAST_SPLATINSERT:%.*]] = insertelement <vscale x 8 x i64> poison, i64 [[TMP2]], i64 0
+; CHECK-NEXT:    [[BROADCAST_SPLAT:%.*]] = shufflevector <vscale x 8 x i64> [[BROADCAST_SPLATINSERT]], <vscale x 8 x i64> poison, <vscale x 8 x i32> zeroinitializer
+; CHECK-NEXT:    [[TMP3:%.*]] = mul <vscale x 8 x i64> [[VEC_IND]], splat (i64 7)
+; CHECK-NEXT:    [[TMP4:%.*]] = getelementptr i8, ptr [[START:%.*]], <vscale x 8 x i64> [[TMP3]]
+; CHECK-NEXT:    call void @llvm.vp.scatter.nxv8i8.nxv8p0(<vscale x 8 x i8> zeroinitializer, <vscale x 8 x ptr> align 1 [[TMP4]], <vscale x 8 x i1> splat (i1 true), i32 [[TMP1]])
+; CHECK-NEXT:    [[AVL_NEXT]] = sub nuw i64 [[AVL]], [[TMP2]]
+; CHECK-NEXT:    [[VEC_IND_NEXT]] = add <vscale x 8 x i64> [[VEC_IND]], [[BROADCAST_SPLAT]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i64 [[AVL_NEXT]], 0
+; CHECK-NEXT:    br i1 [[TMP5]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP9:![0-9]+]]
+; CHECK:       middle.block:
+; CHECK-NEXT:    br label [[EXIT:%.*]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
 ;
 entry:
   br label %loop

diff  --git a/llvm/test/Transforms/LoopVectorize/RISCV/tail-folding-gather-scatter.ll b/llvm/test/Transforms/LoopVectorize/RISCV/tail-folding-gather-scatter.ll
index abc58ab22913a..a1a50684cd751 100644
--- a/llvm/test/Transforms/LoopVectorize/RISCV/tail-folding-gather-scatter.ll
+++ b/llvm/test/Transforms/LoopVectorize/RISCV/tail-folding-gather-scatter.ll
@@ -38,12 +38,10 @@ define void @gather_scatter(ptr noalias %in, ptr noalias %out, ptr noalias %inde
 ; NO-VP-NEXT:  entry:
 ; NO-VP-NEXT:    [[TMP11:%.*]] = call i64 @llvm.vscale.i64()
 ; NO-VP-NEXT:    [[TMP12:%.*]] = shl nuw i64 [[TMP11]], 1
-; NO-VP-NEXT:    [[UMAX:%.*]] = call i64 @llvm.umax.i64(i64 [[TMP12]], i64 4)
-; NO-VP-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[N:%.*]], [[UMAX]]
+; NO-VP-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[N:%.*]], [[TMP12]]
 ; NO-VP-NEXT:    br i1 [[MIN_ITERS_CHECK]], label [[SCALAR_PH:%.*]], label [[ENTRY:%.*]]
 ; NO-VP:       vector.ph:
-; NO-VP-NEXT:    [[TMP2:%.*]] = call i64 @llvm.vscale.i64()
-; NO-VP-NEXT:    [[TMP3:%.*]] = shl nuw i64 [[TMP2]], 1
+; NO-VP-NEXT:    [[TMP3:%.*]] = shl nuw i64 [[TMP11]], 1
 ; NO-VP-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[N]], [[TMP3]]
 ; NO-VP-NEXT:    [[N_VEC:%.*]] = sub i64 [[N]], [[N_MOD_VF]]
 ; NO-VP-NEXT:    [[TMP4:%.*]] = trunc i64 [[TMP3]] to i32
@@ -93,8 +91,12 @@ for.body:
   store float %1, ptr %arrayidx7, align 4
   %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
   %exitcond.not = icmp eq i64 %indvars.iv.next, %n
-  br i1 %exitcond.not, label %for.end, label %for.body
+  br i1 %exitcond.not, label %for.end, label %for.body, !llvm.loop !0
 
 for.end:
   ret void
 }
+
+!0 = distinct !{!0, !1, !2}
+!1 = !{!"llvm.loop.vectorize.width", i32 2}
+!2 = !{!"llvm.loop.vectorize.scalable.enable", i1 true}

diff  --git a/llvm/test/Transforms/LoopVectorize/cast-costs.ll b/llvm/test/Transforms/LoopVectorize/cast-costs.ll
index 4020807988635..3d81cae7a552b 100644
--- a/llvm/test/Transforms/LoopVectorize/cast-costs.ll
+++ b/llvm/test/Transforms/LoopVectorize/cast-costs.ll
@@ -4,8 +4,8 @@
 
 define void @trunc_store(ptr %dst) {
 ; CHECK-LABEL: 'trunc_store'
-; CHECK:  Cost of 0 for VF 2: EMIT-SCALAR vp<[[VP5:%[0-9]+]]> = trunc vp<[[VP4:%[0-9]+]]> to i8
-; CHECK:  Cost of 0 for VF 4: EMIT-SCALAR vp<[[VP5]]> = trunc vp<[[VP4]]> to i8
+; CHECK:  Cost of 1 for VF 2: EMIT-SCALAR vp<[[VP5:%[0-9]+]]> = trunc vp<[[VP4:%[0-9]+]]> to i8
+; CHECK:  Cost of 1 for VF 4: EMIT-SCALAR vp<[[VP5]]> = trunc vp<[[VP4]]> to i8
 ;
 entry:
   br label %loop
@@ -27,10 +27,10 @@ define i32 @sext_reduc(i32 %x, i32 %y) {
 ; CHECK-LABEL: 'sext_reduc'
 ; CHECK:  Cost of 1 for VF 2: WIDEN-CAST vp<[[VP6:%[0-9]+]]> = trunc ir<%red.next> to i1
 ; CHECK:  Cost of 1 for VF 2: WIDEN-CAST vp<[[VP7:%[0-9]+]]> = sext vp<[[VP6]]> to i32
-; CHECK:  Cost of 0 for VF 2: EMIT-SCALAR vp<[[VP10:%[0-9]+]]> = sext vp<[[VP9:%[0-9]+]]> to i32
+; CHECK:  Cost of 1 for VF 2: EMIT-SCALAR vp<[[VP10:%[0-9]+]]> = sext vp<[[VP9:%[0-9]+]]> to i32
 ; CHECK:  Cost of 1 for VF 4: WIDEN-CAST vp<[[VP6]]> = trunc ir<%red.next> to i1
 ; CHECK:  Cost of 1 for VF 4: WIDEN-CAST vp<[[VP7]]> = sext vp<[[VP6]]> to i32
-; CHECK:  Cost of 0 for VF 4: EMIT-SCALAR vp<[[VP10]]> = sext vp<[[VP9]]> to i32
+; CHECK:  Cost of 1 for VF 4: EMIT-SCALAR vp<[[VP10]]> = sext vp<[[VP9]]> to i32
 ;
 entry:
   br label %for.body
@@ -53,11 +53,11 @@ define i8 @reduc_add_trunc(ptr %A) {
 ; CHECK:  Cost of 0 for VF 2: WIDEN-CAST ir<%zext> = zext ir<%load> to i32
 ; CHECK:  Cost of 1 for VF 2: WIDEN-CAST vp<[[VP7:%[0-9]+]]> = trunc ir<%red.next> to i8
 ; CHECK:  Cost of 1 for VF 2: WIDEN-CAST vp<[[VP8:%[0-9]+]]> = zext vp<[[VP7]]> to i32
-; CHECK:  Cost of 0 for VF 2: EMIT-SCALAR vp<[[VP11:%[0-9]+]]> = zext vp<[[VP10:%[0-9]+]]> to i32
+; CHECK:  Cost of 1 for VF 2: EMIT-SCALAR vp<[[VP11:%[0-9]+]]> = zext vp<[[VP10:%[0-9]+]]> to i32
 ; CHECK:  Cost of 0 for VF 4: WIDEN-CAST ir<%zext> = zext ir<%load> to i32
 ; CHECK:  Cost of 1 for VF 4: WIDEN-CAST vp<[[VP7]]> = trunc ir<%red.next> to i8
 ; CHECK:  Cost of 1 for VF 4: WIDEN-CAST vp<[[VP8]]> = zext vp<[[VP7]]> to i32
-; CHECK:  Cost of 0 for VF 4: EMIT-SCALAR vp<[[VP11]]> = zext vp<[[VP10]]> to i32
+; CHECK:  Cost of 1 for VF 4: EMIT-SCALAR vp<[[VP11]]> = zext vp<[[VP10]]> to i32
 ;
 entry:
   br label %loop

diff  --git a/llvm/test/Transforms/LoopVectorize/vscale-cost.ll b/llvm/test/Transforms/LoopVectorize/vscale-cost.ll
index 8291237cd3d63..2cc60c7a331b1 100644
--- a/llvm/test/Transforms/LoopVectorize/vscale-cost.ll
+++ b/llvm/test/Transforms/LoopVectorize/vscale-cost.ll
@@ -6,8 +6,8 @@
 
 define void @scalablevf(ptr %dst.start, i8 %a, i8 %b) {
 ; CHECK-LABEL: 'scalablevf'
-; CHECK:  Cost of 0 for VF vscale x 4: EMIT-SCALAR vp<[[VP2:%[0-9]+]]> = vscale i64
-; CHECK:  Cost of 0 for VF vscale x 4: EMIT-SCALAR vp<[[VP2]]> = vscale i64
+; CHECK:  Cost of 1 for VF vscale x 4: EMIT-SCALAR vp<[[VP2:%[0-9]+]]> = vscale i64
+; CHECK:  Cost of 1 for VF vscale x 4: EMIT-SCALAR vp<[[VP2]]> = vscale i64
 ;
 entry:
   br label %loop


        


More information about the llvm-commits mailing list