[llvm] [TwoAddressInstruction] Check if segment was found when updating subreg LIs (PR #65916)

Luke Lau via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 10 16:53:03 PDT 2023


https://github.com/lukel97 created https://github.com/llvm/llvm-project/pull/65916:

This patch fixes a crash I was seeing when working with subregisters in a
separate upcoming patch. Some of the RVV tests have -early-live-intervals
enabled, which triggers this subregister liveness updating code in
TwoAddressInstruction.

The INSERT_SUBREG in the test case gets converted to a COPY, so it tries to
update the subranges for %1 below:

********** INTERVALS **********
V8 [0B,16r:0) 0 at 0B-phi
%0 [16r,32r:0) 0 at 16r  weight:0.000000e+00
%1 [32r,48r:0) 0 at 32r  L000000000000003C [32r,48r:0) 0 at 32r  L00000000000003C0 [32r,32d:0) 0 at 32r  weight:0.000000e+00
%2 EMPTY  weight:0.000000e+00
%3 [48r,48d:0) 0 at 48r  weight:0.000000e+00

0B	bb.0:
	  liveins: $v8
16B	  %0:vr = COPY $v8
32B	  undef %1.sub_vrm1_0:vrm8 = COPY %0:vr
48B	  dead %3:vrm4 = COPY %1.sub_vrm4_0:vrm8
64B	  PseudoRET

The subrange for %1 L00000000000003C0 [32r,32d:0) doesn't overlap with
sub_vrm1_0's lane mask, so it tries to merge 0 at 32r. It calls
FindSegmentContaining(32B), 32B being the instruction index for the
INSERT_SUBREG-turned-COPY. But 32B isn't actually in [32r,32d:0) so it returns
end(). The code wasn't checking for end() though so it crashed when
dereferencing DefSeg.

I'm not familiar with this area in the slightest, but I presume we wanted to
find the segment at 32r? And in this test case there's no other segment in the
subrange anyway, so we need to check if DefSeg exists.

I also did a quick check, nothing in llvm-check-codegen seems to trigger this
code. Not sure if that will change if -early-live-intervals is enabled by
default.


>From 5da784840c5f773e21eb224ee5887e82df7b6d50 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Mon, 11 Sep 2023 00:44:33 +0100
Subject: [PATCH] [TwoAddressInstruction] Check if segment was found when
 updating subreg LIs

This patch fixes a crash I was seeing when working with subregisters in a
separate upcoming patch. Some of the RVV tests have -early-live-intervals
enabled, which triggers this subregister liveness updating code in
TwoAddressInstruction.

The INSERT_SUBREG in the test case gets converted to a COPY, so it tries to
update the subranges for %1 below:

********** INTERVALS **********
V8 [0B,16r:0) 0 at 0B-phi
%0 [16r,32r:0) 0 at 16r  weight:0.000000e+00
%1 [32r,48r:0) 0 at 32r  L000000000000003C [32r,48r:0) 0 at 32r  L00000000000003C0 [32r,32d:0) 0 at 32r  weight:0.000000e+00
%2 EMPTY  weight:0.000000e+00
%3 [48r,48d:0) 0 at 48r  weight:0.000000e+00

0B	bb.0:
	  liveins: $v8
16B	  %0:vr = COPY $v8
32B	  undef %1.sub_vrm1_0:vrm8 = COPY %0:vr
48B	  dead %3:vrm4 = COPY %1.sub_vrm4_0:vrm8
64B	  PseudoRET

The subrange for %1 L00000000000003C0 [32r,32d:0) doesn't overlap with
sub_vrm1_0's lane mask, so it tries to merge 0 at 32r. It calls
FindSegmentContaining(32B), 32B being the instruction index for the
INSERT_SUBREG-turned-COPY. But 32B isn't actually in [32r,32d:0) so it returns
end(). The code wasn't checking for end() though so it crashed when
dereferencing DefSeg.

I'm not familiar with this area in the slightest, but I presume we wanted to
find the segment at 32r? And in this test case there's no other segment in the
subrange anyway, so we need to check if DefSeg exists.

I also did a quick check, nothing in llvm-check-codegen seems to trigger this
code. Not sure if that will change if -early-live-intervals is enabled by
default.
---
 .../lib/CodeGen/TwoAddressInstructionPass.cpp |  5 +++--
 ...ressinstruction-subreg-liveness-update.mir | 22 +++++++++++++++++++
 2 files changed, 25 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/CodeGen/RISCV/rvv/twoaddressinstruction-subreg-liveness-update.mir

diff --git a/llvm/lib/CodeGen/TwoAddressInstructionPass.cpp b/llvm/lib/CodeGen/TwoAddressInstructionPass.cpp
index 45f61262faf9391..6ceb4b43522f00b 100644
--- a/llvm/lib/CodeGen/TwoAddressInstructionPass.cpp
+++ b/llvm/lib/CodeGen/TwoAddressInstructionPass.cpp
@@ -1868,12 +1868,13 @@ bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &Func) {
             // %reg.subidx.
             LaneBitmask LaneMask =
                 TRI->getSubRegIndexLaneMask(mi->getOperand(0).getSubReg());
-            SlotIndex Idx = LIS->getInstructionIndex(*mi);
+            SlotIndex Idx = LIS->getInstructionIndex(*mi).getRegSlot();
             for (auto &S : LI.subranges()) {
               if ((S.LaneMask & LaneMask).none()) {
                 LiveRange::iterator UseSeg = S.FindSegmentContaining(Idx);
                 LiveRange::iterator DefSeg = std::next(UseSeg);
-                S.MergeValueNumberInto(DefSeg->valno, UseSeg->valno);
+                if (DefSeg != S.end())
+                  S.MergeValueNumberInto(DefSeg->valno, UseSeg->valno);
               }
             }
 
diff --git a/llvm/test/CodeGen/RISCV/rvv/twoaddressinstruction-subreg-liveness-update.mir b/llvm/test/CodeGen/RISCV/rvv/twoaddressinstruction-subreg-liveness-update.mir
new file mode 100644
index 000000000000000..abafc580a968f9e
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvv/twoaddressinstruction-subreg-liveness-update.mir
@@ -0,0 +1,22 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
+# RUN: llc %s -o - -mtriple=riscv64 -mattr=+v -run-pass=liveintervals,twoaddressinstruction,register-coalescer | FileCheck %s
+
+...
+---
+name:            insert_v2i64_nxv16i64
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $v8
+    ; CHECK-LABEL: name: insert_v2i64_nxv16i64
+    ; CHECK: liveins: $v8
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: KILL $v8
+    ; CHECK-NEXT: PseudoRET
+    %0:vr = COPY killed $v8
+    %2:vrm8 = INSERT_SUBREG undef %1:vrm8, killed %0, %subreg.sub_vrm1_0
+    %3:vrm4 = COPY %2.sub_vrm4_0:vrm8
+
+    PseudoRET
+
+...



More information about the llvm-commits mailing list