; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5

; RUN: llc -mtriple arm64e-apple-darwin \
; RUN:   -aarch64-enable-collect-loh=false \
; RUN:   -aarch64-min-jump-table-entries=1 -aarch64-enable-atomic-cfg-tidy=0 \
; RUN:   -o - %s | FileCheck %s --check-prefix=MACHO

; RUN: llc -mtriple arm64e-apple-darwin \
; RUN:   -fast-isel \
; RUN:   -aarch64-enable-collect-loh=false \
; RUN:   -aarch64-min-jump-table-entries=1 -aarch64-enable-atomic-cfg-tidy=0 \
; RUN:   -o - %s | FileCheck %s --check-prefix=MACHO

; RUN: llc -mtriple arm64e-apple-darwin \
; RUN:   -global-isel -global-isel-abort=1 -verify-machineinstrs \
; RUN:   -aarch64-enable-collect-loh=false \
; RUN:   -aarch64-min-jump-table-entries=1 -aarch64-enable-atomic-cfg-tidy=0 \
; RUN:   -o - %s | FileCheck %s --check-prefix=MACHO

; RUN: llc -mtriple aarch64-elf -mattr=+pauth \
; RUN:   -aarch64-min-jump-table-entries=1 -aarch64-enable-atomic-cfg-tidy=0 \
; RUN:   -o - %s | FileCheck %s --check-prefix=ELF

; RUN: llc -mtriple aarch64-elf -mattr=+pauth \
; RUN:   -fast-isel \
; RUN:   -aarch64-min-jump-table-entries=1 -aarch64-enable-atomic-cfg-tidy=0 \
; RUN:   -o - %s | FileCheck %s --check-prefix=ELF

; RUN: llc -mtriple aarch64-elf -mattr=+pauth \
; RUN:   -global-isel -global-isel-abort=1 -verify-machineinstrs \
; RUN:   -aarch64-min-jump-table-entries=1 -aarch64-enable-atomic-cfg-tidy=0 \
; RUN:   -o - %s | FileCheck %s --check-prefix=ELF

;; The discriminator is the same for all blockaddresses in the function.
;; ptrauth_string_discriminator("test_indirectbr blockaddress") == 34947

define i32 @test_indirectbr() #0 {
; MACHO-LABEL: test_indirectbr:
; MACHO:       ; %bb.0: ; %entry
; MACHO-NEXT:    stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill
; MACHO-NEXT:    adrp x16, Ltmp0@PAGE
; MACHO-NEXT:    add x16, x16, Ltmp0@PAGEOFF
; MACHO-NEXT:    mov x17, #34947 ; =0x8883
; MACHO-NEXT:    pacia x16, x17
; MACHO-NEXT:    mov x0, x16
; MACHO-NEXT:    adrp x16, Ltmp1@PAGE
; MACHO-NEXT:    add x16, x16, Ltmp1@PAGEOFF
; MACHO-NEXT:    mov x17, #34947 ; =0x8883
; MACHO-NEXT:    pacia x16, x17
; MACHO-NEXT:    mov x1, x16
; MACHO-NEXT:    bl _dummy_choose
; MACHO-NEXT:    mov x17, #34947 ; =0x8883
; MACHO-NEXT:    braa x0, x17
; MACHO-NEXT:  Ltmp0: ; Block address taken
; MACHO-NEXT:  LBB0_1: ; %bb1
; MACHO-NEXT:    mov w0, #1 ; =0x1
; MACHO-NEXT:    ldp x29, x30, [sp], #16 ; 16-byte Folded Reload
; MACHO-NEXT:    ret
; MACHO-NEXT:  Ltmp1: ; Block address taken
; MACHO-NEXT:  LBB0_2: ; %bb2
; MACHO-NEXT:    mov w0, #2 ; =0x2
; MACHO-NEXT:    ldp x29, x30, [sp], #16 ; 16-byte Folded Reload
; MACHO-NEXT:    ret
;
; ELF-LABEL: test_indirectbr:
; ELF:       // %bb.0: // %entry
; ELF-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
; ELF-NEXT:    adrp x16, .Ltmp0
; ELF-NEXT:    add x16, x16, :lo12:.Ltmp0
; ELF-NEXT:    mov x17, #34947 // =0x8883
; ELF-NEXT:    pacia x16, x17
; ELF-NEXT:    mov x0, x16
; ELF-NEXT:    adrp x16, .Ltmp1
; ELF-NEXT:    add x16, x16, :lo12:.Ltmp1
; ELF-NEXT:    mov x17, #34947 // =0x8883
; ELF-NEXT:    pacia x16, x17
; ELF-NEXT:    mov x1, x16
; ELF-NEXT:    bl dummy_choose
; ELF-NEXT:    mov x17, #34947 // =0x8883
; ELF-NEXT:    braa x0, x17
; ELF-NEXT:  .Ltmp0: // Block address taken
; ELF-NEXT:  .LBB0_1: // %bb1
; ELF-NEXT:    mov w0, #1 // =0x1
; ELF-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
; ELF-NEXT:    ret
; ELF-NEXT:  .Ltmp1: // Block address taken
; ELF-NEXT:  .LBB0_2: // %bb2
; ELF-NEXT:    mov w0, #2 // =0x2
; ELF-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
; ELF-NEXT:    ret
entry:
  %tmp0 = call ptr @dummy_choose(ptr blockaddress(@test_indirectbr, %bb1), ptr blockaddress(@test_indirectbr, %bb2))
  indirectbr ptr %tmp0, [label %bb1, label %bb2]

