llvm/llvm/test/Transforms/FunctionAttrs/cold.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals --version 2
; RUN: opt -passes=function-attrs -S < %s | FileCheck --check-prefixes=COMMON,FNATTRS %s
; RUN: opt -passes=attributor-light -S < %s | FileCheck --check-prefixes=COMMON,ATTRIBUTOR %s

declare i32 @get_val()

declare void @cold0() cold
declare void @cold1() cold
declare void @cold_at_cb()

declare void @not_cold0()
declare void @not_cold1()
declare void @not_cold2()

define void @test_no_exit_fail() {
; COMMON: Function Attrs: nofree norecurse noreturn nosync nounwind memory(none)
; COMMON-LABEL: define void @test_no_exit_fail
; COMMON-SAME: () #[[ATTR1:[0-9]+]] {
; COMMON-NEXT:  entry:
; COMMON-NEXT:    br label [[WHILE_BODY:%.*]]
; COMMON:       while.body:
; COMMON-NEXT:    br label [[WHILE_BODY]]
;
entry:
  br label %while.body

while.body:
  br label %while.body
}

define void @test_no_exit_fail2() {
; COMMON: Function Attrs: noreturn
; COMMON-LABEL: define void @test_no_exit_fail2
; COMMON-SAME: () #[[ATTR2:[0-9]+]] {
; COMMON-NEXT:  entry:
; COMMON-NEXT:    br label [[WHILE_BODY:%.*]]
; COMMON:       while.body:
; COMMON-NEXT:    call void @not_cold0()
; COMMON-NEXT:    br label [[WHILE_BODY2:%.*]]
; COMMON:       while.body2:
; COMMON-NEXT:    call void @not_cold1()
; COMMON-NEXT:    br label [[WHILE_BODY]]
;
entry:
  br label %while.body

while.body:
  call void @not_cold0()
  br label %while.body2

while.body2:
  call void @not_cold1()
  br label %while.body
}

define void @test_no_exit() {
; FNATTRS: Function Attrs: cold noreturn
; FNATTRS-LABEL: define void @test_no_exit
; FNATTRS-SAME: () #[[ATTR3:[0-9]+]] {
; FNATTRS-NEXT:  entry:
; FNATTRS-NEXT:    br label [[WHILE_BODY:%.*]]
; FNATTRS:       while.body:
; FNATTRS-NEXT:    call void @cold0()
; FNATTRS-NEXT:    br label [[WHILE_BODY]]
;
; ATTRIBUTOR: Function Attrs: noreturn
; ATTRIBUTOR-LABEL: define void @test_no_exit
; ATTRIBUTOR-SAME: () #[[ATTR2]] {
; ATTRIBUTOR-NEXT:  entry:
; ATTRIBUTOR-NEXT:    br label [[WHILE_BODY:%.*]]
; ATTRIBUTOR:       while.body:
; ATTRIBUTOR-NEXT:    call void @cold0()
; ATTRIBUTOR-NEXT:    br label [[WHILE_BODY]]
;
entry:
  br label %while.body

while.body:
  call void @cold0()
  br label %while.body
}

define void @test_no_exit2() {
; FNATTRS: Function Attrs: cold noreturn
; FNATTRS-LABEL: define void @test_no_exit2
; FNATTRS-SAME: () #[[ATTR3]] {
; FNATTRS-NEXT:  entry:
; FNATTRS-NEXT:    br label [[WHILE_BODY:%.*]]
; FNATTRS:       while.body:
; FNATTRS-NEXT:    call void @not_cold0()
; FNATTRS-NEXT:    br label [[WHILE_BODY2:%.*]]
; FNATTRS:       while.body2:
; FNATTRS-NEXT:    call void @cold1()
; FNATTRS-NEXT:    br label [[WHILE_BODY]]
;
; ATTRIBUTOR: Function Attrs: noreturn
; ATTRIBUTOR-LABEL: define void @test_no_exit2
; ATTRIBUTOR-SAME: () #[[ATTR2]] {
; ATTRIBUTOR-NEXT:  entry:
; ATTRIBUTOR-NEXT:    br label [[WHILE_BODY:%.*]]
; ATTRIBUTOR:       while.body:
; ATTRIBUTOR-NEXT:    call void @not_cold0()
; ATTRIBUTOR-NEXT:    br label [[WHILE_BODY2:%.*]]
; ATTRIBUTOR:       while.body2:
; ATTRIBUTOR-NEXT:    call void @cold1()
; ATTRIBUTOR-NEXT:    br label [[WHILE_BODY]]
;
entry:
  br label %while.body

while.body:
  call void @not_cold0()
  br label %while.body2

while.body2:
  call void @cold1()
  br label %while.body
}

