From: Kirill A. Korinsky Subject: Re: llvm: backport [RegisterCoalescer] Avoid retrying high-cost joins for live intervals To: Theo Buehler Cc: tech@openbsd.org, ports@openbsd.org, robert@openbsd.org Date: Wed, 02 Sep 2026 23:16:38 +0200 On Wed, 02 Sep 2026 21:13:21 +0200, Theo Buehler wrote: > > 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 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. > Thanks. I'd like to go it in tomorrow, if no one object. > 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 &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 &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 &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 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 &CurrentErasedInstrs); > > ++ /// src/dst of the copy instruction CopyMI. > > ++ JoinResult joinCopy(MachineInstr *CopyMI, > > ++ SmallPtrSetImpl &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 &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 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 > > > -- wbr, Kirill