llvm/llvm/test/CodeGen/AArch64/branch-relax-cross-section.mir

# RUN: llc -mtriple=aarch64-none-linux-gnu -run-pass branch-relaxation -aarch64-b-offset-bits=64 -aarch64-tbz-offset-bits=9 -aarch64-cbz-offset-bits=9 %s -o - | FileCheck %s
# RUN: llc -mtriple=aarch64-none-linux-gnu -run-pass branch-relaxation -aarch64-tbz-offset-bits=9 -aarch64-cbz-offset-bits=9 %s -o - | FileCheck --check-prefix=INDIRECT %s

--- |
  declare i32 @bar()
  declare i32 @baz()
  declare i32 @qux()
  
  define void @relax_tbz(i1 zeroext %0) {
    br i1 %0, label %false_block, label %true_block
  
  false_block:                                      ; preds = %1
    %2 = call i32 @baz()
    br label %end
  
  end:                                              ; preds = %true_block, %false_block
    %3 = tail call i32 @qux()
    ret void
  
  true_block:                                       ; preds = %1
    %4 = call i32 @bar()
    br label %end
  }

  define void @tbz_hot_to_cold(i1 zeroext %0) {
    br i1 %0, label %hot_block, label %cold_block
  
  hot_block:                                        ; preds = %1
    %2 = call i32 @baz()
    br label %end
  
  end:                                              ; preds = %cold_block, %hot_block
    %3 = tail call i32 @qux()
    ret void
  
  cold_block:                                       ; preds = %1
    %4 = call i32 @bar()
    br label %end
  }

  define void @tbz_no_valid_tramp(i1 zeroext %0) {
    br i1 %0, label %hot, label %cold
  
  hot:                                              ; preds = %1
    %2 = call i32 @baz()
    call void asm sideeffect ".space 1024", ""()
    br label %end
  
  end:                                              ; preds = %cold, %hot
    %3 = tail call i32 @qux()
    ret void
  
  cold:                                             ; preds = %1
    %4 = call i32 @bar()
    br label %end
  }

  define void @tbz_cold_to_hot(i1 zeroext %0) {
    br i1 %0, label %cold_block, label %hot_block
  
  cold_block:                                       ; preds = %1
    %2 = call i32 @baz()
    br label %end
  
  end:                                              ; preds = %hot_block, %cold_block
    %3 = tail call i32 @qux()
    ret void
  
  hot_block:                                        ; preds = %1
    %4 = call i32 @bar()
    br label %end
  }

  define void @tbz_tramp_pushed_oob(i1 zeroext %0, i1 zeroext %1) {
  entry:
    %x16 = call i64 asm sideeffect "mov x16, 1", "={x16}"()
    br i1 %0, label %unrelaxable, label %cold

  unrelaxable:                                      ; preds = %entry
    br i1 %1, label %end, label %cold

  end:                                              ; preds = %unrelaxable
    call void asm sideeffect ".space 996", ""()
    call void asm sideeffect "# reg use $0", "{x16}"(i64 %x16)
    ret void

  cold:                                            ; preds = %entry, %unrelaxable
    call void asm sideeffect "# reg use $0", "{x16}"(i64 %x16)
    ret void
  }


  define void @x16_used_cold_to_hot() {
  entry:
    %x16 = call i64 asm sideeffect "mov x16, 1", "={x16}"()
    %cmp = icmp eq i64 %x16, 0
    br i1 %cmp, label %hot, label %cold

  hot:                                            ; preds = %cold, %entry
    call void asm sideeffect "# reg use $0", "{x16}"(i64 %x16)
    ret void

  cold:                                           ; preds = %entry
    call void asm sideeffect ".space 4", ""()
    br label %hot
  }

  define void @all_used_cold_to_hot() {
  entry:
    %x0 = call i64 asm sideeffect "mov x0, 1", "={x0}"()
    %x1 = call i64 asm sideeffect "mov x1, 1", "={x1}"()
    %x2 = call i64 asm sideeffect "mov x2, 1", "={x2}"()
    %x3 = call i64 asm sideeffect "mov x3, 1", "={x3}"()
    %x4 = call i64 asm sideeffect "mov x4, 1", "={x4}"()
    %x5 = call i64 asm sideeffect "mov x5, 1", "={x5}"()
    %x6 = call i64 asm sideeffect "mov x6, 1", "={x6}"()
    %x7 = call i64 asm sideeffect "mov x7, 1", "={x7}"()
    %x8 = call i64 asm sideeffect "mov x8, 1", "={x8}"()
    %x9 = call i64 asm sideeffect "mov x9, 1", "={x9}"()
    %x10 = call i64 asm sideeffect "mov x10, 1", "={x10}"()
    %x11 = call i64 asm sideeffect "mov x11, 1", "={x11}"()
    %x12 = call i64 asm sideeffect "mov x12, 1", "={x12}"()
    %x13 = call i64 asm sideeffect "mov x13, 1", "={x13}"()
    %x14 = call i64 asm sideeffect "mov x14, 1", "={x14}"()
    %x15 = call i64 asm sideeffect "mov x15, 1", "={x15}"()
    %x17 = call i64 asm sideeffect "mov x17, 1", "={x17}"()
    %x18 = call i64 asm sideeffect "mov x18, 1", "={x18}"()
    %x19 = call i64 asm sideeffect "mov x19, 1", "={x19}"()
    %x20 = call i64 asm sideeffect "mov x20, 1", "={x20}"()
    %x21 = call i64 asm sideeffect "mov x21, 1", "={x21}"()
    %x22 = call i64 asm sideeffect "mov x22, 1", "={x22}"()
    %x23 = call i64 asm sideeffect "mov x23, 1", "={x23}"()
    %x24 = call i64 asm sideeffect "mov x24, 1", "={x24}"()
    %x25 = call i64 asm sideeffect "mov x25, 1", "={x25}"()
    %x26 = call i64 asm sideeffect "mov x26, 1", "={x26}"()
    %x27 = call i64 asm sideeffect "mov x27, 1", "={x27}"()
    %x28 = call i64 asm sideeffect "mov x28, 1", "={x28}"()
    br label %cold

  exit:                                             ; preds = %cold
    call void asm sideeffect "# reg use $0", "{x0}"(i64 %x0)
    call void asm sideeffect "# reg use $0", "{x1}"(i64 %x1)
    call void asm sideeffect "# reg use $0", "{x2}"(i64 %x2)
    call void asm sideeffect "# reg use $0", "{x3}"(i64 %x3)
    call void asm sideeffect "# reg use $0", "{x4}"(i64 %x4)
    call void asm sideeffect "# reg use $0", "{x5}"(i64 %x5)
    call void asm sideeffect "# reg use $0", "{x6}"(i64 %x6)
    call void asm sideeffect "# reg use $0", "{x7}"(i64 %x7)
    call void asm sideeffect "# reg use $0", "{x8}"(i64 %x8)
    call void asm sideeffect "# reg use $0", "{x9}"(i64 %x9)
    call void asm sideeffect "# reg use $0", "{x10}"(i64 %x10)
    call void asm sideeffect "# reg use $0", "{x11}"(i64 %x11)
    call void asm sideeffect "# reg use $0", "{x12}"(i64 %x12)
    call void asm sideeffect "# reg use $0", "{x13}"(i64 %x13)
    call void asm sideeffect "# reg use $0", "{x14}"(i64 %x14)
    call void asm sideeffect "# reg use $0", "{x15}"(i64 %x15)
    call void asm sideeffect "# reg use $0", "{x16}"(i64 %x16)
    call void asm sideeffect "# reg use $0", "{x17}"(i64 %x17)
    call void asm sideeffect "# reg use $0", "{x18}"(i64 %x18)
    call void asm sideeffect "# reg use $0", "{x19}"(i64 %x19)
    call void asm sideeffect "# reg use $0", "{x20}"(i64 %x20)
    call void asm sideeffect "# reg use $0", "{x21}"(i64 %x21)
    call void asm sideeffect "# reg use $0", "{x22}"(i64 %x22)
    call void asm sideeffect "# reg use $0", "{x23}"(i64 %x23)
    call void asm sideeffect "# reg use $0", "{x24}"(i64 %x24)
    call void asm sideeffect "# reg use $0", "{x25}"(i64 %x25)
    call void asm sideeffect "# reg use $0", "{x26}"(i64 %x26)
    call void asm sideeffect "# reg use $0", "{x27}"(i64 %x27)
    call void asm sideeffect "# reg use $0", "{x28}"(i64 %x28)
    ret void

  cold:                                             ; preds = %entry
    %x16 = call i64 asm sideeffect "mov x16, 1", "={x16}"()
    br label %exit
  }

