Skip to content

Commit a31c941

Browse files
authored
[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.
1 parent 7c15144 commit a31c941

4 files changed

Lines changed: 241 additions & 2 deletions

File tree

llvm/lib/Target/AMDGPU/SIInstrInfo.cpp

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "llvm/MC/MCContext.h"
3636
#include "llvm/Support/CommandLine.h"
3737
#include "llvm/Target/TargetMachine.h"
38+
#include <tuple>
3839

3940
using namespace llvm;
4041

@@ -126,6 +127,39 @@ static bool canRemat(const MachineInstr &MI) {
126127
return false;
127128
}
128129

130+
// Split relocation flags for 64-bit global-address materialization into a
131+
// common base and the hi/lo relocation variants.
132+
static std::tuple<unsigned, unsigned, unsigned>
133+
splitGlobalAddressRelocFlags(const GCNSubtarget &ST,
134+
const MachineOperand &SrcOp) {
135+
unsigned SrcFlags = SrcOp.getTargetFlags();
136+
137+
// Infer the relocation type from the existing flags on the global operand.
138+
// The relocation type should have been determined earlier in the pipeline.
139+
unsigned LoReloc = SIInstrInfo::MO_ABS32_LO;
140+
unsigned HiReloc = SIInstrInfo::MO_ABS32_HI;
141+
142+
if (SrcFlags & SIInstrInfo::MO_REL32) {
143+
LoReloc = SIInstrInfo::MO_REL32_LO;
144+
HiReloc = SIInstrInfo::MO_REL32_HI;
145+
} else if (SrcFlags & SIInstrInfo::MO_GOTPCREL32_LO) {
146+
LoReloc = SIInstrInfo::MO_GOTPCREL32_LO;
147+
HiReloc = SIInstrInfo::MO_GOTPCREL32_HI;
148+
} else if (SrcFlags & SIInstrInfo::MO_GOTPCREL64) {
149+
// For 64-bit GOT-relative, use the 64-bit relocation.
150+
LoReloc = SIInstrInfo::MO_GOTPCREL64;
151+
HiReloc = SIInstrInfo::MO_GOTPCREL64;
152+
}
153+
154+
unsigned BaseFlags =
155+
SrcFlags & ~(SIInstrInfo::MO_ABS32_LO | SIInstrInfo::MO_ABS32_HI |
156+
SIInstrInfo::MO_REL32_LO | SIInstrInfo::MO_REL32_HI |
157+
SIInstrInfo::MO_GOTPCREL32_LO |
158+
SIInstrInfo::MO_GOTPCREL32_HI | SIInstrInfo::MO_GOTPCREL64);
159+
160+
return std::make_tuple(BaseFlags, LoReloc, HiReloc);
161+
}
162+
129163
bool SIInstrInfo::isReMaterializableImpl(
130164
const MachineInstr &MI) const {
131165

@@ -1913,6 +1947,7 @@ bool SIInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
19131947
MachineBasicBlock &MBB = *MI.getParent();
19141948
DebugLoc DL = MBB.findDebugLoc(MI);
19151949
const AMDGPU::LaneMaskConstants &LMC = AMDGPU::LaneMaskConstants::get(ST);
1950+
19161951
switch (MI.getOpcode()) {
19171952
default: return TargetInstrInfo::expandPostRAPseudo(MI);
19181953
case AMDGPU::S_MOV_B64_term:
@@ -2037,10 +2072,25 @@ bool SIInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
20372072
if (ST.hasVMovB64Inst() && Mov64RC->contains(Dst)) {
20382073
MI.setDesc(Mov64Desc);
20392074
if (SrcOp.isReg() || isInlineConstant(MI, 1) ||
2040-
isUInt<32>(SrcOp.getImm()) || ST.has64BitLiterals())
2075+
(SrcOp.isImm() &&
2076+
(isUInt<32>(SrcOp.getImm()) || ST.has64BitLiterals())) ||
2077+
(SrcOp.isGlobal() && ST.has64BitLiterals()))
20412078
break;
20422079
}
2043-
if (SrcOp.isImm()) {
2080+
if (SrcOp.isGlobal()) {
2081+
// The address is unknown until link time, so the PK_MOV inline-constant
2082+
// shortcut cannot apply.
2083+
const GlobalValue *GV = SrcOp.getGlobal();
2084+
int64_t Offset = SrcOp.getOffset();
2085+
unsigned BaseFlags, LoReloc, HiReloc;
2086+
std::tie(BaseFlags, LoReloc, HiReloc) =
2087+
splitGlobalAddressRelocFlags(ST, SrcOp);
2088+
2089+
BuildMI(MBB, MI, DL, get(AMDGPU::V_MOV_B32_e32), DstLo)
2090+
.addGlobalAddress(GV, Offset, BaseFlags | LoReloc);
2091+
BuildMI(MBB, MI, DL, get(AMDGPU::V_MOV_B32_e32), DstHi)
2092+
.addGlobalAddress(GV, Offset, BaseFlags | HiReloc);
2093+
} else if (SrcOp.isImm()) {
20442094
APInt Imm(64, SrcOp.getImm());
20452095
APInt Lo(32, Imm.getLoBits(32).getZExtValue());
20462096
APInt Hi(32, Imm.getHiBits(32).getZExtValue());
@@ -2102,6 +2152,25 @@ bool SIInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
21022152
break;
21032153
}
21042154

2155+
if (SrcOp.isGlobal()) {
2156+
Register Dst = MI.getOperand(0).getReg();
2157+
Register DstLo = RI.getSubReg(Dst, AMDGPU::sub0);
2158+
Register DstHi = RI.getSubReg(Dst, AMDGPU::sub1);
2159+
const GlobalValue *GV = SrcOp.getGlobal();
2160+
int64_t Offset = SrcOp.getOffset();
2161+
unsigned BaseFlags, LoReloc, HiReloc;
2162+
std::tie(BaseFlags, LoReloc, HiReloc) =
2163+
splitGlobalAddressRelocFlags(ST, SrcOp);
2164+
2165+
BuildMI(MBB, MI, DL, get(AMDGPU::S_MOV_B32), DstLo)
2166+
.addGlobalAddress(GV, Offset, BaseFlags | LoReloc);
2167+
BuildMI(MBB, MI, DL, get(AMDGPU::S_MOV_B32), DstHi)
2168+
.addGlobalAddress(GV, Offset, BaseFlags | HiReloc);
2169+
MI.eraseFromParent();
2170+
break;
2171+
}
2172+
2173+
// SrcOp is immediate
21052174
APInt Imm(64, SrcOp.getImm());
21062175
if (Imm.isIntN(32) || isInlineConstant(Imm)) {
21072176
MI.setDesc(get(AMDGPU::S_MOV_B64));
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1100 < %s | FileCheck --check-prefix=HSA %s
3+
4+
; Verify that V_MOV_B64_PSEUDO and S_MOV_B64_IMM_PSEUDO preserve non-ABS
5+
; relocation intent on HSA and lower via gotpcrel32 lo/hi address materialization.
6+
7+
@gv = external addrspace(4) constant [6 x i32]
8+
declare i32 @llvm.amdgcn.workitem.id.x() #0
9+
10+
define amdgpu_kernel void @v_mov_b64_pseudo_globaladdr_hsa(ptr addrspace(1) %out) {
11+
; HSA-LABEL: v_mov_b64_pseudo_globaladdr_hsa:
12+
; HSA: s_add_u32 s{{[0-9]+}}, s{{[0-9]+}}, gv@gotpcrel32@lo+4
13+
; HSA: s_addc_u32 s{{[0-9]+}}, s{{[0-9]+}}, gv@gotpcrel32@hi+12
14+
entry:
15+
%tid = call i32 @llvm.amdgcn.workitem.id.x()
16+
%masked = and i32 %tid, 1
17+
%cond = icmp ne i32 %masked, 0
18+
br i1 %cond, label %other, label %join
19+
20+
other:
21+
br label %join
22+
23+
join:
24+
%sink = phi ptr addrspace(4) [ null, %entry ], [ @gv, %other ]
25+
%sink.i64 = ptrtoint ptr addrspace(4) %sink to i64
26+
store i64 %sink.i64, ptr addrspace(1) %out, align 8
27+
ret void
28+
}
29+
30+
define amdgpu_kernel void @s_mov_b64_imm_pseudo_globaladdr_hsa(
31+
ptr addrspace(1) %out, i1 inreg %cond) {
32+
; HSA-LABEL: s_mov_b64_imm_pseudo_globaladdr_hsa:
33+
; HSA: s_add_u32 s{{[0-9]+}}, s{{[0-9]+}}, gv@gotpcrel32@lo+4
34+
; HSA: s_addc_u32 s{{[0-9]+}}, s{{[0-9]+}}, gv@gotpcrel32@hi+12
35+
entry:
36+
br i1 %cond, label %other, label %join
37+
38+
other:
39+
br label %join
40+
41+
join:
42+
%sink = phi ptr addrspace(4) [ null, %entry ], [ @gv, %other ]
43+
%sink.i64 = ptrtoint ptr addrspace(4) %sink to i64
44+
store i64 %sink.i64, ptr addrspace(1) %out, align 8
45+
ret void
46+
}
47+
48+
attributes #0 = { nounwind readnone speculatable willreturn }
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1100 -verify-machineinstrs -run-pass=postrapseudos -o - %s | FileCheck %s
2+
3+
# This test verifies that rel32 target flags on 64-bit global-address pseudos
4+
# are split into rel32 lo/hi flags when post-RA pseudos are expanded.
5+
6+
--- |
7+
define amdgpu_kernel void @v_mov_b64_pseudo_globaladdr_rel32() {
8+
ret void
9+
}
10+
11+
@gv = external addrspace(1) global i32
12+
...
13+
14+
---
15+
name: v_mov_b64_pseudo_globaladdr_rel32
16+
tracksRegLiveness: true
17+
body: |
18+
bb.0:
19+
liveins: $exec
20+
21+
; CHECK-LABEL: name: v_mov_b64_pseudo_globaladdr_rel32
22+
; CHECK: $vgpr0 = V_MOV_B32_e32 target-flags(amdgpu-rel32-lo) @gv, implicit $exec
23+
; CHECK-NEXT: $vgpr1 = V_MOV_B32_e32 target-flags(amdgpu-rel32-hi) @gv, implicit $exec
24+
25+
$vgpr0_vgpr1 = V_MOV_B64_PSEUDO target-flags(amdgpu-rel32-lo) @gv, implicit $exec
26+
...
27+
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc -mtriple=amdgcn--amdpal -mcpu=gfx1010 < %s | FileCheck --check-prefix=GFX10 %s
3+
; RUN: llc -mtriple=amdgcn--amdpal -mcpu=gfx1100 < %s | FileCheck --check-prefix=GFX11 %s
4+
5+
; Verify that V_MOV_B64_PSEUDO and S_MOV_B64_IMM_PSEUDO are expanded into a
6+
; pair of 32-bit moves of the absolute hi/lo halves of a global address when
7+
; the subtarget does not support 64-bit literals.
8+
9+
@gv = external addrspace(4) constant [6 x i32]
10+
11+
; Divergent select of @gv lowers to V_MOV_B64_PSEUDO with a GlobalAddress
12+
; operand which expandPostRAPseudo splits into v_mov_b32 abs32@lo/@hi.
13+
define amdgpu_ps ptr addrspace(4) @v_mov_b64_pseudo_globaladdr(i1 %cond) {
14+
; GFX10-LABEL: v_mov_b64_pseudo_globaladdr:
15+
; GFX10: ; %bb.0: ; %entry
16+
; GFX10-NEXT: v_and_b32_e32 v2, 1, v0
17+
; GFX10-NEXT: v_mov_b32_e32 v0, 0
18+
; GFX10-NEXT: v_mov_b32_e32 v1, 0
19+
; GFX10-NEXT: v_cmp_ne_u32_e32 vcc_lo, 1, v2
20+
; GFX10-NEXT: s_and_saveexec_b32 s0, vcc_lo
21+
; GFX10-NEXT: ; %bb.1: ; %other
22+
; GFX10-NEXT: v_mov_b32_e32 v0, gv@abs32@lo
23+
; GFX10-NEXT: v_mov_b32_e32 v1, gv@abs32@hi
24+
; GFX10-NEXT: ; %bb.2: ; %join
25+
; GFX10-NEXT: s_or_b32 exec_lo, exec_lo, s0
26+
; GFX10-NEXT: v_readfirstlane_b32 s0, v0
27+
; GFX10-NEXT: v_readfirstlane_b32 s1, v1
28+
; GFX10-NEXT: ; return to shader part epilog
29+
;
30+
; GFX11-LABEL: v_mov_b64_pseudo_globaladdr:
31+
; GFX11: ; %bb.0: ; %entry
32+
; GFX11-NEXT: v_dual_mov_b32 v1, 0 :: v_dual_and_b32 v2, 1, v0
33+
; GFX11-NEXT: v_mov_b32_e32 v0, 0
34+
; GFX11-NEXT: s_mov_b32 s0, exec_lo
35+
; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_2)
36+
; GFX11-NEXT: v_cmpx_ne_u32_e32 1, v2
37+
; GFX11-NEXT: ; %bb.1: ; %other
38+
; GFX11-NEXT: v_mov_b32_e32 v0, gv@abs32@lo
39+
; GFX11-NEXT: v_mov_b32_e32 v1, gv@abs32@hi
40+
; GFX11-NEXT: ; %bb.2: ; %join
41+
; GFX11-NEXT: s_or_b32 exec_lo, exec_lo, s0
42+
; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
43+
; GFX11-NEXT: v_readfirstlane_b32 s0, v0
44+
; GFX11-NEXT: v_readfirstlane_b32 s1, v1
45+
; GFX11-NEXT: ; return to shader part epilog
46+
entry:
47+
br i1 %cond, label %join, label %other
48+
49+
other:
50+
br label %join
51+
52+
join:
53+
%sink = phi ptr addrspace(4) [ null, %entry ], [ @gv, %other ]
54+
ret ptr addrspace(4) %sink
55+
}
56+
57+
; Uniform select of @gv lowers to S_MOV_B64_IMM_PSEUDO with a GlobalAddress
58+
; operand which expandPostRAPseudo splits into s_mov_b32 abs32@lo/@hi.
59+
define amdgpu_ps ptr addrspace(4) @s_mov_b64_imm_pseudo_globaladdr(i1 inreg %cond) {
60+
; GFX10-LABEL: s_mov_b64_imm_pseudo_globaladdr:
61+
; GFX10: ; %bb.0: ; %entry
62+
; GFX10-NEXT: s_bitcmp1_b32 s0, 0
63+
; GFX10-NEXT: s_cselect_b32 s0, -1, 0
64+
; GFX10-NEXT: s_and_b32 vcc_lo, exec_lo, s0
65+
; GFX10-NEXT: s_mov_b64 s[0:1], 0
66+
; GFX10-NEXT: s_cbranch_vccnz .LBB1_2
67+
; GFX10-NEXT: ; %bb.1: ; %other
68+
; GFX10-NEXT: s_mov_b32 s1, gv@abs32@hi
69+
; GFX10-NEXT: s_mov_b32 s0, gv@abs32@lo
70+
; GFX10-NEXT: .LBB1_2: ; %join
71+
; GFX10-NEXT: ; return to shader part epilog
72+
;
73+
; GFX11-LABEL: s_mov_b64_imm_pseudo_globaladdr:
74+
; GFX11: ; %bb.0: ; %entry
75+
; GFX11-NEXT: s_bitcmp1_b32 s0, 0
76+
; GFX11-NEXT: s_cselect_b32 s0, -1, 0
77+
; GFX11-NEXT: s_delay_alu instid0(SALU_CYCLE_1)
78+
; GFX11-NEXT: s_and_b32 vcc_lo, exec_lo, s0
79+
; GFX11-NEXT: s_mov_b64 s[0:1], 0
80+
; GFX11-NEXT: s_cbranch_vccnz .LBB1_2
81+
; GFX11-NEXT: ; %bb.1: ; %other
82+
; GFX11-NEXT: s_mov_b32 s1, gv@abs32@hi
83+
; GFX11-NEXT: s_mov_b32 s0, gv@abs32@lo
84+
; GFX11-NEXT: .LBB1_2: ; %join
85+
; GFX11-NEXT: ; return to shader part epilog
86+
entry:
87+
br i1 %cond, label %join, label %other
88+
89+
other:
90+
br label %join
91+
92+
join:
93+
%sink = phi ptr addrspace(4) [ null, %entry ], [ @gv, %other ]
94+
ret ptr addrspace(4) %sink
95+
}

0 commit comments

Comments
 (0)