; 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_7 ; CHECK-NEXT: LBB3_1: ## %entry ; CHECK-NEXT: pushq %rax ; CHECK-NEXT: .cfi_def_cfa_offset 16 ; CHECK-NEXT: movq %rdi, %rax ; CHECK-NEXT: orq %rsi, %rax ; CHECK-NEXT: sete %al ; CHECK-NEXT: testq %rdi, %rdi ; CHECK-NEXT: je LBB3_5 ; CHECK-NEXT: ## %bb.2: ## %entry ; CHECK-NEXT: testq %rsi, %rsi ; CHECK-NEXT: je LBB3_5 ; CHECK-NEXT: ## %bb.3: ## %if.end4.i ; CHECK-NEXT: movq 8(%rdi), %rdx ; CHECK-NEXT: cmpq 8(%rsi), %rdx ; CHECK-NEXT: jne LBB3_6 ; CHECK-NEXT: ## %bb.4: ## %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_5: ## %__go_ptr_strings_equal.exit ; CHECK-NEXT: ## kill: def $al killed $al killed $eax ; CHECK-NEXT: popq %rcx ; CHECK-NEXT: retq ; CHECK-NEXT: LBB3_6: ; CHECK-NEXT: xorl %eax, %eax ; CHECK-NEXT: ## kill: def $al killed $al killed $eax ; CHECK-NEXT: popq %rcx ; CHECK-NEXT: retq ; CHECK-NEXT: LBB3_7: ; 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_7 ; NOCOMPACTUNWIND-NEXT: .LBB3_1: # %entry ; NOCOMPACTUNWIND-NEXT: pushq %rax ; NOCOMPACTUNWIND-NEXT: .cfi_def_cfa_offset 16 ; NOCOMPACTUNWIND-NEXT: movq %rdi, %rax ; NOCOMPACTUNWIND-NEXT: orq %rsi, %rax ; NOCOMPACTUNWIND-NEXT: sete %al ; NOCOMPACTUNWIND-NEXT: testq %rdi, %rdi ; NOCOMPACTUNWIND-NEXT: je .LBB3_5 ; NOCOMPACTUNWIND-NEXT: # %bb.2: # %entry ; NOCOMPACTUNWIND-NEXT: testq %rsi, %rsi ; NOCOMPACTUNWIND-NEXT: je .LBB3_5 ; NOCOMPACTUNWIND-NEXT: # %bb.3: # %if.end4.i ; NOCOMPACTUNWIND-NEXT: movq 8(%rdi), %rdx ; NOCOMPACTUNWIND-NEXT: cmpq 8(%rsi), %rdx ; NOCOMPACTUNWIND-NEXT: jne .LBB3_6 ; NOCOMPACTUNWIND-NEXT: # %bb.4: # %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_5: # %__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_6: ; 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_7: ; 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(...)