...
---
name:            relax_tbz
tracksRegLiveness: true
liveins:
  - { reg: '$w0', virtual-reg: '' }
stack:
  - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16,
      stack-id: default, callee-saved-register: '$lr', callee-saved-restored: true,
      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
body:             |
  ; CHECK-LABEL: name: relax_tbz
  ; COM: Check that cross-section conditional branches are
  ; COM:   relaxed.
  ; CHECK: bb.0 (%ir-block.1, bbsections 1):
  ; CHECK-NEXT: successors: %bb.3
  ; CHECK:  TBNZW
  ; CHECK-SAME:   %bb.3
  ; CHECK:      B %bb.2
  ; CHECK-NEXT: {{  $}}
  ; CHECK-NEXT: bb.3 (%ir-block.1, bbsections 1):
  ; CHECK-NEXT: successors: %bb.1
  ; CHECK-NEXT: {{  $}}
  ; CHECK-NEXT:    B %bb.1
  ; CHECK-NEXT: {{  $}}
  ; CHECK-NEXT:  bb.1.false_block (bbsections 2):
  ; CHECK:    TCRETURNdi @qux, 0, csr_aarch64_aapcs, implicit $sp
  ; CHECK-NEXT: {{  $}}
  ; CHECK-NEXT:  bb.2.true_block (bbsections 3):
  ; CHECK:    TCRETURNdi @qux, 0, csr_aarch64_aapcs, implicit $sp
  bb.0 (%ir-block.1, bbsections 1):
    successors: %bb.1, %bb.2
    liveins: $w0, $lr

    early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store (s64) into %stack.0)
    TBZW killed renamable $w0, 0, %bb.2
    B %bb.1

  bb.1.false_block (bbsections 2):
    BL @baz, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $w0
    early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
    TCRETURNdi @qux, 0, csr_aarch64_aapcs, implicit $sp

  bb.2.true_block (bbsections 3):
    BL @bar, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $w0
    early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
    TCRETURNdi @qux, 0, csr_aarch64_aapcs, implicit $sp