bb1:
  ret i32 1

bb2:
  ret i32 2
}

define ptr @test_indirectbr_other_function() #0 {
; MACHO-LABEL: test_indirectbr_other_function:
; MACHO:       ; %bb.0:
; MACHO-NEXT:    adrp x16, Ltmp0@PAGE
; MACHO-NEXT:    add x16, x16, Ltmp0@PAGEOFF
; MACHO-NEXT:    mov x17, #34947 ; =0x8883
; MACHO-NEXT:    pacia x16, x17
; MACHO-NEXT:    mov x0, x16
; MACHO-NEXT:    ret
;
; ELF-LABEL: test_indirectbr_other_function:
; ELF:       // %bb.0:
; ELF-NEXT:    adrp x16, .Ltmp0
; ELF-NEXT:    add x16, x16, :lo12:.Ltmp0
; ELF-NEXT:    mov x17, #34947 // =0x8883
; ELF-NEXT:    pacia x16, x17
; ELF-NEXT:    mov x0, x16
; ELF-NEXT:    ret
  ret ptr blockaddress(@test_indirectbr, %bb1)
}

;; Test another function to compare the discriminator.
;; ptrauth_string_discriminator("test_indirectbr_2 blockaddress") == 40224

define i32 @test_indirectbr_2() #0 {
; MACHO-LABEL: test_indirectbr_2:
; MACHO:       ; %bb.0: ; %entry
; MACHO-NEXT:    stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill
; MACHO-NEXT:    adrp x16, Ltmp2@PAGE
; MACHO-NEXT:    add x16, x16, Ltmp2@PAGEOFF
; MACHO-NEXT:    mov x17, #40224 ; =0x9d20
; MACHO-NEXT:    pacia x16, x17
; MACHO-NEXT:    mov x0, x16
; MACHO-NEXT:    adrp x16, Ltmp3@PAGE
; MACHO-NEXT:    add x16, x16, Ltmp3@PAGEOFF
; MACHO-NEXT:    mov x17, #40224 ; =0x9d20
; MACHO-NEXT:    pacia x16, x17
; MACHO-NEXT:    mov x1, x16
; MACHO-NEXT:    bl _dummy_choose
; MACHO-NEXT:    mov x17, #40224 ; =0x9d20
; MACHO-NEXT:    braa x0, x17
; MACHO-NEXT:  Ltmp2: ; Block address taken
; MACHO-NEXT:  LBB2_1: ; %bb1
; MACHO-NEXT:    mov w0, #1 ; =0x1
; MACHO-NEXT:    ldp x29, x30, [sp], #16 ; 16-byte Folded Reload
; MACHO-NEXT:    ret
; MACHO-NEXT:  Ltmp3: ; Block address taken
; MACHO-NEXT:  LBB2_2: ; %bb2
; MACHO-NEXT:    mov w0, #2 ; =0x2
; MACHO-NEXT:    ldp x29, x30, [sp], #16 ; 16-byte Folded Reload
; MACHO-NEXT:    ret
;
; ELF-LABEL: test_indirectbr_2:
; ELF:       // %bb.0: // %entry
; ELF-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
; ELF-NEXT:    adrp x16, .Ltmp2
; ELF-NEXT:    add x16, x16, :lo12:.Ltmp2
; ELF-NEXT:    mov x17, #40224 // =0x9d20
; ELF-NEXT:    pacia x16, x17
; ELF-NEXT:    mov x0, x16
; ELF-NEXT:    adrp x16, .Ltmp3
; ELF-NEXT:    add x16, x16, :lo12:.Ltmp3
; ELF-NEXT:    mov x17, #40224 // =0x9d20
; ELF-NEXT:    pacia x16, x17
; ELF-NEXT:    mov x1, x16
; ELF-NEXT:    bl dummy_choose
; ELF-NEXT:    mov x17, #40224 // =0x9d20
; ELF-NEXT:    braa x0, x17
; ELF-NEXT:  .Ltmp2: // Block address taken
; ELF-NEXT:  .LBB2_1: // %bb1
; ELF-NEXT:    mov w0, #1 // =0x1
; ELF-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
; ELF-NEXT:    ret
; ELF-NEXT:  .Ltmp3: // Block address taken
; ELF-NEXT:  .LBB2_2: // %bb2
; ELF-NEXT:    mov w0, #2 // =0x2
; ELF-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
; ELF-NEXT:    ret
entry:
  %tmp0 = call ptr @dummy_choose(ptr blockaddress(@test_indirectbr_2, %bb1), ptr blockaddress(@test_indirectbr_2, %bb2))
  indirectbr ptr %tmp0, [label %bb1, label %bb2]

