[llvm-branch-commits] [llvm] [LV][REVEC] Correctly compute register usage (PR #213987)

Gaƫtan Bossu via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Aug 5 03:04:12 PDT 2026


https://github.com/gbossu updated https://github.com/llvm/llvm-project/pull/213987

>From 40338c54ed0cea71df1ba3ea5f37f30cdd570bb3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABtan=20Bossu?= <gaetan.bossu at arm.com>
Date: Tue, 4 Aug 2026 15:01:21 +0000
Subject: [PATCH] [LV][REVEC] Correctly compute register usage

For REVEC, the initial types might already be vectors, so make sure the
right register class is picked.
---
 .../Transforms/Vectorize/VPlanAnalysis.cpp    | 29 ++++++++------
 .../LoopVectorize/revec-reg-usage.ll          | 39 +++++++++++++++++++
 2 files changed, 56 insertions(+), 12 deletions(-)
 create mode 100644 llvm/test/Transforms/LoopVectorize/revec-reg-usage.ll

diff --git a/llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp b/llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp
index 77a33339eb5f9..969be883e353d 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp
@@ -189,11 +189,12 @@ SmallVector<VPRegisterUsage, 8> llvm::calculateRegisterUsageForPlan(
 
   const auto &TTICapture = TTI;
   auto GetRegUsage = [&TTICapture](Type *Ty, ElementCount VF) -> unsigned {
-    if (Ty->isTokenTy() || !VectorType::isValidElementType(Ty) ||
+    Type *EltTy = Ty->getScalarType();
+    if (Ty->isTokenTy() || !VectorType::isValidElementType(EltTy) ||
         (VF.isScalable() &&
-         !TTICapture.isElementTypeLegalForScalableVector(Ty)))
+         !TTICapture.isElementTypeLegalForScalableVector(EltTy)))
       return 0;
-    return TTICapture.getRegUsageForType(VectorType::get(Ty, VF));
+    return TTICapture.getRegUsageForType(toVectorTy(Ty, VF));
   };
 
   VPValue *CanIV = LoopRegion->getCanonicalIV();
@@ -248,6 +249,10 @@ SmallVector<VPRegisterUsage, 8> llvm::calculateRegisterUsageForPlan(
             match(VPV, m_ExtractLastPart(m_VPValue())))
           continue;
 
+        // For REVEC, the initial type might be a vector.
+        Type *InitialTy = VPV->getScalarType();
+        Type *EltTy = InitialTy->getScalarType();
+
         if (VFs[J].isScalar() ||
             isa<VPRegionValue, VPReplicateRecipe, VPDerivedIVRecipe,
                 VPCurrentIterationPHIRecipe, VPScalarIVStepsRecipe>(VPV) ||
@@ -255,7 +260,7 @@ SmallVector<VPRegisterUsage, 8> llvm::calculateRegisterUsageForPlan(
             (isa<VPReductionPHIRecipe>(VPV) &&
              (cast<VPReductionPHIRecipe>(VPV))->isInLoop())) {
           unsigned ClassID =
-              TTI.getRegisterClassForType(false, VPV->getScalarType());
+              TTI.getRegisterClassForType(InitialTy->isVectorTy(), EltTy);
           // FIXME: The target might use more than one register for the type
           // even in the scalar case.
           RegUsage[ClassID] += 1;
@@ -271,9 +276,8 @@ SmallVector<VPRegisterUsage, 8> llvm::calculateRegisterUsageForPlan(
                               << " to " << VF << " for " << *R << "\n";);
           }
 
-          Type *ScalarTy = VPV->getScalarType();
-          unsigned ClassID = TTI.getRegisterClassForType(true, ScalarTy);
-          RegUsage[ClassID] += GetRegUsage(ScalarTy, VF);
+          unsigned ClassID = TTI.getRegisterClassForType(true, EltTy);
+          RegUsage[ClassID] += GetRegUsage(InitialTy, VF);
         }
       }
 
@@ -307,12 +311,13 @@ SmallVector<VPRegisterUsage, 8> llvm::calculateRegisterUsageForPlan(
     for (auto *In : LoopInvariants) {
       // FIXME: The target might use more than one register for the type
       // even in the scalar case.
-      bool IsScalar = vputils::onlyScalarValuesUsed(In);
+      bool OnlyFirstLane = vputils::onlyScalarValuesUsed(In);
+      Type *InitialTy = In->getScalarType();
 
-      ElementCount VF = IsScalar ? ElementCount::getFixed(1) : VFs[Idx];
-      unsigned ClassID =
-          TTI.getRegisterClassForType(VF.isVector(), In->getScalarType());
-      Invariant[ClassID] += GetRegUsage(In->getScalarType(), VF);
+      ElementCount VF = OnlyFirstLane ? ElementCount::getFixed(1) : VFs[Idx];
+      unsigned ClassID = TTI.getRegisterClassForType(
+          VF.isVector() || InitialTy->isVectorTy(), InitialTy->getScalarType());
+      Invariant[ClassID] += GetRegUsage(InitialTy, VF);
     }
 
     LLVM_DEBUG({
diff --git a/llvm/test/Transforms/LoopVectorize/revec-reg-usage.ll b/llvm/test/Transforms/LoopVectorize/revec-reg-usage.ll
new file mode 100644
index 0000000000000..89f6c3969bf3c
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/revec-reg-usage.ll
@@ -0,0 +1,39 @@
+; REQUIRES: asserts
+; RUN: opt -disable-output -passes=loop-vectorize -vectorize-vector-loops \
+; RUN:     -force-vector-width=1 -debug-only=vplan < %s 2>&1 \
+; RUN:     | FileCheck %s
+; RUN: opt -disable-output -passes=loop-vectorize -vectorize-vector-loops \
+; RUN:     -force-vector-width="vscale x 1" -debug-only=vplan < %s 2>&1 \
+; RUN:     | FileCheck %s
+
+; When re-vectorising with VF = vscale x 1, the number of used registers is
+; expected to remain the same, as we are turning fixed vectors into scalable
+; ones and they belong to the same class according to the generic getRegisterClassForType.
+
+; CHECK:      LV(REG): Found max usage: 2 item
+; CHECK-NEXT: LV(REG): RegisterClass: Generic::ScalarRC, 3 registers
+; CHECK-NEXT: LV(REG): RegisterClass: Generic::VectorRC, 2 registers
+; CHECK-NEXT: LV(REG): Found invariant usage: 2 item
+; CHECK-NEXT: LV(REG): RegisterClass: Generic::ScalarRC, 1 registers
+; CHECK-NEXT: LV(REG): RegisterClass: Generic::VectorRC, 1 registers
+define void @register_usage(ptr noalias %dst, ptr noalias %src,
+                            ptr noalias %threshold.ptr, i64 %n) {
+entry:
+  %threshold = load <4 x i32>, ptr %threshold.ptr, align 16
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+  %src.gep = getelementptr inbounds <4 x i32>, ptr %src, i64 %iv
+  %dst.gep = getelementptr inbounds <4 x i32>, ptr %dst, i64 %iv
+  %v = load <4 x i32>, ptr %src.gep, align 16
+  %cmp = icmp sgt <4 x i32> %v, %threshold
+  %sel = select <4 x i1> %cmp, <4 x i32> %v, <4 x i32> %threshold
+  store <4 x i32> %sel, ptr %dst.gep, align 16
+  %iv.next = add nuw i64 %iv, 1
+  %done = icmp eq i64 %iv.next, %n
+  br i1 %done, label %exit, label %loop
+
+exit:
+  ret void
+}



More information about the llvm-branch-commits mailing list