[llvm] [LV] Fix the cost model for freeze instructions (PR #197188)
David Sherwood via llvm-commits
llvm-commits at lists.llvm.org
Tue May 12 06:14:39 PDT 2026
https://github.com/david-arm created https://github.com/llvm/llvm-project/pull/197188
While working on a PR to add a cost model for VPDerivedIV recipes I noticed that a loop in or_reduction_with_freeze:
test/Transforms/LoopVectorize/AArch64/reduction-cost.ll
stopped vectorising because the cost model decided it was no longer worth it. However, the main cause of this was the incredibly high cost (14) of freeze for VF=2. We were using the cost of a vector mul instruction as a proxy for the freeze cost, which is incredibly bad for an AArch64 target without SVE since the operation needs scalarising.
As far as I understand, the freeze instruction does not lead to any actual code being generated and acts merely as a barrier to potentially unsafe optimisations. As such, I've updated the cost model to return 0 instead.
>From 88b881dfaa37ace832065f42034ee3e54cf56d33 Mon Sep 17 00:00:00 2001
From: David Sherwood <david.sherwood at arm.com>
Date: Tue, 12 May 2026 13:10:47 +0000
Subject: [PATCH] [LV] Fix the cost model for freeze instructions
While working on a PR to add a cost model for VPDerivedIV
recipes I noticed that a loop in or_reduction_with_freeze:
test/Transforms/LoopVectorize/AArch64/reduction-cost.ll
stopped vectorising because the cost model decided it was
no longer worth it. However, the main cause of this was
the incredibly high cost (14) of freeze for VF=2. We were
using the cost of a vector mul instruction as a proxy for
the freeze cost, which is incredibly bad for an AArch64
target without SVE since the operation needs scalarising.
As far as I understand, the freeze instruction does not
lead to any actual code being generated and acts merely
as a barrier to potentially unsafe optimisations. As such,
I've updated the cost model to return 0 instead.
---
llvm/lib/Transforms/Vectorize/LoopVectorize.cpp | 4 ++++
llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp | 6 +++---
.../test/Transforms/LoopVectorize/AArch64/reduction-cost.ll | 2 +-
.../LoopVectorize/X86/CostModel/vpinstruction-cost.ll | 6 +++---
4 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 1ace2275e2b6d..a91ebaeaaff28 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -5529,6 +5529,10 @@ LoopVectorizationCostModel::getInstructionCost(Instruction *I,
if (VF.isScalable())
return InstructionCost::getInvalid();
return TTI.getArithmeticInstrCost(Instruction::Mul, RetTy, Config.CostKind);
+ case Instruction::Freeze:
+ // This will never lead to any real code being generated. It acts purely
+ // as a blocker for optimizations.
+ return 0;
default:
// This opcode is unknown. Assume that it is the same as 'mul'.
return TTI.getArithmeticInstrCost(Instruction::Mul, VectorTy,
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 11a91dcd46867..f699403de65d5 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -992,9 +992,9 @@ InstructionCost VPRecipeWithIRFlags::getCostForRecipeWithOpcode(
RHSInfo, Operands, CtxI, &Ctx.TLI);
}
case Instruction::Freeze:
- // This opcode is unknown. Assume that it is the same as 'mul'.
- return Ctx.TTI.getArithmeticInstrCost(Instruction::Mul, ResultTy,
- Ctx.CostKind);
+ // This will never lead to any real code being generated. It acts purely
+ // as a blocker for optimizations.
+ return 0;
case Instruction::ExtractValue:
return Ctx.TTI.getInsertExtractValueCost(Instruction::ExtractValue,
Ctx.CostKind);
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/reduction-cost.ll b/llvm/test/Transforms/LoopVectorize/AArch64/reduction-cost.ll
index 92e75f26fffcb..66e6585ceece4 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/reduction-cost.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/reduction-cost.ll
@@ -75,7 +75,7 @@ define i32 @or_reduction_with_freeze(ptr %dst, ptr %src) {
; CHECK-NEXT: [[TMP0:%.*]] = sub i64 [[DST6]], [[SRC7]]
; CHECK-NEXT: [[TMP1:%.*]] = lshr i64 [[TMP0]], 3
; CHECK-NEXT: [[TMP2:%.*]] = add nuw nsw i64 [[TMP1]], 1
-; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP2]], 18
+; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP2]], 10
; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_SCEVCHECK:.*]]
; CHECK: [[VECTOR_SCEVCHECK]]:
; CHECK-NEXT: [[TMP3:%.*]] = trunc i64 [[DST1]] to i3
diff --git a/llvm/test/Transforms/LoopVectorize/X86/CostModel/vpinstruction-cost.ll b/llvm/test/Transforms/LoopVectorize/X86/CostModel/vpinstruction-cost.ll
index 12d32872e1453..aeb222e677e63 100644
--- a/llvm/test/Transforms/LoopVectorize/X86/CostModel/vpinstruction-cost.ll
+++ b/llvm/test/Transforms/LoopVectorize/X86/CostModel/vpinstruction-cost.ll
@@ -104,7 +104,7 @@ define void @test_vpinstruction_freeze_cost(ptr %src, ptr noalias %dst) {
; CHECK: LV: Found an estimated cost of 0 for VF 1 For instruction: %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
; CHECK: LV: Found an estimated cost of 0 for VF 1 For instruction: %g.src = getelementptr inbounds i64, ptr %src, i64 %iv
; CHECK: LV: Found an estimated cost of 1 for VF 1 For instruction: %l = load i64, ptr %g.src, align 8
-; CHECK: LV: Found an estimated cost of 1 for VF 1 For instruction: %fr = freeze i64 %l
+; CHECK: LV: Found an estimated cost of 0 for VF 1 For instruction: %fr = freeze i64 %l
; CHECK: LV: Found an estimated cost of 0 for VF 1 For instruction: %g.dst = getelementptr inbounds i64, ptr %dst, i64 %iv
; CHECK: LV: Found an estimated cost of 1 for VF 1 For instruction: store i64 %fr, ptr %g.dst, align 8
; CHECK: LV: Found an estimated cost of 1 for VF 1 For instruction: %iv.next = add nuw nsw i64 %iv, 1
@@ -117,7 +117,7 @@ define void @test_vpinstruction_freeze_cost(ptr %src, ptr noalias %dst) {
; CHECK: Cost of 0 for VF 2: CLONE ir<%g.src> = getelementptr inbounds ir<%src>, vp<[[VP4]]>
; CHECK: Cost of 0 for VF 2: vp<[[VP5:%[0-9]+]]> = vector-pointer inbounds ir<%g.src>
; CHECK: Cost of 1 for VF 2: WIDEN ir<%l> = load vp<[[VP5]]>
-; CHECK: Cost of 2 for VF 2: WIDEN ir<%fr> = freeze ir<%l>
+; CHECK: Cost of 0 for VF 2: WIDEN ir<%fr> = freeze ir<%l>
; CHECK: Cost of 0 for VF 2: CLONE ir<%g.dst> = getelementptr inbounds ir<%dst>, vp<[[VP4]]>
; CHECK: Cost of 0 for VF 2: vp<[[VP6:%[0-9]+]]> = vector-pointer inbounds ir<%g.dst>
; CHECK: Cost of 1 for VF 2: WIDEN store vp<[[VP6]]>, ir<%fr>
@@ -142,7 +142,7 @@ define void @test_vpinstruction_freeze_cost(ptr %src, ptr noalias %dst) {
; CHECK: Cost of 0 for VF 4: CLONE ir<%g.src> = getelementptr inbounds ir<%src>, vp<[[VP4]]>
; CHECK: Cost of 0 for VF 4: vp<[[VP5]]> = vector-pointer inbounds ir<%g.src>
; CHECK: Cost of 1 for VF 4: WIDEN ir<%l> = load vp<[[VP5]]>
-; CHECK: Cost of 2 for VF 4: WIDEN ir<%fr> = freeze ir<%l>
+; CHECK: Cost of 0 for VF 4: WIDEN ir<%fr> = freeze ir<%l>
; CHECK: Cost of 0 for VF 4: CLONE ir<%g.dst> = getelementptr inbounds ir<%dst>, vp<[[VP4]]>
; CHECK: Cost of 0 for VF 4: vp<[[VP6]]> = vector-pointer inbounds ir<%g.dst>
; CHECK: Cost of 1 for VF 4: WIDEN store vp<[[VP6]]>, ir<%fr>
More information about the llvm-commits
mailing list