...
---
name:            tbz_hot_to_cold
tracksRegLiveness: true
liveins:
  - { reg: '$w0', virtual-reg: '' }
stack:
  - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16,
      stack-id: default, callee-saved-register: '$lr', callee-saved-restored: true,
      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
body:             |
  ; CHECK-LABEL: name: tbz_hot_to_cold
  ; COM: Check that branch relaxation relaxes cross-section conditional
  ; COM:   branches by creating trampolines after all other hot basic blocks.
  ; CHECK: bb.0 (%ir-block.1):
  ; CHECK-NEXT: successors: %bb.1
  ; CHECK-SAME:                  , %bb.3
  ; CHECK:  TBZW
  ; CHECK-SAME: %bb.3
  ; CHECK:  bb.1.hot_block:
  ; CHECK:    TCRETURNdi @qux, 0, csr_aarch64_aapcs, implicit $sp
  ; CHECK:  bb.3 (%ir-block.1):
  ; CHECK-NEXT:    successors: %bb.2
  ; CHECK-NEXT: {{  $}}
  ; CHECK-NEXT:    B %bb.2
  ; CHECK-NEXT: {{  $}}
  ; CHECK-NEXT:  bb.2.cold_block (bbsections Cold):
  ; CHECK:    TCRETURNdi @qux, 0, csr_aarch64_aapcs, implicit $sp
  bb.0 (%ir-block.1):
    successors: %bb.1, %bb.2
    liveins: $w0, $lr

    early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store (s64) into %stack.0)
    TBZW killed renamable $w0, 0, %bb.2

  bb.1.hot_block:
    BL @baz, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $w0
    early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
    TCRETURNdi @qux, 0, csr_aarch64_aapcs, implicit $sp

  bb.2.cold_block (bbsections Cold):
    BL @bar, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $w0
    early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
    TCRETURNdi @qux, 0, csr_aarch64_aapcs, implicit $sp

