[llvm] 5fcab35 - [AMDGPU] Add assembler check for GFX1250 unclaused vmem workaround (#209517)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 17 02:39:24 PDT 2026
Author: Jay Foad
Date: 2026-07-17T10:39:20+01:00
New Revision: 5fcab35be3b450256e3b02a735900071c0b74a54
URL: https://github.com/llvm/llvm-project/commit/5fcab35be3b450256e3b02a735900071c0b74a54
DIFF: https://github.com/llvm/llvm-project/commit/5fcab35be3b450256e3b02a735900071c0b74a54.diff
LOG: [AMDGPU] Add assembler check for GFX1250 unclaused vmem workaround (#209517)
Warn if an entrypoint does not start with the standard workaround
sequence.
Added:
llvm/test/MC/AMDGPU/amdhsa-kernel-prologue.s
Modified:
llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
llvm/test/MC/AMDGPU/hsa-gfx1250-v4.s
llvm/test/MC/AMDGPU/hsa-gfx1251-v4.s
Removed:
################################################################################
diff --git a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
index 300a254662857..7ead3d6f2b263 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);
@@ -1710,6 +1725,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);
@@ -5936,6 +5952,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;
}
@@ -6142,6 +6160,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());
@@ -7070,8 +7092,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: GLOBAL_WB followed by V_NOP");
+ }
+ }
+ }
+ 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..824eef3611c1a
--- /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: GLOBAL_WB followed by V_NOP
+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: GLOBAL_WB followed by V_NOP
+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
More information about the llvm-commits
mailing list