[llvm] [RegisterCoalescer] Fix compile-time blowup with partially-reserved physregs (PR #181728)
Brian Cain via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 16 11:25:10 PST 2026
https://github.com/androm3da created https://github.com/llvm/llvm-project/pull/181728
canJoinPhys checks isReserved on the super-register but joinReservedPhysReg additionally requires every register-unit root to be reserved. When a target reserves only part of a super-register (e.g. Hexagon -ffixed-r19 reserves R19 and D9, but not R18), the mismatch causes joinReservedPhysReg to fail, reMaterializeDef to fail, and the copy to be unconditionally retried (Again = true) every worklist round. In large functions this O(N^2) retry behaviour leads to multi-hour compile times.
Add the same regunit-root-reserved check to canJoinPhys so that it returns false early, routing through the !canJoinPhys path where Again is only set when IsDefCopy is true.
>From 89741d54892359d09a6a2cf5395e4a13b18d32a7 Mon Sep 17 00:00:00 2001
From: Brian Cain <brian.cain at oss.qualcomm.com>
Date: Mon, 16 Feb 2026 11:21:16 -0800
Subject: [PATCH] [RegisterCoalescer] Fix compile-time blowup with
partially-reserved physregs
canJoinPhys checks isReserved on the super-register but
joinReservedPhysReg additionally requires every register-unit root to
be reserved. When a target reserves only part of a super-register
(e.g. Hexagon -ffixed-r19 reserves R19 and D9, but not R18), the
mismatch causes joinReservedPhysReg to fail, reMaterializeDef to fail,
and the copy to be unconditionally retried (Again = true) every
worklist round. In large functions this O(N^2) retry behaviour leads
to multi-hour compile times.
Add the same regunit-root-reserved check to canJoinPhys so that it
returns false early, routing through the !canJoinPhys path where Again
is only set when IsDefCopy is true.
---
llvm/lib/CodeGen/RegisterCoalescer.cpp | 14 +++++++++++++
.../coalescer-partial-reserved-physreg.mir | 20 +++++++++++++++++++
2 files changed, 34 insertions(+)
create mode 100644 llvm/test/CodeGen/Hexagon/coalescer-partial-reserved-physreg.mir
diff --git a/llvm/lib/CodeGen/RegisterCoalescer.cpp b/llvm/lib/CodeGen/RegisterCoalescer.cpp
index 586c27b7e3baf..6db602ee5fb2a 100644
--- a/llvm/lib/CodeGen/RegisterCoalescer.cpp
+++ b/llvm/lib/CodeGen/RegisterCoalescer.cpp
@@ -1982,6 +1982,20 @@ bool RegisterCoalescer::canJoinPhys(const CoalescerPair &CP) {
return false;
}
+ // Verify all register unit roots are reserved. joinReservedPhysReg requires
+ // this, so reject early to route the copy through the !canJoinPhys path
+ // where Again is only set when IsDefCopy is true.
+ if (!MRI->isConstantPhysReg(CP.getDstReg())) {
+ for (MCRegUnit Unit : TRI->regunits(CP.getDstReg())) {
+ for (MCRegUnitRootIterator RI(Unit, TRI); RI.isValid(); ++RI) {
+ if (!MRI->isReserved(*RI)) {
+ LLVM_DEBUG(dbgs() << "\tNot all register unit roots reserved.\n");
+ return false;
+ }
+ }
+ }
+ }
+
LiveInterval &JoinVInt = LIS->getInterval(CP.getSrcReg());
if (JoinVInt.containsOneValue())
return true;
diff --git a/llvm/test/CodeGen/Hexagon/coalescer-partial-reserved-physreg.mir b/llvm/test/CodeGen/Hexagon/coalescer-partial-reserved-physreg.mir
new file mode 100644
index 0000000000000..1b3c2f306edec
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/coalescer-partial-reserved-physreg.mir
@@ -0,0 +1,20 @@
+# RUN: llc -mtriple=hexagon -mattr=+reserved-r19 \
+# RUN: -run-pass=register-coalescer -o - %s | FileCheck %s
+#
+# Regression test for a compile-time blowup in the register coalescer with
+# partially-reserved physical registers.
+#
+# CHECK-LABEL: name: test
+# CHECK: bb.0:
+---
+name: test
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $r31
+
+ %0:doubleregs = A2_tfrpi 1
+ $r18 = COPY %0.isub_lo:doubleregs
+ J2_jumpr $r31, implicit-def dead $pc, implicit $r18
+
+...
More information about the llvm-commits
mailing list