[llvm-branch-commits] [llvm] AMDGPU: Don't include stack size of chain callees (PR #234520)

Diana Picus via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Oct 22 01:00:30 PDT 2026


https://github.com/rovka created https://github.com/llvm/llvm-project/pull/234520

Chain callees are always tail called into and overwrite the caller's
stack. Therefore, their stack size should not be added up to that of
their caller when computing the resource usage.

Assisted-by: AI

>From 56b4538ca6c52f884c3d78a94c2c88034d338407 Mon Sep 17 00:00:00 2001
From: Diana Picus <diana-magda.picus at amd.com>
Date: Tue, 13 Oct 2026 14:34:22 +0200
Subject: [PATCH 1/2] AMDGPU: Precommit testcases for stack metadata. NFC

---
 .../CodeGen/AMDGPU/amdpal-chain-metadata.ll   | 123 +++++++++++++++++-
 1 file changed, 119 insertions(+), 4 deletions(-)

diff --git a/llvm/test/CodeGen/AMDGPU/amdpal-chain-metadata.ll b/llvm/test/CodeGen/AMDGPU/amdpal-chain-metadata.ll
index 8716b81d952992..4f3d1e0bdcbbd7 100644
--- a/llvm/test/CodeGen/AMDGPU/amdpal-chain-metadata.ll
+++ b/llvm/test/CodeGen/AMDGPU/amdpal-chain-metadata.ll
@@ -1,16 +1,63 @@
 ; RUN: llc -mtriple=amdgpu11.00--amdpal <%s | FileCheck %s
 
 ; CHECK-LABEL: {{^}}amdgpu_cs_chain_func:
-; CHECK:           .amdgpu_pal_metadata
+; CHECK:         .set .Lamdgpu_cs_chain_func.private_seg_size, 16{{$}}
+
+; CHECK-LABEL: {{^}}chain_callee_smaller_stack:
+; CHECK:         .set .Lchain_callee_smaller_stack.private_seg_size, 36+max(.Lamdgpu_cs_chain_func.private_seg_size){{$}}
+
+; CHECK-LABEL: {{^}}chain_callee_larger_stack:
+; CHECK:         .set .Lchain_callee_larger_stack.private_seg_size, 8+max(.Lamdgpu_cs_chain_func.private_seg_size){{$}}
+
+; CHECK-LABEL: {{^}}chain_and_wwf:
+; CHECK:         .set .Lchain_and_wwf.private_seg_size, 80+max(.Lwwf_alloca.private_seg_size, .Lamdgpu_cs_chain_func.private_seg_size){{$}}
+
+; CHECK-LABEL: {{^}}wwf_alloca:
+; CHECK:         .set .Lwwf_alloca.private_seg_size, 28{{$}}
+
+; CHECK-LABEL: {{^}}gfx_alloca:
+; CHECK:         .set .Lgfx_alloca.private_seg_size, 28{{$}}
+
+; CHECK-LABEL: {{^}}chain_and_gfx:
+; CHECK:         .set .Lchain_and_gfx.private_seg_size, 32+max(.Lgfx_alloca.private_seg_size, .Lamdgpu_cs_chain_func.private_seg_size){{$}}
+
+; CHECK-LABEL: {{^}}cs_to_chain_and_wwf:
+; CHECK:         .set .Lcs_to_chain_and_wwf.private_seg_size, 12+max(.Lchain_and_wwf.private_seg_size){{$}}
+
+; CHECK-LABEL: {{^}}chain_indirect_and_wwf:
+; CHECK:         .set .Lchain_indirect_and_wwf.private_seg_size, 64+max(.Lwwf_alloca.private_seg_size){{$}}
+; CHECK:         .set .Lchain_indirect_and_wwf.has_indirect_call, 1{{$}}
+
+; CHECK-LABEL: .amdgpu_pal_metadata
 ; CHECK-NEXT: ---
 ; CHECK-NEXT: amdpal.pipelines:
 ; CHECK-NEXT:   - .api:            Vulkan
+; CHECK-LABEL:         .hardware_stages:
+; CHECK:      .cs:
+; CHECK:             .entry_point_symbol: cs_to_chain_and_wwf
+; CHECK:             .scratch_memory_size: 0x80{{$}}
 ; CHECK:         .shader_functions:
-; CHECK-NEXT:      amdgpu_cs_chain_func:
+; CHECK-LABEL:      amdgpu_cs_chain_func:
 ; CHECK:             .backend_stack_size: 0x10{{$}}
 ; CHECK:             .stack_frame_size_in_bytes: 0x10{{$}}
-; CHECK-NEXT:            .vgpr_count:
-; CHECK-NEXT:    .shaders:
+; CHECK-LABEL:      chain_and_gfx:
+; CHECK:             .backend_stack_size: 0x20{{$}}
+; CHECK:             .stack_frame_size_in_bytes: 0x20{{$}}
+; CHECK-LABEL:      chain_and_wwf:
+; CHECK:             .backend_stack_size: 0x50{{$}}
+; CHECK:             .stack_frame_size_in_bytes: 0x50{{$}}
+; CHECK-LABEL:      chain_callee_larger_stack:
+; CHECK:             .backend_stack_size: 0x8{{$}}
+; CHECK:             .stack_frame_size_in_bytes: 0x8{{$}}
+; CHECK-LABEL:      chain_callee_smaller_stack:
+; CHECK:             .backend_stack_size: 0x24{{$}}
+; CHECK:             .stack_frame_size_in_bytes: 0x24{{$}}
+; CHECK-LABEL:      chain_indirect_and_wwf:
+; CHECK:             .backend_stack_size: 0x40{{$}}
+; CHECK:             .stack_frame_size_in_bytes: 0x40{{$}}
+; CHECK-LABEL:      gfx_alloca:
+; CHECK:             .backend_stack_size: 0x1c{{$}}
+; CHECK:             .stack_frame_size_in_bytes: 0x1c{{$}}
 ; CHECK:amdpal.version:
 ; CHECK-NEXT:  - 0x3
 ; CHECK-NEXT:  - 0
@@ -25,11 +72,79 @@ define amdgpu_cs_chain void @amdgpu_cs_chain_func(<40 x i32> %should_spill) {
   ret void
 }
 
+define amdgpu_cs_chain void @chain_callee_smaller_stack(<40 x i32> %v) {
+.entry:
+  %a = alloca [8 x i32], addrspace(5)
+  store volatile i32 1, ptr addrspace(5) %a
+  call void (ptr, i32, {}, <40 x i32>, i32, ...) @llvm.amdgcn.cs.chain.p0.i32.s.v40i32(ptr @amdgpu_cs_chain_func, i32 -1, {} inreg poison, <40 x i32> %v, i32 0)
+  unreachable
+}
+
+define amdgpu_cs_chain void @chain_callee_larger_stack(<40 x i32> %v) {
+.entry:
+  %a = alloca [1 x i32], addrspace(5)
+  store volatile i32 1, ptr addrspace(5) %a
+  call void (ptr, i32, {}, <40 x i32>, i32, ...) @llvm.amdgcn.cs.chain.p0.i32.s.v40i32(ptr @amdgpu_cs_chain_func, i32 -1, {} inreg poison, <40 x i32> %v, i32 0)
+  unreachable
+}
+
+define amdgpu_cs_chain void @chain_and_wwf(<40 x i32> %v) {
+.entry:
+  %a = alloca [16 x i32], addrspace(5)
+  store i32 2, ptr addrspace(5) %a
+  call void (ptr, ...) @llvm.amdgcn.call.whole.wave(ptr @wwf_alloca, ptr addrspace(5) %a)
+  call void (ptr, i32, {}, <40 x i32>, i32, ...) @llvm.amdgcn.cs.chain.p0.i32.s.v40i32(ptr @amdgpu_cs_chain_func, i32 -1, {} inreg poison, <40 x i32> %v, i32 0)
+  unreachable
+}
+
+define amdgpu_gfx_whole_wave void @wwf_alloca(i1 %active, ptr addrspace(5) %p) {
+  %a = alloca [4 x i32], addrspace(5)
+  store volatile i32 3, ptr addrspace(5) %a
+  store i32 4, ptr addrspace(5) %p
+  ret void
+}
+
+define amdgpu_cs_chain void @chain_and_gfx(<40 x i32> %v) {
+.entry:
+  %a = alloca [4 x i32], addrspace(5)
+  store i32 6, ptr addrspace(5) %a
+  call amdgpu_gfx void @gfx_alloca(ptr addrspace(5) %a)
+  call void (ptr, i32, {}, <40 x i32>, i32, ...) @llvm.amdgcn.cs.chain.p0.i32.s.v40i32(ptr @amdgpu_cs_chain_func, i32 -1, {} inreg poison, <40 x i32> %v, i32 0)
+  unreachable
+}
+
+define amdgpu_gfx void @gfx_alloca(ptr addrspace(5) %p) {
+  %a = alloca [6 x i32], addrspace(5)
+  store volatile i32 7, ptr addrspace(5) %a
+  store i32 8, ptr addrspace(5) %p
+  ret void
+}
+
+define amdgpu_cs void @cs_to_chain_and_wwf(<40 x i32> %v) {
+.entry:
+  %a = alloca [2 x i32], addrspace(5)
+  store volatile i32 9, ptr addrspace(5) %a
+  call void (ptr, i32, {}, <40 x i32>, i32, ...) @llvm.amdgcn.cs.chain.p0.i32.s.v40i32(ptr @chain_and_wwf, i32 -1, {} inreg poison, <40 x i32> %v, i32 0)
+  unreachable
+}
+
+define amdgpu_cs_chain void @chain_indirect_and_wwf(ptr inreg %callee, <40 x i32> %v) {
+.entry:
+  %a = alloca [12 x i32], addrspace(5)
+  store i32 10, ptr addrspace(5) %a
+  call void (ptr, ...) @llvm.amdgcn.call.whole.wave(ptr @wwf_alloca, ptr addrspace(5) %a)
+  call void (ptr, i32, {}, <40 x i32>, i32, ...) @llvm.amdgcn.cs.chain.p0.i32.s.v40i32(ptr %callee, i32 -1, {} inreg poison, <40 x i32> %v, i32 0)
+  unreachable
+}
+
 define amdgpu_cs_chain_preserve void @amdgpu_cs_chain_preserve_func() {
 .entry:
   ret void
 }
 
