[llvm] [ShrinkWrap] Modify shrink wrapping to accommodate functions terminated by no-return blocks (PR #167548)
Nathan Corbyn via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 25 09:13:44 PST 2025
https://github.com/cofibrant updated https://github.com/llvm/llvm-project/pull/167548
>From 3dcc75ddeedd60e4f306aa85a75bf20881a1651f Mon Sep 17 00:00:00 2001
From: Nathan Corbyn <n_corbyn at apple.com>
Date: Tue, 11 Nov 2025 17:07:57 +0000
Subject: [PATCH 1/3] [AArch64] [ShrinkWrap] Add test identifying missed shrink
wrapping opportunity
---
.../CodeGen/AArch64/shrinkwrap-no-return.ll | 77 +++++++++++++++++++
1 file changed, 77 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/shrinkwrap-no-return.ll
diff --git a/llvm/test/CodeGen/AArch64/shrinkwrap-no-return.ll b/llvm/test/CodeGen/AArch64/shrinkwrap-no-return.ll
new file mode 100644
index 0000000000000..7263de8ecdc70
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/shrinkwrap-no-return.ll
@@ -0,0 +1,77 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=aarch64 -o - %s | FileCheck %s
+
+ at exception = external hidden constant { ptr, ptr, ptr }
+
+define noundef i32 @early_exit_or_throw(i32 %in) personality ptr @__gxx_personality_v0 {
+; CHECK-LABEL: early_exit_or_throw:
+; CHECK: .Lfunc_begin0:
+; CHECK-NEXT: .cfi_startproc
+; CHECK-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0
+; CHECK-NEXT: .cfi_lsda 28, .Lexception0
+; CHECK-NEXT: // %bb.0: // %entry
+; CHECK-NEXT: str x30, [sp, #-32]! // 8-byte Folded Spill
+; CHECK-NEXT: stp x20, x19, [sp, #16] // 16-byte Folded Spill
+; CHECK-NEXT: .cfi_def_cfa_offset 32
+; CHECK-NEXT: .cfi_offset w19, -8
+; CHECK-NEXT: .cfi_offset w20, -16
+; CHECK-NEXT: .cfi_offset w30, -32
+; CHECK-NEXT: cmp w0, #1
+; CHECK-NEXT: b.eq .LBB1_2
+; CHECK-NEXT: // %bb.1: // %exit
+; CHECK-NEXT: ldp x20, x19, [sp, #16] // 16-byte Folded Reload
+; CHECK-NEXT: mov w0, wzr
+; CHECK-NEXT: ldr x30, [sp], #32 // 8-byte Folded Reload
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB1_2: // %setup
+; CHECK-NEXT: mov w0, #32 // =0x20
+; CHECK-NEXT: bl __cxa_allocate_exception
+; CHECK-NEXT: mov x19, x0
+; CHECK-NEXT: .Ltmp0: // EH_LABEL
+; CHECK-NEXT: bl construct_exception
+; CHECK-NEXT: .Ltmp1: // EH_LABEL
+; CHECK-NEXT: // %bb.3: // %throw
+; CHECK-NEXT: adrp x2, :got:destruct_exception
+; CHECK-NEXT: adrp x1, exception
+; CHECK-NEXT: add x1, x1, :lo12:exception
+; CHECK-NEXT: ldr x2, [x2, :got_lo12:destruct_exception]
+; CHECK-NEXT: mov x0, x19
+; CHECK-NEXT: bl __cxa_throw
+; CHECK-NEXT: .LBB1_4: // %teardown
+; CHECK-NEXT: .Ltmp2: // EH_LABEL
+; CHECK-NEXT: mov x20, x0
+; CHECK-NEXT: mov x0, x19
+; CHECK-NEXT: bl __cxa_free_exception
+; CHECK-NEXT: mov x0, x20
+; CHECK-NEXT: bl _Unwind_Resume
+entry:
+ %cmp = icmp eq i32 %in, 1
+ br i1 %cmp, label %setup, label %exit
+
+setup:
+ %exception = tail call ptr @__cxa_allocate_exception(i64 32) nounwind
+ %call = invoke noundef ptr @construct_exception(ptr noundef nonnull %exception) to label %throw unwind label %teardown
+
+throw:
+ tail call void @__cxa_throw(ptr nonnull %exception, ptr nonnull @exception, ptr nonnull @destruct_exception) noreturn
+ unreachable
+
+teardown:
+ %caught = landingpad { ptr, i32 } cleanup
+ tail call void @__cxa_free_exception(ptr nonnull %exception) nounwind
+ resume { ptr, i32 } %caught
+
+exit:
+ ret i32 0
+}
+
+declare i32 @__gxx_personality_v0(...)
+
+declare ptr @__cxa_allocate_exception(i64) local_unnamed_addr
+declare void @__cxa_free_exception(ptr) local_unnamed_addr
+declare void @__cxa_throw(ptr, ptr, ptr) local_unnamed_addr cold noreturn
+
+declare noundef ptr @construct_exception(ptr noundef nonnull returned) unnamed_addr
+declare noundef ptr @destruct_exception(ptr noundef nonnull returned) unnamed_addr mustprogress nounwind ssp uwtable(sync)
+
+declare void @noreturn() noreturn
>From 789cfcf84e8e52e33aa15ba530e2c402bd2d6b1c Mon Sep 17 00:00:00 2001
From: Nathan Corbyn <n_corbyn at apple.com>
Date: Tue, 11 Nov 2025 14:12:37 +0000
Subject: [PATCH 2/3] [ShrinkWrap] Ignore no-return blocks in shrink wrapping
---
llvm/include/llvm/CodeGen/MachineBasicBlock.h | 7 +++++++
llvm/lib/CodeGen/ShrinkWrap.cpp | 12 +++++-------
.../CodeGen/AArch64/shrinkwrap-no-return.ll | 19 +++++++++----------
3 files changed, 21 insertions(+), 17 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/MachineBasicBlock.h b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
index fcf7bab09fcff..a56cf56c81cd9 100644
--- a/llvm/include/llvm/CodeGen/MachineBasicBlock.h
+++ b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
@@ -988,6 +988,13 @@ class MachineBasicBlock
return !empty() && back().isEHScopeReturn();
}
+ /// Convenience function that returns true if the block exits the function
+ /// without returning.
+ bool isNoReturnBlock() const {
+ return !empty() && succ_empty() && !back().isReturn() &&
+ !back().isIndirectBranch();
+ }
+
/// Split a basic block into 2 pieces at \p SplitPoint. A new block will be
/// inserted after this block, and all instructions after \p SplitInst moved
/// to it (\p SplitInst will be in the original block). If \p LIS is provided,
diff --git a/llvm/lib/CodeGen/ShrinkWrap.cpp b/llvm/lib/CodeGen/ShrinkWrap.cpp
index 83581052560cb..c2221cacc5bd5 100644
--- a/llvm/lib/CodeGen/ShrinkWrap.cpp
+++ b/llvm/lib/CodeGen/ShrinkWrap.cpp
@@ -697,14 +697,12 @@ void ShrinkWrapImpl::updateSaveRestorePoints(MachineBasicBlock &MBB,
if (!Restore)
Restore = &MBB;
- else if (MPDT->getNode(&MBB)) // If the block is not in the post dom tree, it
- // means the block never returns. If that's the
- // case, we don't want to call
- // `findNearestCommonDominator`, which will
- // return `Restore`.
+ else if (MBB.isNoReturnBlock()) {
+ // MBB exits the function without returning, so we don't need an epilogue
+ // here. This is common for things like cleanup landing pads etc. In these
+ // cases, we can skip updating `Restore`.
+ } else
Restore = MPDT->findNearestCommonDominator(Restore, &MBB);
- else
- Restore = nullptr; // Abort, we can't find a restore point in this case.
// Make sure we would be able to insert the restore code before the
// terminator.
diff --git a/llvm/test/CodeGen/AArch64/shrinkwrap-no-return.ll b/llvm/test/CodeGen/AArch64/shrinkwrap-no-return.ll
index 7263de8ecdc70..55e8b539e0a35 100644
--- a/llvm/test/CodeGen/AArch64/shrinkwrap-no-return.ll
+++ b/llvm/test/CodeGen/AArch64/shrinkwrap-no-return.ll
@@ -10,26 +10,25 @@ define noundef i32 @early_exit_or_throw(i32 %in) personality ptr @__gxx_personal
; CHECK-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0
; CHECK-NEXT: .cfi_lsda 28, .Lexception0
; CHECK-NEXT: // %bb.0: // %entry
+; CHECK-NEXT: cmp w0, #1
+; CHECK-NEXT: b.eq .LBB0_2
+; CHECK-NEXT: // %bb.1: // %exit
+; CHECK-NEXT: mov w0, wzr
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB0_2: // %setup
; CHECK-NEXT: str x30, [sp, #-32]! // 8-byte Folded Spill
; CHECK-NEXT: stp x20, x19, [sp, #16] // 16-byte Folded Spill
; CHECK-NEXT: .cfi_def_cfa_offset 32
; CHECK-NEXT: .cfi_offset w19, -8
; CHECK-NEXT: .cfi_offset w20, -16
; CHECK-NEXT: .cfi_offset w30, -32
-; CHECK-NEXT: cmp w0, #1
-; CHECK-NEXT: b.eq .LBB1_2
-; CHECK-NEXT: // %bb.1: // %exit
-; CHECK-NEXT: ldp x20, x19, [sp, #16] // 16-byte Folded Reload
-; CHECK-NEXT: mov w0, wzr
-; CHECK-NEXT: ldr x30, [sp], #32 // 8-byte Folded Reload
-; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB1_2: // %setup
; CHECK-NEXT: mov w0, #32 // =0x20
; CHECK-NEXT: bl __cxa_allocate_exception
-; CHECK-NEXT: mov x19, x0
; CHECK-NEXT: .Ltmp0: // EH_LABEL
; CHECK-NEXT: bl construct_exception
; CHECK-NEXT: .Ltmp1: // EH_LABEL
+; CHECK-NEXT: ldp x20, x19, [sp, #16] // 16-byte Folded Reload
+; CHECK-NEXT: ldr x30, [sp], #32 // 8-byte Folded Reload
; CHECK-NEXT: // %bb.3: // %throw
; CHECK-NEXT: adrp x2, :got:destruct_exception
; CHECK-NEXT: adrp x1, exception
@@ -37,7 +36,7 @@ define noundef i32 @early_exit_or_throw(i32 %in) personality ptr @__gxx_personal
; CHECK-NEXT: ldr x2, [x2, :got_lo12:destruct_exception]
; CHECK-NEXT: mov x0, x19
; CHECK-NEXT: bl __cxa_throw
-; CHECK-NEXT: .LBB1_4: // %teardown
+; CHECK-NEXT: .LBB0_4: // %teardown
; CHECK-NEXT: .Ltmp2: // EH_LABEL
; CHECK-NEXT: mov x20, x0
; CHECK-NEXT: mov x0, x19
>From 8d8b30869a714a100018f7967293add648b8effc Mon Sep 17 00:00:00 2001
From: Nathan Corbyn <n_corbyn at apple.com>
Date: Tue, 25 Nov 2025 17:13:29 +0000
Subject: [PATCH 3/3] Update test
---
.../CodeGen/AArch64/shrinkwrap-no-return.ll | 98 ++++++++++++-------
1 file changed, 64 insertions(+), 34 deletions(-)
diff --git a/llvm/test/CodeGen/AArch64/shrinkwrap-no-return.ll b/llvm/test/CodeGen/AArch64/shrinkwrap-no-return.ll
index 55e8b539e0a35..8acb653e9ee1d 100644
--- a/llvm/test/CodeGen/AArch64/shrinkwrap-no-return.ll
+++ b/llvm/test/CodeGen/AArch64/shrinkwrap-no-return.ll
@@ -1,48 +1,80 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
-; RUN: llc -mtriple=aarch64 -o - %s | FileCheck %s
+; RUN: llc -mtriple=arm64-apple-ios -o - %s | FileCheck %s
@exception = external hidden constant { ptr, ptr, ptr }
-define noundef i32 @early_exit_or_throw(i32 %in) personality ptr @__gxx_personality_v0 {
-; CHECK-LABEL: early_exit_or_throw:
-; CHECK: .Lfunc_begin0:
+define noundef i32 @call_with_no_ret(i32 %in) personality ptr @__gxx_personality_v0 {
+; CHECK-LABEL: call_with_no_ret:
+; CHECK: Lfunc_begin0:
; CHECK-NEXT: .cfi_startproc
-; CHECK-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0
-; CHECK-NEXT: .cfi_lsda 28, .Lexception0
-; CHECK-NEXT: // %bb.0: // %entry
+; CHECK-NEXT: .cfi_personality 155, ___gxx_personality_v0
+; CHECK-NEXT: .cfi_lsda 16, Lexception0
+; CHECK-NEXT: ; %bb.0: ; %entry
; CHECK-NEXT: cmp w0, #1
-; CHECK-NEXT: b.eq .LBB0_2
-; CHECK-NEXT: // %bb.1: // %exit
+; CHECK-NEXT: b.eq LBB0_2
+; CHECK-NEXT: ; %bb.1: ; %exit
; CHECK-NEXT: mov w0, wzr
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB0_2: // %setup
-; CHECK-NEXT: str x30, [sp, #-32]! // 8-byte Folded Spill
-; CHECK-NEXT: stp x20, x19, [sp, #16] // 16-byte Folded Spill
+; CHECK-NEXT: LBB0_2: ; %setup
+; CHECK-NEXT: stp x20, x19, [sp, #-32]! ; 16-byte Folded Spill
+; CHECK-NEXT: stp x29, x30, [sp, #16] ; 16-byte Folded Spill
; CHECK-NEXT: .cfi_def_cfa_offset 32
-; CHECK-NEXT: .cfi_offset w19, -8
-; CHECK-NEXT: .cfi_offset w20, -16
-; CHECK-NEXT: .cfi_offset w30, -32
-; CHECK-NEXT: mov w0, #32 // =0x20
-; CHECK-NEXT: bl __cxa_allocate_exception
-; CHECK-NEXT: .Ltmp0: // EH_LABEL
-; CHECK-NEXT: bl construct_exception
-; CHECK-NEXT: .Ltmp1: // EH_LABEL
-; CHECK-NEXT: ldp x20, x19, [sp, #16] // 16-byte Folded Reload
-; CHECK-NEXT: ldr x30, [sp], #32 // 8-byte Folded Reload
-; CHECK-NEXT: // %bb.3: // %throw
-; CHECK-NEXT: adrp x2, :got:destruct_exception
-; CHECK-NEXT: adrp x1, exception
-; CHECK-NEXT: add x1, x1, :lo12:exception
-; CHECK-NEXT: ldr x2, [x2, :got_lo12:destruct_exception]
+; CHECK-NEXT: .cfi_offset w30, -8
+; CHECK-NEXT: .cfi_offset w29, -16
+; CHECK-NEXT: .cfi_offset w19, -24
+; CHECK-NEXT: .cfi_offset w20, -32
+; CHECK-NEXT: mov w0, #32 ; =0x20
+; CHECK-NEXT: bl ___cxa_allocate_exception
+; CHECK-NEXT: Ltmp0: ; EH_LABEL
+; CHECK-NEXT: bl _construct_exception
+; CHECK-NEXT: Ltmp1: ; EH_LABEL
+; CHECK-NEXT: ldp x29, x30, [sp, #16] ; 16-byte Folded Reload
+; CHECK-NEXT: ldp x20, x19, [sp], #32 ; 16-byte Folded Reload
+; CHECK-NEXT: ; %bb.3: ; %throw
+; CHECK-NEXT: Lloh0:
+; CHECK-NEXT: adrp x2, _destruct_exception at GOTPAGE
+; CHECK-NEXT: Lloh1:
+; CHECK-NEXT: adrp x1, _exception at PAGE
+; CHECK-NEXT: Lloh2:
+; CHECK-NEXT: add x1, x1, _exception at PAGEOFF
+; CHECK-NEXT: Lloh3:
+; CHECK-NEXT: ldr x2, [x2, _destruct_exception at GOTPAGEOFF]
; CHECK-NEXT: mov x0, x19
-; CHECK-NEXT: bl __cxa_throw
-; CHECK-NEXT: .LBB0_4: // %teardown
-; CHECK-NEXT: .Ltmp2: // EH_LABEL
+; CHECK-NEXT: bl ___cxa_throw
+; CHECK-NEXT: LBB0_4: ; %teardown
+; CHECK-NEXT: Ltmp2: ; EH_LABEL
; CHECK-NEXT: mov x20, x0
; CHECK-NEXT: mov x0, x19
-; CHECK-NEXT: bl __cxa_free_exception
+; CHECK-NEXT: bl ___cxa_free_exception
; CHECK-NEXT: mov x0, x20
-; CHECK-NEXT: bl _Unwind_Resume
+; CHECK-NEXT: bl __Unwind_Resume
+; CHECK-NEXT: .loh AdrpAdd Lloh1, Lloh2
+; CHECK-NEXT: .loh AdrpLdrGot Lloh0, Lloh3
+; CHECK-NEXT: Lfunc_end0:
+; CHECK-NEXT: .cfi_endproc
+; CHECK-NEXT: .section __TEXT,__gcc_except_tab
+; CHECK-NEXT: .p2align 2, 0x0
+; CHECK-NEXT: GCC_except_table0:
+; CHECK-NEXT: Lexception0:
+; CHECK-NEXT: .byte 255 ; @LPStart Encoding = omit
+; CHECK-NEXT: .byte 255 ; @TType Encoding = omit
+; CHECK-NEXT: .byte 1 ; Call site Encoding = uleb128
+; CHECK-NEXT: .uleb128 Lcst_end0-Lcst_begin0
+; CHECK-NEXT: Lcst_begin0:
+; CHECK-NEXT: .uleb128 Lfunc_begin0-Lfunc_begin0 ; >> Call Site 1 <<
+; CHECK-NEXT: .uleb128 Ltmp0-Lfunc_begin0 ; Call between Lfunc_begin0 and Ltmp0
+; CHECK-NEXT: .byte 0 ; has no landing pad
+; CHECK-NEXT: .byte 0 ; On action: cleanup
+; CHECK-NEXT: .uleb128 Ltmp0-Lfunc_begin0 ; >> Call Site 2 <<
+; CHECK-NEXT: .uleb128 Ltmp1-Ltmp0 ; Call between Ltmp0 and Ltmp1
+; CHECK-NEXT: .uleb128 Ltmp2-Lfunc_begin0 ; jumps to Ltmp2
+; CHECK-NEXT: .byte 0 ; On action: cleanup
+; CHECK-NEXT: .uleb128 Ltmp1-Lfunc_begin0 ; >> Call Site 3 <<
+; CHECK-NEXT: .uleb128 Lfunc_end0-Ltmp1 ; Call between Ltmp1 and Lfunc_end0
+; CHECK-NEXT: .byte 0 ; has no landing pad
+; CHECK-NEXT: .byte 0 ; On action: cleanup
+; CHECK-NEXT: Lcst_end0:
+; CHECK-NEXT: .p2align 2, 0x0
entry:
%cmp = icmp eq i32 %in, 1
br i1 %cmp, label %setup, label %exit
@@ -72,5 +104,3 @@ declare void @__cxa_throw(ptr, ptr, ptr) local_unnamed_addr cold noreturn
declare noundef ptr @construct_exception(ptr noundef nonnull returned) unnamed_addr
declare noundef ptr @destruct_exception(ptr noundef nonnull returned) unnamed_addr mustprogress nounwind ssp uwtable(sync)
-
-declare void @noreturn() noreturn
More information about the llvm-commits
mailing list