define dso_local void @test_entry(i32 noundef %x) {
; FNATTRS: Function Attrs: cold
; FNATTRS-LABEL: define dso_local void @test_entry
; FNATTRS-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] {
; FNATTRS-NEXT:  entry:
; FNATTRS-NEXT:    tail call void @cold0()
; FNATTRS-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[X]], 0
; FNATTRS-NEXT:    br i1 [[TOBOOL_NOT]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
; FNATTRS:       if.then:
; FNATTRS-NEXT:    tail call void @not_cold0()
; FNATTRS-NEXT:    br label [[IF_END]]
; FNATTRS:       if.end:
; FNATTRS-NEXT:    tail call void @not_cold1()
; FNATTRS-NEXT:    ret void
;
; ATTRIBUTOR-LABEL: define dso_local void @test_entry
; ATTRIBUTOR-SAME: (i32 noundef [[X:%.*]]) {
; ATTRIBUTOR-NEXT:  entry:
; ATTRIBUTOR-NEXT:    tail call void @cold0()
; ATTRIBUTOR-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[X]], 0
; ATTRIBUTOR-NEXT:    br i1 [[TOBOOL_NOT]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
; ATTRIBUTOR:       if.then:
; ATTRIBUTOR-NEXT:    tail call void @not_cold0()
; ATTRIBUTOR-NEXT:    br label [[IF_END]]
; ATTRIBUTOR:       if.end:
; ATTRIBUTOR-NEXT:    tail call void @not_cold1()
; ATTRIBUTOR-NEXT:    ret void
;
entry:
  tail call void @cold0()
  %tobool.not = icmp eq i32 %x, 0
  br i1 %tobool.not, label %if.end, label %if.then

if.then:
  tail call void @not_cold0()
  br label %if.end

if.end:
  tail call void @not_cold1()
  ret void
}

define dso_local void @test_hot_fail(i32 noundef %x) hot {
; FNATTRS: Function Attrs: hot
; FNATTRS-LABEL: define dso_local void @test_hot_fail
; FNATTRS-SAME: (i32 noundef [[X:%.*]]) #[[ATTR4:[0-9]+]] {
; FNATTRS-NEXT:  entry:
; FNATTRS-NEXT:    tail call void @cold0()
; FNATTRS-NEXT:    ret void
;
; ATTRIBUTOR: Function Attrs: hot
; ATTRIBUTOR-LABEL: define dso_local void @test_hot_fail
; ATTRIBUTOR-SAME: (i32 noundef [[X:%.*]]) #[[ATTR3:[0-9]+]] {
; ATTRIBUTOR-NEXT:  entry:
; ATTRIBUTOR-NEXT:    tail call void @cold0()
; ATTRIBUTOR-NEXT:    ret void
;
entry:
  tail call void @cold0()
  ret void
}

define dso_local void @test_br2(i32 noundef %x) {
; FNATTRS: Function Attrs: cold
; FNATTRS-LABEL: define dso_local void @test_br2
; FNATTRS-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0]] {
; FNATTRS-NEXT:  entry:
; FNATTRS-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[X]], 0
; FNATTRS-NEXT:    br i1 [[TOBOOL_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
; FNATTRS:       if.then:
; FNATTRS-NEXT:    tail call void @cold0()
; FNATTRS-NEXT:    br label [[IF_END:%.*]]
; FNATTRS:       if.else:
; FNATTRS-NEXT:    tail call void @cold1()
; FNATTRS-NEXT:    br label [[IF_END]]
; FNATTRS:       if.end:
; FNATTRS-NEXT:    ret void
;
; ATTRIBUTOR-LABEL: define dso_local void @test_br2
; ATTRIBUTOR-SAME: (i32 noundef [[X:%.*]]) {
; ATTRIBUTOR-NEXT:  entry:
; ATTRIBUTOR-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[X]], 0
; ATTRIBUTOR-NEXT:    br i1 [[TOBOOL_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
; ATTRIBUTOR:       if.then:
; ATTRIBUTOR-NEXT:    tail call void @cold0()
; ATTRIBUTOR-NEXT:    br label [[IF_END:%.*]]
; ATTRIBUTOR:       if.else:
; ATTRIBUTOR-NEXT:    tail call void @cold1()
; ATTRIBUTOR-NEXT:    br label [[IF_END]]
; ATTRIBUTOR:       if.end:
; ATTRIBUTOR-NEXT:    ret void
;
entry:
  %tobool.not = icmp eq i32 %x, 0
  br i1 %tobool.not, label %if.else, label %if.then

if.then:
  tail call void @cold0()
  br label %if.end

if.else:
  tail call void @cold1()
  br label %if.end

if.end:
  ret void
}

define dso_local void @test_exit(i32 noundef %x) {
; FNATTRS: Function Attrs: cold
; FNATTRS-LABEL: define dso_local void @test_exit
; FNATTRS-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0]] {
; FNATTRS-NEXT:  entry:
; FNATTRS-NEXT:    tail call void @not_cold0()
; FNATTRS-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[X]], 0
; FNATTRS-NEXT:    br i1 [[TOBOOL_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
; FNATTRS:       if.then:
; FNATTRS-NEXT:    tail call void @not_cold1()
; FNATTRS-NEXT:    br label [[IF_END:%.*]]
; FNATTRS:       if.else:
; FNATTRS-NEXT:    tail call void @not_cold2()
; FNATTRS-NEXT:    br label [[IF_END]]
; FNATTRS:       if.end:
; FNATTRS-NEXT:    tail call void @cold0()
; FNATTRS-NEXT:    ret void
;
; ATTRIBUTOR-LABEL: define dso_local void @test_exit
; ATTRIBUTOR-SAME: (i32 noundef [[X:%.*]]) {
; ATTRIBUTOR-NEXT:  entry:
; ATTRIBUTOR-NEXT:    tail call void @not_cold0()
; ATTRIBUTOR-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[X]], 0
; ATTRIBUTOR-NEXT:    br i1 [[TOBOOL_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
; ATTRIBUTOR:       if.then:
; ATTRIBUTOR-NEXT:    tail call void @not_cold1()
; ATTRIBUTOR-NEXT:    br label [[IF_END:%.*]]
; ATTRIBUTOR:       if.else:
; ATTRIBUTOR-NEXT:    tail call void @not_cold2()
; ATTRIBUTOR-NEXT:    br label [[IF_END]]
; ATTRIBUTOR:       if.end:
; ATTRIBUTOR-NEXT:    tail call void @cold0()
; ATTRIBUTOR-NEXT:    ret void
;
entry:
  tail call void @not_cold0()
  %tobool.not = icmp eq i32 %x, 0
  br i1 %tobool.not, label %if.else, label %if.then

if.then:
  tail call void @not_cold1()
  br label %if.end

if.else:
  tail call void @not_cold2()
  br label %if.end

if.end:
  tail call void @cold0()
  ret void
}

define dso_local void @test_complex(i32 noundef %x) {
; FNATTRS: Function Attrs: cold
; FNATTRS-LABEL: define dso_local void @test_complex
; FNATTRS-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0]] {
; FNATTRS-NEXT:  entry:
; FNATTRS-NEXT:    tail call void @not_cold0()
; FNATTRS-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[X]], 0
; FNATTRS-NEXT:    br i1 [[TOBOOL_NOT]], label [[IF_ELSE11:%.*]], label [[IF_THEN:%.*]]
; FNATTRS:       if.then:
; FNATTRS-NEXT:    [[CALL:%.*]] = tail call i32 @get_val()
; FNATTRS-NEXT:    [[TOBOOL1_NOT:%.*]] = icmp eq i32 [[CALL]], 0
; FNATTRS-NEXT:    br i1 [[TOBOOL1_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]
; FNATTRS:       if.then2:
; FNATTRS-NEXT:    tail call void @cold1()
; FNATTRS-NEXT:    br label [[IF_END12:%.*]]
; FNATTRS:       if.else:
; FNATTRS-NEXT:    [[CALL3:%.*]] = tail call i32 @get_val()
; FNATTRS-NEXT:    [[TOBOOL4_NOT:%.*]] = icmp eq i32 [[CALL3]], 0
; FNATTRS-NEXT:    br i1 [[TOBOOL4_NOT]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]
; FNATTRS:       if.then5:
; FNATTRS-NEXT:    tail call void @cold0()
; FNATTRS-NEXT:    br label [[IF_END12]]
; FNATTRS:       if.else6:
; FNATTRS-NEXT:    tail call void @not_cold0()
; FNATTRS-NEXT:    [[CALL7:%.*]] = tail call i32 @get_val()
; FNATTRS-NEXT:    switch i32 [[CALL7]], label [[SW_DEFAULT:%.*]] [
; FNATTRS-NEXT:      i32 0, label [[SW_BB:%.*]]
; FNATTRS-NEXT:      i32 1, label [[SW_BB8:%.*]]
; FNATTRS-NEXT:      i32 2, label [[SW_BB9:%.*]]
; FNATTRS-NEXT:    ]
; FNATTRS:       sw.bb:
; FNATTRS-NEXT:    tail call void @not_cold0()
; FNATTRS-NEXT:    br label [[CALL_COLD:%.*]]
; FNATTRS:       sw.bb8:
; FNATTRS-NEXT:    tail call void @not_cold1()
; FNATTRS-NEXT:    br label [[CALL_COLD]]
; FNATTRS:       sw.bb9:
; FNATTRS-NEXT:    tail call void @not_cold2()
; FNATTRS-NEXT:    br label [[CALL_COLD]]
; FNATTRS:       sw.default:
; FNATTRS-NEXT:    tail call void @cold0()
; FNATTRS-NEXT:    br label [[IF_END12]]
; FNATTRS:       call_cold:
; FNATTRS-NEXT:    tail call void @cold_at_cb() #[[ATTR0]]
; FNATTRS-NEXT:    br label [[IF_END12]]
; FNATTRS:       if.else11:
; FNATTRS-NEXT:    tail call void @cold0()
; FNATTRS-NEXT:    br label [[IF_END12]]
; FNATTRS:       if.end12:
; FNATTRS-NEXT:    ret void
;
; ATTRIBUTOR-LABEL: define dso_local void @test_complex
; ATTRIBUTOR-SAME: (i32 noundef [[X:%.*]]) {
; ATTRIBUTOR-NEXT:  entry:
; ATTRIBUTOR-NEXT:    tail call void @not_cold0()
; ATTRIBUTOR-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[X]], 0
; ATTRIBUTOR-NEXT:    br i1 [[TOBOOL_NOT]], label [[IF_ELSE11:%.*]], label [[IF_THEN:%.*]]
; ATTRIBUTOR:       if.then:
; ATTRIBUTOR-NEXT:    [[CALL:%.*]] = tail call i32 @get_val()
; ATTRIBUTOR-NEXT:    [[TOBOOL1_NOT:%.*]] = icmp eq i32 [[CALL]], 0
; ATTRIBUTOR-NEXT:    br i1 [[TOBOOL1_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]
; ATTRIBUTOR:       if.then2:
; ATTRIBUTOR-NEXT:    tail call void @cold1()
; ATTRIBUTOR-NEXT:    br label [[IF_END12:%.*]]
; ATTRIBUTOR:       if.else:
; ATTRIBUTOR-NEXT:    [[CALL3:%.*]] = tail call i32 @get_val()
; ATTRIBUTOR-NEXT:    [[TOBOOL4_NOT:%.*]] = icmp eq i32 [[CALL3]], 0
; ATTRIBUTOR-NEXT:    br i1 [[TOBOOL4_NOT]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]
; ATTRIBUTOR:       if.then5:
; ATTRIBUTOR-NEXT:    tail call void @cold0()
; ATTRIBUTOR-NEXT:    br label [[IF_END12]]
; ATTRIBUTOR:       if.else6:
; ATTRIBUTOR-NEXT:    tail call void @not_cold0()
; ATTRIBUTOR-NEXT:    [[CALL7:%.*]] = tail call i32 @get_val()
; ATTRIBUTOR-NEXT:    switch i32 [[CALL7]], label [[SW_DEFAULT:%.*]] [
; ATTRIBUTOR-NEXT:      i32 0, label [[SW_BB:%.*]]
; ATTRIBUTOR-NEXT:      i32 1, label [[SW_BB8:%.*]]
; ATTRIBUTOR-NEXT:      i32 2, label [[SW_BB9:%.*]]
; ATTRIBUTOR-NEXT:    ]
; ATTRIBUTOR:       sw.bb:
; ATTRIBUTOR-NEXT:    tail call void @not_cold0()
; ATTRIBUTOR-NEXT:    br label [[CALL_COLD:%.*]]
; ATTRIBUTOR:       sw.bb8:
; ATTRIBUTOR-NEXT:    tail call void @not_cold1()
; ATTRIBUTOR-NEXT:    br label [[CALL_COLD]]
; ATTRIBUTOR:       sw.bb9:
; ATTRIBUTOR-NEXT:    tail call void @not_cold2()
; ATTRIBUTOR-NEXT:    br label [[CALL_COLD]]
; ATTRIBUTOR:       sw.default:
; ATTRIBUTOR-NEXT:    tail call void @cold0()
; ATTRIBUTOR-NEXT:    br label [[IF_END12]]
; ATTRIBUTOR:       call_cold:
; ATTRIBUTOR-NEXT:    tail call void @cold_at_cb() #[[ATTR0:[0-9]+]]
; ATTRIBUTOR-NEXT:    br label [[IF_END12]]
; ATTRIBUTOR:       if.else11:
; ATTRIBUTOR-NEXT:    tail call void @cold0()
; ATTRIBUTOR-NEXT:    br label [[IF_END12]]
; ATTRIBUTOR:       if.end12:
; ATTRIBUTOR-NEXT:    ret void
;
entry:
  tail call void @not_cold0()
  %tobool.not = icmp eq i32 %x, 0
  br i1 %tobool.not, label %if.else11, label %if.then

if.then:
  %call = tail call i32 @get_val()
  %tobool1.not = icmp eq i32 %call, 0
  br i1 %tobool1.not, label %if.else, label %if.then2

if.then2:
  tail call void @cold1()
  br label %if.end12

if.else:
  %call3 = tail call i32 @get_val()
  %tobool4.not = icmp eq i32 %call3, 0
  br i1 %tobool4.not, label %if.else6, label %if.then5

if.then5:
  tail call void @cold0()
  br label %if.end12

if.else6:
  tail call void @not_cold0()
  %call7 = tail call i32 @get_val()
  switch i32 %call7, label %sw.default [
  i32 0, label %sw.bb
  i32 1, label %sw.bb8
  i32 2, label %sw.bb9
  ]

sw.bb:
  tail call void @not_cold0()
  br label %call_cold

sw.bb8:
  tail call void @not_cold1()
  br label %call_cold

sw.bb9:
  tail call void @not_cold2()
  br label %call_cold

sw.default:
  tail call void @cold0()
  br label %if.end12

call_cold:
  tail call void @cold_at_cb() cold
  br label %if.end12

if.else11:
  tail call void @cold0()
  br label %if.end12

if.end12:
  ret void
}

define dso_local void @test_complex2(i32 noundef %x) {
; FNATTRS: Function Attrs: cold
; FNATTRS-LABEL: define dso_local void @test_complex2
; FNATTRS-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0]] {
; FNATTRS-NEXT:  entry:
; FNATTRS-NEXT:    tail call void @not_cold0()
; FNATTRS-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[X]], 0
; FNATTRS-NEXT:    [[CALL12:%.*]] = tail call i32 @get_val()
; FNATTRS-NEXT:    br i1 [[TOBOOL_NOT]], label [[IF_ELSE11:%.*]], label [[IF_THEN:%.*]]
; FNATTRS:       if.then:
; FNATTRS-NEXT:    [[TOBOOL1_NOT:%.*]] = icmp eq i32 [[CALL12]], 0
; FNATTRS-NEXT:    br i1 [[TOBOOL1_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]
; FNATTRS:       if.then2:
; FNATTRS-NEXT:    tail call void @cold1()
; FNATTRS-NEXT:    br label [[IF_END16:%.*]]
; FNATTRS:       if.else:
; FNATTRS-NEXT:    [[CALL3:%.*]] = tail call i32 @get_val()
; FNATTRS-NEXT:    [[TOBOOL4_NOT:%.*]] = icmp eq i32 [[CALL3]], 0
; FNATTRS-NEXT:    br i1 [[TOBOOL4_NOT]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]
; FNATTRS:       if.then5:
; FNATTRS-NEXT:    tail call void @cold0()
; FNATTRS-NEXT:    br label [[IF_END16]]
; FNATTRS:       if.else6:
; FNATTRS-NEXT:    tail call void @not_cold0()
; FNATTRS-NEXT:    [[CALL7:%.*]] = tail call i32 @get_val()
; FNATTRS-NEXT:    switch i32 [[CALL7]], label [[SW_DEFAULT:%.*]] [
; FNATTRS-NEXT:      i32 0, label [[SW_BB:%.*]]
; FNATTRS-NEXT:      i32 1, label [[SW_BB8:%.*]]
; FNATTRS-NEXT:      i32 2, label [[SW_BB9:%.*]]
; FNATTRS-NEXT:    ]
; FNATTRS:       sw.bb:
; FNATTRS-NEXT:    tail call void @not_cold0()
; FNATTRS-NEXT:    br label [[CALL_COLD:%.*]]
; FNATTRS:       sw.bb8:
; FNATTRS-NEXT:    tail call void @not_cold1()
; FNATTRS-NEXT:    br label [[CALL_COLD]]
; FNATTRS:       sw.bb9:
; FNATTRS-NEXT:    tail call void @not_cold2()
; FNATTRS-NEXT:    br label [[CALL_COLD]]
; FNATTRS:       sw.default:
; FNATTRS-NEXT:    tail call void @cold0()
; FNATTRS-NEXT:    br label [[IF_END16]]
; FNATTRS:       call_cold:
; FNATTRS-NEXT:    tail call void @cold_at_cb() #[[ATTR0]]
; FNATTRS-NEXT:    br label [[IF_END16]]
; FNATTRS:       if.else11:
; FNATTRS-NEXT:    [[CMP:%.*]] = icmp slt i32 [[CALL12]], 1
; FNATTRS-NEXT:    br i1 [[CMP]], label [[IF_END14:%.*]], label [[FOR_BODY:%.*]]
; FNATTRS:       if.end14:
; FNATTRS-NEXT:    tail call void @cold1()
; FNATTRS-NEXT:    br label [[IF_END16]]
; FNATTRS:       for.body:
; FNATTRS-NEXT:    [[I_021:%.*]] = phi i32 [ [[INC:%.*]], [[FOR_BODY]] ], [ 0, [[IF_ELSE11]] ]
; FNATTRS-NEXT:    tail call void @cold0()
; FNATTRS-NEXT:    [[INC]] = add nuw nsw i32 [[I_021]], 1
; FNATTRS-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INC]], [[CALL12]]
; FNATTRS-NEXT:    br i1 [[EXITCOND_NOT]], label [[IF_END16]], label [[FOR_BODY]]
; FNATTRS:       if.end16:
; FNATTRS-NEXT:    ret void
;
; ATTRIBUTOR-LABEL: define dso_local void @test_complex2
; ATTRIBUTOR-SAME: (i32 noundef [[X:%.*]]) {
; ATTRIBUTOR-NEXT:  entry:
; ATTRIBUTOR-NEXT:    tail call void @not_cold0()
; ATTRIBUTOR-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[X]], 0
; ATTRIBUTOR-NEXT:    [[CALL12:%.*]] = tail call i32 @get_val()
; ATTRIBUTOR-NEXT:    br i1 [[TOBOOL_NOT]], label [[IF_ELSE11:%.*]], label [[IF_THEN:%.*]]
; ATTRIBUTOR:       if.then:
; ATTRIBUTOR-NEXT:    [[TOBOOL1_NOT:%.*]] = icmp eq i32 [[CALL12]], 0
; ATTRIBUTOR-NEXT:    br i1 [[TOBOOL1_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]
; ATTRIBUTOR:       if.then2:
; ATTRIBUTOR-NEXT:    tail call void @cold1()
; ATTRIBUTOR-NEXT:    br label [[IF_END16:%.*]]
; ATTRIBUTOR:       if.else:
; ATTRIBUTOR-NEXT:    [[CALL3:%.*]] = tail call i32 @get_val()
; ATTRIBUTOR-NEXT:    [[TOBOOL4_NOT:%.*]] = icmp eq i32 [[CALL3]], 0
; ATTRIBUTOR-NEXT:    br i1 [[TOBOOL4_NOT]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]
; ATTRIBUTOR:       if.then5:
; ATTRIBUTOR-NEXT:    tail call void @cold0()
; ATTRIBUTOR-NEXT:    br label [[IF_END16]]
; ATTRIBUTOR:       if.else6:
; ATTRIBUTOR-NEXT:    tail call void @not_cold0()
; ATTRIBUTOR-NEXT:    [[CALL7:%.*]] = tail call i32 @get_val()
; ATTRIBUTOR-NEXT:    switch i32 [[CALL7]], label [[SW_DEFAULT:%.*]] [
; ATTRIBUTOR-NEXT:      i32 0, label [[SW_BB:%.*]]
; ATTRIBUTOR-NEXT:      i32 1, label [[SW_BB8:%.*]]
; ATTRIBUTOR-NEXT:      i32 2, label [[SW_BB9:%.*]]
; ATTRIBUTOR-NEXT:    ]
; ATTRIBUTOR:       sw.bb:
; ATTRIBUTOR-NEXT:    tail call void @not_cold0()
; ATTRIBUTOR-NEXT:    br label [[CALL_COLD:%.*]]
; ATTRIBUTOR:       sw.bb8:
; ATTRIBUTOR-NEXT:    tail call void @not_cold1()
; ATTRIBUTOR-NEXT:    br label [[CALL_COLD]]
; ATTRIBUTOR:       sw.bb9:
; ATTRIBUTOR-NEXT:    tail call void @not_cold2()
; ATTRIBUTOR-NEXT:    br label [[CALL_COLD]]
; ATTRIBUTOR:       sw.default:
; ATTRIBUTOR-NEXT:    tail call void @cold0()
; ATTRIBUTOR-NEXT:    br label [[IF_END16]]
; ATTRIBUTOR:       call_cold:
; ATTRIBUTOR-NEXT:    tail call void @cold_at_cb() #[[ATTR0]]
; ATTRIBUTOR-NEXT:    br label [[IF_END16]]
; ATTRIBUTOR:       if.else11:
; ATTRIBUTOR-NEXT:    [[CMP:%.*]] = icmp slt i32 [[CALL12]], 1
; ATTRIBUTOR-NEXT:    br i1 [[CMP]], label [[IF_END14:%.*]], label [[FOR_BODY:%.*]]
; ATTRIBUTOR:       if.end14:
; ATTRIBUTOR-NEXT:    tail call void @cold1()
; ATTRIBUTOR-NEXT:    br label [[IF_END16]]
; ATTRIBUTOR:       for.body:
; ATTRIBUTOR-NEXT:    [[I_021:%.*]] = phi i32 [ [[INC:%.*]], [[FOR_BODY]] ], [ 0, [[IF_ELSE11]] ]
; ATTRIBUTOR-NEXT:    tail call void @cold0()
; ATTRIBUTOR-NEXT:    [[INC]] = add nuw nsw i32 [[I_021]], 1
; ATTRIBUTOR-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INC]], [[CALL12]]
; ATTRIBUTOR-NEXT:    br i1 [[EXITCOND_NOT]], label [[IF_END16]], label [[FOR_BODY]]
; ATTRIBUTOR:       if.end16:
; ATTRIBUTOR-NEXT:    ret void
;
entry:
  tail call void @not_cold0()
  %tobool.not = icmp eq i32 %x, 0
  %call12 = tail call i32 @get_val()
  br i1 %tobool.not, label %if.else11, label %if.then

if.then:
  %tobool1.not = icmp eq i32 %call12, 0
  br i1 %tobool1.not, label %if.else, label %if.then2

if.then2:
  tail call void @cold1()
  br label %if.end16

if.else:
  %call3 = tail call i32 @get_val()
  %tobool4.not = icmp eq i32 %call3, 0
  br i1 %tobool4.not, label %if.else6, label %if.then5

if.then5:
  tail call void @cold0()
  br label %if.end16

if.else6:
  tail call void @not_cold0()
  %call7 = tail call i32 @get_val()
  switch i32 %call7, label %sw.default [
  i32 0, label %sw.bb
  i32 1, label %sw.bb8
  i32 2, label %sw.bb9
  ]

sw.bb:
  tail call void @not_cold0()
  br label %call_cold

sw.bb8:
  tail call void @not_cold1()
  br label %call_cold

sw.bb9:
  tail call void @not_cold2()
  br label %call_cold

sw.default:
  tail call void @cold0()
  br label %if.end16

call_cold:
  tail call void @cold_at_cb() cold
  br label %if.end16

if.else11:
  %cmp = icmp slt i32 %call12, 1
  br i1 %cmp, label %if.end14, label %for.body

if.end14:
  tail call void @cold1()
  br label %if.end16

for.body:
  %i.021 = phi i32 [ %inc, %for.body ], [ 0, %if.else11 ]
  tail call void @cold0()
  %inc = add nuw nsw i32 %i.021, 1
  %exitcond.not = icmp eq i32 %inc, %call12
  br i1 %exitcond.not, label %if.end16, label %for.body

if.end16:
  ret void
}

define dso_local void @test_complex_fail(i32 noundef %x) {
; COMMON-LABEL: define dso_local void @test_complex_fail
; COMMON-SAME: (i32 noundef [[X:%.*]]) {
; COMMON-NEXT:  entry:
; COMMON-NEXT:    tail call void @not_cold0()
; COMMON-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[X]], 0
; COMMON-NEXT:    br i1 [[TOBOOL_NOT]], label [[IF_ELSE11:%.*]], label [[IF_THEN:%.*]]
; COMMON:       if.then:
; COMMON-NEXT:    [[CALL:%.*]] = tail call i32 @get_val()
; COMMON-NEXT:    [[TOBOOL1_NOT:%.*]] = icmp eq i32 [[CALL]], 0
; COMMON-NEXT:    br i1 [[TOBOOL1_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]
; COMMON:       if.then2:
; COMMON-NEXT:    tail call void @cold1()
; COMMON-NEXT:    br label [[IF_END12:%.*]]
; COMMON:       if.else:
; COMMON-NEXT:    [[CALL3:%.*]] = tail call i32 @get_val()
; COMMON-NEXT:    [[TOBOOL4_NOT:%.*]] = icmp eq i32 [[CALL3]], 0
; COMMON-NEXT:    br i1 [[TOBOOL4_NOT]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]
; COMMON:       if.then5:
; COMMON-NEXT:    tail call void @cold0()
; COMMON-NEXT:    br label [[IF_END12]]
; COMMON:       if.else6:
; COMMON-NEXT:    tail call void @not_cold0()
; COMMON-NEXT:    [[CALL7:%.*]] = tail call i32 @get_val()
; COMMON-NEXT:    switch i32 [[CALL7]], label [[SW_DEFAULT:%.*]] [
; COMMON-NEXT:      i32 0, label [[SW_BB:%.*]]
; COMMON-NEXT:      i32 1, label [[SW_BB8:%.*]]
; COMMON-NEXT:      i32 2, label [[SW_BB9:%.*]]
; COMMON-NEXT:    ]
; COMMON:       sw.bb:
; COMMON-NEXT:    tail call void @not_cold0()
; COMMON-NEXT:    br label [[CALL_COLD:%.*]]
; COMMON:       sw.bb8:
; COMMON-NEXT:    tail call void @not_cold1()
; COMMON-NEXT:    br label [[CALL_COLD]]
; COMMON:       sw.bb9:
; COMMON-NEXT:    tail call void @not_cold2()
; COMMON-NEXT:    br label [[IF_END12]]
; COMMON:       sw.default:
; COMMON-NEXT:    tail call void @cold0()
; COMMON-NEXT:    br label [[IF_END12]]
; COMMON:       call_cold:
; COMMON-NEXT:    tail call void @cold_at_cb() #[[ATTR0:[0-9]+]]
; COMMON-NEXT:    br label [[IF_END12]]
; COMMON:       if.else11:
; COMMON-NEXT:    tail call void @cold0()
; COMMON-NEXT:    br label [[IF_END12]]
; COMMON:       if.end12:
; COMMON-NEXT:    ret void
;
entry:
  tail call void @not_cold0()
  %tobool.not = icmp eq i32 %x, 0
  br i1 %tobool.not, label %if.else11, label %if.then

if.then:
  %call = tail call i32 @get_val()
  %tobool1.not = icmp eq i32 %call, 0
  br i1 %tobool1.not, label %if.else, label %if.then2

if.then2:
  tail call void @cold1()
  br label %if.end12

if.else:
  %call3 = tail call i32 @get_val()
  %tobool4.not = icmp eq i32 %call3, 0
  br i1 %tobool4.not, label %if.else6, label %if.then5

if.then5:
  tail call void @cold0()
  br label %if.end12

if.else6:
  tail call void @not_cold0()
  %call7 = tail call i32 @get_val()
  switch i32 %call7, label %sw.default [
  i32 0, label %sw.bb
  i32 1, label %sw.bb8
  i32 2, label %sw.bb9
  ]

sw.bb:
  tail call void @not_cold0()
  br label %call_cold

sw.bb8:
  tail call void @not_cold1()
  br label %call_cold

sw.bb9:
  tail call void @not_cold2()
  br label %if.end12

sw.default:
  tail call void @cold0()
  br label %if.end12

call_cold:
  tail call void @cold_at_cb() cold
  br label %if.end12

if.else11:
  tail call void @cold0()
  br label %if.end12

if.end12:
  ret void
}

define dso_local void @test_complex2_fail(i32 noundef %x) {
; COMMON-LABEL: define dso_local void @test_complex2_fail
; COMMON-SAME: (i32 noundef [[X:%.*]]) {
; COMMON-NEXT:  entry:
; COMMON-NEXT:    tail call void @not_cold0()
; COMMON-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[X]], 0
; COMMON-NEXT:    [[CALL12:%.*]] = tail call i32 @get_val()
; COMMON-NEXT:    br i1 [[TOBOOL_NOT]], label [[IF_ELSE11:%.*]], label [[IF_THEN:%.*]]
; COMMON:       if.then:
; COMMON-NEXT:    [[TOBOOL1_NOT:%.*]] = icmp eq i32 [[CALL12]], 0
; COMMON-NEXT:    br i1 [[TOBOOL1_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]
; COMMON:       if.then2:
; COMMON-NEXT:    tail call void @cold1()
; COMMON-NEXT:    br label [[IF_END16:%.*]]
; COMMON:       if.else:
; COMMON-NEXT:    [[CALL3:%.*]] = tail call i32 @get_val()
; COMMON-NEXT:    [[TOBOOL4_NOT:%.*]] = icmp eq i32 [[CALL3]], 0
; COMMON-NEXT:    br i1 [[TOBOOL4_NOT]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]
; COMMON:       if.then5:
; COMMON-NEXT:    tail call void @cold0()
; COMMON-NEXT:    br label [[IF_END16]]
; COMMON:       if.else6:
; COMMON-NEXT:    tail call void @not_cold0()
; COMMON-NEXT:    [[CALL7:%.*]] = tail call i32 @get_val()
; COMMON-NEXT:    switch i32 [[CALL7]], label [[SW_DEFAULT:%.*]] [
; COMMON-NEXT:      i32 0, label [[SW_BB:%.*]]
; COMMON-NEXT:      i32 1, label [[SW_BB8:%.*]]
; COMMON-NEXT:      i32 2, label [[SW_BB9:%.*]]
; COMMON-NEXT:    ]
; COMMON:       sw.bb:
; COMMON-NEXT:    tail call void @not_cold0()
; COMMON-NEXT:    br label [[CALL_COLD:%.*]]
; COMMON:       sw.bb8:
; COMMON-NEXT:    tail call void @not_cold1()
; COMMON-NEXT:    br label [[CALL_COLD]]
; COMMON:       sw.bb9:
; COMMON-NEXT:    tail call void @not_cold2()
; COMMON-NEXT:    br label [[CALL_COLD]]
; COMMON:       sw.default:
; COMMON-NEXT:    tail call void @cold0()
; COMMON-NEXT:    br label [[IF_END16]]
; COMMON:       call_cold:
; COMMON-NEXT:    tail call void @cold_at_cb() #[[ATTR0]]
; COMMON-NEXT:    br label [[IF_END16]]
; COMMON:       if.else11:
; COMMON-NEXT:    [[CMP:%.*]] = icmp slt i32 [[CALL12]], 1
; COMMON-NEXT:    br i1 [[CMP]], label [[IF_END14:%.*]], label [[FOR_BODY:%.*]]
; COMMON:       if.end14:
; COMMON-NEXT:    tail call void @not_cold1()
; COMMON-NEXT:    br label [[IF_END16]]
; COMMON:       for.body:
; COMMON-NEXT:    [[I_021:%.*]] = phi i32 [ [[INC:%.*]], [[FOR_BODY]] ], [ 0, [[IF_ELSE11]] ]
; COMMON-NEXT:    tail call void @cold0()
; COMMON-NEXT:    [[INC]] = add nuw nsw i32 [[I_021]], 1
; COMMON-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INC]], [[CALL12]]
; COMMON-NEXT:    br i1 [[EXITCOND_NOT]], label [[IF_END16]], label [[FOR_BODY]]
; COMMON:       if.end16:
; COMMON-NEXT:    ret void
;
entry:
  tail call void @not_cold0()
  %tobool.not = icmp eq i32 %x, 0
  %call12 = tail call i32 @get_val()
  br i1 %tobool.not, label %if.else11, label %if.then

if.then:
  %tobool1.not = icmp eq i32 %call12, 0
  br i1 %tobool1.not, label %if.else, label %if.then2

if.then2:
  tail call void @cold1()
  br label %if.end16

if.else:
  %call3 = tail call i32 @get_val()
  %tobool4.not = icmp eq i32 %call3, 0
  br i1 %tobool4.not, label %if.else6, label %if.then5

if.then5:
  tail call void @cold0()
  br label %if.end16

if.else6:
  tail call void @not_cold0()
  %call7 = tail call i32 @get_val()
  switch i32 %call7, label %sw.default [
  i32 0, label %sw.bb
  i32 1, label %sw.bb8
  i32 2, label %sw.bb9
  ]

sw.bb:
  tail call void @not_cold0()
  br label %call_cold

sw.bb8:
  tail call void @not_cold1()
  br label %call_cold

sw.bb9:
  tail call void @not_cold2()
  br label %call_cold

sw.default:
  tail call void @cold0()
  br label %if.end16

call_cold:
  tail call void @cold_at_cb() cold
  br label %if.end16

if.else11:
  %cmp = icmp slt i32 %call12, 1
  br i1 %cmp, label %if.end14, label %for.body

if.end14:
  tail call void @not_cold1()
  br label %if.end16

for.body:
  %i.021 = phi i32 [ %inc, %for.body ], [ 0, %if.else11 ]
  tail call void @cold0()
  %inc = add nuw nsw i32 %i.021, 1
  %exitcond.not = icmp eq i32 %inc, %call12
  br i1 %exitcond.not, label %if.end16, label %for.body

if.end16:
  ret void
}

;.
; FNATTRS: attributes #[[ATTR0]] = { cold }
; FNATTRS: attributes #[[ATTR1]] = { nofree norecurse noreturn nosync nounwind memory(none) }
; FNATTRS: attributes #[[ATTR2]] = { noreturn }
; FNATTRS: attributes #[[ATTR3]] = { cold noreturn }
; FNATTRS: attributes #[[ATTR4]] = { hot }
;.
; ATTRIBUTOR: attributes #[[ATTR0]] = { cold }
; ATTRIBUTOR: attributes #[[ATTR1]] = { nofree norecurse noreturn nosync nounwind memory(none) }
; ATTRIBUTOR: attributes #[[ATTR2]] = { noreturn }
; ATTRIBUTOR: attributes #[[ATTR3]] = { hot }
;.