+declare void @llvm.amdgcn.call.whole.wave(ptr, ...)
+declare void @llvm.amdgcn.cs.chain.p0.i32.s.v40i32(ptr, i32, {}, <40 x i32>, i32 immarg, ...)
+
 declare amdgpu_gfx void @use(...)
 
 !amdgpu.pal.metadata.msgpack = !{!0}

>From 0cbd5d08f9f90b37e3222e478dba9327e14b8a3d Mon Sep 17 00:00:00 2001
From: Diana Picus <diana-magda.picus at amd.com>
Date: Tue, 13 Oct 2026 14:55:28 +0200
Subject: [PATCH 2/2] AMDGPU: Don't include stack size of chain callees

Chain callees are always tail called into and overwrite the caller's
stack. Therefore, their stack size should not be added up to that of
their caller when computing the resource usage.

Assisted-by: AI
---
 llvm/lib/Target/AMDGPU/AMDGPUMCResourceInfo.cpp      |  5 ++++-
 .../Target/AMDGPU/AMDGPUResourceUsageAnalysis.cpp    |  8 +++++---
 llvm/test/CodeGen/AMDGPU/amdpal-chain-metadata.ll    | 12 ++++++------
 3 files changed, 15 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/AMDGPUMCResourceInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPUMCResourceInfo.cpp