bb1:
  ret i32 1

bb2:
  ret i32 2
}

;; Check we don't interfere with jump-table BRIND lowering.

; MACHO-LABEL: test_jumptable:
; MACHO:        adrp x9, LJTI3_0@PAGE
; MACHO-NEXT:   add x9, x9, LJTI3_0@PAGEOFF
; MACHO-NEXT:   adr x10, LBB3_2
; MACHO-NEXT:   ldrb w11, [x9, x8]
; MACHO-NEXT:   add x10, x10, x11, lsl #2
; MACHO-NEXT:   br x10

; ELF-LABEL: test_jumptable:
; ELF:        adrp x9, .LJTI3_0
; ELF-NEXT:   add x9, x9, :lo12:.LJTI3_0
; ELF-NEXT:   adr x10, .LBB3_2
; ELF-NEXT:   ldrb w11, [x9, x8]
; ELF-NEXT:   add x10, x10, x11, lsl #2
; ELF-NEXT:   br x10
define i32 @test_jumptable(i32 %in) #0 {
  switch i32 %in, label %def [
    i32 0, label %lbl1
    i32 1, label %lbl2
  ]

def:
  ret i32 0

lbl1:
  ret i32 1

lbl2:
  ret i32 2
}

; MACHO-LABEL: .globl _test_indirectbr_array
; MACHO-NEXT:  .p2align 4
; MACHO-NEXT:  _test_indirectbr_array:
; MACHO-NEXT:   .quad Ltmp0@AUTH(ia,34947)
; MACHO-NEXT:   .quad Ltmp1@AUTH(ia,34947)
; MACHO-NEXT:   .quad Ltmp2@AUTH(ia,40224)
; MACHO-NEXT:   .quad Ltmp3@AUTH(ia,40224)

; ELF-LABEL: .globl test_indirectbr_array
; ELF-NEXT:  .p2align 4, 0x0
; ELF-NEXT:  test_indirectbr_array:
; ELF-NEXT:   .xword .Ltmp0@AUTH(ia,34947)
; ELF-NEXT:   .xword .Ltmp1@AUTH(ia,34947)
; ELF-NEXT:   .xword .Ltmp2@AUTH(ia,40224)
; ELF-NEXT:   .xword .Ltmp3@AUTH(ia,40224)
; ELF-NEXT:   .size test_indirectbr_array, 32

@test_indirectbr_array = constant [4 x ptr] [
  ptr blockaddress(@test_indirectbr, %bb1), ptr blockaddress(@test_indirectbr, %bb2),
  ptr blockaddress(@test_indirectbr_2, %bb1), ptr blockaddress(@test_indirectbr_2, %bb2)
]

declare ptr @dummy_choose(ptr, ptr)

attributes #0 = { "ptrauth-indirect-gotos" nounwind }
