[llvm-branch-commits] [llvm] [MIR][AMDGPU] Serialize register allocation anti-hints (PR #218073)
Syadus Sefat via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Aug 26 12:06:42 PDT 2026
https://github.com/mssefat updated https://github.com/llvm/llvm-project/pull/218073
>From 244fb01f8407f2138d07509ee26c2d3097bce79d Mon Sep 17 00:00:00 2001
From: mssefat <syadus.sefat at gmail.com>
Date: Wed, 19 Aug 2026 14:18:37 -0500
Subject: [PATCH 1/2] [MIR] Serialize register allocation anti-hints
---
.../include/llvm/CodeGen/MIRParser/MIParser.h | 1 +
llvm/include/llvm/CodeGen/MIRYamlMapping.h | 4 +
llvm/lib/CodeGen/MIRParser/MIRParser.cpp | 18 +++
llvm/lib/CodeGen/MIRPrinter.cpp | 12 ++
...r-allocation-antihints-mir-print-parse.mir | 121 ++++++++++++++++++
5 files changed, 156 insertions(+)
create mode 100644 llvm/test/CodeGen/MIR/AMDGPU/register-allocation-antihints-mir-print-parse.mir
diff --git a/llvm/include/llvm/CodeGen/MIRParser/MIParser.h b/llvm/include/llvm/CodeGen/MIRParser/MIParser.h
index 622862279cfdd..d163451a8a588 100644
--- a/llvm/include/llvm/CodeGen/MIRParser/MIParser.h
+++ b/llvm/include/llvm/CodeGen/MIRParser/MIParser.h
@@ -47,6 +47,7 @@ struct VRegInfo {
} D;
Register VReg;
Register PreferredReg;
+ SmallVector<Register, 4> AntiHints;
uint8_t Flags = 0;
};
diff --git a/llvm/include/llvm/CodeGen/MIRYamlMapping.h b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
index 76f5e38a045ff..05f6be547f367 100644
--- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h
+++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
@@ -203,6 +203,7 @@ struct VirtualRegisterDefinition {
StringValue Class;
StringValue PreferredRegister;
std::vector<FlowStringValue> RegisterFlags;
+ std::vector<FlowStringValue> AntiHints;
// VirtRegMap state.
// SplitFrom: id-form virtual register only (e.g. '%0'); physregs and named
// vregs are rejected by the parser.
@@ -227,6 +228,9 @@ template <> struct MappingTraits<VirtualRegisterDefinition> {
StringValue()); // Don't print out when it's empty.
YamlIO.mapOptional("flags", Reg.RegisterFlags,
std::vector<FlowStringValue>());
+ if (!YamlIO.outputting() || !Reg.AntiHints.empty())
+ YamlIO.mapOptional("anti-hints", Reg.AntiHints,
+ std::vector<FlowStringValue>());
// MIRPrinter sets WriteDefaultValues=true unless -simplify-mir is passed,
// so a plain mapOptional with an empty default would still emit the keys
// and change every existing test's output.
diff --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
index 6f1e7594f34da..8783078485877 100644
--- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -772,6 +772,22 @@ bool MIRParserImpl::parseRegisterInfo(PerFunctionMIParsingState &PFS,
FlagStringValue.Value + "'");
Info.Flags |= FlagValue;
}
+ if (!VReg.AntiHints.empty() && Info.Kind != VRegInfo::NORMAL)
+ return error(VReg.AntiHints.front().SourceRange.Start,
+ Twine("anti-hints can only be set for normal vregs"));
+
+ for (const auto &AntiHintValue : VReg.AntiHints) {
+ Register AntiHintReg;
+ if (parseRegisterReference(PFS, AntiHintReg, AntiHintValue.Value, Error))
+ return error(Error, AntiHintValue.SourceRange);
+
+ if (!AntiHintReg.isVirtual())
+ return error(AntiHintValue.SourceRange.Start,
+ Twine("anti-hint '") + AntiHintValue.Value +
+ "' must be a virtual register");
+
+ Info.AntiHints.push_back(AntiHintReg);
+ }
RegInfo.noteNewVirtualRegister(Info.VReg);
}
@@ -878,6 +894,8 @@ bool MIRParserImpl::setupRegisterInfo(const PerFunctionMIParsingState &PFS,
MRI.setRegClass(Reg, Info.D.RC);
if (Info.PreferredReg != 0)
MRI.setSimpleHint(Reg, Info.PreferredReg);
+ if (!Info.AntiHints.empty())
+ MRI.addRegAllocationAntiHints(Reg, Info.AntiHints);
break;
case VRegInfo::GENERIC:
break;
diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp
index 8acd6f14ebc2e..d4dff3be9041a 100644
--- a/llvm/lib/CodeGen/MIRPrinter.cpp
+++ b/llvm/lib/CodeGen/MIRPrinter.cpp
@@ -323,6 +323,18 @@ static void convertMRI(yaml::MachineFunction &YamlMF, const MachineFunction &MF,
if (PreferredReg)
printRegMIR(PreferredReg, VReg.PreferredRegister, TRI);
printRegFlags(Reg, VReg.RegisterFlags, MF, TRI);
+
+ // Print the anti-hints.
+ const auto &AntiHints = RegInfo.getRegAllocationAntiHints(Reg);
+ if (!AntiHints.empty()) {
+ std::vector<yaml::FlowStringValue> AntiHintStrings;
+ for (Register AntiHint : AntiHints) {
+ yaml::FlowStringValue AntiHintStr;
+ printRegMIR(AntiHint, AntiHintStr, TRI);
+ AntiHintStrings.push_back(std::move(AntiHintStr));
+ }
+ VReg.AntiHints = std::move(AntiHintStrings);
+ }
if (VRM) {
Register Orig = VRM->getPreSplitReg(Reg);
if (Orig && Orig != Reg) {
diff --git a/llvm/test/CodeGen/MIR/AMDGPU/register-allocation-antihints-mir-print-parse.mir b/llvm/test/CodeGen/MIR/AMDGPU/register-allocation-antihints-mir-print-parse.mir
new file mode 100644
index 0000000000000..574fe61c416de
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/AMDGPU/register-allocation-antihints-mir-print-parse.mir
@@ -0,0 +1,121 @@
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx942 -run-pass=none -o - %s | FileCheck %s
+
+---
+name: single_anti_hint
+tracksRegLiveness: true
+# CHECK-LABEL: name: single_anti_hint
+# CHECK: registers:
+# CHECK: - { id: 3, class: vreg_128_align2, preferred-register: '', flags: [ ],
+# CHECK-NEXT: anti-hints: [ '%1' ] }
+registers:
+ - { id: 0, class: vgpr_32 }
+ - { id: 1, class: vreg_512_align2 }
+ - { id: 2, class: vreg_512_align2 }
+ - { id: 3, class: vreg_128_align2, anti-hints: [ '%1' ] }
+body: |
+ bb.0:
+ %0:vgpr_32 = IMPLICIT_DEF
+ %1:vreg_512_align2 = IMPLICIT_DEF
+ %2:vreg_512_align2 = contract V_MFMA_F32_32X32X16_FP8_FP8_vgprcd_e64 %1.sub0_sub1, %1.sub2_sub3, %1, 0, 0, 0, implicit $mode, implicit $exec
+ %3:vreg_128_align2 = DS_READ_B128_gfx9 %0, 0, 0, implicit $exec :: (load (s128), addrspace 3)
+ S_ENDPGM 0, implicit %2, implicit %3
+...
+
+---
+name: multiple_anti_hints
+tracksRegLiveness: true
+# CHECK-LABEL: name: multiple_anti_hints
+# CHECK: registers:
+# CHECK: - { id: 3, class: vgpr_32, preferred-register: '', flags: [ ], anti-hints: [
+# CHECK-NEXT: '%1',
+# CHECK-NEXT: '%2' ] }
+# CHECK-NEXT: - { id: 4, class: vreg_128_align2, preferred-register: '', flags: [ ],
+# CHECK-NEXT: anti-hints: [ '%2' ] }
+registers:
+ - { id: 0, class: vgpr_32 }
+ - { id: 1, class: vreg_512_align2 }
+ - { id: 2, class: vreg_512_align2 }
+ - { id: 3, class: vgpr_32, anti-hints: [ '%1', '%2' ] }
+ - { id: 4, class: vreg_128_align2, anti-hints: [ '%2' ] }
+body: |
+ bb.0:
+ %0:vgpr_32 = IMPLICIT_DEF
+ %1:vreg_512_align2 = IMPLICIT_DEF
+ %2:vreg_512_align2 = contract V_MFMA_F32_32X32X16_FP8_FP8_vgprcd_e64 %1.sub0_sub1, %1.sub2_sub3, %1, 0, 0, 0, implicit $mode, implicit $exec
+ %3:vgpr_32 = V_ADD_U32_e32 4096, %0, implicit $exec
+ %4:vreg_128_align2 = DS_READ_B128_gfx9 %3, 0, 0, implicit $exec :: (load (s128), addrspace 3)
+ S_ENDPGM 0, implicit %2, implicit %4
+...
+
+---
+name: duplicate_anti_hints
+tracksRegLiveness: true
+# CHECK-LABEL: name: duplicate_anti_hints
+# CHECK: registers:
+# CHECK: - { id: 2, class: vgpr_32, preferred-register: '', flags: [ ], anti-hints: [
+# CHECK-NEXT: '%1' ] }
+registers:
+ - { id: 0, class: vgpr_32 }
+ - { id: 1, class: vreg_512_align2 }
+ - { id: 2, class: vgpr_32, anti-hints: [ '%1', '%1' ] }
+body: |
+ bb.0:
+ %0:vgpr_32 = IMPLICIT_DEF
+ %1:vreg_512_align2 = IMPLICIT_DEF
+ %2:vgpr_32 = V_ADD_U32_e32 4096, %0, implicit $exec
+ S_ENDPGM 0, implicit %1, implicit %2
+...
+
+---
+name: anti_hint_with_preferred_register
+tracksRegLiveness: true
+# CHECK-LABEL: name: anti_hint_with_preferred_register
+# CHECK: registers:
+# CHECK: - { id: 2, class: vgpr_32, preferred-register: '$vgpr8', flags: [ ],
+# CHECK-NEXT: anti-hints: [ '%1' ] }
+registers:
+ - { id: 0, class: vgpr_32 }
+ - { id: 1, class: vreg_512_align2 }
+ - { id: 2, class: vgpr_32, preferred-register: '$vgpr8', anti-hints: [ '%1' ] }
+body: |
+ bb.0:
+ %0:vgpr_32 = IMPLICIT_DEF
+ %1:vreg_512_align2 = IMPLICIT_DEF
+ %2:vgpr_32 = V_ADD_U32_e32 4096, %0, implicit $exec
+ S_ENDPGM 0, implicit %1, implicit %2
+...
+
+---
+name: empty_anti_hints
+tracksRegLiveness: true
+# CHECK-LABEL: name: empty_anti_hints
+# CHECK: registers:
+# CHECK: - { id: 1, class: vgpr_32, preferred-register: '', flags: [ ] }
+# CHECK-NEXT: liveins:
+registers:
+ - { id: 0, class: vgpr_32 }
+ - { id: 1, class: vgpr_32, anti-hints: [ ] }
+body: |
+ bb.0:
+ %0:vgpr_32 = IMPLICIT_DEF
+ %1:vgpr_32 = V_ADD_U32_e32 4096, %0, implicit $exec
+ S_ENDPGM 0, implicit %1
+...
+
+---
+name: no_anti_hints
+tracksRegLiveness: true
+# CHECK-LABEL: name: no_anti_hints
+# CHECK: registers:
+# CHECK-NEXT: - { id: 0, class: vgpr_32, preferred-register: '', flags: [ ] }
+# CHECK-NEXT: - { id: 1, class: vgpr_32, preferred-register: '', flags: [ ] }
+# CHECK-NEXT: liveins:
+registers:
+ - { id: 0, class: vgpr_32 }
+ - { id: 1, class: vgpr_32 }
+body: |
+ bb.0:
+ %0:vgpr_32 = IMPLICIT_DEF
+ %1:vgpr_32 = V_ADD_U32_e32 4096, %0, implicit $exec
+ S_ENDPGM 0, implicit %1
+...
>From 4b809a2ba5791f96d69b6801b94e1c1e7586bed7 Mon Sep 17 00:00:00 2001
From: mssefat <syadus.sefat at gmail.com>
Date: Wed, 26 Aug 2026 13:50:20 -0500
Subject: [PATCH 2/2] Addressed review
---
llvm/include/llvm/CodeGen/MIRYamlMapping.h | 6 +++---
llvm/lib/CodeGen/MIRParser/MIRParser.cpp | 5 +++--
.../register-allocation-antihints-mir-print-parse.mir | 2 +-
3 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/MIRYamlMapping.h b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
index 05f6be547f367..142ace2cf765f 100644
--- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h
+++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
@@ -228,13 +228,13 @@ template <> struct MappingTraits<VirtualRegisterDefinition> {
StringValue()); // Don't print out when it's empty.
YamlIO.mapOptional("flags", Reg.RegisterFlags,
std::vector<FlowStringValue>());
- if (!YamlIO.outputting() || !Reg.AntiHints.empty())
- YamlIO.mapOptional("anti-hints", Reg.AntiHints,
- std::vector<FlowStringValue>());
// MIRPrinter sets WriteDefaultValues=true unless -simplify-mir is passed,
// so a plain mapOptional with an empty default would still emit the keys
// and change every existing test's output.
// Skip the call on output when empty to keep them off entirely.
+ if (!YamlIO.outputting() || !Reg.AntiHints.empty())
+ YamlIO.mapOptional("anti-hints", Reg.AntiHints,
+ std::vector<FlowStringValue>());
if (!YamlIO.outputting() || !Reg.SplitFrom.Value.empty())
YamlIO.mapOptional("split-from", Reg.SplitFrom, StringValue());
if (!YamlIO.outputting() || !Reg.AssignedPhys.Value.empty())
diff --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
index 8783078485877..febb010bb4d09 100644
--- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -781,10 +781,11 @@ bool MIRParserImpl::parseRegisterInfo(PerFunctionMIParsingState &PFS,
if (parseRegisterReference(PFS, AntiHintReg, AntiHintValue.Value, Error))
return error(Error, AntiHintValue.SourceRange);
- if (!AntiHintReg.isVirtual())
+ if (!AntiHintReg.isVirtual()) {
return error(AntiHintValue.SourceRange.Start,
- Twine("anti-hint '") + AntiHintValue.Value +
+ "anti-hint '" + Twine(AntiHintValue.Value) +
"' must be a virtual register");
+ }
Info.AntiHints.push_back(AntiHintReg);
}
diff --git a/llvm/test/CodeGen/MIR/AMDGPU/register-allocation-antihints-mir-print-parse.mir b/llvm/test/CodeGen/MIR/AMDGPU/register-allocation-antihints-mir-print-parse.mir
index 574fe61c416de..12e15c3ef55b8 100644
--- a/llvm/test/CodeGen/MIR/AMDGPU/register-allocation-antihints-mir-print-parse.mir
+++ b/llvm/test/CodeGen/MIR/AMDGPU/register-allocation-antihints-mir-print-parse.mir
@@ -1,4 +1,4 @@
-# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx942 -run-pass=none -o - %s | FileCheck %s
+# RUN: llc -mtriple=amdgpu9.42-amd-amdhsa -run-pass=none -o - %s | FileCheck %s
---
name: single_anti_hint
More information about the llvm-branch-commits
mailing list