...
---
name:            tbz_no_valid_tramp
tracksRegLiveness: true
liveins:
  - { reg: '$w0', virtual-reg: '' }
stack:
  - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16, 
      stack-id: default, callee-saved-register: '$lr', callee-saved-restored: true, 
      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
machineFunctionInfo:
  hasRedZone:      false
body:             |
  ; CHECK-LABEL: name: tbz_no_valid_tramp
  ; COM: Check that branch relaxation doesn't insert a trampoline if there is no
  ; COM:   viable insertion location.
  ; CHECK:    bb.0 (%ir-block.1):
  ; CHECK-NEXT:    successors: %bb.1
  ; CHECK-SAME:                     , %bb.3
  ; CHECK:    CBNZW
  ; CHECK-SAME:    %bb.1
  ; CHECK-NEXT: B
  ; CHECK-SAME:   %bb.3
  ; CHECK:  bb.1.hot:
  ; CHECK:    TCRETURNdi
  ; CHECK:  bb.2.cold (bbsections Cold):
  ; CHECK:    TCRETURNdi
  bb.0 (%ir-block.1):
    successors: %bb.1, %bb.2
    liveins: $w0, $lr
  
    early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store (s64) into %stack.0)
    CBZW killed renamable $w0, %bb.2
  
  bb.1.hot:
    BL @baz, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $w0
    INLINEASM &".space 1024", 1 /* sideeffect attdialect */
    early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
    TCRETURNdi @qux, 0, csr_aarch64_aapcs, implicit $sp
  
  bb.2.cold (bbsections Cold):
    BL @bar, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $w0
    early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
    TCRETURNdi @qux, 0, csr_aarch64_aapcs, implicit $sp

...
---
name:            tbz_cold_to_hot
tracksRegLiveness: true
liveins:
  - { reg: '$w0', virtual-reg: '' }
stack:
  - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16, 
      stack-id: default, callee-saved-register: '$lr', callee-saved-restored: true, 
      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
machineFunctionInfo:
  hasRedZone:      false
body:             |
  ; CHECK-LABEL: name: tbz_cold_to_hot
  ; COM: Check that relaxation of conditional branches from the Cold section to
  ; COM:   the Hot section doesn't modify the Hot section.
  ; CHECK:  bb.0 (%ir-block.1, bbsections Cold):
  ; CHECK-NEXT:    successors: %bb.1
  ; CHECK-SAME:                     , %bb.2
  ; CHECK:    CBNZW
  ; CHECK-SAME:     %bb.1
  ; CHECK-NEXT:    B %bb.2
  ; CHECK:  bb.1.cold_block (bbsections Cold):
  ; CHECK:    TCRETURNdi
  ; CHECK:  bb.2.hot_block:
  ; CHECK:    TCRETURNdi
  bb.0 (%ir-block.1, bbsections Cold):
    successors: %bb.1, %bb.2
    liveins: $w0, $lr
  
    early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store (s64) into %stack.0)
    CBZW killed renamable $w0, %bb.2
  
  bb.1.cold_block (bbsections Cold):
    BL @baz, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $w0
    early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
    TCRETURNdi @qux, 0, csr_aarch64_aapcs, implicit $sp
  
  bb.2.hot_block:
    BL @bar, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $w0
    early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
    TCRETURNdi @qux, 0, csr_aarch64_aapcs, implicit $sp

...
---
name:            tbz_tramp_pushed_oob
tracksRegLiveness: true
liveins:
  - { reg: '$w0', virtual-reg: '' }
  - { reg: '$w1', virtual-reg: '' }
stack:
  - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16,
      stack-id: default, callee-saved-register: '$lr', callee-saved-restored: true,
      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
machineFunctionInfo:
  hasRedZone:      false
