; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
; RUN: llc -mtriple=x86_64-apple-darwin10.6 < %s | FileCheck %s
; RUN: llc -mtriple=x86_64-linux < %s | FileCheck %s --check-prefix=NOCOMPACTUNWIND
;
; Note: This test cannot be merged with the shrink-wrapping tests
; because the booleans set on the command line take precedence on
; the target logic that disable shrink-wrapping.
; The current compact unwind scheme does not work when the prologue is not at
; the start (the instructions before the prologue cannot be described).
; Currently we choose to not perform shrink-wrapping for functions without FP
; not marked as nounwind. PR25614
;
; No shrink-wrapping should occur here, until the CFI information are fixed.
define i32 @framelessUnwind(i32 %a, i32 %b) #0 {
; CHECK-LABEL: framelessUnwind:
; CHECK: ## %bb.0:
; CHECK-NEXT: pushq %rax
; CHECK-NEXT: .cfi_def_cfa_offset 16
; CHECK-NEXT: movl %edi, %eax
; CHECK-NEXT: cmpl %esi, %edi
; CHECK-NEXT: jge LBB0_2
; CHECK-NEXT: ## %bb.1: ## %true
; CHECK-NEXT: movl %eax, {{[0-9]+}}(%rsp)
; CHECK-NEXT: leaq {{[0-9]+}}(%rsp), %rsi
; CHECK-NEXT: xorl %edi, %edi
; CHECK-NEXT: callq _doSomething
; CHECK-NEXT: LBB0_2: ## %false
; CHECK-NEXT: popq %rcx
; CHECK-NEXT: retq
;
; NOCOMPACTUNWIND-LABEL: framelessUnwind:
; NOCOMPACTUNWIND: # %bb.0:
; NOCOMPACTUNWIND-NEXT: movl %edi, %eax
; NOCOMPACTUNWIND-NEXT: cmpl %esi, %edi
; NOCOMPACTUNWIND-NEXT: jge .LBB0_2
; NOCOMPACTUNWIND-NEXT: # %bb.1: # %true
; NOCOMPACTUNWIND-NEXT: pushq %rax
; NOCOMPACTUNWIND-NEXT: .cfi_def_cfa_offset 16
; NOCOMPACTUNWIND-NEXT: movl %eax, {{[0-9]+}}(%rsp)
; NOCOMPACTUNWIND-NEXT: leaq {{[0-9]+}}(%rsp), %rsi
; NOCOMPACTUNWIND-NEXT: xorl %edi, %edi
; NOCOMPACTUNWIND-NEXT: callq doSomething@PLT
; NOCOMPACTUNWIND-NEXT: addq $8, %rsp
; NOCOMPACTUNWIND-NEXT: .cfi_def_cfa_offset 8
; NOCOMPACTUNWIND-NEXT: .LBB0_2: # %false
; NOCOMPACTUNWIND-NEXT: retq
%tmp = alloca i32, align 4
%tmp2 = icmp slt i32 %a, %b
br i1 %tmp2, label %true, label %false
true:
store i32 %a, ptr %tmp, align 4
%tmp4 = call i32 @doSomething(i32 0, ptr %tmp)
br label %false
false:
%tmp.0 = phi i32 [ %tmp4, %true ], [ %a, %0 ]
ret i32 %tmp.0
}
declare i32 @doSomething(i32, ptr)
attributes #0 = { "frame-pointer"="none" }
; Shrink-wrapping should occur here. We have a frame pointer.
define i32 @frameUnwind(i32 %a, i32 %b) #1 {
; CHECK-LABEL: frameUnwind:
; CHECK: ## %bb.0:
; CHECK-NEXT: movl %edi, %eax
; CHECK-NEXT: cmpl %esi, %edi
; CHECK-NEXT: jge LBB1_2
; CHECK-NEXT: ## %bb.1: ## %true
; CHECK-NEXT: pushq %rbp
; CHECK-NEXT: .cfi_def_cfa_offset 16
; CHECK-NEXT: .cfi_offset %rbp, -16
; CHECK-NEXT: movq %rsp, %rbp
; CHECK-NEXT: .cfi_def_cfa_register %rbp
; CHECK-NEXT: subq $16, %rsp
; CHECK-NEXT: movl %eax, -4(%rbp)
; CHECK-NEXT: leaq -4(%rbp), %rsi
; CHECK-NEXT: xorl %edi, %edi
; CHECK-NEXT: callq _doSomething
; CHECK-NEXT: addq $16, %rsp
; CHECK-NEXT: popq %rbp
; CHECK-NEXT: LBB1_2: ## %false
; CHECK-NEXT: retq
;
; NOCOMPACTUNWIND-LABEL: frameUnwind:
; NOCOMPACTUNWIND: # %bb.0:
; NOCOMPACTUNWIND-NEXT: movl %edi, %eax
; NOCOMPACTUNWIND-NEXT: cmpl %esi, %edi
; NOCOMPACTUNWIND-NEXT: jge .LBB1_2
; NOCOMPACTUNWIND-NEXT: # %bb.1: # %true
; NOCOMPACTUNWIND-NEXT: pushq %rbp
; NOCOMPACTUNWIND-NEXT: .cfi_def_cfa_offset 16
; NOCOMPACTUNWIND-NEXT: .cfi_offset %rbp, -16
; NOCOMPACTUNWIND-NEXT: movq %rsp, %rbp
; NOCOMPACTUNWIND-NEXT: .cfi_def_cfa_register %rbp
; NOCOMPACTUNWIND-NEXT: subq $16, %rsp
; NOCOMPACTUNWIND-NEXT: movl %eax, -4(%rbp)
; NOCOMPACTUNWIND-NEXT: leaq -4(%rbp), %rsi
; NOCOMPACTUNWIND-NEXT: xorl %edi, %edi
; NOCOMPACTUNWIND-NEXT: callq doSomething@PLT
; NOCOMPACTUNWIND-NEXT: addq $16, %rsp
; NOCOMPACTUNWIND-NEXT: popq %rbp
; NOCOMPACTUNWIND-NEXT: .cfi_def_cfa %rsp, 8
; NOCOMPACTUNWIND-NEXT: .cfi_restore %rbp
; NOCOMPACTUNWIND-NEXT: .LBB1_2: # %false
; NOCOMPACTUNWIND-NEXT: retq
%tmp = alloca i32, align 4
%tmp2 = icmp slt i32 %a, %b
br i1 %tmp2, label %true, label %false
true:
store i32 %a, ptr %tmp, align 4
%tmp4 = call i32 @doSomething(i32 0, ptr %tmp)
br label %false
false:
%tmp.0 = phi i32 [ %tmp4, %true ], [ %a, %0 ]
ret i32 %tmp.0
}
attributes #1 = { "frame-pointer"="all" }
; Shrink-wrapping should occur here. We do not have to unwind.
define i32 @framelessnoUnwind(i32 %a, i32 %b) #2 {
; CHECK-LABEL: framelessnoUnwind:
; CHECK: ## %bb.0:
; CHECK-NEXT: movl %edi, %eax
; CHECK-NEXT: cmpl %esi, %edi
; CHECK-NEXT: jge LBB2_2
; CHECK-NEXT: ## %bb.1: ## %true
; CHECK-NEXT: pushq %rax
; CHECK-NEXT: movl %eax, {{[0-9]+}}(%rsp)
; CHECK-NEXT: leaq {{[0-9]+}}(%rsp), %rsi
; CHECK-NEXT: xorl %edi, %edi
; CHECK-NEXT: callq _doSomething
; CHECK-NEXT: addq $8, %rsp
; CHECK-NEXT: LBB2_2: ## %false
; CHECK-NEXT: retq
;
; NOCOMPACTUNWIND-LABEL: framelessnoUnwind:
; NOCOMPACTUNWIND: # %bb.0:
; NOCOMPACTUNWIND-NEXT: movl %edi, %eax
; NOCOMPACTUNWIND-NEXT: cmpl %esi, %edi
; NOCOMPACTUNWIND-NEXT: jge .LBB2_2
; NOCOMPACTUNWIND-NEXT: # %bb.1: # %true
; NOCOMPACTUNWIND-NEXT: pushq %rax
; NOCOMPACTUNWIND-NEXT: movl %eax, {{[0-9]+}}(%rsp)
; NOCOMPACTUNWIND-NEXT: leaq {{[0-9]+}}(%rsp), %rsi
; NOCOMPACTUNWIND-NEXT: xorl %edi, %edi
; NOCOMPACTUNWIND-NEXT: callq doSomething@PLT
; NOCOMPACTUNWIND-NEXT: addq $8, %rsp
; NOCOMPACTUNWIND-NEXT: .LBB2_2: # %false
; NOCOMPACTUNWIND-NEXT: retq
%tmp = alloca i32, align 4
%tmp2 = icmp slt i32 %a, %b
br i1 %tmp2, label %true, label %false
true:
store i32 %a, ptr %tmp, align 4
%tmp4 = call i32 @doSomething(i32 0, ptr %tmp)
br label %false
false:
%tmp.0 = phi i32 [ %tmp4, %true ], [ %a, %0 ]
ret i32 %tmp.0
}
attributes #2 = { "frame-pointer"="none" nounwind }
; Check that we generate correct code for segmented stack.
; We used to emit the code at the entry point of the function
; instead of just before the prologue.
; For now, shrink-wrapping is disabled on segmented stack functions: PR26107.
define zeroext i1 @segmentedStack(ptr readonly %vk1, ptr readonly %vk2, i64 %key_size) #5 {
; CHECK-LABEL: segmentedStack:
; CHECK: ## %bb.0:
; CHECK-NEXT: cmpq %gs:816, %rsp
; CHECK-NEXT: jbe LBB3_6
; CHECK-NEXT: LBB3_1: ## %entry
; CHECK-NEXT: pushq %rax
; CHECK-NEXT: .cfi_def_cfa_offset 16
; CHECK-NEXT: testq %rdi, %rdi
; CHECK-NEXT: sete %al
; CHECK-NEXT: testq %rsi, %rsi
; CHECK-NEXT: sete %cl
; CHECK-NEXT: orb %al, %cl
; CHECK-NEXT: movq %rdi, %rax
; CHECK-NEXT: orq %rsi, %rax
; CHECK-NEXT: sete %al
; CHECK-NEXT: testb %cl, %cl
; CHECK-NEXT: jne LBB3_4
; CHECK-NEXT: ## %bb.2: ## %if.end4.i
; CHECK-NEXT: movq 8(%rdi), %rdx
; CHECK-NEXT: cmpq 8(%rsi), %rdx
; CHECK-NEXT: jne LBB3_5
; CHECK-NEXT: ## %bb.3: ## %land.rhs.i.i
; CHECK-NEXT: movq (%rsi), %rsi
; CHECK-NEXT: movq (%rdi), %rdi
; CHECK-NEXT: callq _memcmp
; CHECK-NEXT: testl %eax, %eax
; CHECK-NEXT: sete %al
; CHECK-NEXT: LBB3_4: ## %__go_ptr_strings_equal.exit
; CHECK-NEXT: ## kill: def $al killed $al killed $eax
; CHECK-NEXT: popq %rcx
; CHECK-NEXT: retq
; CHECK-NEXT: LBB3_5:
; CHECK-NEXT: xorl %eax, %eax
; CHECK-NEXT: ## kill: def $al killed $al killed $eax
; CHECK-NEXT: popq %rcx
; CHECK-NEXT: retq
; CHECK-NEXT: LBB3_6:
; CHECK-NEXT: movl $8, %r10d
; CHECK-NEXT: movl $0, %r11d
; CHECK-NEXT: callq ___morestack
; CHECK-NEXT: retq
; CHECK-NEXT: jmp LBB3_1
;
; NOCOMPACTUNWIND-LABEL: segmentedStack:
; NOCOMPACTUNWIND: # %bb.0:
; NOCOMPACTUNWIND-NEXT: cmpq %fs:112, %rsp
; NOCOMPACTUNWIND-NEXT: jbe .LBB3_6
; NOCOMPACTUNWIND-NEXT: .LBB3_1: # %entry
; NOCOMPACTUNWIND-NEXT: pushq %rax
; NOCOMPACTUNWIND-NEXT: .cfi_def_cfa_offset 16
; NOCOMPACTUNWIND-NEXT: testq %rdi, %rdi
; NOCOMPACTUNWIND-NEXT: sete %al
; NOCOMPACTUNWIND-NEXT: testq %rsi, %rsi
; NOCOMPACTUNWIND-NEXT: sete %cl
; NOCOMPACTUNWIND-NEXT: orb %al, %cl
; NOCOMPACTUNWIND-NEXT: movq %rdi, %rax
; NOCOMPACTUNWIND-NEXT: orq %rsi, %rax
; NOCOMPACTUNWIND-NEXT: sete %al
; NOCOMPACTUNWIND-NEXT: testb %cl, %cl
; NOCOMPACTUNWIND-NEXT: jne .LBB3_4
; NOCOMPACTUNWIND-NEXT: # %bb.2: # %if.end4.i
; NOCOMPACTUNWIND-NEXT: movq 8(%rdi), %rdx
; NOCOMPACTUNWIND-NEXT: cmpq 8(%rsi), %rdx
; NOCOMPACTUNWIND-NEXT: jne .LBB3_5
; NOCOMPACTUNWIND-NEXT: # %bb.3: # %land.rhs.i.i
; NOCOMPACTUNWIND-NEXT: movq (%rsi), %rsi
; NOCOMPACTUNWIND-NEXT: movq (%rdi), %rdi
; NOCOMPACTUNWIND-NEXT: callq memcmp@PLT
; NOCOMPACTUNWIND-NEXT: testl %eax, %eax
; NOCOMPACTUNWIND-NEXT: sete %al
; NOCOMPACTUNWIND-NEXT: .LBB3_4: # %__go_ptr_strings_equal.exit
; NOCOMPACTUNWIND-NEXT: # kill: def $al killed $al killed $eax
; NOCOMPACTUNWIND-NEXT: popq %rcx
; NOCOMPACTUNWIND-NEXT: .cfi_def_cfa_offset 8
; NOCOMPACTUNWIND-NEXT: retq
; NOCOMPACTUNWIND-NEXT: .LBB3_5:
; NOCOMPACTUNWIND-NEXT: .cfi_def_cfa_offset 16
; NOCOMPACTUNWIND-NEXT: xorl %eax, %eax
; NOCOMPACTUNWIND-NEXT: # kill: def $al killed $al killed $eax
; NOCOMPACTUNWIND-NEXT: popq %rcx
; NOCOMPACTUNWIND-NEXT: .cfi_def_cfa_offset 8
; NOCOMPACTUNWIND-NEXT: retq
; NOCOMPACTUNWIND-NEXT: .LBB3_6:
; NOCOMPACTUNWIND-NEXT: movl $8, %r10d
; NOCOMPACTUNWIND-NEXT: movl $0, %r11d
; NOCOMPACTUNWIND-NEXT: callq __morestack
; NOCOMPACTUNWIND-NEXT: retq
; NOCOMPACTUNWIND-NEXT: jmp .LBB3_1
entry:
%cmp.i = icmp eq ptr %vk1, null
%cmp1.i = icmp eq ptr %vk2, null
%brmerge.i = or i1 %cmp.i, %cmp1.i
%cmp1.mux.i = and i1 %cmp.i, %cmp1.i
br i1 %brmerge.i, label %__go_ptr_strings_equal.exit, label %if.end4.i
if.end4.i: ; preds = %entry
%tmp = getelementptr inbounds i8, ptr %vk1, i64 8
%tmp2 = load i64, ptr %tmp, align 8
%tmp3 = getelementptr inbounds i8, ptr %vk2, i64 8
%tmp5 = load i64, ptr %tmp3, align 8
%cmp.i.i = icmp eq i64 %tmp2, %tmp5
br i1 %cmp.i.i, label %land.rhs.i.i, label %__go_ptr_strings_equal.exit
land.rhs.i.i: ; preds = %if.end4.i
%tmp7 = load ptr, ptr %vk2, align 8
%tmp9 = load ptr, ptr %vk1, align 8
%call.i.i = tail call i32 @memcmp(ptr %tmp9, ptr %tmp7, i64 %tmp2) #5
%cmp4.i.i = icmp eq i32 %call.i.i, 0
br label %__go_ptr_strings_equal.exit
__go_ptr_strings_equal.exit: ; preds = %land.rhs.i.i, %if.end4.i, %entry
%retval.0.i = phi i1 [ %cmp1.mux.i, %entry ], [ false, %if.end4.i ], [ %cmp4.i.i, %land.rhs.i.i ]
ret i1 %retval.0.i
}
; Function Attrs: nounwind readonly
declare i32 @memcmp(ptr nocapture, ptr nocapture, i64) #5
attributes #5 = { nounwind readonly ssp uwtable "split-stack" }
; Check that correctly take into account the jumps to landing pad.
; We used to consider function that may throw like regular
; function calls.
; Therefore, in this example, we were happily inserting the epilogue
; right after the call to throw_exception. Because of that we would not
; execute the epilogue when an execption occur and bad things will
; happen.
; PR36513
define void @with_nounwind(i1 %cond) nounwind personality ptr @my_personality {
; CHECK-LABEL: with_nounwind:
; CHECK: ## %bb.0: ## %entry
; CHECK-NEXT: pushq %rax
; CHECK-NEXT: .cfi_def_cfa_offset 16
; CHECK-NEXT: testb $1, %dil
; CHECK-NEXT: jne LBB4_1
; CHECK-NEXT: ## %bb.4: ## %return
; CHECK-NEXT: popq %rax
; CHECK-NEXT: retq
; CHECK-NEXT: LBB4_1: ## %throw
; CHECK-NEXT: Ltmp0:
; CHECK-NEXT: callq _throw_exception
; CHECK-NEXT: Ltmp1:
; CHECK-NEXT: ## %bb.2: ## %unreachable
; CHECK-NEXT: ud2
; CHECK-NEXT: LBB4_3: ## %landing
; CHECK-NEXT: Ltmp2:
; CHECK-NEXT: popq %rax
; CHECK-NEXT: retq
; CHECK-NEXT: Lfunc_end0:
;
; NOCOMPACTUNWIND-LABEL: with_nounwind:
; NOCOMPACTUNWIND: # %bb.0: # %entry
; NOCOMPACTUNWIND-NEXT: pushq %rax
; NOCOMPACTUNWIND-NEXT: .cfi_def_cfa_offset 16
; NOCOMPACTUNWIND-NEXT: testb $1, %dil
; NOCOMPACTUNWIND-NEXT: jne .LBB4_1
; NOCOMPACTUNWIND-NEXT: # %bb.4: # %return
; NOCOMPACTUNWIND-NEXT: popq %rax
; NOCOMPACTUNWIND-NEXT: .cfi_def_cfa_offset 8
; NOCOMPACTUNWIND-NEXT: retq
; NOCOMPACTUNWIND-NEXT: .LBB4_1: # %throw
; NOCOMPACTUNWIND-NEXT: .cfi_def_cfa_offset 16
; NOCOMPACTUNWIND-NEXT: .Ltmp0:
; NOCOMPACTUNWIND-NEXT: callq throw_exception@PLT
; NOCOMPACTUNWIND-NEXT: .Ltmp1:
; NOCOMPACTUNWIND-NEXT: # %bb.2: # %unreachable
; NOCOMPACTUNWIND-NEXT: .LBB4_3: # %landing
; NOCOMPACTUNWIND-NEXT: .Ltmp2:
; NOCOMPACTUNWIND-NEXT: popq %rax
; NOCOMPACTUNWIND-NEXT: .cfi_def_cfa_offset 8
; NOCOMPACTUNWIND-NEXT: retq
entry:
br i1 %cond, label %throw, label %return
throw:
invoke void @throw_exception()
to label %unreachable unwind label %landing
unreachable:
unreachable
landing:
%pad = landingpad { ptr, i32 }
catch ptr null
ret void
return:
ret void
}
; Check landing pad again.
; This time checks that we can shrink-wrap when the epilogue does not
; span accross several blocks.
define void @with_nounwind_same_succ(i1 %cond) nounwind personality ptr @my_personality2 {
; CHECK-LABEL: with_nounwind_same_succ:
; CHECK: ## %bb.0: ## %entry
; CHECK-NEXT: testb $1, %dil
; CHECK-NEXT: je LBB5_4
; CHECK-NEXT: ## %bb.1: ## %throw
; CHECK-NEXT: pushq %rax
; CHECK-NEXT: .cfi_def_cfa_offset 16
; CHECK-NEXT: Ltmp3:
; CHECK-NEXT: callq _throw_exception
; CHECK-NEXT: Ltmp4:
; CHECK-NEXT: LBB5_3: ## %fallthrough
; CHECK-NEXT: ## InlineAsm Start
; CHECK-NEXT: nop
; CHECK-NEXT: ## InlineAsm End
; CHECK-NEXT: popq %rax
; CHECK-NEXT: LBB5_4: ## %return
; CHECK-NEXT: retq
; CHECK-NEXT: LBB5_2: ## %landing
; CHECK-NEXT: Ltmp5:
; CHECK-NEXT: jmp LBB5_3
; CHECK-NEXT: Lfunc_end1:
;
; NOCOMPACTUNWIND-LABEL: with_nounwind_same_succ:
; NOCOMPACTUNWIND: # %bb.0: # %entry
; NOCOMPACTUNWIND-NEXT: testb $1, %dil
; NOCOMPACTUNWIND-NEXT: je .LBB5_4
; NOCOMPACTUNWIND-NEXT: # %bb.1: # %throw
; NOCOMPACTUNWIND-NEXT: pushq %rax
; NOCOMPACTUNWIND-NEXT: .cfi_def_cfa_offset 16
; NOCOMPACTUNWIND-NEXT: .Ltmp3:
; NOCOMPACTUNWIND-NEXT: callq throw_exception@PLT
; NOCOMPACTUNWIND-NEXT: .Ltmp4:
; NOCOMPACTUNWIND-NEXT: .LBB5_3: # %fallthrough
; NOCOMPACTUNWIND-NEXT: #APP
; NOCOMPACTUNWIND-NEXT: nop
; NOCOMPACTUNWIND-NEXT: #NO_APP
; NOCOMPACTUNWIND-NEXT: popq %rax
; NOCOMPACTUNWIND-NEXT: .cfi_def_cfa_offset 8
; NOCOMPACTUNWIND-NEXT: .LBB5_4: # %return
; NOCOMPACTUNWIND-NEXT: retq
; NOCOMPACTUNWIND-NEXT: .LBB5_2: # %landing
; NOCOMPACTUNWIND-NEXT: .cfi_def_cfa_offset 16
; NOCOMPACTUNWIND-NEXT: .Ltmp5:
; NOCOMPACTUNWIND-NEXT: jmp .LBB5_3
entry:
br i1 %cond, label %throw, label %return
throw:
invoke void @throw_exception()
to label %fallthrough unwind label %landing
landing:
%pad = landingpad { ptr, i32 }
catch ptr null
br label %fallthrough
fallthrough:
tail call void asm "nop", ""()
br label %return
return:
ret void
}
declare void @throw_exception()
declare i32 @my_personality(...)
declare i32 @my_personality2(...)