[llvm] [AMDGPU] Add assembler check for GFX1250 unclaused vmem workaround (PR #209517)
Jay Foad via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 16 08:39:59 PDT 2026
https://github.com/jayfoad updated https://github.com/llvm/llvm-project/pull/209517
>From 100f88b8e868f51c89ff817dbd3909b5c576ea8b Mon Sep 17 00:00:00 2001
From: Jay Foad <jay.foad at amd.com>
Date: Fri, 12 Jun 2026 12:31:16 +0100
Subject: [PATCH 1/2] [AMDGPU] Add assembler check for GFX1250 unclaused vmem
workaround
Warn if an entrypoint does not start with the standard workaround
sequence.
---
.../AMDGPU/AsmParser/AMDGPUAsmParser.cpp | 49 +++++++++++++++++++
llvm/test/MC/AMDGPU/amdhsa-kernel-prologue.s | 28 +++++++++++
llvm/test/MC/AMDGPU/hsa-gfx1250-v4.s | 12 +++++
llvm/test/MC/AMDGPU/hsa-gfx1251-v4.s | 12 +++++
4 files changed, 101 insertions(+)
create mode 100644 llvm/test/MC/AMDGPU/amdhsa-kernel-prologue.s
diff --git a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
index f019c280997d6..a2b6a68a78f88 100644
--- a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
+++ b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
@@ -1412,6 +1412,21 @@ class AMDGPUAsmParser : public MCTargetAsmParser {
/// update the target ID first.
bool TargetDirectiveEmitted = false;
+ /// State for checking that every kernel named in a .amdhsa_kernel directive
+ /// begins with the required prologue instruction sequence. Because the
+ /// directive may appear either before or after the kernel's label (it is
+ /// normally emitted after the function body, in .rodata), validation is
+ /// deferred to onEndOfFile(). We record an order-independent timeline of
+ /// parsed labels and emitted instruction opcodes, plus the set of symbols
+ /// named by .amdhsa_kernel directives, and match them up at end of file.
+ SmallVector<unsigned> OpcodeStream;
+ SmallVector<std::tuple<const MCSymbol *, SMLoc, unsigned>>
+ OpcodeStreamSymbols;
+ SmallPtrSet<const MCSymbol *, 8> AMDHSAKernelSymbols;
+
+ /// Verify recorded kernel prologues.
+ void checkKernelPrologues();
+
private:
void createConstantSymbol(StringRef Id, int64_t Val);
@@ -1708,6 +1723,7 @@ class AMDGPUAsmParser : public MCTargetAsmParser {
uint64_t &ErrorInfo,
bool MatchingInlineAsm) override;
bool ParseDirective(AsmToken DirectiveID) override;
+ void doBeforeLabelEmit(MCSymbol *Symbol, SMLoc IDLoc) override;
void onEndOfFile() override;
ParseStatus parseOperand(OperandVector &Operands, StringRef Mnemonic,
OperandMode Mode = OperandMode_Default);
@@ -5933,6 +5949,8 @@ bool AMDGPUAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
}
emitTargetDirective();
Out.emitInstruction(Inst, getSTI());
+ // Record for kernel prologue checking.
+ OpcodeStream.push_back(Inst.getOpcode());
return false;
}
@@ -6139,6 +6157,10 @@ bool AMDGPUAsmParser::ParseDirectiveAMDHSAKernel() {
if (getParser().parseIdentifier(KernelName))
return true;
+ // Remember the kernel name so its prologue can be checked at end of file.
+ // The matching label may have been parsed already or may follow later.
+ AMDHSAKernelSymbols.insert(getContext().getOrCreateSymbol(KernelName));
+
AMDGPU::MCKernelDescriptor KD =
AMDGPU::MCKernelDescriptor::getDefaultAmdhsaKernelDescriptor(
&getSTI(), getContext());
@@ -7067,8 +7089,35 @@ bool AMDGPUAsmParser::ParseDirectiveAMDGPUInfo() {
return false;
}
+void AMDGPUAsmParser::doBeforeLabelEmit(MCSymbol *Symbol, SMLoc IDLoc) {
+ // Record every parsed label in the timeline so that, at end of file, the
+ // instructions following a kernel's label can be located regardless of
+ // whether the .amdhsa_kernel directive came before or after the label.
+ OpcodeStreamSymbols.emplace_back(Symbol, IDLoc, OpcodeStream.size());
+}
+
+void AMDGPUAsmParser::checkKernelPrologues() {
+ if (getFeatureBits()[AMDGPU::FeatureRequiresInitialUnclausedVmem]) {
+ static const unsigned Required[] = {GLOBAL_WB_gfx12, V_NOP_e32_gfx12};
+ for (auto [Sym, Loc, Offset] : OpcodeStreamSymbols) {
+ if (!AMDHSAKernelSymbols.contains(Sym))
+ continue;
+ ArrayRef<unsigned> Prologue = ArrayRef(OpcodeStream).drop_front(Offset);
+ if (Prologue.take_front(std::size(Required)) != ArrayRef(Required)) {
+ Warning(Loc, "kernel '" + Sym->getName() +
+ "' does not begin with the required prologue "
+ "sequence");
+ }
+ }
+ }
+ OpcodeStream.clear();
+ OpcodeStreamSymbols.clear();
+ AMDHSAKernelSymbols.clear();
+}
+
void AMDGPUAsmParser::onEndOfFile() {
emitTargetDirective();
+ checkKernelPrologues();
if (InfoData)
getTargetStreamer().emitAMDGPUInfo(*InfoData);
}
diff --git a/llvm/test/MC/AMDGPU/amdhsa-kernel-prologue.s b/llvm/test/MC/AMDGPU/amdhsa-kernel-prologue.s
new file mode 100644
index 0000000000000..604a16e48ed7a
--- /dev/null
+++ b/llvm/test/MC/AMDGPU/amdhsa-kernel-prologue.s
@@ -0,0 +1,28 @@
+// RUN: llvm-mc -triple=amdgcn-amd-amdhsa -mcpu=gfx1250 %s -filetype=null 2>&1 | FileCheck %s -implicit-check-not=warning: -check-prefix=GFX1250
+
+// GFX1250: :[[@LINE+1]]:1: warning: kernel 'test_wrong_before' does not begin with the required prologue sequence
+test_wrong_before:
+ s_nop 1
+
+.amdhsa_kernel test_wrong_before
+ .amdhsa_next_free_sgpr 0
+ .amdhsa_next_free_vgpr 0
+.end_amdhsa_kernel
+
+.amdhsa_kernel test_wrong_after
+ .amdhsa_next_free_sgpr 0
+ .amdhsa_next_free_vgpr 0
+.end_amdhsa_kernel
+
+// GFX1250: :[[@LINE+1]]:1: warning: kernel 'test_wrong_after' does not begin with the required prologue sequence
+test_wrong_after:
+ s_nop 2
+
+.amdhsa_kernel test_correct
+ .amdhsa_next_free_sgpr 0
+ .amdhsa_next_free_vgpr 0
+.end_amdhsa_kernel
+
+test_correct:
+ global_wb
+ v_nop
diff --git a/llvm/test/MC/AMDGPU/hsa-gfx1250-v4.s b/llvm/test/MC/AMDGPU/hsa-gfx1250-v4.s
index 294f46cbde48f..bb877ede1f4c1 100644
--- a/llvm/test/MC/AMDGPU/hsa-gfx1250-v4.s
+++ b/llvm/test/MC/AMDGPU/hsa-gfx1250-v4.s
@@ -70,31 +70,43 @@
.p2align 8
.type minimal, at function
minimal:
+ global_wb scope:SCOPE_CU
+ v_nop
s_endpgm
.p2align 8
.type complete, at function
complete:
+ global_wb scope:SCOPE_CU
+ v_nop
s_endpgm
.p2align 8
.type special_sgpr, at function
special_sgpr:
+ global_wb scope:SCOPE_CU
+ v_nop
s_endpgm
.p2align 8
.type disabled_user_sgpr, at function
disabled_user_sgpr:
+ global_wb scope:SCOPE_CU
+ v_nop
s_endpgm
.p2align 8
.type max_lds_size, at function
max_lds_size:
+ global_wb scope:SCOPE_CU
+ v_nop
s_endpgm
.p2align 8
.type max_vgprs, at function
max_vgprs:
+ global_wb scope:SCOPE_CU
+ v_nop
s_endpgm
.rodata
diff --git a/llvm/test/MC/AMDGPU/hsa-gfx1251-v4.s b/llvm/test/MC/AMDGPU/hsa-gfx1251-v4.s
index 8e1e34651be6c..201d374f0ec28 100644
--- a/llvm/test/MC/AMDGPU/hsa-gfx1251-v4.s
+++ b/llvm/test/MC/AMDGPU/hsa-gfx1251-v4.s
@@ -70,31 +70,43 @@
.p2align 8
.type minimal, at function
minimal:
+ global_wb scope:SCOPE_CU
+ v_nop
s_endpgm
.p2align 8
.type complete, at function
complete:
+ global_wb scope:SCOPE_CU
+ v_nop
s_endpgm
.p2align 8
.type special_sgpr, at function
special_sgpr:
+ global_wb scope:SCOPE_CU
+ v_nop
s_endpgm
.p2align 8
.type disabled_user_sgpr, at function
disabled_user_sgpr:
+ global_wb scope:SCOPE_CU
+ v_nop
s_endpgm
.p2align 8
.type max_lds_size, at function
max_lds_size:
+ global_wb scope:SCOPE_CU
+ v_nop
s_endpgm
.p2align 8
.type max_vgprs, at function
max_vgprs:
+ global_wb scope:SCOPE_CU
+ v_nop
s_endpgm
.rodata
>From e89b467f1374dd2111696d88fb4d1870411c5e88 Mon Sep 17 00:00:00 2001
From: Jay Foad <jay.foad at amd.com>
Date: Thu, 16 Jul 2026 16:37:48 +0100
Subject: [PATCH 2/2] More explicit message
---
llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp | 2 +-
llvm/test/MC/AMDGPU/amdhsa-kernel-prologue.s | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
index a2b6a68a78f88..efc98536096f6 100644
--- a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
+++ b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
@@ -7106,7 +7106,7 @@ void AMDGPUAsmParser::checkKernelPrologues() {
if (Prologue.take_front(std::size(Required)) != ArrayRef(Required)) {
Warning(Loc, "kernel '" + Sym->getName() +
"' does not begin with the required prologue "
- "sequence");
+ "sequence: GLOBAL_WB followed by V_NOP");
}
}
}
diff --git a/llvm/test/MC/AMDGPU/amdhsa-kernel-prologue.s b/llvm/test/MC/AMDGPU/amdhsa-kernel-prologue.s
index 604a16e48ed7a..824eef3611c1a 100644
--- a/llvm/test/MC/AMDGPU/amdhsa-kernel-prologue.s
+++ b/llvm/test/MC/AMDGPU/amdhsa-kernel-prologue.s
@@ -1,6 +1,6 @@
// RUN: llvm-mc -triple=amdgcn-amd-amdhsa -mcpu=gfx1250 %s -filetype=null 2>&1 | FileCheck %s -implicit-check-not=warning: -check-prefix=GFX1250
-// GFX1250: :[[@LINE+1]]:1: warning: kernel 'test_wrong_before' does not begin with the required prologue sequence
+// GFX1250: :[[@LINE+1]]:1: warning: kernel 'test_wrong_before' does not begin with the required prologue sequence: GLOBAL_WB followed by V_NOP
test_wrong_before:
s_nop 1
@@ -14,7 +14,7 @@ test_wrong_before:
.amdhsa_next_free_vgpr 0
.end_amdhsa_kernel
-// GFX1250: :[[@LINE+1]]:1: warning: kernel 'test_wrong_after' does not begin with the required prologue sequence
+// GFX1250: :[[@LINE+1]]:1: warning: kernel 'test_wrong_after' does not begin with the required prologue sequence: GLOBAL_WB followed by V_NOP
test_wrong_after:
s_nop 2
More information about the llvm-commits
mailing list