body:             |
  ; INDIRECT-LABEL: name: tbz_tramp_pushed_oob
  ; COM: Check that a conditional branch to a trampoline is properly relaxed
  ; COM:   if the trampoline is pushed out of range.
  ; INDIRECT:      bb.0.entry:
  ; INDIRECT-NEXT:   successors: %bb.1
  ; INDIRECT-SAME:                    , %[[TRAMP1:bb.[0-9]+]]
  ; INDIRECT:        TBNZW
  ; INDIRECT-SAME:         %bb.1
  ; INDIRECT-NEXT:    B{{ }}
  ; INDIRECT-SAME:           %[[TRAMP1]]
  ; INDIRECT:      bb.1.unrelaxable:
  ; INDIRECT-NEXT:   successors: %bb.2
  ; INDIRECT-SAME:                    , %[[TRAMP2:bb.[0-9]+]]
  ; INDIRECT:        TBNZW
  ; INDIRECT-SAME:         %bb.2
  ; INDIRECT:      [[TRAMP2]]
  ; INDIRECT-NEXT:   successors: %bb.6
  ; INDIRECT:      bb.2.end:
  ; INDIRECT:        TCRETURNdi
  ; INDIRECT:      [[TRAMP1]].entry:
  ; INDIRECT-NEXT:   successors: %[[TRAMP1_SPILL:bb.[0-9]+]]
  ; INDIRECT:      [[TRAMP1_SPILL]].entry:
  ; INDIRECT-NEXT:   successors: %[[TRAMP1_RESTORE:bb.[0-9]+]]
  ; INDIRECT:        early-clobber $sp = STRXpre $[[SPILL_REGISTER:x[0-9]+]], $sp, -16
  ; INDIRECT-NEXT:   B %[[TRAMP1_RESTORE:bb.[0-9]+]]
  ; INDIRECT:      [[TRAMP1_RESTORE]].cold (bbsections Cold):
  ; INDIRECT-NEXT:   successors: %bb.3
  ; INDIRECT-NEXT:   {{ $}}
  ; INDIRECT-NEXT:   early-clobber $sp, $[[SPILL_REGISTER]] = LDRXpost $sp, 16
  ; INDIRECT:      bb.3.cold (bbsections Cold):
  ; INDIRECT:        TCRETURNdi

  bb.0.entry (%ir-block.entry):
    successors: %bb.1, %bb.3
    liveins: $w0, $w1, $lr

    early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store (s64) into %stack.0)
    INLINEASM &"mov x16, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x16
    TBZW killed renamable $w0, 0, %bb.3

  bb.1.unrelaxable:
    successors: %bb.2, %bb.3
    liveins: $w1, $x16

    TBNZW killed renamable $w1, 0, %bb.2

    B %bb.3

  bb.2.end:
    liveins: $x16

    INLINEASM &".space 996", 1 /* sideeffect attdialect */
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x16
    early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
    TCRETURNdi @qux, 0, csr_aarch64_aapcs, implicit $sp
  
  bb.3.cold (bbsections Cold):
    liveins: $x16

    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x16
    early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
    TCRETURNdi @qux, 0, csr_aarch64_aapcs, implicit $sp

...

name:            x16_used_cold_to_hot
tracksRegLiveness: true
liveins:         []
machineFunctionInfo:
  hasRedZone:      false
