[llvm] [CodeGen] Mark LIFETIME_START and LIFETIME_END as not safe to move (PR #211179)

Luke Lau via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 22 18:46:28 PDT 2026


https://github.com/lukel97 updated https://github.com/llvm/llvm-project/pull/211179

>From 84a649ba86a58257c66ac3e32ee93a7b4d12f36c Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Wed, 22 Jul 2026 14:02:07 +0800
Subject: [PATCH 1/7] Precommit test

---
 llvm/test/CodeGen/RISCV/lifetime-licm.mir | 43 +++++++++++++++++++++++
 1 file changed, 43 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/lifetime-licm.mir

diff --git a/llvm/test/CodeGen/RISCV/lifetime-licm.mir b/llvm/test/CodeGen/RISCV/lifetime-licm.mir
new file mode 100644
index 0000000000000..daeaa6c05e34a
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/lifetime-licm.mir
@@ -0,0 +1,43 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=riscv32 -run-pass=early-machinelicm -verify-machineinstrs -o - %s | FileCheck %s
+# RUN: llc -mtriple=riscv64 -run-pass=early-machinelicm -verify-machineinstrs -o - %s | FileCheck %s
+---
+name: dont_hoist_lifetime_start_end
+tracksRegLiveness: true
+stack:
+  - { id: 0, size: 4 }
+body: |
+  ; CHECK-LABEL: name: dont_hoist_lifetime_start_end
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   %start:gpr = ADDI $x0, 10
+  ; CHECK-NEXT:   LIFETIME_START %stack.0
+  ; CHECK-NEXT:   LIFETIME_END %stack.0
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.2(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   %iv:gpr = PHI %start, %bb.0, %ivnext, %bb.1
+  ; CHECK-NEXT:   %ivnext:gpr = ADDI %iv, -1
+  ; CHECK-NEXT:   BNE %ivnext, $x0, %bb.1
+  ; CHECK-NEXT:   PseudoBR %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   PseudoRET
+  bb.0:
+    %start:gpr = ADDI $x0, 10
+    PseudoBR %bb.1
+
+  bb.1:
+    %iv:gpr = PHI %start, %bb.0, %ivnext, %bb.1
+    LIFETIME_START %stack.0
+    LIFETIME_END %stack.0
+    %ivnext:gpr = ADDI %iv, -1
+    BNE %ivnext, $x0, %bb.1
+    PseudoBR %bb.2
+
+  bb.2:
+    PseudoRET
+...

>From 1e955319ccf3f95d014e6f949cd32bda62ba3d39 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Wed, 22 Jul 2026 14:17:58 +0800
Subject: [PATCH 2/7] [CodeGen] Mark LIFETIME_START and LIFETIME_END as
 mayLoad/mayStore

PR #210028 added a run of EarlyMachineLICM before StackColoring removed LIFETIME_START/LIFETIME_END markers, and it ended up hoisting them which led to miscompiles. This adds the mayLoad/mayStore flags to match how the lifetime_start/lifetime_end intrinsics are marked as reading and writing from memory, which prevents them from being reordered by LICM.
---
 llvm/include/llvm/Target/Target.td        | 4 ++++
 llvm/test/CodeGen/RISCV/lifetime-licm.mir | 4 ++--
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index cb97ab5d1bae4..f527ca880a64b 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -1498,6 +1498,8 @@ def LIFETIME_START : StandardPseudoInstruction {
   let AsmString = "LIFETIME_START";
   let hasSideEffects = false;
   let isMeta = true;
+  let mayLoad = true;
+  let mayStore = true;
 }
 def LIFETIME_END : StandardPseudoInstruction {
   let OutOperandList = (outs);
@@ -1505,6 +1507,8 @@ def LIFETIME_END : StandardPseudoInstruction {
   let AsmString = "LIFETIME_END";
   let hasSideEffects = false;
   let isMeta = true;
+  let mayLoad = true;
+  let mayStore = true;
 }
 def PSEUDO_PROBE : StandardPseudoInstruction {
   let OutOperandList = (outs);
diff --git a/llvm/test/CodeGen/RISCV/lifetime-licm.mir b/llvm/test/CodeGen/RISCV/lifetime-licm.mir
index daeaa6c05e34a..f4aef364eefb6 100644
--- a/llvm/test/CodeGen/RISCV/lifetime-licm.mir
+++ b/llvm/test/CodeGen/RISCV/lifetime-licm.mir
@@ -12,14 +12,14 @@ body: |
   ; CHECK-NEXT:   successors: %bb.1(0x80000000)
   ; CHECK-NEXT: {{  $}}
   ; CHECK-NEXT:   %start:gpr = ADDI $x0, 10
-  ; CHECK-NEXT:   LIFETIME_START %stack.0
-  ; CHECK-NEXT:   LIFETIME_END %stack.0
   ; CHECK-NEXT:   PseudoBR %bb.1
   ; CHECK-NEXT: {{  $}}
   ; CHECK-NEXT: bb.1:
   ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.2(0x40000000)
   ; CHECK-NEXT: {{  $}}
   ; CHECK-NEXT:   %iv:gpr = PHI %start, %bb.0, %ivnext, %bb.1
+  ; CHECK-NEXT:   LIFETIME_START %stack.0
+  ; CHECK-NEXT:   LIFETIME_END %stack.0
   ; CHECK-NEXT:   %ivnext:gpr = ADDI %iv, -1
   ; CHECK-NEXT:   BNE %ivnext, $x0, %bb.1
   ; CHECK-NEXT:   PseudoBR %bb.2

>From a35280945498a737583b3e8869abbb21aee8f688 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Wed, 22 Jul 2026 17:03:29 +0800
Subject: [PATCH 3/7] Mark isLifetimeMarker as unsafe to move instead

---
 llvm/include/llvm/Target/Target.td | 4 ----
 llvm/lib/CodeGen/MachineInstr.cpp  | 2 +-
 2 files changed, 1 insertion(+), 5 deletions(-)

diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index f527ca880a64b..cb97ab5d1bae4 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -1498,8 +1498,6 @@ def LIFETIME_START : StandardPseudoInstruction {
   let AsmString = "LIFETIME_START";
   let hasSideEffects = false;
   let isMeta = true;
-  let mayLoad = true;
-  let mayStore = true;
 }
 def LIFETIME_END : StandardPseudoInstruction {
   let OutOperandList = (outs);
@@ -1507,8 +1505,6 @@ def LIFETIME_END : StandardPseudoInstruction {
   let AsmString = "LIFETIME_END";
   let hasSideEffects = false;
   let isMeta = true;
-  let mayLoad = true;
-  let mayStore = true;
 }
 def PSEUDO_PROBE : StandardPseudoInstruction {
   let OutOperandList = (outs);
diff --git a/llvm/lib/CodeGen/MachineInstr.cpp b/llvm/lib/CodeGen/MachineInstr.cpp
index 0fbeea153d3c9..ced2b5f60a0b5 100644
--- a/llvm/lib/CodeGen/MachineInstr.cpp
+++ b/llvm/lib/CodeGen/MachineInstr.cpp
@@ -1360,7 +1360,7 @@ bool MachineInstr::isSafeToMove(bool &SawStore) const {
   // Don't touch instructions that have non-trivial invariants.  For example,
   // terminators have to be at the end of a basic block.
   if (isPosition() || isDebugInstr() || isTerminator() ||
-      isJumpTableDebugInfo())
+      isJumpTableDebugInfo() || isLifetimeMarker())
     return false;
 
   // Don't touch instructions which can have non-load/store effects.

>From c56ae46668c5e46f7f9ddccdd58001db40789baa Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Wed, 22 Jul 2026 17:06:28 +0800
Subject: [PATCH 4/7] Remove riscv32 RUN

---
 llvm/test/CodeGen/RISCV/lifetime-licm.mir | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/test/CodeGen/RISCV/lifetime-licm.mir b/llvm/test/CodeGen/RISCV/lifetime-licm.mir
index f4aef364eefb6..3f810a6e4da32 100644
--- a/llvm/test/CodeGen/RISCV/lifetime-licm.mir
+++ b/llvm/test/CodeGen/RISCV/lifetime-licm.mir
@@ -1,5 +1,4 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
-# RUN: llc -mtriple=riscv32 -run-pass=early-machinelicm -verify-machineinstrs -o - %s | FileCheck %s
 # RUN: llc -mtriple=riscv64 -run-pass=early-machinelicm -verify-machineinstrs -o - %s | FileCheck %s
 ---
 name: dont_hoist_lifetime_start_end

>From 3c543e647862408179c6f05ed86e8449bae0f4e1 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Wed, 22 Jul 2026 17:24:29 +0800
Subject: [PATCH 5/7] Remove isLifetimeMarker check from wouldBeTriviallyDead

---
 llvm/lib/CodeGen/MachineInstr.cpp | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/llvm/lib/CodeGen/MachineInstr.cpp b/llvm/lib/CodeGen/MachineInstr.cpp
index ced2b5f60a0b5..1067f186208c4 100644
--- a/llvm/lib/CodeGen/MachineInstr.cpp
+++ b/llvm/lib/CodeGen/MachineInstr.cpp
@@ -1403,11 +1403,6 @@ bool MachineInstr::wouldBeTriviallyDead() const {
   if (isFakeUse())
     return false;
 
-  // LIFETIME markers should be preserved.
-  // FIXME: Why are LIFETIME markers not considered in MachineInstr::isPosition?
-  if (isLifetimeMarker())
-    return false;
-
   // If we can move an instruction, we can remove it.  Otherwise, it has
   // a side-effect of some sort.
   bool SawStore = false;

>From 72fe3db47c440f489c46aeb700745de52f676841 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke_lau at icloud.com>
Date: Wed, 22 Jul 2026 17:26:41 +0800
Subject: [PATCH 6/7] Remove -verify-machineinstrs

Co-authored-by: Matt Arsenault <arsenm2 at gmail.com>
---
 llvm/test/CodeGen/RISCV/lifetime-licm.mir | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/test/CodeGen/RISCV/lifetime-licm.mir b/llvm/test/CodeGen/RISCV/lifetime-licm.mir
index 3f810a6e4da32..66b8c22c1ba72 100644
--- a/llvm/test/CodeGen/RISCV/lifetime-licm.mir
+++ b/llvm/test/CodeGen/RISCV/lifetime-licm.mir
@@ -1,5 +1,5 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
-# RUN: llc -mtriple=riscv64 -run-pass=early-machinelicm -verify-machineinstrs -o - %s | FileCheck %s
+# RUN: llc -mtriple=riscv64 -run-pass=early-machinelicm -o - %s | FileCheck %s
 ---
 name: dont_hoist_lifetime_start_end
 tracksRegLiveness: true

>From f61a14ef2958bc427509c125828122b4673f2cde Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Thu, 23 Jul 2026 09:43:28 +0800
Subject: [PATCH 7/7] Move FIXME

---
 llvm/include/llvm/CodeGen/MachineInstr.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/llvm/include/llvm/CodeGen/MachineInstr.h b/llvm/include/llvm/CodeGen/MachineInstr.h
index 2efd3d4d6f095..b04018e43bbe0 100644
--- a/llvm/include/llvm/CodeGen/MachineInstr.h
+++ b/llvm/include/llvm/CodeGen/MachineInstr.h
@@ -1368,6 +1368,7 @@ class MachineInstr
   }
 
   // True if the instruction represents a position in the function.
+  // FIXME: Why are LIFETIME markers not considered in MachineInstr::isPosition?
   bool isPosition() const { return isLabel() || isCFIInstruction(); }
 
   bool isNonListDebugValue() const {



More information about the llvm-commits mailing list