[llvm] [AMDGPU] Detect illegal 64 relocs in SIFold (PR #219141)
David Stuttard via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 27 01:17:23 PDT 2026
https://github.com/dstutt created https://github.com/llvm/llvm-project/pull/219141
Had some cases where operand folding was missing that a reloc
might be 64 bit and thus can't be folded into a VOP3/VOP3P/VOPD
instructions even if the target supports 64 bit literals.
Enhanced verifier to pick up violations as well.
Also updated target-flags.mir test to use a specific variant due to the
enhanced verifier checks.
>From 48e2b33eeb4a69cf3b48082991593ca4d54b1653 Mon Sep 17 00:00:00 2001
From: David Stuttard <david.stuttard at amd.com>
Date: Wed, 26 Aug 2026 14:18:24 +0100
Subject: [PATCH] [AMDGPU] Detect illegal 64 relocs in SIFold
Had some cases where operand folding was missing that a reloc
might be 64 bit and thus can't be folded into a VOP3/VOP3P/VOPD
instructions even if the target supports 64 bit literals.
Enhanced verifier to pick up violations as well.
Also updated target-flags.mir test to use a specific variant due to the
enhanced verifier checks.
---
llvm/lib/Target/AMDGPU/SIInstrInfo.cpp | 31 ++++++++++
llvm/test/CodeGen/AMDGPU/literal64-symbol.ll | 57 +++++++++++++++++++
llvm/test/CodeGen/MIR/AMDGPU/target-flags.mir | 2 +-
3 files changed, 89 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/CodeGen/AMDGPU/literal64-symbol.ll
diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
index bc419d813f171..c7ecac4de8b6f 100644
--- a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
@@ -127,6 +127,17 @@ static bool canRemat(const MachineInstr &MI) {
return false;
}
+static bool is64BitReloc(unsigned TargetFlags) {
+ switch (TargetFlags & SIInstrInfo::MO_MASK) {
+ case SIInstrInfo::MO_ABS64:
+ case SIInstrInfo::MO_REL64:
+ case SIInstrInfo::MO_GOTPCREL64:
+ return true;
+ default:
+ 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>
@@ -5431,6 +5442,18 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI,
ErrInfo = "illegal 64-bit immediate value for operand.";
return false;
}
+ // A global with a 64-bit relocation resolves to a 64-bit literal at link
+ // time. It cannot be encoded without 64-bit literal support, nor in
+ // 8-byte encodings (e.g. VOP3, VOP3P, VOPD) which cannot carry one.
+ // V_MOV_B64_PSEUDO and S_MOV_B64_IMM_PSEUDO are exempt: they split the
+ // relocation into lo/hi halves when expanded in expandPostRAPseudo.
+ if (MO.isGlobal() && is64BitReloc(MO.getTargetFlags()) &&
+ MI.getOpcode() != AMDGPU::V_MOV_B64_PSEUDO &&
+ MI.getOpcode() != AMDGPU::S_MOV_B64_IMM_PSEUDO &&
+ (!ST.has64BitLiterals() || Desc.getSize() != 4)) {
+ ErrInfo = "illegal 64-bit relocation for operand.";
+ return false;
+ }
break;
case AMDGPU::OPERAND_INLINE_SPLIT_BARRIER_INT32:
case AMDGPU::OPERAND_INPUT_MODS:
@@ -6781,6 +6804,14 @@ bool SIInstrInfo::isOperandLegal(const MachineInstr &MI, unsigned OpIdx,
// Handle non-register types that are treated like immediates.
assert(MO->isImm() || MO->isTargetIndex() || MO->isFI() || MO->isGlobal());
+ // A global address with a 64-bit relocation resolves to a 64-bit literal at
+ // link time. The 64-bit literal encoding is only available on targets with
+ // has64BitLiterals(), and even then only for single-DWORD (4-byte) base
+ // instructions.
+ if (MO->isGlobal() && is64BitReloc(MO->getTargetFlags()) &&
+ (!ST.has64BitLiterals() || InstDesc.getSize() != 4))
+ return false;
+
if (!DefinedRC) {
// This operand expects an immediate.
return true;
diff --git a/llvm/test/CodeGen/AMDGPU/literal64-symbol.ll b/llvm/test/CodeGen/AMDGPU/literal64-symbol.ll
new file mode 100644
index 0000000000000..83e305ea6b3d7
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/literal64-symbol.ll
@@ -0,0 +1,57 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 3
+; RUN: llc -mtriple=amdgpu12.00 < %s | FileCheck %s --check-prefixes=GFX12
+; RUN: llc -mtriple=amdgpu12.50 < %s | FileCheck %s --check-prefixes=GFX1250
+; RUN: llc -mtriple=amdgpu13.10 < %s | FileCheck %s --check-prefixes=GFX13
+
+ at sym = external addrspace(4) constant [2 x <3 x i32>]
+
+; An MO_ABS64 global must not be folded into a VOP3 (here v_mad_co_u64_u32) as a
+; 64-bit literal: no VOP3 encoding can carry one even when 64-bit literals are
+; supported. It must be materialized into an SGPR first.
+define amdgpu_gs ptr addrspace(4) @v_mad_symbol(i32 %idx) {
+; GFX12-LABEL: v_mad_symbol:
+; GFX12: ; %bb.0:
+; GFX12-NEXT: s_getpc_b64 s[0:1]
+; GFX12-NEXT: s_sext_i32_i16 s1, s1
+; GFX12-NEXT: s_add_co_u32 s0, s0, sym at gotpcrel32@lo+8
+; GFX12-NEXT: s_add_co_ci_u32 s1, s1, sym at gotpcrel32@hi+16
+; GFX12-NEXT: s_load_b64 s[0:1], s[0:1], 0x0
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: v_mad_co_u64_u32 v[0:1], null, v0, 24, s[0:1]
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX12-NEXT: v_readfirstlane_b32 s0, v0
+; GFX12-NEXT: v_readfirstlane_b32 s1, v1
+; GFX12-NEXT: s_wait_alu depctr_va_sdst(0)
+; GFX12-NEXT: ; return to shader part epilog
+;
+; GFX1250-LABEL: v_mad_symbol:
+; GFX1250: ; %bb.0:
+; GFX1250-NEXT: s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 25, 1), 1 ; msbs: dst=0 src0=0 src1=0 src2=0
+; GFX1250-NEXT: s_mov_b64 s[64:65], 0
+; GFX1250-NEXT: v_nop
+; GFX1250-NEXT: global_prefetch_b8 v0, s[64:65] scope:SCOPE_SE
+; GFX1250-NEXT: s_get_pc_i64 s[0:1]
+; GFX1250-NEXT: s_add_nc_u64 s[0:1], s[0:1], sym at gotpcrel+4
+; GFX1250-NEXT: s_load_b64 s[0:1], s[0:1], 0x0 nv
+; GFX1250-NEXT: s_wait_kmcnt 0x0
+; GFX1250-NEXT: v_mad_nc_u64_u32 v[0:1], v0, 24, s[0:1]
+; GFX1250-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX1250-NEXT: v_readfirstlane_b32 s0, v0
+; GFX1250-NEXT: v_readfirstlane_b32 s1, v1
+; GFX1250-NEXT: ; return to shader part epilog
+;
+; GFX13-LABEL: v_mad_symbol:
+; GFX13: ; %bb.0:
+; GFX13-NEXT: s_get_pc_i64 s[0:1]
+; GFX13-NEXT: s_add_nc_u64 s[0:1], s[0:1], sym at gotpcrel+4
+; GFX13-NEXT: s_load_b64 s[0:1], s[0:1], 0x0 nv
+; GFX13-NEXT: s_wait_kmcnt 0x0
+; GFX13-NEXT: v_mad_co_u64_u32 v[0:1], null, v0, 24, s[0:1]
+; GFX13-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX13-NEXT: v_readfirstlane_b32 s0, v0
+; GFX13-NEXT: v_readfirstlane_b32 s1, v1
+; GFX13-NEXT: ; return to shader part epilog
+ %ext = zext i32 %idx to i64
+ %gep = getelementptr [24 x i8], ptr addrspace(4) @sym, i64 %ext
+ ret ptr addrspace(4) %gep
+}
diff --git a/llvm/test/CodeGen/MIR/AMDGPU/target-flags.mir b/llvm/test/CodeGen/MIR/AMDGPU/target-flags.mir
index 3bce5400e576b..db63c7ecde6c1 100644
--- a/llvm/test/CodeGen/MIR/AMDGPU/target-flags.mir
+++ b/llvm/test/CodeGen/MIR/AMDGPU/target-flags.mir
@@ -1,5 +1,5 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
-# RUN: llc -mtriple=amdgpu6.00 -run-pass none -o - %s | FileCheck %s
+# RUN: llc -mtriple=amdgpu12.50 -run-pass none -o - %s | FileCheck %s
--- |
define amdgpu_kernel void @flags() {
ret void
More information about the llvm-commits
mailing list