setjmp-spills.ll 3.93 KB
; 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() personality void ()* @personality {
; 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 } 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
}