[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