[llvm] r199180 - Fix llc to not reuse spill slots in functions that invoke setjmp()
Mark Seaborn
mseaborn at chromium.org
Mon Jan 13 20:20:01 PST 2014
Author: mseaborn
Date: Mon Jan 13 22:20:01 2014
New Revision: 199180
URL: http://llvm.org/viewvc/llvm-project?rev=199180&view=rev
Log:
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.
Added:
llvm/trunk/test/CodeGen/X86/setjmp-spills.ll
Modified:
llvm/trunk/lib/IR/Function.cpp
Modified: llvm/trunk/lib/IR/Function.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Function.cpp?rev=199180&r1=199179&r2=199180&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Function.cpp (original)
+++ llvm/trunk/lib/IR/Function.cpp Mon Jan 13 22:20:01 2014
@@ -736,10 +736,8 @@ bool Function::isDefTriviallyDead() cons
bool Function::callsFunctionThatReturnsTwice() const {
for (const_inst_iterator
I = inst_begin(this), E = inst_end(this); I != E; ++I) {
- const CallInst* callInst = dyn_cast<CallInst>(&*I);
- if (!callInst)
- continue;
- if (callInst->canReturnTwice())
+ ImmutableCallSite CS(&*I);
+ if (CS && CS.hasFnAttr(Attribute::ReturnsTwice))
return true;
}
Added: llvm/trunk/test/CodeGen/X86/setjmp-spills.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/setjmp-spills.ll?rev=199180&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/X86/setjmp-spills.ll (added)
+++ llvm/trunk/test/CodeGen/X86/setjmp-spills.ll Mon Jan 13 22:20:01 2014
@@ -0,0 +1,141 @@
+; RUN: llc < %s -mtriple=i386-linux | FileCheck %s -check-prefix=X86-32
+; RUN: llc < %s -mtriple=x86_64-linux | FileCheck %s -check-prefix=X86-64
+
+declare i32 @get_val()
+declare void @use_val(i32)
+declare i1 @setjmp()
+declare void @longjmp()
+declare void @personality()
+
+
+; Test that llc avoids reusing spill slots in functions that call
+; setjmp(), whether they use "call" or "invoke" for calling setjmp()
+; (PR18244).
+
+define void @setjmp_caller() {
+; X86-32-LABEL: setjmp_caller:
+; X86-64-LABEL: setjmp_caller:
+; This code keeps enough variables live across the setjmp() call that
+; they don't all fit in registers and the compiler will allocate a
+; spill slot.
+ %a1 = call i32 @get_val()
+ %a2 = call i32 @get_val()
+ %a3 = call i32 @get_val()
+ %a4 = call i32 @get_val()
+ %a5 = call i32 @get_val()
+ %a6 = call i32 @get_val()
+ %a7 = call i32 @get_val()
+ %a8 = call i32 @get_val()
+; X86-32: movl %eax, [[SPILL_SLOT:[0-9]+]](%esp)
+; X86-32: calll get_val
+; X86-64: movl %eax, [[SPILL_SLOT:[0-9]+]](%rsp)
+; X86-64: callq get_val
+
+ %setjmp_result = call i1 @setjmp() returns_twice
+ br i1 %setjmp_result, label %second, label %first
+; X86-32: calll setjmp
+; X86-64: callq setjmp
+
+; Again, keep enough variables live that they need spill slots. Since
+; this function calls a returns_twice function (setjmp()), the
+; compiler should not reuse the spill slots. longjmp() can return to
+; where the first spill slots were still live.
+first:
+ %b1 = call i32 @get_val()
+ %b2 = call i32 @get_val()
+ %b3 = call i32 @get_val()
+ %b4 = call i32 @get_val()
+ %b5 = call i32 @get_val()
+ %b6 = call i32 @get_val()
+ %b7 = call i32 @get_val()
+ %b8 = call i32 @get_val()
+ call void @use_val(i32 %b1)
+ call void @use_val(i32 %b2)
+ call void @use_val(i32 %b3)
+ call void @use_val(i32 %b4)
+ call void @use_val(i32 %b5)
+ call void @use_val(i32 %b6)
+ call void @use_val(i32 %b7)
+ call void @use_val(i32 %b8)
+ call void @longjmp()
+ unreachable
+; X86-32-NOT: movl {{.*}}, [[SPILL_SLOT]](%esp)
+; X86-64-NOT: movl {{.*}}, [[SPILL_SLOT]](%rsp)
+
+second:
+ call void @use_val(i32 %a1)
+ call void @use_val(i32 %a2)
+ call void @use_val(i32 %a3)
+ call void @use_val(i32 %a4)
+ call void @use_val(i32 %a5)
+ call void @use_val(i32 %a6)
+ call void @use_val(i32 %a7)
+ call void @use_val(i32 %a8)
+ ret void
+}
+
+
+; This is the same as above, but using "invoke" rather than "call" to
+; call setjmp().
+
+define void @setjmp_invoker() {
+; X86-32-LABEL: setjmp_invoker:
+; X86-64-LABEL: setjmp_invoker:
+ %a1 = call i32 @get_val()
+ %a2 = call i32 @get_val()
+ %a3 = call i32 @get_val()
+ %a4 = call i32 @get_val()
+ %a5 = call i32 @get_val()
+ %a6 = call i32 @get_val()
+ %a7 = call i32 @get_val()
+ %a8 = call i32 @get_val()
+; X86-32: movl %eax, [[SPILL_SLOT:[0-9]+]](%esp)
+; X86-32: calll get_val
+; X86-64: movl %eax, [[SPILL_SLOT:[0-9]+]](%rsp)
+; X86-64: callq get_val
+
+ %setjmp_result = invoke i1 @setjmp() returns_twice
+ to label %cont unwind label %lpad
+; X86-32: calll setjmp
+; X86-64: callq setjmp
+
+cont:
+ br i1 %setjmp_result, label %second, label %first
+
+lpad:
+ %lp = landingpad { i8*, i32 } personality void ()* @personality cleanup
+ unreachable
+
+first:
+ %b1 = call i32 @get_val()
+ %b2 = call i32 @get_val()
+ %b3 = call i32 @get_val()
+ %b4 = call i32 @get_val()
+ %b5 = call i32 @get_val()
+ %b6 = call i32 @get_val()
+ %b7 = call i32 @get_val()
+ %b8 = call i32 @get_val()
+ call void @use_val(i32 %b1)
+ call void @use_val(i32 %b2)
+ call void @use_val(i32 %b3)
+ call void @use_val(i32 %b4)
+ call void @use_val(i32 %b5)
+ call void @use_val(i32 %b6)
+ call void @use_val(i32 %b7)
+ call void @use_val(i32 %b8)
+ call void @longjmp()
+ unreachable
+; X86-32-NOT: movl {{.*}}, [[SPILL_SLOT]](%esp)
+; X86-64-NOT: movl {{.*}}, [[SPILL_SLOT]](%rsp)
+
+second:
+ call void @use_val(i32 %a1)
+ call void @use_val(i32 %a2)
+ call void @use_val(i32 %a3)
+ call void @use_val(i32 %a4)
+ call void @use_val(i32 %a5)
+ call void @use_val(i32 %a6)
+ call void @use_val(i32 %a7)
+ call void @use_val(i32 %a8)
+ ret void
+}
More information about the llvm-commits
mailing list