// Test how BOLT handles indirect branch sequence of instructions in
// AArch64MCPlus builder.

// clang-format off

// REQUIRES: system-linux, asserts

// RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown -mattr=+pauth %s -o %t.o
// RUN: %clang %cflags --target=aarch64-unknown-linux %t.o -o %t.exe -Wl,-q
// RUN: llvm-bolt %t.exe -o %t.bolt --print-cfg --debug-only=mcplus -v=1 2>&1 \
// RUN:   | FileCheck %s

// Pattern 1: there is no shift amount after the 'add' instruction.
//
//   adr     x6, 0x219fb0 <sigall_set+0x88>
//   add     x6, x6, x14, lsl #2
//   ldr     w7, [x6]
//   add     x6, x6, w7, sxtw => no shift amount
//   br      x6
//

// Pattern 2: nop/adr pair is used in place of adrp/add
//
//  nop   => nop/adr instead of adrp/add
//  adr     x13, 0x215a18 <_nl_value_type_LC_COLLATE+0x50>
//  ldrh    w13, [x13, w12, uxtw #1]
//  adr     x12, 0x247b30 <__gettextparse+0x5b0>
//  add     x13, x12, w13, sxth #2
//  br      x13

  .section .text
  .align 4
  .globl _start
  .type  _start, %function
_start:
  bl      test1
  bl      test2
// mov x0, #4
// mov w8, #93
// svc #0

// Pattern 1
// CHECK: BOLT-DEBUG: failed to match indirect branch: ShiftVAL != 2
  .globl test1
  .type  test1, %function
test1:
  mov     x1, #0
  nop
  adr     x3, datatable
  add     x3, x3, x1, lsl #2
  ldr     w2, [x3]
  add     x3, x3, w2, sxtw
  br      x3
test1_0:
   ret
test1_1:
   ret
test1_2:
   ret
   .size test1, .-test1

// Temporary workaround for PC-relative relocations from datatable leaking into
// test2 function and creating phantom entry points.
.skip 0x100

// Pattern 2
// CHECK: BOLT-DEBUG: failed to match indirect branch: nop/adr instead of adrp/add
  .globl test2
  .type  test2, %function
test2:
  nop
  adr     x3, jump_table
  ldrh    w3, [x3, x1, lsl #1]
  nop
  adr     x1, test2_0
  add     x3, x1, w3, sxth #2
  br      x3
test2_0:
  ret
test2_1:
  ret

// Make sure BOLT does not crash trying to disassemble BRA* instructions.
  .globl test_braa
  .type  test_braa, %function
test_braa:
  braa x0, x1

  .globl test_brab
  .type  test_brab, %function
test_brab:
  brab x0, x1

  .globl test_braaz
  .type  test_braaz, %function
test_braaz:
  braaz x0

  .globl test_brabz
  .type  test_brabz, %function
test_brabz:
  brabz x0

  .section .rodata,"a",@progbits
datatable:
  .word test1_0-datatable
  .word test1_1-datatable
  .word test1_2-datatable

jump_table:
  .hword  (test2_0-test2_0)>>2
  .hword  (test2_1-test2_0)>>2