index 1731b0463a0991..a33a1d3c8fc05a 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUMCResourceInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUMCResourceInfo.cpp
@@ -371,7 +371,10 @@ void MCResourceInfo::gatherResourceInfo(
     for (const Function *Callee : FRI.Callees) {
       if (!Seen.insert(Callee).second)
         continue;
-      if (!Callee->isDeclaration()) {
+
+      // Chain callees use the same stack frame. Exclude them.
+      if (!Callee->isDeclaration() &&
+          !AMDGPU::isChainCC(Callee->getCallingConv())) {
         MCSymbol *CalleeFnSym = TM.getSymbol(&Callee->getFunction());
         MCSymbol *CalleeValSym =
             getSymbol(CalleeFnSym->getName(), RIK_PrivateSegSize, OutContext);
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUResourceUsageAnalysis.cpp b/llvm/lib/Target/AMDGPU/AMDGPUResourceUsageAnalysis.cpp
index aab43f23cf6065..c2077e940ed3e3 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUResourceUsageAnalysis.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUResourceUsageAnalysis.cpp
@@ -306,9 +306,11 @@ AMDGPUResourceUsageAnalysisImpl::analyzeResourceUsage(
         }
 
         if (IsIndirect) {
-          Info.CalleeSegmentSize =
-              std::max(Info.CalleeSegmentSize,
-                       static_cast<uint64_t>(AssumedStackSizeForExternalCall));
+          // Chain callees use the same stack frame. Exclude them.
+          if (!IsChainCall)
+            Info.CalleeSegmentSize = std::max(
+                Info.CalleeSegmentSize,
+                static_cast<uint64_t>(AssumedStackSizeForExternalCall));
 
           // Register usage of indirect calls gets handled later
           Info.UsesVCC = true;
diff --git a/llvm/test/CodeGen/AMDGPU/amdpal-chain-metadata.ll b/llvm/test/CodeGen/AMDGPU/amdpal-chain-metadata.ll
index 4f3d1e0bdcbbd7..d972dd7884902e 100644
--- a/llvm/test/CodeGen/AMDGPU/amdpal-chain-metadata.ll
+++ b/llvm/test/CodeGen/AMDGPU/amdpal-chain-metadata.ll
@@ -4,13 +4,13 @@
 ; CHECK:         .set .Lamdgpu_cs_chain_func.private_seg_size, 16{{$}}
 
 ; CHECK-LABEL: {{^}}chain_callee_smaller_stack:
-; CHECK:         .set .Lchain_callee_smaller_stack.private_seg_size, 36+max(.Lamdgpu_cs_chain_func.private_seg_size){{$}}
+; CHECK:         .set .Lchain_callee_smaller_stack.private_seg_size, 36{{$}}
 
 ; CHECK-LABEL: {{^}}chain_callee_larger_stack:
-; CHECK:         .set .Lchain_callee_larger_stack.private_seg_size, 8+max(.Lamdgpu_cs_chain_func.private_seg_size){{$}}
+; CHECK:         .set .Lchain_callee_larger_stack.private_seg_size, 8{{$}}
 
 ; CHECK-LABEL: {{^}}chain_and_wwf:
-; CHECK:         .set .Lchain_and_wwf.private_seg_size, 80+max(.Lwwf_alloca.private_seg_size, .Lamdgpu_cs_chain_func.private_seg_size){{$}}
+; CHECK:         .set .Lchain_and_wwf.private_seg_size, 80+max(.Lwwf_alloca.private_seg_size){{$}}
 
 ; CHECK-LABEL: {{^}}wwf_alloca:
 ; CHECK:         .set .Lwwf_alloca.private_seg_size, 28{{$}}
@@ -19,10 +19,10 @@
 ; CHECK:         .set .Lgfx_alloca.private_seg_size, 28{{$}}
 
 ; CHECK-LABEL: {{^}}chain_and_gfx:
-; CHECK:         .set .Lchain_and_gfx.private_seg_size, 32+max(.Lgfx_alloca.private_seg_size, .Lamdgpu_cs_chain_func.private_seg_size){{$}}
+; CHECK:         .set .Lchain_and_gfx.private_seg_size, 32+max(.Lgfx_alloca.private_seg_size){{$}}
 
 ; CHECK-LABEL: {{^}}cs_to_chain_and_wwf:
-; CHECK:         .set .Lcs_to_chain_and_wwf.private_seg_size, 12+max(.Lchain_and_wwf.private_seg_size){{$}}
+; CHECK:         .set .Lcs_to_chain_and_wwf.private_seg_size, 12{{$}}
 
 ; CHECK-LABEL: {{^}}chain_indirect_and_wwf:
 ; CHECK:         .set .Lchain_indirect_and_wwf.private_seg_size, 64+max(.Lwwf_alloca.private_seg_size){{$}}
@@ -35,7 +35,7 @@
 ; CHECK-LABEL:         .hardware_stages:
 ; CHECK:      .cs:
 ; CHECK:             .entry_point_symbol: cs_to_chain_and_wwf
-; CHECK:             .scratch_memory_size: 0x80{{$}}
+; CHECK:             .scratch_memory_size: 0x10{{$}}
 ; CHECK:         .shader_functions:
 ; CHECK-LABEL:      amdgpu_cs_chain_func:
 ; CHECK:             .backend_stack_size: 0x10{{$}}



More information about the llvm-branch-commits mailing list