[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