[llvm] CodeGen: Clear physreg ranges after SplitCriticalEdge (PR #223172)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Sat Sep 12 13:38:35 PDT 2026
https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/223172
After critical edge spliting replaces a terminator, clear referenced
physreg ranges. The block's terminators may be replaced, and may
reference physical registers (e.g. WebAssebly's ARGUMENTS. When
LiveIntervals is available, repairIntervalsInRange only repairs virtual
registers, so the tracked physreg units were stale.
It feels like a bug that repairIntervalsInRange doesn't touch physregs,
but I've left that for a future change.
Co-Authored-By: Claude claude-opus-4.8 <noreply at anthropic.com>
>From 1180206e06c72ff6ca84366507d0f9b3a9d4391c Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sat, 12 Sep 2026 10:30:09 +0200
Subject: [PATCH] CodeGen: Clear physreg ranges after SplitCriticalEdge
After critical edge spliting replaces a terminator, clear referenced
physreg ranges. The block's terminators may be replaced, and may
reference physical registers (e.g. WebAssebly's ARGUMENTS. When
LiveIntervals is available, repairIntervalsInRange only repairs virtual
registers, so the tracked physreg units were stale.
It feels like a bug that repairIntervalsInRange doesn't touch physregs,
but I've left that for a future change.
Co-Authored-By: Claude claude-opus-4.8 <noreply at anthropic.com>
---
llvm/lib/CodeGen/MachineBasicBlock.cpp | 7 +++
.../splitcriticaledge-physreg-liveness.mir | 60 +++++++++++++++++++
2 files changed, 67 insertions(+)
create mode 100644 llvm/test/CodeGen/WebAssembly/splitcriticaledge-physreg-liveness.mir
diff --git a/llvm/lib/CodeGen/MachineBasicBlock.cpp b/llvm/lib/CodeGen/MachineBasicBlock.cpp
index 736e455740547..fe9f9a52c3d7b 100644
--- a/llvm/lib/CodeGen/MachineBasicBlock.cpp
+++ b/llvm/lib/CodeGen/MachineBasicBlock.cpp
@@ -1388,6 +1388,13 @@ MachineBasicBlock *MachineBasicBlock::SplitCriticalEdge(
// Update all intervals for registers whose uses may have been modified by
// updateTerminator().
LIS->repairIntervalsInRange(this, getFirstTerminator(), end(), UsedRegs);
+
+ // repairIntervalsInRange() does not update physregs; clear their ranges
+ // since updateTerminator() may have replaced defs.
+ for (Register Reg : UsedRegs) {
+ if (Reg.isPhysical())
+ LIS->removeAllRegUnitsForPhysReg(Reg.asMCReg());
+ }
}
if (MDTU)
diff --git a/llvm/test/CodeGen/WebAssembly/splitcriticaledge-physreg-liveness.mir b/llvm/test/CodeGen/WebAssembly/splitcriticaledge-physreg-liveness.mir
new file mode 100644
index 0000000000000..e3b4b7d966f6d
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/splitcriticaledge-physreg-liveness.mir
@@ -0,0 +1,60 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=wasm32-unknown-unknown \
+# RUN: -run-pass=liveintervals,phi-node-elimination \
+# RUN: -precompute-phys-liveness -verify-machineinstrs %s -o - | FileCheck %s
+
+# Splitting the critical edge bb.0 -> bb.2 rewrites terminators that
+# def the ARGUMENTS physreg. Its regunit ranges must be recomputed.
+
+---
+name: split_physreg_terminator
+tracksRegLiveness: true
+liveins:
+ - { reg: '$arguments' }
+body: |
+ ; CHECK-LABEL: name: split_physreg_terminator
+ ; CHECK: bb.0:
+ ; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.3(0x40000000)
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[ARGUMENT_i32_:%[0-9]+]]:i32 = ARGUMENT_i32 0, implicit $arguments
+ ; CHECK-NEXT: [[CONST_I32_:%[0-9]+]]:i32 = CONST_I32 -1, implicit-def dead $arguments
+ ; CHECK-NEXT: [[GT_S_I32_:%[0-9]+]]:i32 = GT_S_I32 [[ARGUMENT_i32_]], [[CONST_I32_]], implicit-def dead $arguments
+ ; CHECK-NEXT: BR_UNLESS %bb.1, [[GT_S_I32_]], implicit-def $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.3:
+ ; CHECK-NEXT: successors: %bb.2(0x80000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:i32 = COPY [[ARGUMENT_i32_]]
+ ; CHECK-NEXT: BR %bb.2, implicit-def $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.1:
+ ; CHECK-NEXT: successors: %bb.2(0x80000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[CONST_I32_1:%[0-9]+]]:i32 = CONST_I32 3, implicit-def dead $arguments
+ ; CHECK-NEXT: [[DIV_S_I32_:%[0-9]+]]:i32 = DIV_S_I32 [[ARGUMENT_i32_]], [[CONST_I32_1]], implicit-def dead $arguments
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:i32 = COPY [[DIV_S_I32_]]
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.2:
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:i32 = COPY [[COPY]]
+ ; CHECK-NEXT: RETURN [[COPY1]], implicit-def dead $arguments
+ bb.0:
+ successors: %bb.1, %bb.2
+ liveins: $arguments
+
+ %0:i32 = ARGUMENT_i32 0, implicit killed $arguments
+ %1:i32 = CONST_I32 -1, implicit-def dead $arguments
+ %2:i32 = GT_S_I32 %0, killed %1, implicit-def dead $arguments
+ BR_IF %bb.2, killed %2, implicit-def dead $arguments
+ BR %bb.1, implicit-def dead $arguments
+
+ bb.1:
+ successors: %bb.2
+
+ %3:i32 = CONST_I32 3, implicit-def dead $arguments
+ %4:i32 = DIV_S_I32 killed %0, killed %3, implicit-def dead $arguments
+
+ bb.2:
+ %5:i32 = PHI %0, %bb.0, %4, %bb.1
+ RETURN killed %5, implicit-def dead $arguments
+...
More information about the llvm-commits
mailing list