https://github.com/mssefat updated https://github.com/llvm/llvm-project/pull/218073
>From 244fb01f8407f2138d07509ee26c2d3097bce79d Mon Sep 17 00:00:00 2001 From: mssefat <[email protected]> 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 <[email protected]> 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 _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
