[llvm] [AMDGPU] Added amdgpu-register-budget attribute to distribute the VGPR and AGPR budget from the kernels to the functions (PR #215705)

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 11 17:45:58 PDT 2026


github-actions[bot] wrote:

<!--LLVM CODE FORMAT COMMENT: {clang-format}-->


:warning: C/C++ code formatter, clang-format found issues in your code. :warning:

<details>
<summary>
You can test this locally with the following command:
</summary>

``````````bash
git-clang-format --diff origin/main HEAD --extensions cpp -- llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp llvm/lib/Target/AMDGPU/GCNSubtarget.cpp --diff_from_common_commit
``````````

:warning:
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing `origin/main` to the base branch/commit you want to compare against.
:warning:

</details>

<details>
<summary>
View the diff from clang-format here.
</summary>

``````````diff
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp b/llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp
index 09405f244..5b9f974e7 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp
@@ -1442,7 +1442,8 @@ struct RegisterBudgetState {
   bool Unknown = true;
 
   bool operator==(const RegisterBudgetState &Other) const {
-    return Unknown == Other.Unknown && VGPRs == Other.VGPRs && AGPRs ==  Other.AGPRs;
+    return Unknown == Other.Unknown && VGPRs == Other.VGPRs &&
+           AGPRs == Other.AGPRs;
   }
   bool operator!=(const RegisterBudgetState &Other) const {
     return !(*this == Other);
@@ -1464,27 +1465,28 @@ struct RegisterBudgetState {
 
 /// An abstract attribute to propagate the register file split a kernel was
 /// compiled with down the call graph to its device functions, emitted as
-/// "amdgpu-register-budget". Entry functions seed the split from their own vector
-/// register budget; every other function inherits the tightest split over its
-/// callers.
+/// "amdgpu-register-budget". Entry functions seed the split from their own
+/// vector register budget; every other function inherits the tightest split
+/// over its callers.
 struct AAAMDGPURegisterBudget
     : public StateWrapper<BooleanState, AbstractAttribute> {
   using Base = StateWrapper<BooleanState, AbstractAttribute>;
   AAAMDGPURegisterBudget(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
 
   static AAAMDGPURegisterBudget &createForPosition(const IRPosition &IRP,
-                                               Attributor &A) {
+                                                   Attributor &A) {
     if (IRP.getPositionKind() == IRPosition::IRP_FUNCTION)
       return *new (A.Allocator) AAAMDGPURegisterBudget(IRP, A);
     llvm_unreachable(
         "AAAMDGPURegisterBudget is only valid for function position");
   }
 
-  // When we known not all callers are known, we know that any unknown caller that reaches
-  // this function will have a pessimistic amdgpu-agpr-alloc attribute. This being pessimistic 
-  // means that the budget for the number of VGPRs and AGPRs will be split in half for the unknown 
-  // caller. We also know that the FlatWorkGroupSize attribute will also be pessimistic for at 
-  // least the current function (the one being called in the indirect callsite)
+  // When we known not all callers are known, we know that any unknown caller
+  // that reaches this function will have a pessimistic amdgpu-agpr-alloc
+  // attribute. This being pessimistic means that the budget for the number of
+  // VGPRs and AGPRs will be split in half for the unknown caller. We also know
+  // that the FlatWorkGroupSize attribute will also be pessimistic for at least
+  // the current function (the one being called in the indirect callsite)
   unsigned computePessimisticValue(Attributor &A) const {
     Function *F = getAssociatedFunction();
     auto &InfoCache = static_cast<AMDGPUInformationCache &>(A.getInfoCache());
@@ -1492,8 +1494,9 @@ struct AAAMDGPURegisterBudget
     unsigned MaxWG = ST.getMaxFlatWorkGroupSize();
     unsigned Occ = std::clamp(ST.getWavesPerEUForWorkGroup(MaxWG), 1u,
                               ST.getMaxWavesPerEU());
-    unsigned Budget = ST.getMaxNumVGPRs(Occ, AMDGPU::getDynamicVGPRBlockSize(*F));
-    return Budget / 2;  // 128/2 == 64 on gfx90a at the max work-group size
+    unsigned Budget =
+        ST.getMaxNumVGPRs(Occ, AMDGPU::getDynamicVGPRBlockSize(*F));
+    return Budget / 2; // 128/2 == 64 on gfx90a at the max work-group size
   }
 
   ChangeStatus updateImpl(Attributor &A) override {
@@ -1514,18 +1517,17 @@ struct AAAMDGPURegisterBudget
       unsigned MaxRegs = ST.getMaxNumVGPRs(*F);
       if (!AGPRAlloc || !AGPRAlloc->isValidState()) {
         VGPRBudget = AGPRBudget = MaxRegs / 2; // pessimistic
-        if(VGPRBudget == computePessimisticValue(A))
+        if (VGPRBudget == computePessimisticValue(A))
           return indicatePessimisticFixpoint();
-      }
-      else
-      {
+      } else {
         AGPRBudget = AGPRAlloc->getAssumed();
         AGPRBudget = alignTo(AGPRBudget, 4);
         VGPRBudget = MaxRegs - std::min(MaxRegs, AGPRBudget);
       }
-        
+
       Budget = {VGPRBudget, AGPRBudget, /*Unknown=*/false};
-      LLVM_DEBUG(dbgs() << "Register budget for " << F->getName() << ": " << VGPRBudget << ", " << AGPRBudget << "\n");
+      LLVM_DEBUG(dbgs() << "Register budget for " << F->getName() << ": "
+                        << VGPRBudget << ", " << AGPRBudget << "\n");
     } else {
       RegisterBudgetState Merged;
 
@@ -1541,17 +1543,19 @@ struct AAAMDGPURegisterBudget
           return true;
         }
         AbstractCallSite ACS(&U);
-        const Use *EffectiveUse = ACS && ACS.isCallbackCall() ? &ACS.getCalleeUseForCallback() : &U;
-        if(!ACS || !ACS.isCallee(EffectiveUse)) 
+        const Use *EffectiveUse =
+            ACS && ACS.isCallbackCall() ? &ACS.getCalleeUseForCallback() : &U;
+        if (!ACS || !ACS.isCallee(EffectiveUse))
           return true;
 
         Function *Caller = ACS.getInstruction()->getFunction();
-        const auto *CallerAA = A.getAAFor<AAAMDGPURegisterBudget>(*this, IRPosition::function(*Caller), DepClassTy::REQUIRED);
-        if(!CallerAA || !CallerAA->isValidState())
+        const auto *CallerAA = A.getAAFor<AAAMDGPURegisterBudget>(
+            *this, IRPosition::function(*Caller), DepClassTy::REQUIRED);
+        if (!CallerAA || !CallerAA->isValidState())
           return true;
 
         const RegisterBudgetState &CallerBudget = CallerAA->getBudget();
-        if(!CallerBudget.Unknown)
+        if (!CallerBudget.Unknown)
           Merged.merge(CallerBudget);
         return true;
       };
@@ -1560,11 +1564,15 @@ struct AAAMDGPURegisterBudget
 
       // Checks for unknown call sites.
       bool DummyUAI = false;
-      bool AllCallsitesKnown = A.checkForAllCallSites([](AbstractCallSite) { return true; }, *this, true, DummyUAI);
+      bool AllCallsitesKnown = A.checkForAllCallSites(
+          [](AbstractCallSite) { return true; }, *this, true, DummyUAI);
       if (!AllCallsitesKnown && !Merged.Unknown) {
-        if (std::optional<unsigned> PessimisticValue = computePessimisticValue(A)) {
-          Merged.merge({*PessimisticValue, *PessimisticValue, /*Unknown=*/false});
-        } else return indicatePessimisticFixpoint();
+        if (std::optional<unsigned> PessimisticValue =
+                computePessimisticValue(A)) {
+          Merged.merge(
+              {*PessimisticValue, *PessimisticValue, /*Unknown=*/false});
+        } else
+          return indicatePessimisticFixpoint();
       }
       // Stays unknown when no caller contributed a budget, so that functions
       // outside any kernel's reach are left unconstrained.
diff --git a/llvm/lib/Target/AMDGPU/GCNSubtarget.cpp b/llvm/lib/Target/AMDGPU/GCNSubtarget.cpp
index f6e56a9c7..e14ac289c 100644
--- a/llvm/lib/Target/AMDGPU/GCNSubtarget.cpp
+++ b/llvm/lib/Target/AMDGPU/GCNSubtarget.cpp
@@ -675,11 +675,13 @@ GCNSubtarget::getMaxNumVectorRegs(const Function &F) const {
     std::tie(MinNumAGPRs, MaxNumAGPRs) =
         AMDGPU::getIntegerPairAttribute(F, "amdgpu-agpr-alloc", DefaultNumAGPR,
                                         /*OnlyFirstRequired=*/true);
-    std::tie(VGPRCap, AGPRCap) =
-        AMDGPU::getIntegerPairAttribute(F, "amdgpu-register-budget", DefaultRegisterBudget,
-                                        /*OnlyFirstRequired=*/false);
-    
-    if (MinNumAGPRs == DefaultNumAGPR.first || (VGPRCap == DefaultRegisterBudget.first && !AMDGPU::isEntryFunctionCC(F.getCallingConv()))) {
+    std::tie(VGPRCap, AGPRCap) = AMDGPU::getIntegerPairAttribute(
+        F, "amdgpu-register-budget", DefaultRegisterBudget,
+        /*OnlyFirstRequired=*/false);
+
+    if (MinNumAGPRs == DefaultNumAGPR.first ||
+        (VGPRCap == DefaultRegisterBudget.first &&
+         !AMDGPU::isEntryFunctionCC(F.getCallingConv()))) {
       MinNumAGPRs = MaxNumAGPRs = MaxVectorRegs / 2;
     } else {
       // Align to accum_offset's allocation granularity.
@@ -692,7 +694,8 @@ GCNSubtarget::getMaxNumVectorRegs(const Function &F) const {
     MaxNumAGPRs = std::min(std::max(MinNumAGPRs, MaxNumAGPRs), MaxVectorRegs);
     MinNumAGPRs = std::min({MinNumAGPRs, TotalNumAGPRs, MaxNumAGPRs});
 
-    MaxNumVGPRs = std::min({MaxVectorRegs - MinNumAGPRs, NumArchVGPRs, VGPRCap});
+    MaxNumVGPRs =
+        std::min({MaxVectorRegs - MinNumAGPRs, NumArchVGPRs, VGPRCap});
     MaxNumAGPRs = std::min({MaxVectorRegs - MaxNumVGPRs, MaxNumAGPRs, AGPRCap});
 
     LLVM_DEBUG(dbgs() << "MaxNumVGPRs: " << MaxNumVGPRs << ", MaxNumAGPRs: "

``````````

</details>


https://github.com/llvm/llvm-project/pull/215705


More information about the llvm-commits mailing list