Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit dfa550a

Browse files
author
Mark Seaborn
committed
Fix llc to not reuse spill slots in functions that invoke setjmp()
We need to ensure that StackSlotColoring.cpp does not reuse stack spill slots in functions that call "returns_twice" functions such as setjmp(), otherwise this can lead to miscompiled code, because a stack slot would be clobbered when it's still live. This was already handled correctly for functions that call setjmp() (though this wasn't covered by a test), but not for functions that invoke setjmp(). We fix this by changing callsFunctionThatReturnsTwice() to check for invoke instructions. This fixes PR18244. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@199180 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 3f7ae00 commit dfa550a

File tree

2 files changed

+143
-4
lines changed

2 files changed

+143
-4
lines changed

lib/IR/Function.cpp

+2-4
Original file line numberDiff line numberDiff line change
@@ -736,10 +736,8 @@ bool Function::isDefTriviallyDead() const {
736736
bool Function::callsFunctionThatReturnsTwice() const {
737737
for (const_inst_iterator
738738
I = inst_begin(this), E = inst_end(this); I != E; ++I) {
739-
const CallInst* callInst = dyn_cast<CallInst>(&*I);
740-
if (!callInst)
741-
continue;
742-
if (callInst->canReturnTwice())
739+
ImmutableCallSite CS(&*I);
740+
if (CS && CS.hasFnAttr(Attribute::ReturnsTwice))
743741
return true;
744742
}
745743

test/CodeGen/X86/setjmp-spills.ll

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
; RUN: llc < %s -mtriple=i386-linux | FileCheck %s -check-prefix=X86-32
2+
; RUN: llc < %s -mtriple=x86_64-linux | FileCheck %s -check-prefix=X86-64
3+
4+
declare i32 @get_val()
5+
declare void @use_val(i32)
6+
declare i1 @setjmp()
7+
declare void @longjmp()
8+
declare void @personality()
9+
10+
11+
; Test that llc avoids reusing spill slots in functions that call
12+
; setjmp(), whether they use "call" or "invoke" for calling setjmp()
13+
; (PR18244).
14+
15+
define void @setjmp_caller() {
16+
; X86-32-LABEL: setjmp_caller:
17+
; X86-64-LABEL: setjmp_caller:
18+
; This code keeps enough variables live across the setjmp() call that
19+
; they don't all fit in registers and the compiler will allocate a
20+
; spill slot.
21+
%a1 = call i32 @get_val()
22+
%a2 = call i32 @get_val()
23+
%a3 = call i32 @get_val()
24+
%a4 = call i32 @get_val()
25+
%a5 = call i32 @get_val()
26+
%a6 = call i32 @get_val()
27+
%a7 = call i32 @get_val()
28+
%a8 = call i32 @get_val()
29+
; X86-32: movl %eax, [[SPILL_SLOT:[0-9]+]](%esp)
30+
; X86-32: calll get_val
31+
; X86-64: movl %eax, [[SPILL_SLOT:[0-9]+]](%rsp)
32+
; X86-64: callq get_val
33+
34+
%setjmp_result = call i1 @setjmp() returns_twice
35+
br i1 %setjmp_result, label %second, label %first
36+
; X86-32: calll setjmp
37+
; X86-64: callq setjmp
38+
39+
; Again, keep enough variables live that they need spill slots. Since
40+
; this function calls a returns_twice function (setjmp()), the
41+
; compiler should not reuse the spill slots. longjmp() can return to
42+
; where the first spill slots were still live.
43+
first:
44+
%b1 = call i32 @get_val()
45+
%b2 = call i32 @get_val()
46+
%b3 = call i32 @get_val()
47+
%b4 = call i32 @get_val()
48+
%b5 = call i32 @get_val()
49+
%b6 = call i32 @get_val()
50+
%b7 = call i32 @get_val()
51+
%b8 = call i32 @get_val()
52+
call void @use_val(i32 %b1)
53+
call void @use_val(i32 %b2)
54+
call void @use_val(i32 %b3)
55+
call void @use_val(i32 %b4)
56+
call void @use_val(i32 %b5)
57+
call void @use_val(i32 %b6)
58+
call void @use_val(i32 %b7)
59+
call void @use_val(i32 %b8)
60+
call void @longjmp()
61+
unreachable
62+
; X86-32-NOT: movl {{.*}}, [[SPILL_SLOT]](%esp)
63+
; X86-64-NOT: movl {{.*}}, [[SPILL_SLOT]](%rsp)
64+
65+
second:
66+
call void @use_val(i32 %a1)
67+
call void @use_val(i32 %a2)
68+
call void @use_val(i32 %a3)
69+
call void @use_val(i32 %a4)
70+
call void @use_val(i32 %a5)
71+
call void @use_val(i32 %a6)
72+
call void @use_val(i32 %a7)
73+
call void @use_val(i32 %a8)
74+
ret void
75+
}
76+
77+
78+
; This is the same as above, but using "invoke" rather than "call" to
79+
; call setjmp().
80+
81+
define void @setjmp_invoker() {
82+
; X86-32-LABEL: setjmp_invoker:
83+
; X86-64-LABEL: setjmp_invoker:
84+
%a1 = call i32 @get_val()
85+
%a2 = call i32 @get_val()
86+
%a3 = call i32 @get_val()
87+
%a4 = call i32 @get_val()
88+
%a5 = call i32 @get_val()
89+
%a6 = call i32 @get_val()
90+
%a7 = call i32 @get_val()
91+
%a8 = call i32 @get_val()
92+
; X86-32: movl %eax, [[SPILL_SLOT:[0-9]+]](%esp)
93+
; X86-32: calll get_val
94+
; X86-64: movl %eax, [[SPILL_SLOT:[0-9]+]](%rsp)
95+
; X86-64: callq get_val
96+
97+
%setjmp_result = invoke i1 @setjmp() returns_twice
98+
to label %cont unwind label %lpad
99+
; X86-32: calll setjmp
100+
; X86-64: callq setjmp
101+
102+
cont:
103+
br i1 %setjmp_result, label %second, label %first
104+
105+
lpad:
106+
%lp = landingpad { i8*, i32 } personality void ()* @personality cleanup
107+
unreachable
108+
109+
first:
110+
%b1 = call i32 @get_val()
111+
%b2 = call i32 @get_val()
112+
%b3 = call i32 @get_val()
113+
%b4 = call i32 @get_val()
114+
%b5 = call i32 @get_val()
115+
%b6 = call i32 @get_val()
116+
%b7 = call i32 @get_val()
117+
%b8 = call i32 @get_val()
118+
call void @use_val(i32 %b1)
119+
call void @use_val(i32 %b2)
120+
call void @use_val(i32 %b3)
121+
call void @use_val(i32 %b4)
122+
call void @use_val(i32 %b5)
123+
call void @use_val(i32 %b6)
124+
call void @use_val(i32 %b7)
125+
call void @use_val(i32 %b8)
126+
call void @longjmp()
127+
unreachable
128+
; X86-32-NOT: movl {{.*}}, [[SPILL_SLOT]](%esp)
129+
; X86-64-NOT: movl {{.*}}, [[SPILL_SLOT]](%rsp)
130+
131+
second:
132+
call void @use_val(i32 %a1)
133+
call void @use_val(i32 %a2)
134+
call void @use_val(i32 %a3)
135+
call void @use_val(i32 %a4)
136+
call void @use_val(i32 %a5)
137+
call void @use_val(i32 %a6)
138+
call void @use_val(i32 %a7)
139+
call void @use_val(i32 %a8)
140+
ret void
141+
}

0 commit comments

Comments
 (0)