[llvm] a31c941 - [AMDGPU] Support global address in V/S_MOV_B64 lowering (#203527)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 14 02:00:37 PDT 2026


Author: David Stuttard
Date: 2026-07-14T11:00:33+02:00
New Revision: a31c941fa7fd9eaea855cff3bb40347c0d22243d

URL: https://github.com/llvm/llvm-project/commit/a31c941fa7fd9eaea855cff3bb40347c0d22243d
DIFF: https://github.com/llvm/llvm-project/commit/a31c941fa7fd9eaea855cff3bb40347c0d22243d.diff

LOG: [AMDGPU] Support global address in V/S_MOV_B64 lowering (#203527)

Hit an issue where V_MOV_B64_PSEUDO had a global, which wasn't
previously handled.
Added support for this, and also for the S_MOV_B64_IMM_PSEUDO to make it
symmetrical.

Claude has been used for this commit, primarily assisting creating a
test.

Added: 
    llvm/test/CodeGen/AMDGPU/expand-mov-b64-globaladdr-hsa.ll
    llvm/test/CodeGen/AMDGPU/expand-mov-b64-globaladdr-rel32.mir
    llvm/test/CodeGen/AMDGPU/expand-mov-b64-globaladdr.ll

Modified: 
    llvm/lib/Target/AMDGPU/SIInstrInfo.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
index 81b7bf7f769ad..66e252a461cd3 100644
--- a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
@@ -35,6 +35,7 @@
 #include "llvm/MC/MCContext.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Target/TargetMachine.h"
+#include <tuple>
 
 using namespace llvm;
 
@@ -126,6 +127,39 @@ static bool canRemat(const MachineInstr &MI) {
   return false;
 }
 
+// Split relocation flags for 64-bit global-address materialization into a
+// common base and the hi/lo relocation variants.
+static std::tuple<unsigned, unsigned, unsigned>
+splitGlobalAddressRelocFlags(const GCNSubtarget &ST,
+                             const MachineOperand &SrcOp) {
+  unsigned SrcFlags = SrcOp.getTargetFlags();
+
+  // Infer the relocation type from the existing flags on the global operand.
+  // The relocation type should have been determined earlier in the pipeline.
+  unsigned LoReloc = SIInstrInfo::MO_ABS32_LO;
+  unsigned HiReloc = SIInstrInfo::MO_ABS32_HI;
+
+  if (SrcFlags & SIInstrInfo::MO_REL32) {
+    LoReloc = SIInstrInfo::MO_REL32_LO;
+    HiReloc = SIInstrInfo::MO_REL32_HI;
+  } else if (SrcFlags & SIInstrInfo::MO_GOTPCREL32_LO) {
+    LoReloc = SIInstrInfo::MO_GOTPCREL32_LO;
+    HiReloc = SIInstrInfo::MO_GOTPCREL32_HI;
+  } else if (SrcFlags & SIInstrInfo::MO_GOTPCREL64) {
+    // For 64-bit GOT-relative, use the 64-bit relocation.
+    LoReloc = SIInstrInfo::MO_GOTPCREL64;
+    HiReloc = SIInstrInfo::MO_GOTPCREL64;
+  }
+
+  unsigned BaseFlags =
+      SrcFlags & ~(SIInstrInfo::MO_ABS32_LO | SIInstrInfo::MO_ABS32_HI |
+                   SIInstrInfo::MO_REL32_LO | SIInstrInfo::MO_REL32_HI |
+                   SIInstrInfo::MO_GOTPCREL32_LO |
+                   SIInstrInfo::MO_GOTPCREL32_HI | SIInstrInfo::MO_GOTPCREL64);
+
+  return std::make_tuple(BaseFlags, LoReloc, HiReloc);
+}
+
 bool SIInstrInfo::isReMaterializableImpl(
     const MachineInstr &MI) const {
 
@@ -1913,6 +1947,7 @@ bool SIInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
   MachineBasicBlock &MBB = *MI.getParent();
   DebugLoc DL = MBB.findDebugLoc(MI);
   const AMDGPU::LaneMaskConstants &LMC = AMDGPU::LaneMaskConstants::get(ST);
+
   switch (MI.getOpcode()) {
   default: return TargetInstrInfo::expandPostRAPseudo(MI);
   case AMDGPU::S_MOV_B64_term:
@@ -2037,10 +2072,25 @@ bool SIInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
     if (ST.hasVMovB64Inst() && Mov64RC->contains(Dst)) {
       MI.setDesc(Mov64Desc);
       if (SrcOp.isReg() || isInlineConstant(MI, 1) ||
-          isUInt<32>(SrcOp.getImm()) || ST.has64BitLiterals())
+          (SrcOp.isImm() &&
+           (isUInt<32>(SrcOp.getImm()) || ST.has64BitLiterals())) ||
+          (SrcOp.isGlobal() && ST.has64BitLiterals()))
         break;
     }
-    if (SrcOp.isImm()) {
+    if (SrcOp.isGlobal()) {
+      // The address is unknown until link time, so the PK_MOV inline-constant
+      // shortcut cannot apply.
+      const GlobalValue *GV = SrcOp.getGlobal();
+      int64_t Offset = SrcOp.getOffset();
+      unsigned BaseFlags, LoReloc, HiReloc;
+      std::tie(BaseFlags, LoReloc, HiReloc) =
+          splitGlobalAddressRelocFlags(ST, SrcOp);
+
+      BuildMI(MBB, MI, DL, get(AMDGPU::V_MOV_B32_e32), DstLo)
+          .addGlobalAddress(GV, Offset, BaseFlags | LoReloc);
+      BuildMI(MBB, MI, DL, get(AMDGPU::V_MOV_B32_e32), DstHi)
+          .addGlobalAddress(GV, Offset, BaseFlags | HiReloc);
+    } else if (SrcOp.isImm()) {
       APInt Imm(64, SrcOp.getImm());
       APInt Lo(32, Imm.getLoBits(32).getZExtValue());
       APInt Hi(32, Imm.getHiBits(32).getZExtValue());
@@ -2102,6 +2152,25 @@ bool SIInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
       break;
     }
 
+    if (SrcOp.isGlobal()) {
+      Register Dst = MI.getOperand(0).getReg();
+      Register DstLo = RI.getSubReg(Dst, AMDGPU::sub0);
+      Register DstHi = RI.getSubReg(Dst, AMDGPU::sub1);
+      const GlobalValue *GV = SrcOp.getGlobal();
+      int64_t Offset = SrcOp.getOffset();
+      unsigned BaseFlags, LoReloc, HiReloc;
+      std::tie(BaseFlags, LoReloc, HiReloc) =
+          splitGlobalAddressRelocFlags(ST, SrcOp);
+
+      BuildMI(MBB, MI, DL, get(AMDGPU::S_MOV_B32), DstLo)
+          .addGlobalAddress(GV, Offset, BaseFlags | LoReloc);
+      BuildMI(MBB, MI, DL, get(AMDGPU::S_MOV_B32), DstHi)
+          .addGlobalAddress(GV, Offset, BaseFlags | HiReloc);
+      MI.eraseFromParent();
+      break;
+    }
+
+    // SrcOp is immediate
     APInt Imm(64, SrcOp.getImm());
     if (Imm.isIntN(32) || isInlineConstant(Imm)) {
       MI.setDesc(get(AMDGPU::S_MOV_B64));

diff  --git a/llvm/test/CodeGen/AMDGPU/expand-mov-b64-globaladdr-hsa.ll b/llvm/test/CodeGen/AMDGPU/expand-mov-b64-globaladdr-hsa.ll
new file mode 100644
index 0000000000000..eee79fae87040
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/expand-mov-b64-globaladdr-hsa.ll
@@ -0,0 +1,48 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1100 < %s | FileCheck --check-prefix=HSA %s
+
+; Verify that V_MOV_B64_PSEUDO and S_MOV_B64_IMM_PSEUDO preserve non-ABS
+; relocation intent on HSA and lower via gotpcrel32 lo/hi address materialization.
+
+ at gv = external addrspace(4) constant [6 x i32]
+declare i32 @llvm.amdgcn.workitem.id.x() #0
+
+define amdgpu_kernel void @v_mov_b64_pseudo_globaladdr_hsa(ptr addrspace(1) %out) {
+; HSA-LABEL: v_mov_b64_pseudo_globaladdr_hsa:
+; HSA:       s_add_u32 s{{[0-9]+}}, s{{[0-9]+}}, gv at gotpcrel32@lo+4
+; HSA:       s_addc_u32 s{{[0-9]+}}, s{{[0-9]+}}, gv at gotpcrel32@hi+12
+entry:
+  %tid = call i32 @llvm.amdgcn.workitem.id.x()
+  %masked = and i32 %tid, 1
+  %cond = icmp ne i32 %masked, 0
+  br i1 %cond, label %other, label %join
+
+other:
+  br label %join
+
+join:
+  %sink = phi ptr addrspace(4) [ null, %entry ], [ @gv, %other ]
+  %sink.i64 = ptrtoint ptr addrspace(4) %sink to i64
+  store i64 %sink.i64, ptr addrspace(1) %out, align 8
+  ret void
+}
+
+define amdgpu_kernel void @s_mov_b64_imm_pseudo_globaladdr_hsa(
+    ptr addrspace(1) %out, i1 inreg %cond) {
+; HSA-LABEL: s_mov_b64_imm_pseudo_globaladdr_hsa:
+; HSA:       s_add_u32 s{{[0-9]+}}, s{{[0-9]+}}, gv at gotpcrel32@lo+4
+; HSA:       s_addc_u32 s{{[0-9]+}}, s{{[0-9]+}}, gv at gotpcrel32@hi+12
+entry:
+  br i1 %cond, label %other, label %join
+
+other:
+  br label %join
+
+join:
+  %sink = phi ptr addrspace(4) [ null, %entry ], [ @gv, %other ]
+  %sink.i64 = ptrtoint ptr addrspace(4) %sink to i64
+  store i64 %sink.i64, ptr addrspace(1) %out, align 8
+  ret void
+}
+
+attributes #0 = { nounwind readnone speculatable willreturn }

diff  --git a/llvm/test/CodeGen/AMDGPU/expand-mov-b64-globaladdr-rel32.mir b/llvm/test/CodeGen/AMDGPU/expand-mov-b64-globaladdr-rel32.mir
new file mode 100644
index 0000000000000..3827dc2dd1eb1
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/expand-mov-b64-globaladdr-rel32.mir
@@ -0,0 +1,27 @@
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1100 -verify-machineinstrs -run-pass=postrapseudos -o - %s | FileCheck %s
+
+# This test verifies that rel32 target flags on 64-bit global-address pseudos
+# are split into rel32 lo/hi flags when post-RA pseudos are expanded.
+
+--- |
+  define amdgpu_kernel void @v_mov_b64_pseudo_globaladdr_rel32() {
+    ret void
+  }
+
+  @gv = external addrspace(1) global i32
+...
+
+---
+name: v_mov_b64_pseudo_globaladdr_rel32
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $exec
+
+    ; CHECK-LABEL: name: v_mov_b64_pseudo_globaladdr_rel32
+    ; CHECK: $vgpr0 = V_MOV_B32_e32 target-flags(amdgpu-rel32-lo) @gv, implicit $exec
+    ; CHECK-NEXT: $vgpr1 = V_MOV_B32_e32 target-flags(amdgpu-rel32-hi) @gv, implicit $exec
+
+    $vgpr0_vgpr1 = V_MOV_B64_PSEUDO target-flags(amdgpu-rel32-lo) @gv, implicit $exec
+...
+

diff  --git a/llvm/test/CodeGen/AMDGPU/expand-mov-b64-globaladdr.ll b/llvm/test/CodeGen/AMDGPU/expand-mov-b64-globaladdr.ll
new file mode 100644
index 0000000000000..f59b2d1f59847
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/expand-mov-b64-globaladdr.ll
@@ -0,0 +1,95 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=amdgcn--amdpal -mcpu=gfx1010 < %s | FileCheck --check-prefix=GFX10 %s
+; RUN: llc -mtriple=amdgcn--amdpal -mcpu=gfx1100 < %s | FileCheck --check-prefix=GFX11 %s
+
+; Verify that V_MOV_B64_PSEUDO and S_MOV_B64_IMM_PSEUDO are expanded into a
+; pair of 32-bit moves of the absolute hi/lo halves of a global address when
+; the subtarget does not support 64-bit literals.
+
+ at gv = external addrspace(4) constant [6 x i32]
+
+; Divergent select of @gv lowers to V_MOV_B64_PSEUDO with a GlobalAddress
+; operand which expandPostRAPseudo splits into v_mov_b32 abs32 at lo/@hi.
+define amdgpu_ps ptr addrspace(4) @v_mov_b64_pseudo_globaladdr(i1 %cond) {
+; GFX10-LABEL: v_mov_b64_pseudo_globaladdr:
+; GFX10:       ; %bb.0: ; %entry
+; GFX10-NEXT:    v_and_b32_e32 v2, 1, v0
+; GFX10-NEXT:    v_mov_b32_e32 v0, 0
+; GFX10-NEXT:    v_mov_b32_e32 v1, 0
+; GFX10-NEXT:    v_cmp_ne_u32_e32 vcc_lo, 1, v2
+; GFX10-NEXT:    s_and_saveexec_b32 s0, vcc_lo
+; GFX10-NEXT:  ; %bb.1: ; %other
+; GFX10-NEXT:    v_mov_b32_e32 v0, gv at abs32@lo
+; GFX10-NEXT:    v_mov_b32_e32 v1, gv at abs32@hi
+; GFX10-NEXT:  ; %bb.2: ; %join
+; GFX10-NEXT:    s_or_b32 exec_lo, exec_lo, s0
+; GFX10-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX10-NEXT:    v_readfirstlane_b32 s1, v1
+; GFX10-NEXT:    ; return to shader part epilog
+;
+; GFX11-LABEL: v_mov_b64_pseudo_globaladdr:
+; GFX11:       ; %bb.0: ; %entry
+; GFX11-NEXT:    v_dual_mov_b32 v1, 0 :: v_dual_and_b32 v2, 1, v0
+; GFX11-NEXT:    v_mov_b32_e32 v0, 0
+; GFX11-NEXT:    s_mov_b32 s0, exec_lo
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_2)
+; GFX11-NEXT:    v_cmpx_ne_u32_e32 1, v2
+; GFX11-NEXT:  ; %bb.1: ; %other
+; GFX11-NEXT:    v_mov_b32_e32 v0, gv at abs32@lo
+; GFX11-NEXT:    v_mov_b32_e32 v1, gv at abs32@hi
+; GFX11-NEXT:  ; %bb.2: ; %join
+; GFX11-NEXT:    s_or_b32 exec_lo, exec_lo, s0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX11-NEXT:    v_readfirstlane_b32 s1, v1
+; GFX11-NEXT:    ; return to shader part epilog
+entry:
+  br i1 %cond, label %join, label %other
+
+other:
+  br label %join
+
+join:
+  %sink = phi ptr addrspace(4) [ null, %entry ], [ @gv, %other ]
+  ret ptr addrspace(4) %sink
+}
+
+; Uniform select of @gv lowers to S_MOV_B64_IMM_PSEUDO with a GlobalAddress
+; operand which expandPostRAPseudo splits into s_mov_b32 abs32 at lo/@hi.
+define amdgpu_ps ptr addrspace(4) @s_mov_b64_imm_pseudo_globaladdr(i1 inreg %cond) {
+; GFX10-LABEL: s_mov_b64_imm_pseudo_globaladdr:
+; GFX10:       ; %bb.0: ; %entry
+; GFX10-NEXT:    s_bitcmp1_b32 s0, 0
+; GFX10-NEXT:    s_cselect_b32 s0, -1, 0
+; GFX10-NEXT:    s_and_b32 vcc_lo, exec_lo, s0
+; GFX10-NEXT:    s_mov_b64 s[0:1], 0
+; GFX10-NEXT:    s_cbranch_vccnz .LBB1_2
+; GFX10-NEXT:  ; %bb.1: ; %other
+; GFX10-NEXT:    s_mov_b32 s1, gv at abs32@hi
+; GFX10-NEXT:    s_mov_b32 s0, gv at abs32@lo
+; GFX10-NEXT:  .LBB1_2: ; %join
+; GFX10-NEXT:    ; return to shader part epilog
+;
+; GFX11-LABEL: s_mov_b64_imm_pseudo_globaladdr:
+; GFX11:       ; %bb.0: ; %entry
+; GFX11-NEXT:    s_bitcmp1_b32 s0, 0
+; GFX11-NEXT:    s_cselect_b32 s0, -1, 0
+; GFX11-NEXT:    s_delay_alu instid0(SALU_CYCLE_1)
+; GFX11-NEXT:    s_and_b32 vcc_lo, exec_lo, s0
+; GFX11-NEXT:    s_mov_b64 s[0:1], 0
+; GFX11-NEXT:    s_cbranch_vccnz .LBB1_2
+; GFX11-NEXT:  ; %bb.1: ; %other
+; GFX11-NEXT:    s_mov_b32 s1, gv at abs32@hi
+; GFX11-NEXT:    s_mov_b32 s0, gv at abs32@lo
+; GFX11-NEXT:  .LBB1_2: ; %join
+; GFX11-NEXT:    ; return to shader part epilog
+entry:
+  br i1 %cond, label %join, label %other
+
+other:
+  br label %join
+
+join:
+  %sink = phi ptr addrspace(4) [ null, %entry ], [ @gv, %other ]
+  ret ptr addrspace(4) %sink
+}


        


More information about the llvm-commits mailing list