[llvm] Amdgpu resourceusage calledglobal (PR #192195)

via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 14 23:50:15 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-amdgpu

Author: StevenYangCC

<details>
<summary>Changes</summary>

[AMDGPU] Recover direct callees from called globals
    
    Teach resource usage analysis to consult MachineFunction called-global metadata before falling back to the named callee operand so direct calls are not conservatively treated as indirect.

---
Full diff: https://github.com/llvm/llvm-project/pull/192195.diff


2 Files Affected:

- (modified) llvm/lib/Target/AMDGPU/AMDGPUResourceUsageAnalysis.cpp (+16-10) 
- (added) llvm/test/CodeGen/AMDGPU/resource-usage-called-global.mir (+298) 


``````````diff
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUResourceUsageAnalysis.cpp b/llvm/lib/Target/AMDGPU/AMDGPUResourceUsageAnalysis.cpp
index 4e664e084fb88..46e09528b2ada 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUResourceUsageAnalysis.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUResourceUsageAnalysis.cpp
@@ -59,6 +59,21 @@ static const Function *getCalleeFunction(const MachineOperand &Op) {
   return cast<Function>(Op.getGlobal()->stripPointerCastsAndAliases());
 }
 
+static const Function *getCalleeFunction(const MachineFunction &MF,
+                                         const MachineInstr &MI,
+                                         const SIInstrInfo &TII) {
+  if (MachineFunction::CalledGlobalInfo CGI = MF.tryGetCalledGlobal(&MI);
+      CGI.Callee) {
+    if (const auto *F =
+            dyn_cast<Function>(CGI.Callee->stripPointerCastsAndAliases()))
+      return F;
+  }
+
+  const MachineOperand *CalleeOp =
+      TII.getNamedOperand(MI, AMDGPU::OpName::callee);
+  return CalleeOp ? getCalleeFunction(*CalleeOp) : nullptr;
+}
+
 static bool hasAnyNonFlatUseOfReg(const MachineRegisterInfo &MRI,
                                   const SIInstrInfo &TII, unsigned Reg) {
   for (const MachineOperand &UseOp : MRI.reg_operands(Reg)) {
@@ -253,16 +268,7 @@ AMDGPUResourceUsageAnalysisImpl::analyzeResourceUsage(
       }
 
       if (MI.isCall()) {
-        // Pseudo used just to encode the underlying global. Is there a better
-        // way to track this?
-
-        // TODO: Some of the generic call-like pseudos do not encode the callee,
-        // so we overly conservatively treat this as an indirect call.
-        const MachineOperand *CalleeOp =
-            TII->getNamedOperand(MI, AMDGPU::OpName::callee);
-
-        const Function *Callee =
-            CalleeOp ? getCalleeFunction(*CalleeOp) : nullptr;
+        const Function *Callee = getCalleeFunction(MF, MI, *TII);
 
         auto isSameFunction = [](const MachineFunction &MF, const Function *F) {
           return F == &MF.getFunction();
diff --git a/llvm/test/CodeGen/AMDGPU/resource-usage-called-global.mir b/llvm/test/CodeGen/AMDGPU/resource-usage-called-global.mir
new file mode 100644
index 0000000000000..347e8d886aa41
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/resource-usage-called-global.mir
@@ -0,0 +1,298 @@
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -start-after=prologepilog %s -o - | FileCheck %s
+
+--- |
+  ; ModuleID = '/tmp/amdgpu_called_global_regression.ll'
+  source_filename = "/tmp/amdgpu_called_global_regression.ll"
+  target datalayout = "e-m:e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128:128:48-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9"
+  target triple = "amdgcn-amd-amdhsa"
+
+  define void @callee() #0 {
+  entry:
+    call void asm sideeffect "", "~{v0}"()
+    ret void
+  }
+
+  define void @caller() #0 {
+  entry:
+    call void @callee()
+    ret void
+  }
+
+  attributes #0 = { "target-cpu"="gfx900" }
+...
+---
+name:            callee
+alignment:       4
+exposesReturnsTwice: false
+legalized:       false
+regBankSelected: false
+selected:        false
+failedISel:      false
+tracksRegLiveness: true
+hasWinCFI:       false
+noPhis:          true
+isSSA:           false
+noVRegs:         true
+hasFakeUses:     false
+callsEHReturn:   false
+callsUnwindInit: false
+hasEHContTarget: false
+hasEHScopes:     false
+hasEHFunclets:   false
+isOutlined:      false
+debugInstrRef:   false
+failsVerification: false
+tracksDebugUserValues: true
+registers:       []
+liveins:         []
+frameInfo:
+  isFrameAddressTaken: false
+  isReturnAddressTaken: false
+  hasStackMap:     false
+  hasPatchPoint:   false
+  stackSize:       0
+  offsetAdjustment: 0
+  maxAlignment:    1
+  adjustsStack:    false
+  hasCalls:        false
+  stackProtector:  ''
+  functionContext: ''
+  maxCallFrameSize: 0
+  cvBytesOfCalleeSavedRegisters: 0
+  hasOpaqueSPAdjustment: false
+  hasVAStart:      false
+  hasMustTailInVarArgFunc: false
+  hasTailCall:     false
+  isCalleeSavedInfoValid: true
+  localFrameSize:  0
+fixedStack:      []
+stack:           []
+entry_values:    []
+callSites:       []
+debugValueSubstitutions: []
+constants:       []
+machineFunctionInfo:
+  explicitKernArgSize: 0
+  maxKernArgAlign: 1
+  ldsSize:         0
+  gdsSize:         0
+  dynLDSAlign:     1
+  isEntryFunction: false
+  isChainFunction: false
+  memoryBound:     false
+  waveLimiter:     false
+  hasSpilledSGPRs: false
+  hasSpilledVGPRs: false
+  numWaveDispatchSGPRs: 16
+  numWaveDispatchVGPRs: 0
+  scratchRSrcReg:  '$sgpr0_sgpr1_sgpr2_sgpr3'
+  frameOffsetReg:  '$sgpr33'
+  stackPtrOffsetReg: '$sgpr32'
+  bytesInStackArgArea: 0
+  returnsVoid:     true
+  argumentInfo:
+    privateSegmentBuffer: { reg: '$sgpr0_sgpr1_sgpr2_sgpr3' }
+    dispatchPtr:     { reg: '$sgpr4_sgpr5' }
+    queuePtr:        { reg: '$sgpr6_sgpr7' }
+    dispatchID:      { reg: '$sgpr10_sgpr11' }
+    workGroupIDX:    { reg: '$sgpr12' }
+    workGroupIDY:    { reg: '$sgpr13' }
+    workGroupIDZ:    { reg: '$sgpr14' }
+    LDSKernelId:     { reg: '$sgpr15' }
+    implicitArgPtr:  { reg: '$sgpr8_sgpr9' }
+    workItemIDX:     { reg: '$vgpr31', mask: 1023 }
+    workItemIDY:     { reg: '$vgpr31', mask: 1047552 }
+    workItemIDZ:     { reg: '$vgpr31', mask: 1072693248 }
+  psInputAddr:     0
+  psInputEnable:   0
+  maxMemoryClusterDWords: 8
+  mode:
+    ieee:            true
+    dx10-clamp:      true
+    fp32-input-denormals: true
+    fp32-output-denormals: true
+    fp64-fp16-input-denormals: true
+    fp64-fp16-output-denormals: true
+  highBitsOf32BitAddress: 0
+  occupancy:       10
+  vgprForAGPRCopy: ''
+  sgprForEXECCopy: ''
+  longBranchReservedReg: ''
+  hasInitWholeWave: false
+  dynamicVGPRBlockSize: 0
+  scratchReservedForDynamicVGPRs: 0
+  numKernargPreloadSGPRs: 0
+  isWholeWaveFunction: false
+body:             |
+  ; CHECK-LABEL: {{^}}callee:
+  ; CHECK: .set callee.num_vgpr, 1
+  bb.0.entry:
+    INLINEASM &"", 1 /* sideeffect attdialect */, 12 /* clobber */, implicit-def dead early-clobber $vgpr0
+    SI_RETURN
+
+...
+---
+name:            caller
+alignment:       4
+exposesReturnsTwice: false
+legalized:       false
+regBankSelected: false
+selected:        false
+failedISel:      false
+tracksRegLiveness: true
+hasWinCFI:       false
+noPhis:          true
+isSSA:           false
+noVRegs:         true
+hasFakeUses:     false
+callsEHReturn:   false
+callsUnwindInit: false
+hasEHContTarget: false
+hasEHScopes:     false
+hasEHFunclets:   false
+isOutlined:      false
+debugInstrRef:   false
+failsVerification: false
+tracksDebugUserValues: true
+registers:       []
+liveins:
+  - { reg: '$sgpr4_sgpr5', virtual-reg: '' }
+  - { reg: '$sgpr6_sgpr7', virtual-reg: '' }
+  - { reg: '$sgpr8_sgpr9', virtual-reg: '' }
+  - { reg: '$sgpr10_sgpr11', virtual-reg: '' }
+  - { reg: '$sgpr12', virtual-reg: '' }
+  - { reg: '$sgpr13', virtual-reg: '' }
+  - { reg: '$sgpr14', virtual-reg: '' }
+  - { reg: '$sgpr15', virtual-reg: '' }
+  - { reg: '$vgpr31', virtual-reg: '' }
+frameInfo:
+  isFrameAddressTaken: false
+  isReturnAddressTaken: false
+  hasStackMap:     false
+  hasPatchPoint:   false
+  stackSize:       16
+  offsetAdjustment: 0
+  maxAlignment:    4
+  adjustsStack:    true
+  hasCalls:        true
+  stackProtector:  ''
+  functionContext: ''
+  maxCallFrameSize: 0
+  cvBytesOfCalleeSavedRegisters: 0
+  hasOpaqueSPAdjustment: false
+  hasVAStart:      false
+  hasMustTailInVarArgFunc: false
+  hasTailCall:     false
+  isCalleeSavedInfoValid: true
+  localFrameSize:  0
+fixedStack:      []
+stack:
+  - { id: 2, name: '', type: spill-slot, offset: 0, size: 4, alignment: 4,
+      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+  - { id: 3, name: '', type: spill-slot, offset: 0, size: 4, alignment: 4,
+      stack-id: sgpr-spill, callee-saved-register: '', callee-saved-restored: true,
+      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+  - { id: 4, name: '', type: default, offset: 4, size: 4, alignment: 4,
+      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+entry_values:    []
+callSites:       []
+debugValueSubstitutions: []
+constants:       []
+calledGlobals:
+  - { bb: 0, offset: 11, callee: callee, flags: 0 }
+machineFunctionInfo:
+  explicitKernArgSize: 0
+  maxKernArgAlign: 1
+  ldsSize:         0
+  gdsSize:         0
+  dynLDSAlign:     1
+  isEntryFunction: false
+  isChainFunction: false
+  memoryBound:     false
+  waveLimiter:     false
+  hasSpilledSGPRs: true
+  hasSpilledVGPRs: false
+  numWaveDispatchSGPRs: 16
+  numWaveDispatchVGPRs: 0
+  scratchRSrcReg:  '$sgpr0_sgpr1_sgpr2_sgpr3'
+  frameOffsetReg:  '$sgpr33'
+  stackPtrOffsetReg: '$sgpr32'
+  bytesInStackArgArea: 0
+  returnsVoid:     true
+  argumentInfo:
+    privateSegmentBuffer: { reg: '$sgpr0_sgpr1_sgpr2_sgpr3' }
+    dispatchPtr:     { reg: '$sgpr4_sgpr5' }
+    queuePtr:        { reg: '$sgpr6_sgpr7' }
+    dispatchID:      { reg: '$sgpr10_sgpr11' }
+    workGroupIDX:    { reg: '$sgpr12' }
+    workGroupIDY:    { reg: '$sgpr13' }
+    workGroupIDZ:    { reg: '$sgpr14' }
+    LDSKernelId:     { reg: '$sgpr15' }
+    implicitArgPtr:  { reg: '$sgpr8_sgpr9' }
+    workItemIDX:     { reg: '$vgpr31', mask: 1023 }
+    workItemIDY:     { reg: '$vgpr31', mask: 1047552 }
+    workItemIDZ:     { reg: '$vgpr31', mask: 1072693248 }
+  psInputAddr:     0
+  psInputEnable:   0
+  maxMemoryClusterDWords: 8
+  mode:
+    ieee:            true
+    dx10-clamp:      true
+    fp32-input-denormals: true
+    fp32-output-denormals: true
+    fp64-fp16-input-denormals: true
+    fp64-fp16-output-denormals: true
+  highBitsOf32BitAddress: 0
+  occupancy:       10
+  spillPhysVGPRs:
+    - '$vgpr40'
+  wwmReservedRegs:
+    - '$vgpr40'
+  vgprForAGPRCopy: ''
+  sgprForEXECCopy: ''
+  longBranchReservedReg: ''
+  hasInitWholeWave: false
+  dynamicVGPRBlockSize: 0
+  scratchReservedForDynamicVGPRs: 0
+  numKernargPreloadSGPRs: 0
+  isWholeWaveFunction: false
+body:             |
+  ; CHECK-LABEL: {{^}}caller:
+  ; CHECK: .set caller.num_vgpr, max(41, callee.num_vgpr)
+  ; CHECK: .set caller.num_agpr, max(0, callee.num_agpr)
+  ; CHECK: .set caller.numbered_sgpr, max(34, callee.numbered_sgpr)
+  ; CHECK: .set caller.num_named_barrier, max(0, callee.num_named_barrier)
+  ; CHECK: .set caller.private_seg_size, 16+max(callee.private_seg_size)
+  ; CHECK: .set caller.uses_vcc, or(0, callee.uses_vcc)
+  ; CHECK: .set caller.uses_flat_scratch, or(0, callee.uses_flat_scratch)
+  ; CHECK: .set caller.has_dyn_sized_stack, or(0, callee.has_dyn_sized_stack)
+  ; CHECK: .set caller.has_recursion, or(1, callee.has_recursion)
+  ; CHECK: .set caller.has_indirect_call, or(0, callee.has_indirect_call)
+  bb.0.entry:
+    liveins: $sgpr12, $sgpr13, $sgpr14, $sgpr15, $sgpr30, $sgpr31, $vgpr31, $sgpr4_sgpr5, $sgpr6_sgpr7, $sgpr8_sgpr9, $sgpr10_sgpr11
+
+    $sgpr16 = COPY $sgpr33
+    $sgpr33 = frame-setup COPY $sgpr32
+    $sgpr18_sgpr19 = S_OR_SAVEEXEC_B64 -1, implicit-def $exec, implicit-def dead $scc, implicit $exec
+    BUFFER_STORE_DWORD_OFFSET killed $vgpr40, $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr33, 0, 0, 0, implicit $exec :: ("amdgpu-thread-private" store (s32) into %stack.2, addrspace 5)
+    $exec = S_MOV_B64 killed $sgpr18_sgpr19
+    $vgpr40 = SI_SPILL_S32_TO_VGPR $sgpr16, 2, undef $vgpr40
+    $sgpr32 = frame-setup S_ADD_I32 $sgpr32, 1024, implicit-def dead $scc
+    $vgpr40 = SI_SPILL_S32_TO_VGPR killed $sgpr30, 0, $vgpr40
+    $vgpr40 = SI_SPILL_S32_TO_VGPR killed $sgpr31, 1, $vgpr40
+    renamable $sgpr16_sgpr17 = SI_PC_ADD_REL_OFFSET target-flags(amdgpu-gotprel32-lo) @callee, target-flags(amdgpu-gotprel32-hi) @callee, implicit-def dead $scc
+    renamable $sgpr16_sgpr17 = S_LOAD_DWORDX2_IMM killed renamable $sgpr16_sgpr17, 0, 0 :: (dereferenceable invariant load (s64) from got, addrspace 4)
+    dead $sgpr30_sgpr31 = S_SWAPPC_B64 killed renamable $sgpr16_sgpr17
+    $sgpr31 = SI_RESTORE_S32_FROM_VGPR $vgpr40, 1
+    $sgpr30 = SI_RESTORE_S32_FROM_VGPR $vgpr40, 0
+    $sgpr32 = frame-destroy COPY $sgpr33
+    $sgpr4 = SI_RESTORE_S32_FROM_VGPR $vgpr40, 2
+    $sgpr6_sgpr7 = S_OR_SAVEEXEC_B64 -1, implicit-def $exec, implicit-def dead $scc, implicit $exec
+    $vgpr40 = BUFFER_LOAD_DWORD_OFFSET $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr33, 0, 0, 0, implicit $exec :: ("amdgpu-thread-private" load (s32) from %stack.2, addrspace 5)
+    $exec = S_MOV_B64 killed $sgpr6_sgpr7
+    $sgpr33 = COPY $sgpr4
+    SI_RETURN
+
+...

``````````

</details>


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


More information about the llvm-commits mailing list