[llvm] [CodeGen][MachineOutliner] Ignore debug instructions when checking pa… (PR #227971)

Yongqiang Tian via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 30 23:23:36 PDT 2026


https://github.com/yqtian-se created https://github.com/llvm/llvm-project/pull/227971

…tchable exits

isMBBSafeToOutlineFrom checks the instruction before a return for PATCHABLE_FUNCTION_EXIT and PATCHABLE_TAIL_CALL. A debug instruction between the patchable instruction and the return currently hides it and allows the block to be outlined.

Use prev_nodbg for the backward check while preserving the existing treatment of pseudo probes. Retain the direct-adjacency coverage and add a regression with a DBG_VALUE between PATCHABLE_FUNCTION_EXIT and RET.

Fixes #227922

Assisted-by: OpenAI Codex 5.6 Sol
Assisted-by: Claude (review)

>From 565bcdabc693aa82ef675fac78aa2b9931844417 Mon Sep 17 00:00:00 2001
From: Yongqiang Tian <yqtian668 at gmail.com>
Date: Thu, 1 Oct 2026 06:19:05 +0000
Subject: [PATCH] [CodeGen][MachineOutliner] Ignore debug instructions when
 checking patchable exits

isMBBSafeToOutlineFrom checks the instruction before a return for
PATCHABLE_FUNCTION_EXIT and PATCHABLE_TAIL_CALL. A debug instruction between
the patchable instruction and the return currently hides it and allows the
block to be outlined.

Use prev_nodbg for the backward check while preserving the existing treatment
of pseudo probes. Retain the direct-adjacency coverage and add a regression
with a DBG_VALUE between PATCHABLE_FUNCTION_EXIT and RET.

Fixes #227922

Assisted-by: OpenAI Codex 5.6 Sol
Assisted-by: Claude (review)
---
 llvm/lib/CodeGen/TargetInstrInfo.cpp          |  2 +-
 .../AArch64/machine-outliner-patchable.mir    | 87 +++++++++++++++++++
 2 files changed, 88 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/TargetInstrInfo.cpp b/llvm/lib/CodeGen/TargetInstrInfo.cpp
index 92fc628e888e5..096626d20416e 100644
--- a/llvm/lib/CodeGen/TargetInstrInfo.cpp
+++ b/llvm/lib/CodeGen/TargetInstrInfo.cpp
@@ -2221,7 +2221,7 @@ bool TargetInstrInfo::isMBBSafeToOutlineFrom(MachineBasicBlock &MBB,
     return false;
 
   if (Last != First && Last->isReturn()) {
-    --Last;
+    Last = prev_nodbg(Last, First, /*SkipPseudoOp=*/false);
     if (Last->getOpcode() == TargetOpcode::PATCHABLE_FUNCTION_EXIT ||
         Last->getOpcode() == TargetOpcode::PATCHABLE_TAIL_CALL)
       return false;
diff --git a/llvm/test/CodeGen/AArch64/machine-outliner-patchable.mir b/llvm/test/CodeGen/AArch64/machine-outliner-patchable.mir
index 6e957bceb8f4f..910f4c940330b 100644
--- a/llvm/test/CodeGen/AArch64/machine-outliner-patchable.mir
+++ b/llvm/test/CodeGen/AArch64/machine-outliner-patchable.mir
@@ -16,6 +16,9 @@
     call void @foo(i32 5, i32 6, i32 7, i32 8)
     ret void
   }
+
+  define void @xray2() #1 !dbg !3 { ret void, !dbg !9 }
+  define void @xray3() #1 !dbg !10 { ret void, !dbg !13 }
   
   ; Function Attrs: nounwind
   define void @xray1(i1 %a) #1 {
@@ -34,6 +37,24 @@
   attributes #0 = { minsize }
   attributes #1 = { nounwind "function-instrument"="xray-always" }
 
+  !llvm.dbg.cu = !{!0}
+  !llvm.module.flags = !{!2}
+
+  !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "llvm", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
+  !1 = !DIFile(filename: "machine-outliner-patchable.mir", directory: "/")
+  !2 = !{i32 2, !"Debug Info Version", i32 3}
+  !3 = distinct !DISubprogram(name: "xray2", linkageName: "xray2", scope: !1, file: !1, line: 1, type: !4, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !6)
+  !4 = !DISubroutineType(types: !5)
+  !5 = !{}
+  !6 = !{!7}
+  !7 = !DILocalVariable(name: "x", scope: !3, file: !1, line: 1, type: !8)
+  !8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+  !9 = !DILocation(line: 1, column: 1, scope: !3)
+  !10 = distinct !DISubprogram(name: "xray3", linkageName: "xray3", scope: !1, file: !1, line: 2, type: !4, scopeLine: 2, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
+  !11 = !{!12}
+  !12 = !DILocalVariable(name: "x", scope: !10, file: !1, line: 2, type: !8)
+  !13 = !DILocation(line: 2, column: 1, scope: !10)
+
 ...
 ---
 name:            xray0
@@ -94,6 +115,72 @@ body:             |
 
 ...
 ---
+name:            xray2
+tracksRegLiveness: true
+stack:
+  - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16,
+      stack-id: default, callee-saved-register: '$lr', callee-saved-restored: true,
+      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+machineFunctionInfo:
+  hasRedZone:      false
+body:             |
+  ; CHECK-LABEL: name: xray2
+  ; CHECK:       bb.0:
+  ; CHECK:         early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store (s64) into %stack.0)
+  ; CHECK-NEXT:    $w0 = MOVZWi 1, 0
+  ; CHECK-NEXT:    $w1 = MOVZWi 2, 0
+  ; CHECK-NEXT:    BL @foo, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit killed $w0, implicit killed $w1, implicit-def $sp
+  ; CHECK-NEXT:    early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
+  ; CHECK-NEXT:    PATCHABLE_FUNCTION_EXIT
+  ; CHECK-NEXT:    DBG_VALUE 1, $noreg, !{{[0-9]+}}, !DIExpression()
+  ; CHECK-NEXT:    RET undef $lr
+
+  bb.0:
+    liveins: $lr
+
+    early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store (s64) into %stack.0)
+    $w0 = MOVZWi 1, 0
+    $w1 = MOVZWi 2, 0
+    BL @foo, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit killed $w0, implicit killed $w1, implicit-def $sp
+    early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
+    PATCHABLE_FUNCTION_EXIT
+    DBG_VALUE 1, $noreg, !7, !DIExpression(), debug-location !9
+    RET undef $lr
+...
+---
+name:            xray3
+tracksRegLiveness: true
+stack:
+  - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16,
+      stack-id: default, callee-saved-register: '$lr', callee-saved-restored: true,
+      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+machineFunctionInfo:
+  hasRedZone:      false
+body:             |
+  ; CHECK-LABEL: name: xray3
+  ; CHECK:       bb.0:
+  ; CHECK:         early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store (s64) into %stack.0)
+  ; CHECK-NEXT:    $w0 = MOVZWi 1, 0
+  ; CHECK-NEXT:    $w1 = MOVZWi 2, 0
+  ; CHECK-NEXT:    BL @foo, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit killed $w0, implicit killed $w1, implicit-def $sp
+  ; CHECK-NEXT:    early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
+  ; CHECK-NEXT:    PATCHABLE_FUNCTION_EXIT
+  ; CHECK-NEXT:    DBG_VALUE 1, $noreg, !{{[0-9]+}}, !DIExpression()
+  ; CHECK-NEXT:    RET undef $lr
+
+  bb.0:
+    liveins: $lr
+
+    early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store (s64) into %stack.0)
+    $w0 = MOVZWi 1, 0
+    $w1 = MOVZWi 2, 0
+    BL @foo, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit killed $w0, implicit killed $w1, implicit-def $sp
+    early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
+    PATCHABLE_FUNCTION_EXIT
+    DBG_VALUE 1, $noreg, !12, !DIExpression(), debug-location !13
+    RET undef $lr
+...
+---
 name:            xray1
 tracksRegLiveness: true
 liveins:



More information about the llvm-commits mailing list