From dfa550a1761a85417d0e42c8cd17cd08e753388b Mon Sep 17 00:00:00 2001 From: Mark Seaborn Date: Tue, 14 Jan 2014 04:20:01 +0000 Subject: 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 --- test/CodeGen/X86/setjmp-spills.ll | 141 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 test/CodeGen/X86/setjmp-spills.ll (limited to 'test') diff --git a/test/CodeGen/X86/setjmp-spills.ll b/test/CodeGen/X86/setjmp-spills.ll new file mode 100644 index 0000000000..c35caae97a --- /dev/null +++ b/test/CodeGen/X86/setjmp-spills.ll @@ -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 +} -- cgit v1.2.3