[llvm] [StackColoring] Do not merge stack slots with `returns_twice` call-sites (PR #196542)
via llvm-commits
llvm-commits at lists.llvm.org
Fri May 8 07:07:19 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-x86
Author: Antonio Frighetto (antoniofrighetto)
<details>
<summary>Changes</summary>
Do not merge stack slots on disjoint paths if the function may call setjmp/sigsetjmp, as the current algorithm defaults to computing liveness analysis from the actual uses propagated through the CFG, rather than leveraging lifetime markers, thus making it unsound with `returns_twice` calls.
Fixes: https://github.com/llvm/llvm-project/issues/196468.
---
Full diff: https://github.com/llvm/llvm-project/pull/196542.diff
2 Files Affected:
- (modified) llvm/lib/CodeGen/StackColoring.cpp (+6)
- (added) llvm/test/CodeGen/X86/sjlj-do-not-merge-stack-slots.ll (+50)
``````````diff
diff --git a/llvm/lib/CodeGen/StackColoring.cpp b/llvm/lib/CodeGen/StackColoring.cpp
index 65f9ae5433195..2d708f72f15ed 100644
--- a/llvm/lib/CodeGen/StackColoring.cpp
+++ b/llvm/lib/CodeGen/StackColoring.cpp
@@ -1221,6 +1221,12 @@ bool StackColoring::run(MachineFunction &Func, bool OnlyRemoveMarkers) {
if (!NumSlots)
return false;
+ // Conservatively do not merge stack slots on disjoint paths if we have calls
+ // to setjmp/sigsetjmp, as longjmp may re-enter the function on a different
+ // path.
+ if (MF->exposesReturnsTwice())
+ return false;
+
SmallVector<int, 8> SortedSlots;
SortedSlots.reserve(NumSlots);
Intervals.reserve(NumSlots);
diff --git a/llvm/test/CodeGen/X86/sjlj-do-not-merge-stack-slots.ll b/llvm/test/CodeGen/X86/sjlj-do-not-merge-stack-slots.ll
new file mode 100644
index 0000000000000..ef2da73bbbf5b
--- /dev/null
+++ b/llvm/test/CodeGen/X86/sjlj-do-not-merge-stack-slots.ll
@@ -0,0 +1,50 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=x86_64-- < %s | FileCheck %s
+
+define void @sjlj_do_not_merge_stack_slots() nounwind {
+; CHECK-LABEL: sjlj_do_not_merge_stack_slots:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: subq $40, %rsp
+; CHECK-NEXT: leaq {{[0-9]+}}(%rsp), %rdi
+; CHECK-NEXT: callq setjmp at PLT
+; CHECK-NEXT: testl %eax, %eax
+; CHECK-NEXT: je .LBB0_1
+; CHECK-NEXT: # %bb.2: # %else
+; CHECK-NEXT: leaq {{[0-9]+}}(%rsp), %rdi
+; CHECK-NEXT: callq opaque at PLT
+; CHECK-NEXT: addq $40, %rsp
+; CHECK-NEXT: retq
+; CHECK-NEXT: .LBB0_1: # %then
+; CHECK-NEXT: leaq {{[0-9]+}}(%rsp), %rdi
+; CHECK-NEXT: callq escape at PLT
+; CHECK-NEXT: addq $40, %rsp
+; CHECK-NEXT: retq
+entry:
+ %obj = alloca [8 x i8], align 4
+ %buf = alloca [12 x i8], align 4
+ %obj.1 = alloca [8 x i8], align 4
+ call void @llvm.lifetime.start.p0(ptr %obj)
+ call void @llvm.lifetime.start.p0(ptr %buf)
+ %rv = call i32 @setjmp(ptr %buf)
+ %c = icmp eq i32 %rv, 0
+ br i1 %c, label %then, label %else
+
+then:
+ call void @escape(ptr %obj)
+ br label %exit
+
+else:
+ call void @llvm.lifetime.start.p0(ptr %obj.1)
+ call void @opaque(ptr %obj.1)
+ call void @llvm.lifetime.end.p0(ptr %obj.1)
+ br label %exit
+
+exit:
+ call void @llvm.lifetime.end.p0(ptr %buf)
+ call void @llvm.lifetime.end.p0(ptr %obj)
+ ret void
+}
+
+declare i32 @setjmp(ptr) returns_twice
+declare void @escape(ptr)
+declare void @opaque(ptr)
``````````
</details>
https://github.com/llvm/llvm-project/pull/196542
More information about the llvm-commits
mailing list