Download raw body.
llvm: backport [RegisterCoalescer] Avoid retrying high-cost joins for live intervals
llvm: backport [RegisterCoalescer] Avoid retrying high-cost joins for live intervals
On Wed, Sep 02, 2026 at 08:13:01PM +0200, Kirill A. Korinsky wrote:
> On Wed, 02 Sep 2026 15:38:16 +0200,
> Kirill A. Korinsky <kirill@korins.ky> wrote:
> >
> > tech@,
> >
> > an extreamly long build of libggml which hangs by timeout by naddy's build
> > allows to to catch a regression in LLVM which was fixed in upstream.
> >
> > libcxx update changed the libggml generated ThinLTO workload enough to
> > expose it.
> >
> > As fix here a backport of
> > https://github.com/llvm/llvm-project/commit/fd9e690cdbeb02832cc36d455bffda9e7e813785
> > which allows to build libggml in minutes again.
> >
> > I think that we should see some imporvment on bulk time on sparc64 as well,
> > maybe on other platforms.
> >
> > So, here the diff for both base and ports llvm which I had tested on amd64
> > against libggml build.
> >
>
> ... and I forgot to add tech@.
I get the same diff in base as you when applying the diff from the above
commit. I can confirm that it helps a lot with building the two
pathological ports, libggml and stable-diffusion.cpp,-vulkan.
I can't claim I understand the details but it does not look like
something that would cause regressions in other parts of the ports tree.
I'm happy to run a bulk with this if people would like me to.
ok tb
>
> Index: src/gnu/llvm/llvm/lib/CodeGen/RegisterCoalescer.cpp
> ===================================================================
> RCS file: /home/cvs/src/gnu/llvm/llvm/lib/CodeGen/RegisterCoalescer.cpp,v
> diff -u -p -r1.1.1.6 RegisterCoalescer.cpp
> --- src/gnu/llvm/llvm/lib/CodeGen/RegisterCoalescer.cpp 29 May 2026 11:00:41 -0000 1.1.1.6
> +++ src/gnu/llvm/llvm/lib/CodeGen/RegisterCoalescer.cpp 2 Sep 2026 12:47:21 -0000
> @@ -232,21 +232,26 @@ class RegisterCoalescer : private LiveRa
> void setUndefOnPrunedSubRegUses(LiveInterval &LI, Register Reg,
> LaneBitmask PrunedLanes);
>
> + /// Result of attempting to coalesce a copy.
> + /// - Joined: the copy was removed or otherwise fully handled.
> + /// - Deferred: retry after other coalescing may make progress.
> + /// - Rejected: do not retry, either because the copy is not a coalescing
> + /// candidate or because the join was intentionally rejected.
> + enum class JoinResult { Joined, Deferred, Rejected };
> +
> /// Attempt to join intervals corresponding to SrcReg/DstReg, which are the
> - /// src/dst of the copy instruction CopyMI. This returns true if the copy
> - /// was successfully coalesced away. If it is not currently possible to
> - /// coalesce this interval, but it may be possible if other things get
> - /// coalesced, then it returns true by reference in 'Again'.
> - bool joinCopy(MachineInstr *CopyMI, bool &Again,
> - SmallPtrSetImpl<MachineInstr *> &CurrentErasedInstrs);
> -
> - /// Attempt to join these two intervals. On failure, this
> - /// returns false. The output "SrcInt" will not have been modified, so we
> - /// can use this information below to update aliases.
> - bool joinIntervals(CoalescerPair &CP);
> + /// src/dst of the copy instruction CopyMI.
> + JoinResult joinCopy(MachineInstr *CopyMI,
> + SmallPtrSetImpl<MachineInstr *> &CurrentErasedInstrs);
> +
> + /// Attempt to join these two intervals. On failure, the output "SrcInt"
> + /// will not have been modified, so we can use this information below to
> + /// update aliases. Returns Deferred when it may be possible to join later,
> + /// or Rejected when retrying should be avoided.
> + JoinResult joinIntervals(CoalescerPair &CP);
>
> - /// Attempt joining two virtual registers. Return true on success.
> - bool joinVirtRegs(CoalescerPair &CP);
> + /// Attempt joining two virtual registers.
> + JoinResult joinVirtRegs(CoalescerPair &CP);
>
> /// If a live interval has many valnos and is coalesced with other
> /// live intervals many times, we regard such live interval as having
> @@ -2054,23 +2059,22 @@ void RegisterCoalescer::setUndefOnPruned
> LIS->shrinkToUses(&LI);
> }
>
> -bool RegisterCoalescer::joinCopy(
> - MachineInstr *CopyMI, bool &Again,
> +RegisterCoalescer::JoinResult RegisterCoalescer::joinCopy(
> + MachineInstr *CopyMI,
> SmallPtrSetImpl<MachineInstr *> &CurrentErasedInstrs) {
> - Again = false;
> LLVM_DEBUG(dbgs() << LIS->getInstructionIndex(*CopyMI) << '\t' << *CopyMI);
>
> CoalescerPair CP(*TRI);
> if (!CP.setRegisters(CopyMI)) {
> LLVM_DEBUG(dbgs() << "\tNot coalescable.\n");
> - return false;
> + return JoinResult::Rejected;
> }
>
> if (CP.getNewRC()) {
> if (RegClassInfo.getNumAllocatableRegs(CP.getNewRC()) == 0) {
> LLVM_DEBUG(dbgs() << "\tNo " << TRI->getRegClassName(CP.getNewRC())
> << "are available for allocation\n");
> - return false;
> + return JoinResult::Rejected;
> }
>
> auto SrcRC = MRI->getRegClass(CP.getSrcReg());
> @@ -2084,7 +2088,7 @@ bool RegisterCoalescer::joinCopy(
> if (!TRI->shouldCoalesce(CopyMI, SrcRC, SrcIdx, DstRC, DstIdx,
> CP.getNewRC(), *LIS)) {
> LLVM_DEBUG(dbgs() << "\tSubtarget bailed on coalescing.\n");
> - return false;
> + return JoinResult::Rejected;
> }
> }
>
> @@ -2095,7 +2099,7 @@ bool RegisterCoalescer::joinCopy(
> LLVM_DEBUG(dbgs() << "\tCopy is dead.\n");
> DeadDefs.push_back(CopyMI);
> eliminateDeadDefs();
> - return true;
> + return JoinResult::Joined;
> }
>
> // Eliminate undefs.
> @@ -2103,9 +2107,9 @@ bool RegisterCoalescer::joinCopy(
> // If this is an IMPLICIT_DEF, leave it alone, but don't try to coalesce.
> if (MachineInstr *UndefMI = eliminateUndefCopy(CopyMI)) {
> if (UndefMI->isImplicitDef())
> - return false;
> + return JoinResult::Rejected;
> deleteInstr(CopyMI);
> - return false; // Not coalescable.
> + return JoinResult::Rejected; // Not coalescable.
> }
> }
>
> @@ -2153,7 +2157,7 @@ bool RegisterCoalescer::joinCopy(
> LLVM_DEBUG(dbgs() << "\tMerged values: " << LI << '\n');
> }
> deleteInstr(CopyMI);
> - return true;
> + return JoinResult::Joined;
> }
>
> // Enforce policies.
> @@ -2166,10 +2170,10 @@ bool RegisterCoalescer::joinCopy(
> // the copy instead if it is cheap.
> bool IsDefCopy = false;
> if (reMaterializeDef(CP, CopyMI, IsDefCopy))
> - return true;
> + return JoinResult::Joined;
> if (IsDefCopy)
> - Again = true; // May be possible to coalesce later.
> - return false;
> + return JoinResult::Deferred; // May be possible to coalesce later.
> + return JoinResult::Rejected;
> }
> } else {
> // When possible, let DstReg be the larger interval.
> @@ -2194,17 +2198,18 @@ bool RegisterCoalescer::joinCopy(
> ShrinkMask = LaneBitmask::getNone();
> ShrinkMainRange = false;
>
> - // Okay, attempt to join these two intervals. On failure, this returns false.
> - // Otherwise, if one of the intervals being joined is a physreg, this method
> - // always canonicalizes DstInt to be it. The output "SrcInt" will not have
> - // been modified, so we can use this information below to update aliases.
> - if (!joinIntervals(CP)) {
> + // Okay, attempt to join these two intervals. If one of the intervals being
> + // joined is a physreg and the join succeeds, this method always canonicalizes
> + // DstInt to be it. The output "SrcInt" will not have been modified, so we
> + // can use this information below to update aliases.
> + JoinResult Result = joinIntervals(CP);
> + if (Result != JoinResult::Joined) {
> // Coalescing failed.
>
> // Try rematerializing the definition of the source if it is cheap.
> bool IsDefCopy = false;
> if (reMaterializeDef(CP, CopyMI, IsDefCopy))
> - return true;
> + return JoinResult::Joined;
>
> // If we can eliminate the copy without merging the live segments, do so
> // now.
> @@ -2222,7 +2227,7 @@ bool RegisterCoalescer::joinCopy(
> LLVM_DEBUG(dbgs() << "\t\tshrunk: " << DstLI << '\n');
> }
> LLVM_DEBUG(dbgs() << "\tTrivial!\n");
> - return true;
> + return JoinResult::Joined;
> }
> }
>
> @@ -2230,12 +2235,16 @@ bool RegisterCoalescer::joinCopy(
> // its predecessor.
> if (!CP.isPartial() && !CP.isPhys())
> if (removePartialRedundancy(CP, *CopyMI))
> - return true;
> + return JoinResult::Joined;
>
> // Otherwise, we are unable to join the intervals.
> LLVM_DEBUG(dbgs() << "\tInterference!\n");
> - Again = true; // May be possible to coalesce later.
> - return false;
> + // A high-cost interval is already too expensive to retry. Keeping the copy
> + // in WorkList would make every subsequent successful join rescan it again,
> + // which can dominate compile time.
> + if (Result == JoinResult::Deferred)
> + LLVM_DEBUG(dbgs() << "\tWill retry later.\n");
> + return Result;
> }
>
> // Coalescing to a virtual register that is of a sub-register class of the
> @@ -2307,7 +2316,7 @@ bool RegisterCoalescer::joinCopy(
> });
>
> ++numJoins;
> - return true;
> + return JoinResult::Joined;
> }
>
> bool RegisterCoalescer::joinReservedPhysReg(CoalescerPair &CP) {
> @@ -3698,7 +3707,8 @@ bool RegisterCoalescer::isHighCostLiveIn
> return true;
> }
>
> -bool RegisterCoalescer::joinVirtRegs(CoalescerPair &CP) {
> +RegisterCoalescer::JoinResult
> +RegisterCoalescer::joinVirtRegs(CoalescerPair &CP) {
> SmallVector<VNInfo *, 16> NewVNInfo;
> LiveInterval &RHS = LIS->getInterval(CP.getSrcReg());
> LiveInterval &LHS = LIS->getInterval(CP.getDstReg());
> @@ -3710,17 +3720,24 @@ bool RegisterCoalescer::joinVirtRegs(Coa
>
> LLVM_DEBUG(dbgs() << "\t\tRHS = " << RHS << "\n\t\tLHS = " << LHS << '\n');
>
> - if (isHighCostLiveInterval(LHS) || isHighCostLiveInterval(RHS))
> - return false;
> + if (isHighCostLiveInterval(LHS) || isHighCostLiveInterval(RHS)) {
> + LLVM_DEBUG(dbgs() << "\t\tHigh-cost live interval: RHS valnos="
> + << RHS.valnos.size() << ", segments=" << RHS.size()
> + << "; LHS valnos=" << LHS.valnos.size()
> + << ", segments=" << LHS.size() << '\n');
> + return JoinResult::Rejected;
> + }
>
> - // First compute NewVNInfo and the simple value mappings.
> - // Detect impossible conflicts early.
> + // First compute NewVNInfo and the simple value mappings. Conflicts found
> + // here only reject this attempt; subsequent coalescing may still make the
> + // same copy joinable, so keep it deferred.
> if (!LHSVals.mapValues(RHSVals) || !RHSVals.mapValues(LHSVals))
> - return false;
> + return JoinResult::Deferred;
>
> // Some conflicts can only be resolved after all values have been mapped.
> + // As above, unresolved conflicts are retryable interference.
> if (!LHSVals.resolveConflicts(RHSVals) || !RHSVals.resolveConflicts(LHSVals))
> - return false;
> + return JoinResult::Deferred;
>
> // All clear, the live ranges can be merged.
> if (RHS.hasSubRanges() || LHS.hasSubRanges()) {
> @@ -3875,11 +3892,14 @@ bool RegisterCoalescer::joinVirtRegs(Coa
> LIS->extendToIndices((LiveRange &)LHS, EndPoints);
> }
>
> - return true;
> + return JoinResult::Joined;
> }
>
> -bool RegisterCoalescer::joinIntervals(CoalescerPair &CP) {
> - return CP.isPhys() ? joinReservedPhysReg(CP) : joinVirtRegs(CP);
> +RegisterCoalescer::JoinResult
> +RegisterCoalescer::joinIntervals(CoalescerPair &CP) {
> + if (CP.isPhys())
> + return joinReservedPhysReg(CP) ? JoinResult::Joined : JoinResult::Deferred;
> + return joinVirtRegs(CP);
> }
>
> void RegisterCoalescer::buildVRegToDbgValueMap(MachineFunction &MF) {
> @@ -4095,10 +4115,9 @@ bool RegisterCoalescer::copyCoalesceWork
> MI = nullptr;
> continue;
> }
> - bool Again = false;
> - bool Success = joinCopy(MI, Again, CurrentErasedInstrs);
> - Progress |= Success;
> - if (Success || !Again)
> + JoinResult Result = joinCopy(MI, CurrentErasedInstrs);
> + Progress |= Result == JoinResult::Joined;
> + if (Result != JoinResult::Deferred)
> MI = nullptr;
> }
> // Clear instructions not recorded in `ErasedInstrs` but erased.
> Index: ports/devel/llvm/22/Makefile
> ===================================================================
> RCS file: /home/cvs/ports/devel/llvm/22/Makefile,v
> diff -u -p -r1.25 Makefile
> --- ports/devel/llvm/22/Makefile 21 Aug 2026 13:27:47 -0000 1.25
> +++ ports/devel/llvm/22/Makefile 2 Sep 2026 13:29:36 -0000
> @@ -2,7 +2,7 @@ LLVM_MAJOR = 22
> LLVM_VERSION = ${LLVM_MAJOR}.1.8
> LLVM_PKGSPEC = >=22,<23
>
> -REVISION = 6
> +REVISION = 7
>
> SHARED_LIBS += LLVM 0.0 \
> LTO 0.0 \
> Index: ports/devel/llvm/22/patches/patch-llvm_lib_CodeGen_RegisterCoalescer_cpp
> ===================================================================
> RCS file: ports/devel/llvm/22/patches/patch-llvm_lib_CodeGen_RegisterCoalescer_cpp
> diff -N ports/devel/llvm/22/patches/patch-llvm_lib_CodeGen_RegisterCoalescer_cpp
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ ports/devel/llvm/22/patches/patch-llvm_lib_CodeGen_RegisterCoalescer_cpp 2 Sep 2026 13:32:16 -0000
> @@ -0,0 +1,262 @@
> +Backport: [RegisterCoalescer] Avoid retrying high-cost joins for live intervals
> +https://github.com/llvm/llvm-project/commit/fd9e690cdbeb02832cc36d455bffda9e7e813785
> +
> +Index: llvm/lib/CodeGen/RegisterCoalescer.cpp
> +--- llvm/lib/CodeGen/RegisterCoalescer.cpp.orig
> ++++ llvm/lib/CodeGen/RegisterCoalescer.cpp
> +@@ -232,21 +232,26 @@ class RegisterCoalescer : private LiveRangeEdit::Deleg
> + void setUndefOnPrunedSubRegUses(LiveInterval &LI, Register Reg,
> + LaneBitmask PrunedLanes);
> +
> ++ /// Result of attempting to coalesce a copy.
> ++ /// - Joined: the copy was removed or otherwise fully handled.
> ++ /// - Deferred: retry after other coalescing may make progress.
> ++ /// - Rejected: do not retry, either because the copy is not a coalescing
> ++ /// candidate or because the join was intentionally rejected.
> ++ enum class JoinResult { Joined, Deferred, Rejected };
> ++
> + /// Attempt to join intervals corresponding to SrcReg/DstReg, which are the
> +- /// src/dst of the copy instruction CopyMI. This returns true if the copy
> +- /// was successfully coalesced away. If it is not currently possible to
> +- /// coalesce this interval, but it may be possible if other things get
> +- /// coalesced, then it returns true by reference in 'Again'.
> +- bool joinCopy(MachineInstr *CopyMI, bool &Again,
> +- SmallPtrSetImpl<MachineInstr *> &CurrentErasedInstrs);
> ++ /// src/dst of the copy instruction CopyMI.
> ++ JoinResult joinCopy(MachineInstr *CopyMI,
> ++ SmallPtrSetImpl<MachineInstr *> &CurrentErasedInstrs);
> +
> +- /// Attempt to join these two intervals. On failure, this
> +- /// returns false. The output "SrcInt" will not have been modified, so we
> +- /// can use this information below to update aliases.
> +- bool joinIntervals(CoalescerPair &CP);
> ++ /// Attempt to join these two intervals. On failure, the output "SrcInt"
> ++ /// will not have been modified, so we can use this information below to
> ++ /// update aliases. Returns Deferred when it may be possible to join later,
> ++ /// or Rejected when retrying should be avoided.
> ++ JoinResult joinIntervals(CoalescerPair &CP);
> +
> +- /// Attempt joining two virtual registers. Return true on success.
> +- bool joinVirtRegs(CoalescerPair &CP);
> ++ /// Attempt joining two virtual registers.
> ++ JoinResult joinVirtRegs(CoalescerPair &CP);
> +
> + /// If a live interval has many valnos and is coalesced with other
> + /// live intervals many times, we regard such live interval as having
> +@@ -2054,23 +2059,22 @@ void RegisterCoalescer::setUndefOnPrunedSubRegUses(Liv
> + LIS->shrinkToUses(&LI);
> + }
> +
> +-bool RegisterCoalescer::joinCopy(
> +- MachineInstr *CopyMI, bool &Again,
> ++RegisterCoalescer::JoinResult RegisterCoalescer::joinCopy(
> ++ MachineInstr *CopyMI,
> + SmallPtrSetImpl<MachineInstr *> &CurrentErasedInstrs) {
> +- Again = false;
> + LLVM_DEBUG(dbgs() << LIS->getInstructionIndex(*CopyMI) << '\t' << *CopyMI);
> +
> + CoalescerPair CP(*TRI);
> + if (!CP.setRegisters(CopyMI)) {
> + LLVM_DEBUG(dbgs() << "\tNot coalescable.\n");
> +- return false;
> ++ return JoinResult::Rejected;
> + }
> +
> + if (CP.getNewRC()) {
> + if (RegClassInfo.getNumAllocatableRegs(CP.getNewRC()) == 0) {
> + LLVM_DEBUG(dbgs() << "\tNo " << TRI->getRegClassName(CP.getNewRC())
> + << "are available for allocation\n");
> +- return false;
> ++ return JoinResult::Rejected;
> + }
> +
> + auto SrcRC = MRI->getRegClass(CP.getSrcReg());
> +@@ -2084,7 +2088,7 @@ bool RegisterCoalescer::joinCopy(
> + if (!TRI->shouldCoalesce(CopyMI, SrcRC, SrcIdx, DstRC, DstIdx,
> + CP.getNewRC(), *LIS)) {
> + LLVM_DEBUG(dbgs() << "\tSubtarget bailed on coalescing.\n");
> +- return false;
> ++ return JoinResult::Rejected;
> + }
> + }
> +
> +@@ -2095,7 +2099,7 @@ bool RegisterCoalescer::joinCopy(
> + LLVM_DEBUG(dbgs() << "\tCopy is dead.\n");
> + DeadDefs.push_back(CopyMI);
> + eliminateDeadDefs();
> +- return true;
> ++ return JoinResult::Joined;
> + }
> +
> + // Eliminate undefs.
> +@@ -2103,9 +2107,9 @@ bool RegisterCoalescer::joinCopy(
> + // If this is an IMPLICIT_DEF, leave it alone, but don't try to coalesce.
> + if (MachineInstr *UndefMI = eliminateUndefCopy(CopyMI)) {
> + if (UndefMI->isImplicitDef())
> +- return false;
> ++ return JoinResult::Rejected;
> + deleteInstr(CopyMI);
> +- return false; // Not coalescable.
> ++ return JoinResult::Rejected; // Not coalescable.
> + }
> + }
> +
> +@@ -2153,7 +2157,7 @@ bool RegisterCoalescer::joinCopy(
> + LLVM_DEBUG(dbgs() << "\tMerged values: " << LI << '\n');
> + }
> + deleteInstr(CopyMI);
> +- return true;
> ++ return JoinResult::Joined;
> + }
> +
> + // Enforce policies.
> +@@ -2166,10 +2170,10 @@ bool RegisterCoalescer::joinCopy(
> + // the copy instead if it is cheap.
> + bool IsDefCopy = false;
> + if (reMaterializeDef(CP, CopyMI, IsDefCopy))
> +- return true;
> ++ return JoinResult::Joined;
> + if (IsDefCopy)
> +- Again = true; // May be possible to coalesce later.
> +- return false;
> ++ return JoinResult::Deferred; // May be possible to coalesce later.
> ++ return JoinResult::Rejected;
> + }
> + } else {
> + // When possible, let DstReg be the larger interval.
> +@@ -2194,17 +2198,18 @@ bool RegisterCoalescer::joinCopy(
> + ShrinkMask = LaneBitmask::getNone();
> + ShrinkMainRange = false;
> +
> +- // Okay, attempt to join these two intervals. On failure, this returns false.
> +- // Otherwise, if one of the intervals being joined is a physreg, this method
> +- // always canonicalizes DstInt to be it. The output "SrcInt" will not have
> +- // been modified, so we can use this information below to update aliases.
> +- if (!joinIntervals(CP)) {
> ++ // Okay, attempt to join these two intervals. If one of the intervals being
> ++ // joined is a physreg and the join succeeds, this method always canonicalizes
> ++ // DstInt to be it. The output "SrcInt" will not have been modified, so we
> ++ // can use this information below to update aliases.
> ++ JoinResult Result = joinIntervals(CP);
> ++ if (Result != JoinResult::Joined) {
> + // Coalescing failed.
> +
> + // Try rematerializing the definition of the source if it is cheap.
> + bool IsDefCopy = false;
> + if (reMaterializeDef(CP, CopyMI, IsDefCopy))
> +- return true;
> ++ return JoinResult::Joined;
> +
> + // If we can eliminate the copy without merging the live segments, do so
> + // now.
> +@@ -2222,7 +2227,7 @@ bool RegisterCoalescer::joinCopy(
> + LLVM_DEBUG(dbgs() << "\t\tshrunk: " << DstLI << '\n');
> + }
> + LLVM_DEBUG(dbgs() << "\tTrivial!\n");
> +- return true;
> ++ return JoinResult::Joined;
> + }
> + }
> +
> +@@ -2230,12 +2235,16 @@ bool RegisterCoalescer::joinCopy(
> + // its predecessor.
> + if (!CP.isPartial() && !CP.isPhys())
> + if (removePartialRedundancy(CP, *CopyMI))
> +- return true;
> ++ return JoinResult::Joined;
> +
> + // Otherwise, we are unable to join the intervals.
> + LLVM_DEBUG(dbgs() << "\tInterference!\n");
> +- Again = true; // May be possible to coalesce later.
> +- return false;
> ++ // A high-cost interval is already too expensive to retry. Keeping the copy
> ++ // in WorkList would make every subsequent successful join rescan it again,
> ++ // which can dominate compile time.
> ++ if (Result == JoinResult::Deferred)
> ++ LLVM_DEBUG(dbgs() << "\tWill retry later.\n");
> ++ return Result;
> + }
> +
> + // Coalescing to a virtual register that is of a sub-register class of the
> +@@ -2307,7 +2316,7 @@ bool RegisterCoalescer::joinCopy(
> + });
> +
> + ++numJoins;
> +- return true;
> ++ return JoinResult::Joined;
> + }
> +
> + bool RegisterCoalescer::joinReservedPhysReg(CoalescerPair &CP) {
> +@@ -3698,7 +3707,8 @@ bool RegisterCoalescer::isHighCostLiveInterval(LiveInt
> + return true;
> + }
> +
> +-bool RegisterCoalescer::joinVirtRegs(CoalescerPair &CP) {
> ++RegisterCoalescer::JoinResult
> ++RegisterCoalescer::joinVirtRegs(CoalescerPair &CP) {
> + SmallVector<VNInfo *, 16> NewVNInfo;
> + LiveInterval &RHS = LIS->getInterval(CP.getSrcReg());
> + LiveInterval &LHS = LIS->getInterval(CP.getDstReg());
> +@@ -3710,17 +3720,24 @@ bool RegisterCoalescer::joinVirtRegs(CoalescerPair &CP
> +
> + LLVM_DEBUG(dbgs() << "\t\tRHS = " << RHS << "\n\t\tLHS = " << LHS << '\n');
> +
> +- if (isHighCostLiveInterval(LHS) || isHighCostLiveInterval(RHS))
> +- return false;
> ++ if (isHighCostLiveInterval(LHS) || isHighCostLiveInterval(RHS)) {
> ++ LLVM_DEBUG(dbgs() << "\t\tHigh-cost live interval: RHS valnos="
> ++ << RHS.valnos.size() << ", segments=" << RHS.size()
> ++ << "; LHS valnos=" << LHS.valnos.size()
> ++ << ", segments=" << LHS.size() << '\n');
> ++ return JoinResult::Rejected;
> ++ }
> +
> +- // First compute NewVNInfo and the simple value mappings.
> +- // Detect impossible conflicts early.
> ++ // First compute NewVNInfo and the simple value mappings. Conflicts found
> ++ // here only reject this attempt; subsequent coalescing may still make the
> ++ // same copy joinable, so keep it deferred.
> + if (!LHSVals.mapValues(RHSVals) || !RHSVals.mapValues(LHSVals))
> +- return false;
> ++ return JoinResult::Deferred;
> +
> + // Some conflicts can only be resolved after all values have been mapped.
> ++ // As above, unresolved conflicts are retryable interference.
> + if (!LHSVals.resolveConflicts(RHSVals) || !RHSVals.resolveConflicts(LHSVals))
> +- return false;
> ++ return JoinResult::Deferred;
> +
> + // All clear, the live ranges can be merged.
> + if (RHS.hasSubRanges() || LHS.hasSubRanges()) {
> +@@ -3875,11 +3892,14 @@ bool RegisterCoalescer::joinVirtRegs(CoalescerPair &CP
> + LIS->extendToIndices((LiveRange &)LHS, EndPoints);
> + }
> +
> +- return true;
> ++ return JoinResult::Joined;
> + }
> +
> +-bool RegisterCoalescer::joinIntervals(CoalescerPair &CP) {
> +- return CP.isPhys() ? joinReservedPhysReg(CP) : joinVirtRegs(CP);
> ++RegisterCoalescer::JoinResult
> ++RegisterCoalescer::joinIntervals(CoalescerPair &CP) {
> ++ if (CP.isPhys())
> ++ return joinReservedPhysReg(CP) ? JoinResult::Joined : JoinResult::Deferred;
> ++ return joinVirtRegs(CP);
> + }
> +
> + void RegisterCoalescer::buildVRegToDbgValueMap(MachineFunction &MF) {
> +@@ -4095,10 +4115,9 @@ bool RegisterCoalescer::copyCoalesceWorkList(
> + MI = nullptr;
> + continue;
> + }
> +- bool Again = false;
> +- bool Success = joinCopy(MI, Again, CurrentErasedInstrs);
> +- Progress |= Success;
> +- if (Success || !Again)
> ++ JoinResult Result = joinCopy(MI, CurrentErasedInstrs);
> ++ Progress |= Result == JoinResult::Joined;
> ++ if (Result != JoinResult::Deferred)
> + MI = nullptr;
> + }
> + // Clear instructions not recorded in `ErasedInstrs` but erased.
>
>
> --
> wbr, Kirill
>
llvm: backport [RegisterCoalescer] Avoid retrying high-cost joins for live intervals
llvm: backport [RegisterCoalescer] Avoid retrying high-cost joins for live intervals