| ; RUN: llc -mtriple=aarch64-pc-windows-msvc %s -o - | FileCheck %s |
| |
| define dso_local void @normal_call() local_unnamed_addr section "nc_sect" { |
| entry: |
| call void @a() |
| call void @a() |
| ret void |
| } |
| ; CHECK-LABEL: normal_call: |
| ; CHECK: adrp [[ADRPREG:x[0-9]+]], __imp_a |
| ; CHECK-NEXT: ldr [[LDRREG:x[0-9]+]], [[[ADRPREG]], :lo12:__imp_a] |
| ; CHECK-NEXT: .Limpcall0: |
| ; CHECK-NEXT: blr [[LDRREG]] |
| ; CHECK-NEXT: .Limpcall1: |
| ; CHECK-NEXT: blr [[LDRREG]] |
| |
| define dso_local void @tail_call() local_unnamed_addr section "tc_sect" { |
| entry: |
| tail call void @b() |
| ret void |
| } |
| ; CHECK-LABEL: tail_call: |
| ; CHECK: adrp [[ADRPREG:x[0-9]+]], __imp_b |
| ; CHECK-NEXT: ldr [[LDRREG:x[0-9]+]], [[[ADRPREG]], :lo12:__imp_b] |
| ; CHECK-NEXT: .Limpcall2: |
| ; CHECK-NEXT: br [[LDRREG]] |
| |
| ; Regression test: branch folding would notice that both of these calls become |
| ; branch instructions to the same register and would fold them. However, import |
| ; call optimization requires them to remain separate as they are for different |
| ; functions. |
| define dso_local void @call_one_or_other(i32 %val) local_unnamed_addr { |
| %is_zero = icmp eq i32 %val, 0 |
| br i1 %is_zero, label %call_a, label %call_b |
| |
| call_a: |
| call void @a() |
| br label %finish |
| |
| call_b: |
| call void @b() |
| br label %finish |
| |
| finish: |
| ret void |
| } |
| ; CHECK-LABEL: call_one_or_other: |
| ; CHECK: adrp [[ADRPREG:x[0-9]+]], __imp_b |
| ; CHECK-NEXT: ldr [[LDRREG:x[0-9]+]], [[[ADRPREG]], :lo12:__imp_b] |
| ; CHECK-NEXT: .Limpcall3: |
| ; CHECK-NEXT: blr [[LDRREG]] |
| ; CHECK: adrp [[ADRPREG:x[0-9]+]], __imp_a |
| ; CHECK-NEXT: ldr [[LDRREG:x[0-9]+]], [[[ADRPREG]], :lo12:__imp_a] |
| ; CHECK-NEXT: .Limpcall4: |
| ; CHECK-NEXT: blr [[LDRREG]] |
| |
| declare dllimport void @a() local_unnamed_addr |
| declare dllimport void @b() local_unnamed_addr |
| |
| ; CHECK-LABEL: .section .impcall,"yi" |
| ; CHECK-NEXT: .asciz "Imp_Call_V1" |
| ; CHECK-NEXT: .word 32 |
| ; CHECK-NEXT: .secnum nc_sect |
| ; CHECK-NEXT: .word 19 |
| ; CHECK-NEXT: .secoffset .Limpcall0 |
| ; CHECK-NEXT: .symidx __imp_a |
| ; CHECK-NEXT: .word 19 |
| ; CHECK-NEXT: .secoffset .Limpcall1 |
| ; CHECK-NEXT: .symidx __imp_a |
| ; CHECK-NEXT: .word 20 |
| ; CHECK-NEXT: .secnum tc_sect |
| ; CHECK-NEXT: .word 19 |
| ; CHECK-NEXT: .secoffset .Limpcall2 |
| ; CHECK-NEXT: .symidx __imp_b |
| ; CHECK-NEXT: .word 32 |
| ; CHECK-NEXT: .secnum .text |
| ; CHECK-NEXT: .word 19 |
| ; CHECK-NEXT: .secoffset .Limpcall3 |
| ; CHECK-NEXT: .symidx __imp_b |
| ; CHECK-NEXT: .word 19 |
| ; CHECK-NEXT: .secoffset .Limpcall4 |
| ; CHECK-NEXT: .symidx __imp_a |
| |
| !llvm.module.flags = !{!0} |
| !0 = !{i32 1, !"import-call-optimization", i32 1} |