body:             |
  ; INDIRECT-LABEL: name: x16_used_cold_to_hot
  ; COM: Check that unconditional branches from the cold section to
  ; COM: the hot section manually insert indirect branches if x16
  ; COM: isn't available but there is still a free register.
  ; INDIRECT:       bb.0.entry:
  ; INDIRECT-NEXT:    successors: %bb.1
  ; INDIRECT-SAME:                     , %bb.3
  ; INDIRECT:         TBZW killed renamable $w8, 0, %bb.1
  ; INDIRECT-NEXT:    {{ $}}
  ; INDIRECT-NEXT:  bb.3.entry:
  ; INDIRECT-NEXT:    successors: %bb.4
  ; INDIRECT-NEXT:    liveins: $x16
  ; INDIRECT-NEXT:    {{ $}}
  ; INDIRECT-NEXT:    early-clobber $sp = STRXpre $[[SPILL_REGISTER]], $sp, -16
  ; INDIRECT-NEXT:    B %bb.4
  ; INDIRECT:       bb.1.hot:
  ; INDIRECT-NEXT:    liveins: $x16
  ; INDIRECT:           killed $x16
  ; INDIRECT:         RET undef $lr
  ; INDIRECT:       bb.4.cold (bbsections Cold):
  ; INDIRECT-NEXT:    successors: %bb.2
  ; INDIRECT-NEXT:    {{ $}}
  ; INDIRECT-NEXT:    early-clobber $sp, $[[SPILL_REGISTER]] = LDRXpost $sp, 16
  ; INDIRECT-NEXT:    {{ $}}
  ; INDIRECT-NEXT:  bb.2.cold (bbsections Cold):
  ; INDIRECT-NEXT:    successors: %bb.5
  ; INDIRECT-NEXT:    liveins: $x16
  ; INDIRECT-NEXT:    {{ $}}
  ; INDIRECT-NEXT:    INLINEASM &".space 4", 1 /* sideeffect attdialect */
  ; INDIRECT-NEXT:    {{ $}}
  ; INDIRECT-NEXT:  bb.5.cold (bbsections Cold):
  ; INDIRECT-NEXT:    successors: %bb.1
  ; INDIRECT-NEXT:    liveins: $x16
  ; INDIRECT-NEXT:    {{ $}}
  ; INDIRECT-NEXT:    $[[SCAVENGED_REGISTER:x[0-9]+]] = ADRP target-flags(aarch64-page) <mcsymbol >
  ; INDIRECT-NEXT:    $[[SCAVENGED_REGISTER]] = ADDXri $[[SCAVENGED_REGISTER]], target-flags(aarch64-pageoff, aarch64-nc) <mcsymbol >, 0
  ; INDIRECT-NEXT:    BR $[[SCAVENGED_REGISTER]]

  bb.0.entry:
    successors: %bb.1, %bb.2

    $sp = frame-setup SUBXri $sp, 16, 0
    INLINEASM &"mov x16, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x16
    dead renamable $x8 = SUBSXri $x16, 0, 0, implicit-def $nzcv
    renamable $w8 = CSINCWr $wzr, $wzr, 1, implicit killed $nzcv
    TBZW killed renamable $w8, 0, %bb.1

    B %bb.2

  bb.1.hot:
    liveins: $x16

    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x16
    $sp = frame-destroy ADDXri $sp, 16, 0
    RET undef $lr

  bb.2.cold (bbsections Cold):
    successors: %bb.1
    liveins: $x16

    INLINEASM &".space 4", 1 /* sideeffect attdialect */
    B %bb.1
