| ## This test reproduces the case where C++ exception handling is used and split |
| ## function optimization is enabled. In particular, function foo is splitted |
| ## to two fragments: |
| ## foo: contains 2 try blocks, which invokes bar to throw exception |
| ## foo.cold.1: contains 2 corresponding catch blocks (landing pad) |
| ## |
| ## Similar to split jump table, split landing pad target to different fragment. |
| ## This test is written to ensure BOLT safely handle these targets, e.g., by |
| ## marking them as non-simple. |
| ## |
| ## Steps to write this test: |
| ## - Create a copy of Inputs/src/unreachable.cpp |
| ## - Simplify bar(), focus on throw an exception |
| ## - Create the second switch case in foo() to have multiple landing pads |
| ## - Compile with clang++ to .s |
| ## - Move landing pad code from foo to foo.cold.1 |
| ## - Ensure that all landing pads can be reached normally |
| ## |
| ## Additional details: |
| ## .gcc_except_table specify the landing pads for try blocks |
| ## LPStart = 255 (omit), which means LPStart = foo start |
| ## Landing pads .Ltmp2 and .Ltmp5 in call site record are offset to foo start. |
| |
| |
| # REQUIRES: system-linux |
| # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o |
| # RUN: %clang++ %cxxflags %t.o -o %t.exe -Wl,-q |
| # RUN: llvm-bolt -v=3 %t.exe -o %t.out 2>&1 | FileCheck %s |
| |
| # CHECK: BOLT-WARNING: Ignoring foo |
| # CHECK: BOLT-WARNING: Ignoring foo.cold.1 |
| # CHECK: BOLT-WARNING: skipped 2 functions due to cold fragments |
| |
| .text |
| .globl bar # -- Begin function bar |
| .p2align 4, 0x90 |
| .type bar,@function |
| bar: # @bar |
| .cfi_startproc |
| # %bb.0: # %entry |
| pushq %rbp |
| .cfi_def_cfa_offset 16 |
| .cfi_offset %rbp, -16 |
| movq %rsp, %rbp |
| .cfi_def_cfa_register %rbp |
| subq $16, %rsp |
| movq %rdi, -8(%rbp) |
| cmpq $34, -8(%rbp) |
| jne .LBB0_2 |
| # %bb.1: # %if.then |
| movl $4, %edi |
| callq __cxa_allocate_exception@PLT |
| movq %rax, %rdi |
| movl $0, (%rdi) |
| movq _ZTIi@GOTPCREL(%rip), %rsi |
| xorl %eax, %eax |
| movl %eax, %edx |
| callq __cxa_throw@PLT |
| .LBB0_2: # %if.else |
| movl $8, %edi |
| callq __cxa_allocate_exception@PLT |
| movq %rax, %rdi |
| movq $0, (%rdi) |
| movq _ZTIDn@GOTPCREL(%rip), %rsi |
| xorl %eax, %eax |
| movl %eax, %edx |
| callq __cxa_throw@PLT |
| .Lfunc_end0: |
| .size bar, .Lfunc_end0-bar |
| .cfi_endproc |
| # -- End function |
| .globl foo # -- Begin function foo |
| .p2align 4, 0x90 |
| .type foo,@function |
| foo: # @foo |
| .Lfunc_begin0: |
| .cfi_startproc |
| .cfi_personality 155, DW.ref.__gxx_personality_v0 |
| .cfi_lsda 27, .Lexception0 |
| # %bb.0: # %entry |
| pushq %rbp |
| .cfi_def_cfa_offset 16 |
| .cfi_offset %rbp, -16 |
| movq %rsp, %rbp |
| .cfi_def_cfa_register %rbp |
| subq $48, %rsp |
| movq %rdi, -16(%rbp) |
| movq -16(%rbp), %rdi |
| .Ltmp0: |
| callq bar |
| .Ltmp1: |
| jmp .LBB1_1 |
| .LBB1_1: # %invoke.cont |
| jmp .LBB1_5 |
| .LBB1_5: # %try.cont |
| movq -16(%rbp), %rdi |
| addq $34, %rdi |
| .Ltmp3: |
| callq bar |
| .Ltmp4: |
| jmp .LBB1_6 |
| .LBB1_6: # %invoke.cont2 |
| jmp .LBB1_10 |
| .LBB1_10: # %try.cont8 |
| movq $0, -8(%rbp) |
| .LBB1_11: # %return |
| movq -8(%rbp), %rax |
| addq $48, %rsp |
| popq %rbp |
| .cfi_def_cfa %rsp, 8 |
| retq |
| .LBB1_12: # %eh.resume |
| .cfi_def_cfa %rbp, 16 |
| movq -24(%rbp), %rdi |
| callq _Unwind_Resume@PLT |
| .Lfunc_end1: |
| .size foo, .Lfunc_end1-foo |
| .cfi_endproc |
| .section .gcc_except_table,"a",@progbits |
| .p2align 2 |
| GCC_except_table1: |
| .Lexception0: |
| .byte 255 # @LPStart Encoding = omit |
| .byte 155 # @TType Encoding = indirect pcrel sdata4 |
| .uleb128 .Lttbase0-.Lttbaseref0 |
| .Lttbaseref0: |
| .byte 1 # Call site Encoding = uleb128 |
| .uleb128 .Lcst_end0-.Lcst_begin0 |
| .Lcst_begin0: |
| .uleb128 .Ltmp0-.Lfunc_begin0 # >> Call Site 1 << |
| .uleb128 .Ltmp1-.Ltmp0 # Call between .Ltmp0 and .Ltmp1 |
| .uleb128 .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2 |
| .byte 1 # On action: 1 |
| .uleb128 .Ltmp1-.Lfunc_begin0 # >> Call Site 2 << |
| .uleb128 .Ltmp3-.Ltmp1 # Call between .Ltmp1 and .Ltmp3 |
| .byte 0 # has no landing pad |
| .byte 0 # On action: cleanup |
| .uleb128 .Ltmp3-.Lfunc_begin0 # >> Call Site 3 << |
| .uleb128 .Ltmp4-.Ltmp3 # Call between .Ltmp3 and .Ltmp4 |
| .uleb128 .Ltmp5-.Lfunc_begin0 # jumps to .Ltmp5 |
| .byte 1 # On action: 1 |
| .uleb128 .Ltmp4-.Lfunc_begin0 # >> Call Site 4 << |
| .uleb128 .Lfunc_end1-.Ltmp4 # Call between .Ltmp4 and .Lfunc_end1 |
| .byte 0 # has no landing pad |
| .byte 0 # On action: cleanup |
| .Lcst_end0: |
| .byte 1 # >> Action Record 1 << |
| # Catch TypeInfo 1 |
| .byte 0 # No further actions |
| .p2align 2 |
| # >> Catch TypeInfos << |
| .Ltmp6: # TypeInfo 1 |
| .long .L_ZTIi.DW.stub-.Ltmp6 |
| .Lttbase0: |
| .p2align 2 |
| # -- End function |
| |
| |
| .text |
| .globl foo.cold.1 # -- Begin function foo.cold.1 |
| .p2align 4, 0x90 |
| .type foo.cold.1,@function |
| foo.cold.1: # @foo.cold.1 |
| .Lfunc_begin3: |
| .cfi_startproc |
| .Ltmp2: |
| movq %rax, %rcx |
| movl %edx, %eax |
| movq %rcx, -24(%rbp) |
| movl %eax, -28(%rbp) |
| # %bb.3: # %catch.dispatch |
| movl -28(%rbp), %eax |
| movl $1, %ecx |
| cmpl %ecx, %eax |
| jne .LBB1_12 |
| # %bb.4: # %catch |
| movq -24(%rbp), %rdi |
| callq __cxa_begin_catch@PLT |
| movl (%rax), %eax |
| movl %eax, -32(%rbp) |
| movq $0, -8(%rbp) |
| callq __cxa_end_catch@PLT |
| jmp .LBB1_11 |
| .Ltmp5: |
| movq %rax, %rcx |
| movl %edx, %eax |
| movq %rcx, -24(%rbp) |
| movl %eax, -28(%rbp) |
| # %bb.8: # %catch.dispatch3 |
| movl -28(%rbp), %eax |
| movl $1, %ecx |
| cmpl %ecx, %eax |
| jne .LBB1_12 |
| # %bb.9: # %catch6 |
| movq -24(%rbp), %rdi |
| callq __cxa_begin_catch@PLT |
| movl (%rax), %eax |
| movl %eax, -36(%rbp) |
| movq $0, -8(%rbp) |
| callq __cxa_end_catch@PLT |
| jmp .LBB1_11 |
| .Lfunc_end3: |
| .size foo.cold.1, .Lfunc_end3-foo.cold.1 |
| .cfi_endproc |
| |
| |
| .text |
| .globl main # -- Begin function main |
| .p2align 4, 0x90 |
| .type main,@function |
| main: # @main |
| .cfi_startproc |
| # %bb.0: # %entry |
| pushq %rbp |
| .cfi_def_cfa_offset 16 |
| .cfi_offset %rbp, -16 |
| movq %rsp, %rbp |
| .cfi_def_cfa_register %rbp |
| subq $16, %rsp |
| movl $0, -4(%rbp) |
| movl %edi, -8(%rbp) |
| movq %rsi, -16(%rbp) |
| xorl %eax, %eax |
| movl %eax, %edi |
| callq foo |
| # kill: def $eax killed $eax killed $rax |
| addq $16, %rsp |
| popq %rbp |
| .cfi_def_cfa %rsp, 8 |
| retq |
| .Lfunc_end2: |
| .size main, .Lfunc_end2-main |
| .cfi_endproc |
| # -- End function |
| .data |
| .p2align 3 |
| .L_ZTIi.DW.stub: |
| .quad _ZTIi |
| .hidden DW.ref.__gxx_personality_v0 |
| .weak DW.ref.__gxx_personality_v0 |
| .section .data.DW.ref.__gxx_personality_v0,"aGw",@progbits,DW.ref.__gxx_personality_v0,comdat |
| .p2align 3 |
| .type DW.ref.__gxx_personality_v0,@object |
| .size DW.ref.__gxx_personality_v0, 8 |
| DW.ref.__gxx_personality_v0: |
| .quad __gxx_personality_v0 |
| .section ".note.GNU-stack","",@progbits |
| .addrsig |
| .addrsig_sym bar |
| .addrsig_sym __cxa_allocate_exception |
| .addrsig_sym __cxa_throw |
| .addrsig_sym foo |
| .addrsig_sym __gxx_personality_v0 |
| .addrsig_sym __cxa_begin_catch |
| .addrsig_sym __cxa_end_catch |
| .addrsig_sym _Unwind_Resume |
| .addrsig_sym _ZTIi |
| .addrsig_sym _ZTIDn |
| .addrsig_sym foo.cold.1 |
| .addrsig_sym __cxa_begin_catch |
| .addrsig_sym __cxa_end_catch |