...
---
name:            all_used_cold_to_hot
tracksRegLiveness: true
stack:
  - { id: 0, name: '', type: spill-slot, offset: -8, size: 8, alignment: 8, 
      stack-id: default, callee-saved-register: '$x19', callee-saved-restored: true, 
      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
  - { id: 1, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8, 
      stack-id: default, callee-saved-register: '$x20', callee-saved-restored: true, 
      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
  - { id: 2, name: '', type: spill-slot, offset: -24, size: 8, alignment: 8, 
      stack-id: default, callee-saved-register: '$x21', callee-saved-restored: true, 
      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
  - { id: 3, name: '', type: spill-slot, offset: -32, size: 8, alignment: 8, 
      stack-id: default, callee-saved-register: '$x22', callee-saved-restored: true, 
      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
  - { id: 4, name: '', type: spill-slot, offset: -40, size: 8, alignment: 8, 
      stack-id: default, callee-saved-register: '$x23', callee-saved-restored: true, 
      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
  - { id: 5, name: '', type: spill-slot, offset: -48, size: 8, alignment: 8, 
      stack-id: default, callee-saved-register: '$x24', callee-saved-restored: true, 
      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
  - { id: 6, name: '', type: spill-slot, offset: -56, size: 8, alignment: 8, 
      stack-id: default, callee-saved-register: '$x25', callee-saved-restored: true, 
      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
  - { id: 7, name: '', type: spill-slot, offset: -64, size: 8, alignment: 8, 
      stack-id: default, callee-saved-register: '$x26', callee-saved-restored: true, 
      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
  - { id: 8, name: '', type: spill-slot, offset: -72, size: 8, alignment: 8, 
      stack-id: default, callee-saved-register: '$x27', callee-saved-restored: true, 
      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
  - { id: 9, name: '', type: spill-slot, offset: -80, size: 8, alignment: 8, 
      stack-id: default, callee-saved-register: '$x28', callee-saved-restored: true, 
      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
  - { id: 10, name: '', type: spill-slot, offset: -96, size: 8, alignment: 16, 
      stack-id: default, callee-saved-register: '$fp', callee-saved-restored: true, 
      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
machineFunctionInfo:
  hasRedZone:      false
body:             |
  ; INDIRECT-LABEL: name: all_used_cold_to_hot
  ; COM: Check that unconditional branches from the cold section to
  ; COM: the hot section spill x16 and defer indirect branch
  ; COM: insertion to the linker if there are no free general-purpose
  ; COM: registers.
  ; INDIRECT:      bb.0.entry:
  ; INDIRECT-NEXT:     successors: %bb.3
  ; INDIRECT-NEXT:     liveins: $fp, $x27, $x28, $x25, $x26, $x23, $x24, $x21, $x22, $x19, $x20
  ; INDIRECT-COUNT-29: INLINEASM &"mov
  ; INDIRECT-NEXT:     {{ $}}
  ; INDIRECT:      bb.3.entry:
  ; INDIRECT-NEXT:     successors: %bb.2
  ; INDIRECT-NEXT:     liveins: $fp,  $x0,  $x1,  $x2,  $x3,  $x4,  $x5,  $x6,  $x7,  $x8,
  ; INDIRECT-SAME:              $x9,  $x10, $x11, $x12, $x13, $x14, $x15, $x17, $x18, $x19,
  ; INDIRECT-SAME:              $x20, $x21, $x22, $x23, $x24, $x25, $x26, $x27, $x28
  ; INDIRECT-NEXT:     {{ $}}
  ; INDIRECT-NEXT:     B %bb.2
  ; INDIRECT-NEXT:     {{ $}}
  ; INDIRECT-NEXT:   bb.1.exit:
  ; INDIRECT-NEXT:     liveins: $x0,  $x1,  $x2,  $x3,  $x4,  $x5,  $x6,  $x7,  $x8,  $x9,
  ; INDIRECT-SAME:              $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17, $x18, $x19,
  ; INDIRECT-SAME:              $x20, $x21, $x22, $x23, $x24, $x25, $x26, $x27, $x28, $fp
  ; INDIRECT-NEXT:     {{ $}}
  ; INDIRECT-COUNT-30: INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed
  ; INDIRECT:          RET undef $lr
  ; INDIRECT-NEXT:     {{ $}}
  ; INDIRECT-NEXT:   bb.6.exit:
  ; INDIRECT-NEXT:     successors: %bb.7(0x80000000)
  ; INDIRECT-NEXT:     {{ $}}
  ; INDIRECT-NEXT:     early-clobber $sp, $[[SPILL_REGISTER]] = LDRXpost $sp, 16
  ; INDIRECT-NEXT:     {{ $}}
  ; INDIRECT-NEXT:   bb.7.exit:
  ; INDIRECT-NEXT:     successors: %bb.1(0x80000000)
  ; INDIRECT-NEXT:     {{ $}}
  ; INDIRECT-NEXT:     B %bb.1
  ; INDIRECT-NEXT:     {{ $}}
  ; INDIRECT-NEXT:   bb.2.cold (bbsections Cold):
  ; INDIRECT-NEXT:     successors: %bb.5
  ; INDIRECT-NEXT:     liveins: $x0,  $x1,  $x2,  $x3,  $x4,  $x5,  $x6,  $x7,  $x8,  $x9,
  ; INDIRECT-SAME:              $x10, $x11, $x12, $x13, $x14, $x15, $x17, $x18, $x19, $x20,
  ; INDIRECT-SAME:              $x21, $x22, $x23, $x24, $x25, $x26, $x27, $x28, $fp
  ; INDIRECT-NEXT:     {{ $}}
  ; INDIRECT-NEXT:     INLINEASM &"mov x16, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x16
  ; INDIRECT-NEXT:     {{ $}}
  ; INDIRECT-NEXT:   bb.5.cold (bbsections Cold):
  ; INDIRECT-NEXT:     successors: %bb.6
  ; INDIRECT-NEXT:     liveins: $fp,  $x0,  $x1,  $x2,  $x3,  $x4,  $x5,  $x6,  $x7,  $x8,
  ; INDIRECT-SAME:              $x9,  $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17, $x18,
  ; INDIRECT-SAME:              $x19, $x20, $x21, $x22, $x23, $x24, $x25, $x26, $x27, $x28
  ; INDIRECT-NEXT:     {{ $}}
  ; INDIRECT-NEXT:     early-clobber $sp = STRXpre $[[SPILL_REGISTER]], $sp, -16
  ; INDIRECT-NEXT:     B %bb.6

  bb.0.entry:
    successors: %bb.2
    liveins: $fp, $x27, $x28, $x25, $x26, $x23, $x24, $x21, $x22, $x19, $x20

    $sp = frame-setup SUBXri $sp, 112, 0
    frame-setup STRXui killed $fp, $sp, 2 :: (store (s64) into %stack.10)
    frame-setup STPXi killed $x28, killed $x27, $sp, 4 :: (store (s64) into %stack.9), (store (s64) into %stack.8)
    frame-setup STPXi killed $x26, killed $x25, $sp, 6 :: (store (s64) into %stack.7), (store (s64) into %stack.6)
    frame-setup STPXi killed $x24, killed $x23, $sp, 8 :: (store (s64) into %stack.5), (store (s64) into %stack.4)
    frame-setup STPXi killed $x22, killed $x21, $sp, 10 :: (store (s64) into %stack.3), (store (s64) into %stack.2)
    frame-setup STPXi killed $x20, killed $x19, $sp, 12 :: (store (s64) into %stack.1), (store (s64) into %stack.0)
    INLINEASM &"mov x0, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x0
    INLINEASM &"mov x1, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x1
    INLINEASM &"mov x2, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x2
    INLINEASM &"mov x3, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x3
    INLINEASM &"mov x4, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x4
    INLINEASM &"mov x5, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x5
    INLINEASM &"mov x6, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x6
    INLINEASM &"mov x7, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x7
    INLINEASM &"mov x8, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x8
    INLINEASM &"mov x9, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x9
    INLINEASM &"mov x10, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x10
    INLINEASM &"mov x11, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x11
    INLINEASM &"mov x12, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x12
    INLINEASM &"mov x13, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x13
    INLINEASM &"mov x14, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x14
    INLINEASM &"mov x15, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x15
    INLINEASM &"mov x17, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x17
    INLINEASM &"mov x18, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x18
    INLINEASM &"mov x19, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x19
    INLINEASM &"mov x20, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x20
    INLINEASM &"mov x21, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x21
    INLINEASM &"mov x22, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x22
    INLINEASM &"mov x23, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x23
    INLINEASM &"mov x24, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x24
    INLINEASM &"mov x25, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x25
    INLINEASM &"mov x26, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x26
    INLINEASM &"mov x27, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x27
    INLINEASM &"mov x28, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x28
    INLINEASM &"mov fp, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $fp
    B %bb.2


  bb.1.exit:
    liveins: $x0, $x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17, $x18, $x19, $x20, $x21, $x22, $x23, $x24, $x25, $x26, $x27, $x28, $fp

    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x0
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x1
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x2
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x3
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x4
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x5
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x6
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x7
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x8
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x9
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x10
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x11
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x12
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x13
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x14
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x15
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x16
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x17
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x18
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x19
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x20
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x21
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x22
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x23
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x24
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x25
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x26
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x27
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $x28
    INLINEASM &"# reg use $0", 1 /* sideeffect attdialect */, 9 /* reguse */, killed $fp
    $x20, $x19 = frame-destroy LDPXi $sp, 12 :: (load (s64) from %stack.1), (load (s64) from %stack.0)
    $x22, $x21 = frame-destroy LDPXi $sp, 10 :: (load (s64) from %stack.3), (load (s64) from %stack.2)
    $x24, $x23 = frame-destroy LDPXi $sp, 8 :: (load (s64) from %stack.5), (load (s64) from %stack.4)
    $x26, $x25 = frame-destroy LDPXi $sp, 6 :: (load (s64) from %stack.7), (load (s64) from %stack.6)
    $x28, $x27 = frame-destroy LDPXi $sp, 4 :: (load (s64) from %stack.9), (load (s64) from %stack.8)
    $fp = frame-destroy LDRXui $sp, 2 :: (load (s64) from %stack.10)
    $sp = frame-destroy ADDXri $sp, 112, 0
    RET undef $lr

  bb.2.cold (bbsections Cold):
    successors: %bb.1
    liveins: $x0, $x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15, $x17, $x18, $x19, $x20, $x21, $x22, $x23, $x24, $x25, $x26, $x27, $x28, $fp

    INLINEASM &"mov x16, 1", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x16
    B %bb.1

...