Files
TheRock/compiler/amd-llvm/llvm/test/Transforms/FixIrreducible/callbr.ll
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

870 lines
38 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt < %s -passes='fix-irreducible,verify<loops>' -S | FileCheck %s
; RUN: opt < %s -passes='verify<loops>,fix-irreducible,verify<loops>' -S | FileCheck %s
; RUN: opt < %s -passes='print<cycles>' -disable-output 2>&1 | FileCheck %s --check-prefix CYCLES-BEFORE
; RUN: opt < %s -passes='fix-irreducible,print<cycles>' -disable-output 2>&1 | FileCheck %s --check-prefix CYCLES-AFTER
; CYCLES-BEFORE: CycleInfo for function: callbr_entry
; CYCLES-BEFORE-NEXT: depth=1: entries(indirect fallthrough)
; CYCLES-AFTER: CycleInfo for function: callbr_entry
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard) indirect fallthrough
; CYCLES-BEFORE-NEXT: CycleInfo for function: callbr_entry_targets_with_phi_nodes
; CYCLES-BEFORE-NEXT: depth=1: entries(block1 block)
; CYCLES-AFTER-NEXT: CycleInfo for function: callbr_entry_targets_with_phi_nodes
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard) block1 block
; CYCLES-BEFORE-NEXT: CycleInfo for function: callbr_entry_multiple_indirect_targets
; CYCLES-BEFORE-NEXT: depth=1: entries(indirect fallthrough)
; CYCLES-AFTER-NEXT: CycleInfo for function: callbr_entry_multiple_indirect_targets
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard) indirect fallthrough
; CYCLES-BEFORE-NEXT: CycleInfo for function: callbr_entry_multiple_indirect_targets1
; CYCLES-BEFORE-NEXT: depth=1: entries(indirect1 indirect fallthrough)
; CYCLES-BEFORE-NEXT: depth=2: entries(indirect fallthrough)
; CYCLES-AFTER-NEXT: CycleInfo for function: callbr_entry_multiple_indirect_targets1
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard) indirect1 indirect fallthrough irr.guard1 irr.guard2
; CYCLES-AFTER-NEXT: depth=2: entries(irr.guard2) indirect fallthrough
; CYCLES-BEFORE-NEXT: CycleInfo for function: callbr_header_no_indirect
; CYCLES-BEFORE-NEXT: depth=1: entries(fallthrough callbr)
; CYCLES-AFTER-NEXT: CycleInfo for function: callbr_header_no_indirect
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard) fallthrough callbr callbr.target.fallthrough
; CYCLES-BEFORE-NEXT: CycleInfo for function: callbr_header
; CYCLES-BEFORE-NEXT: depth=1: entries(fallthrough callbr)
; CYCLES-AFTER-NEXT: CycleInfo for function: callbr_header
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard) fallthrough callbr callbr.target.fallthrough
; CYCLES-BEFORE-NEXT: CycleInfo for function: callbr_header_multiple_indirect_targets
; CYCLES-BEFORE-NEXT: depth=1: entries(fallthrough callbr) indirect1
; CYCLES-BEFORE-NEXT: depth=2: entries(callbr) indirect1
; CYCLES-AFTER-NEXT: CycleInfo for function: callbr_header_multiple_indirect_targets
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard) fallthrough callbr indirect1 callbr.target.fallthrough
; CYCLES-AFTER-NEXT: depth=2: entries(callbr) indirect1
; CYCLES-BEFORE-NEXT: CycleInfo for function: callbr_regular
; CYCLES-BEFORE-NEXT: depth=1: entries(fallthrough2 fallthrough1)
; CYCLES-BEFORE-NEXT: depth=1: entries(indirect2 indirect1)
; CYCLES-BEFORE-NEXT: depth=1: entries(nocallbr2 nocallbr1)
; CYCLES-AFTER-NEXT: CycleInfo for function: callbr_regular
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard) fallthrough2 fallthrough1
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard1) indirect2 indirect1
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard2) nocallbr2 nocallbr1
; CYCLES-BEFORE-NEXT: CycleInfo for function: callbr_regular1
; CYCLES-BEFORE-NEXT: depth=1: entries(callbr nocallbr)
; CYCLES-AFTER-NEXT: CycleInfo for function: callbr_regular1
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard) callbr nocallbr
; CYCLES-BEFORE-NEXT: CycleInfo for function: callbr_regular2
; CYCLES-BEFORE-NEXT: depth=1: entries(callbr nocallbr)
; CYCLES-AFTER-NEXT: CycleInfo for function: callbr_regular2
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard) callbr nocallbr
; CYCLES-BEFORE-NEXT: CycleInfo for function: callbr_header_and_regular
; CYCLES-BEFORE-NEXT: depth=1: entries(callbr_header) callbr_regular mid
; CYCLES-BEFORE-NEXT: depth=2: entries(callbr_regular mid)
; CYCLES-AFTER-NEXT: CycleInfo for function: callbr_header_and_regular
; CYCLES-AFTER-NEXT: depth=1: entries(callbr_header) callbr_regular mid callbr_header.target.mid callbr_header.target.callbr_regular irr.guard
; CYCLES-AFTER-NEXT: depth=2: entries(irr.guard) callbr_regular mid
; CYCLES-BEFORE-NEXT: CycleInfo for function: callbr_only
; CYCLES-BEFORE-NEXT: depth=1: entries(callbr_block callbr_header)
; CYCLES-AFTER-NEXT: CycleInfo for function: callbr_only
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard) callbr_block callbr_header callbr_header.target.callbr_block
; CYCLES-BEFORE-NEXT: CycleInfo for function: entry_multiple_callbr
; CYCLES-BEFORE-NEXT: depth=1: entries(cb2 block block1)
; CYCLES-BEFORE-NEXT: depth=2: entries(block block1)
; CYCLES-AFTER-NEXT: CycleInfo for function: entry_multiple_callbr
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard) cb2 block block1 irr.guard1 cb2.target.block1 cb2.target.block irr.guard2
; CYCLES-AFTER-NEXT: depth=2: entries(irr.guard2) block block1
; CYCLES-BEFORE-NEXT: CycleInfo for function: callbr_exit_with_separate_entries
; CYCLES-BEFORE-NEXT: depth=1: entries(l2 l1) cb
; CYCLES-BEFORE-NEXT: depth=2: entries(l1 cb)
; CYCLES-AFTER-NEXT: CycleInfo for function: callbr_exit_with_separate_entries
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard) l2 l1 cb cb.target.l1 irr.guard1
; CYCLES-AFTER-NEXT: depth=2: entries(irr.guard1) l1 cb cb.target.l1
; CYCLES-BEFORE-NEXT: CycleInfo for function: callbr_exit_with_separate_entries1
; CYCLES-BEFORE-NEXT: depth=1: entries(loop2 loop1) cb
; CYCLES-AFTER-NEXT: CycleInfo for function: callbr_exit_with_separate_entries1
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard) loop2 loop1 cb cb.target.loop2
; CYCLES-BEFORE-NEXT: CycleInfo for function: callbr_only_multiple
; CYCLES-BEFORE-NEXT: depth=1: entries(cb3 cb1 cb2)
; CYCLES-BEFORE-NEXT: depth=2: entries(cb1 cb2)
; CYCLES-AFTER-NEXT: CycleInfo for function: callbr_only_multiple
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard) cb3 cb1 cb2 cb2.target.cb3 cb1.target.cb3 irr.guard1 cb2.target.cb1 cb3.target.cb1 irr.guard2
; CYCLES-AFTER-NEXT: depth=2: entries(irr.guard2) cb1 cb2 cb2.target.cb1
; CYCLES-BEFORE-NEXT: CycleInfo for function: callbr_bypass
; CYCLES-BEFORE-NEXT: depth=1: entries(l1 cb) l2
; CYCLES-BEFORE-NEXT: depth=2: entries(cb l2)
; CYCLES-AFTER-NEXT: CycleInfo for function: callbr_bypass
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard) l1 cb l2 cb.target.l1 irr.guard1
; CYCLES-AFTER-NEXT: depth=2: entries(irr.guard1) cb l2
; CYCLES-BEFORE-NEXT: CycleInfo for function: callbr_multiple_with_exit
; CYCLES-BEFORE-NEXT: depth=1: entries(l3 l1 l2)
; CYCLES-BEFORE-NEXT: depth=2: entries(l1 l2)
; CYCLES-AFTER-NEXT: CycleInfo for function: callbr_multiple_with_exit
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard) l3 l1 l2 irr.guard1 irr.guard2
; CYCLES-AFTER-NEXT: depth=2: entries(irr.guard2) l1 l2
; CYCLES-BEFORE-NEXT: CycleInfo for function: callbr_nested
; CYCLES-BEFORE-NEXT: depth=1: entries(bb bh)
; CYCLES-BEFORE-NEXT: depth=1: entries(b h)
; CYCLES-AFTER-NEXT: CycleInfo for function: callbr_nested
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard) bb bh
; CYCLES-AFTER-NEXT: depth=1: entries(irr.guard1) b h
; Fix the irreducible loop in which callbr is the entry (see description at the
; top of FixIrreducible.cpp).
define void @callbr_entry(i1 %c) {
; CHECK-LABEL: define void @callbr_entry(
; CHECK-SAME: i1 [[C:%.*]]) {
; CHECK-NEXT: [[CALLBR:.*:]]
; CHECK-NEXT: callbr void asm "", "!i"()
; CHECK-NEXT: to label %[[CALLBR_TARGET_FALLTHROUGH:.*]] [label %callbr.target.indirect]
; CHECK: [[FALLTHROUGH:.*]]:
; CHECK-NEXT: br i1 [[C]], label %[[IRR_GUARD:.*]], label %[[RET:.*]]
; CHECK: [[INDIRECT:.*]]:
; CHECK-NEXT: br label %[[FALLTHROUGH]]
; CHECK: [[RET]]:
; CHECK-NEXT: ret void
; CHECK: [[CALLBR_TARGET_FALLTHROUGH]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[CALLBR_TARGET_INDIRECT:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[GUARD_INDIRECT:%.*]] = phi i1 [ true, %[[FALLTHROUGH]] ], [ false, %[[CALLBR_TARGET_FALLTHROUGH]] ], [ true, %[[CALLBR_TARGET_INDIRECT]] ]
; CHECK-NEXT: br i1 [[GUARD_INDIRECT]], label %[[INDIRECT]], label %[[FALLTHROUGH]]
;
callbr:
callbr void asm "", "!i"() to label %fallthrough [label %indirect]
fallthrough:
br i1 %c, label %indirect, label %ret
indirect:
br label %fallthrough
ret:
ret void
}
define i32 @callbr_entry_targets_with_phi_nodes(i1 %c) {
; CHECK-LABEL: define i32 @callbr_entry_targets_with_phi_nodes(
; CHECK-SAME: i1 [[C:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: callbr void asm "", "!i"()
; CHECK-NEXT: to label %[[ENTRY_TARGET_BLOCK:.*]] [label %entry.target.block1]
; CHECK: [[BLOCK:.*]]:
; CHECK-NEXT: [[A:%.*]] = phi i32 [ 1, %[[BLOCK1:.*]] ], [ [[A_MOVED:%.*]], %[[IRR_GUARD:.*]] ]
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[BLOCK1]]:
; CHECK-NEXT: br i1 [[C]], label %[[BLOCK]], label %[[RET:.*]]
; CHECK: [[RET]]:
; CHECK-NEXT: ret i32 [[B_MOVED:%.*]]
; CHECK: [[ENTRY_TARGET_BLOCK]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[ENTRY_TARGET_BLOCK1:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[A_MOVED]] = phi i32 [ poison, %[[BLOCK]] ], [ 42, %[[ENTRY_TARGET_BLOCK]] ], [ poison, %[[ENTRY_TARGET_BLOCK1]] ]
; CHECK-NEXT: [[B_MOVED]] = phi i32 [ [[A]], %[[BLOCK]] ], [ poison, %[[ENTRY_TARGET_BLOCK]] ], [ 43, %[[ENTRY_TARGET_BLOCK1]] ]
; CHECK-NEXT: [[GUARD_BLOCK1:%.*]] = phi i1 [ true, %[[BLOCK]] ], [ false, %[[ENTRY_TARGET_BLOCK]] ], [ true, %[[ENTRY_TARGET_BLOCK1]] ]
; CHECK-NEXT: br i1 [[GUARD_BLOCK1]], label %[[BLOCK1]], label %[[BLOCK]]
;
entry:
callbr void asm "", "!i"() to label %block [label %block1]
block:
%a = phi i32 [42, %entry], [1, %block1]
br label %block1
block1:
%b = phi i32 [43, %entry], [%a, %block]
br i1 %c, label %block, label %ret
ret:
ret i32 %b
}
define void @callbr_entry_multiple_indirect_targets(i1 %c) {
; CHECK-LABEL: define void @callbr_entry_multiple_indirect_targets(
; CHECK-SAME: i1 [[C:%.*]]) {
; CHECK-NEXT: [[CALLBR:.*:]]
; CHECK-NEXT: callbr void asm "", "!i,!i,!i"()
; CHECK-NEXT: to label %[[CALLBR_TARGET_FALLTHROUGH:.*]] [label %[[CALLBR_TARGET_INDIRECT:.*]], label %[[INDIRECT1:.*]], label %indirect2]
; CHECK: [[INDIRECT3:.*]]:
; CHECK-NEXT: br i1 [[C]], label %[[IRR_GUARD:.*]], label %[[RET:.*]]
; CHECK: [[INDIRECT:.*]]:
; CHECK-NEXT: br label %[[INDIRECT3]]
; CHECK: [[INDIRECT1]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[INDIRECT2:.*:]]
; CHECK-NEXT: br label %[[RET]]
; CHECK: [[RET]]:
; CHECK-NEXT: ret void
; CHECK: [[CALLBR_TARGET_FALLTHROUGH]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[CALLBR_TARGET_INDIRECT]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[GUARD_INDIRECT:%.*]] = phi i1 [ true, %[[INDIRECT3]] ], [ true, %[[INDIRECT1]] ], [ false, %[[CALLBR_TARGET_FALLTHROUGH]] ], [ true, %[[CALLBR_TARGET_INDIRECT]] ]
; CHECK-NEXT: br i1 [[GUARD_INDIRECT]], label %[[INDIRECT]], label %[[INDIRECT3]]
;
callbr:
callbr void asm "", "!i,!i,!i"() to label %fallthrough [label %indirect, label %indirect1, label %indirect2]
fallthrough:
br i1 %c, label %indirect, label %ret
indirect:
br label %fallthrough
indirect1:
br label %indirect
indirect2:
br label %ret
ret:
ret void
}
define void @callbr_entry_multiple_indirect_targets1(i1 %c, i1 %d) {
; CHECK-LABEL: define void @callbr_entry_multiple_indirect_targets1(
; CHECK-SAME: i1 [[C:%.*]], i1 [[D:%.*]]) {
; CHECK-NEXT: [[CALLBR:.*:]]
; CHECK-NEXT: callbr void asm "", "!i,!i,!i"()
; CHECK-NEXT: to label %[[CALLBR_TARGET_FALLTHROUGH:.*]] [label %[[CALLBR_TARGET_INDIRECT:.*]], label %[[CALLBR_TARGET_INDIRECT1:.*]], label %indirect2]
; CHECK: [[INDIRECT3:.*]]:
; CHECK-NEXT: br i1 [[C]], label %[[IRR_GUARD2:.*]], label %[[RET:.*]]
; CHECK: [[INDIRECT:.*]]:
; CHECK-NEXT: br i1 [[D]], label %[[INDIRECT3]], label %[[IRR_GUARD:.*]]
; CHECK: [[INDIRECT1:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD2]]
; CHECK: [[INDIRECT2:.*:]]
; CHECK-NEXT: br label %[[RET]]
; CHECK: [[RET]]:
; CHECK-NEXT: ret void
; CHECK: [[CALLBR_TARGET_FALLTHROUGH]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[CALLBR_TARGET_INDIRECT]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[CALLBR_TARGET_INDIRECT1]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[GUARD_INDIRECT1:%.*]] = phi i1 [ true, %[[INDIRECT]] ], [ false, %[[CALLBR_TARGET_FALLTHROUGH]] ], [ false, %[[CALLBR_TARGET_INDIRECT]] ], [ true, %[[CALLBR_TARGET_INDIRECT1]] ]
; CHECK-NEXT: [[GUARD_FALLTHROUGH:%.*]] = phi i1 [ false, %[[INDIRECT]] ], [ true, %[[CALLBR_TARGET_FALLTHROUGH]] ], [ false, %[[CALLBR_TARGET_INDIRECT]] ], [ false, %[[CALLBR_TARGET_INDIRECT1]] ]
; CHECK-NEXT: [[GUARD_FALLTHROUGH_INV:%.*]] = xor i1 [[GUARD_FALLTHROUGH]], true
; CHECK-NEXT: br i1 [[GUARD_INDIRECT1]], label %[[INDIRECT1]], label %[[IRR_GUARD1:.*]]
; CHECK: [[IRR_GUARD1]]:
; CHECK-NEXT: br label %[[IRR_GUARD2]]
; CHECK: [[IRR_GUARD2]]:
; CHECK-NEXT: [[GUARD_INDIRECT:%.*]] = phi i1 [ true, %[[INDIRECT3]] ], [ [[GUARD_FALLTHROUGH_INV]], %[[IRR_GUARD1]] ], [ true, %[[INDIRECT1]] ]
; CHECK-NEXT: br i1 [[GUARD_INDIRECT]], label %[[INDIRECT]], label %[[INDIRECT3]]
;
callbr:
callbr void asm "", "!i,!i,!i"() to label %fallthrough [label %indirect, label %indirect1, label %indirect2]
fallthrough:
br i1 %c, label %indirect, label %ret
indirect:
br i1 %d, label %fallthrough, label %indirect1
indirect1:
br label %indirect
indirect2:
br label %ret
ret:
ret void
}
; Fix the irreducible loop in which callbr is the header (see the example at the
; top of FixIrreducible.cpp).
define void @callbr_header_no_indirect(i1 %c, i1 %d) {
; CHECK-LABEL: define void @callbr_header_no_indirect(
; CHECK-SAME: i1 [[C:%.*]], i1 [[D:%.*]]) {
; CHECK-NEXT: [[D_INV:%.*]] = xor i1 [[D]], true
; CHECK-NEXT: br label %[[IRR_GUARD:.*]]
; CHECK: [[CALLBR:.*]]:
; CHECK-NEXT: callbr void asm "", ""()
; CHECK-NEXT: to label %[[CALLBR_TARGET_FALLTHROUGH:.*]] []
; CHECK: [[FALLTHROUGH:.*]]:
; CHECK-NEXT: br i1 [[C]], label %[[CALLBR]], label %[[RET:.*]]
; CHECK: [[RET]]:
; CHECK-NEXT: ret void
; CHECK: [[CALLBR_TARGET_FALLTHROUGH]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[GUARD_FALLTHROUGH:%.*]] = phi i1 [ true, %[[CALLBR_TARGET_FALLTHROUGH]] ], [ [[D_INV]], [[TMP0:%.*]] ]
; CHECK-NEXT: br i1 [[GUARD_FALLTHROUGH]], label %[[FALLTHROUGH]], label %[[CALLBR]]
;
br i1 %d, label %callbr, label %fallthrough
callbr:
callbr void asm "", ""() to label %fallthrough []
fallthrough:
br i1 %c, label %callbr, label %ret
ret:
ret void
}
; Fix the irreducible loop in which callbr is the header.
define void @callbr_header(i1 %c, i1 %d) {
; CHECK-LABEL: define void @callbr_header(
; CHECK-SAME: i1 [[C:%.*]], i1 [[D:%.*]]) {
; CHECK-NEXT: [[D_INV:%.*]] = xor i1 [[D]], true
; CHECK-NEXT: br label %[[IRR_GUARD:.*]]
; CHECK: [[CALLBR:.*]]:
; CHECK-NEXT: callbr void asm "", "!i"()
; CHECK-NEXT: to label %[[CALLBR_TARGET_FALLTHROUGH:.*]] [label %indirect]
; CHECK: [[INDIRECT:.*:]]
; CHECK-NEXT: br label %[[RET:.*]]
; CHECK: [[FALLTHROUGH:.*]]:
; CHECK-NEXT: br i1 [[C]], label %[[CALLBR]], label %[[RET]]
; CHECK: [[RET]]:
; CHECK-NEXT: ret void
; CHECK: [[CALLBR_TARGET_FALLTHROUGH]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[GUARD_FALLTHROUGH:%.*]] = phi i1 [ true, %[[CALLBR_TARGET_FALLTHROUGH]] ], [ [[D_INV]], [[TMP0:%.*]] ]
; CHECK-NEXT: br i1 [[GUARD_FALLTHROUGH]], label %[[FALLTHROUGH]], label %[[CALLBR]]
;
br i1 %d, label %callbr, label %fallthrough
callbr:
callbr void asm "", "!i"() to label %fallthrough [label %indirect]
indirect:
br label %ret
fallthrough:
br i1 %c, label %callbr, label %ret
ret:
ret void
}
define void @callbr_header_multiple_indirect_targets(i1 %c, i1 %d) {
; CHECK-LABEL: define void @callbr_header_multiple_indirect_targets(
; CHECK-SAME: i1 [[C:%.*]], i1 [[D:%.*]]) {
; CHECK-NEXT: [[D_INV:%.*]] = xor i1 [[D]], true
; CHECK-NEXT: br label %[[IRR_GUARD:.*]]
; CHECK: [[CALLBR:.*]]:
; CHECK-NEXT: callbr void asm "", "!i,!i"()
; CHECK-NEXT: to label %[[CALLBR_TARGET_FALLTHROUGH:.*]] [label %[[INDIRECT1:.*]], label %indirect1]
; CHECK: [[INDIRECT1]]:
; CHECK-NEXT: br label %[[RET:.*]]
; CHECK: [[INDIRECT2:.*:]]
; CHECK-NEXT: br label %[[CALLBR]]
; CHECK: [[FALLTHROUGH:.*]]:
; CHECK-NEXT: br i1 [[C]], label %[[CALLBR]], label %[[RET]]
; CHECK: [[RET]]:
; CHECK-NEXT: ret void
; CHECK: [[CALLBR_TARGET_FALLTHROUGH]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[GUARD_FALLTHROUGH:%.*]] = phi i1 [ true, %[[CALLBR_TARGET_FALLTHROUGH]] ], [ [[D_INV]], [[TMP0:%.*]] ]
; CHECK-NEXT: br i1 [[GUARD_FALLTHROUGH]], label %[[FALLTHROUGH]], label %[[CALLBR]]
;
br i1 %d, label %callbr, label %fallthrough
callbr:
callbr void asm "", "!i,!i"() to label %fallthrough [label %indirect, label %indirect1]
indirect:
br label %ret
indirect1:
br label %callbr
fallthrough:
br i1 %c, label %callbr, label %ret
ret:
ret void
}
; Fix the three usual irreducible loops (callbr isn't a part of one of them):
; - fallthrough, fallthrough1, fallthrough2
; - indirect, indirect1, indirect2
; - nocallbr, nocallbr1, nocallbr2
define void @callbr_regular(i1 %c, i1 %d) {
; CHECK-LABEL: define void @callbr_regular(
; CHECK-SAME: i1 [[C:%.*]], i1 [[D:%.*]]) {
; CHECK-NEXT: [[C_INV:%.*]] = xor i1 [[C]], true
; CHECK-NEXT: br i1 [[D]], label %[[CALLBR:.*]], label %[[NOCALLBR:.*]]
; CHECK: [[CALLBR]]:
; CHECK-NEXT: callbr void asm "", "!i"()
; CHECK-NEXT: to label %[[FALLTHROUGH:.*]] [label %indirect]
; CHECK: [[FALLTHROUGH]]:
; CHECK-NEXT: br label %[[IRR_GUARD:.*]]
; CHECK: [[FALLTHROUGH1:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[FALLTHROUGH2:.*]]:
; CHECK-NEXT: br i1 [[D]], label %[[FALLTHROUGH1]], label %[[RET:.*]]
; CHECK: [[INDIRECT:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD1:.*]]
; CHECK: [[INDIRECT1:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD1]]
; CHECK: [[INDIRECT2:.*]]:
; CHECK-NEXT: br i1 [[D]], label %[[INDIRECT1]], label %[[RET]]
; CHECK: [[NOCALLBR]]:
; CHECK-NEXT: br label %[[IRR_GUARD2:.*]]
; CHECK: [[NOCALLBR1:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD2]]
; CHECK: [[NOCALLBR2:.*]]:
; CHECK-NEXT: br i1 [[D]], label %[[NOCALLBR1]], label %[[RET]]
; CHECK: [[RET]]:
; CHECK-NEXT: ret void
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[GUARD_FALLTHROUGH2:%.*]] = phi i1 [ true, %[[FALLTHROUGH1]] ], [ [[C_INV]], %[[FALLTHROUGH]] ]
; CHECK-NEXT: br i1 [[GUARD_FALLTHROUGH2]], label %[[FALLTHROUGH2]], label %[[FALLTHROUGH1]]
; CHECK: [[IRR_GUARD1]]:
; CHECK-NEXT: [[GUARD_INDIRECT2:%.*]] = phi i1 [ true, %[[INDIRECT1]] ], [ [[C_INV]], %[[INDIRECT]] ]
; CHECK-NEXT: br i1 [[GUARD_INDIRECT2]], label %[[INDIRECT2]], label %[[INDIRECT1]]
; CHECK: [[IRR_GUARD2]]:
; CHECK-NEXT: [[GUARD_NOCALLBR2:%.*]] = phi i1 [ true, %[[NOCALLBR1]] ], [ [[C_INV]], %[[NOCALLBR]] ]
; CHECK-NEXT: br i1 [[GUARD_NOCALLBR2]], label %[[NOCALLBR2]], label %[[NOCALLBR1]]
;
br i1 %d, label %callbr, label %nocallbr
callbr:
callbr void asm "", "!i"() to label %fallthrough [label %indirect]
fallthrough:
br i1 %c, label %fallthrough1, label %fallthrough2
fallthrough1:
br label %fallthrough2
fallthrough2:
br i1 %d, label %fallthrough1, label %ret
indirect:
br i1 %c, label %indirect1, label %indirect2
indirect1:
br label %indirect2
indirect2:
br i1 %d, label %indirect1, label %ret
nocallbr:
br i1 %c, label %nocallbr1, label %nocallbr2
nocallbr1:
br label %nocallbr2
nocallbr2:
br i1 %d, label %nocallbr1, label %ret
ret:
ret void
}
; Fix an irreducible loop in which callbr is a regular block (neither entry nor
; header). See the example at the top of FixIrreducible.cpp.
define void @callbr_regular1(i1 %c) {
; CHECK-LABEL: define void @callbr_regular1(
; CHECK-SAME: i1 [[C:%.*]]) {
; CHECK-NEXT: [[C_INV:%.*]] = xor i1 [[C]], true
; CHECK-NEXT: br label %[[IRR_GUARD:.*]]
; CHECK: [[NOCALLBR:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[CALLBR:.*]]:
; CHECK-NEXT: callbr void asm "", "!i"()
; CHECK-NEXT: to label %[[RET:.*]] [label %nocallbr]
; CHECK: [[RET]]:
; CHECK-NEXT: ret void
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[GUARD_CALLBR:%.*]] = phi i1 [ true, %[[NOCALLBR]] ], [ [[C_INV]], [[TMP0:%.*]] ]
; CHECK-NEXT: br i1 [[GUARD_CALLBR]], label %[[CALLBR]], label %[[NOCALLBR]]
;
br i1 %c, label %nocallbr, label %callbr
nocallbr:
br label %callbr
callbr:
callbr void asm "", "!i"() to label %ret [label %nocallbr]
ret:
ret void
}
; Fix an irreducible loop in which callbr is a regular block (neither entry nor
; header). See the example at the top of FixIrreducible.cpp.
define void @callbr_regular2(i1 %c) {
; CHECK-LABEL: define void @callbr_regular2(
; CHECK-SAME: i1 [[C:%.*]]) {
; CHECK-NEXT: [[C_INV:%.*]] = xor i1 [[C]], true
; CHECK-NEXT: br label %[[IRR_GUARD:.*]]
; CHECK: [[NOCALLBR:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[CALLBR:.*]]:
; CHECK-NEXT: callbr void asm "", "!i"()
; CHECK-NEXT: to label %[[NOCALLBR]] [label %ret]
; CHECK: [[RET:.*:]]
; CHECK-NEXT: ret void
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[GUARD_CALLBR:%.*]] = phi i1 [ true, %[[NOCALLBR]] ], [ [[C_INV]], [[TMP0:%.*]] ]
; CHECK-NEXT: br i1 [[GUARD_CALLBR]], label %[[CALLBR]], label %[[NOCALLBR]]
;
br i1 %c, label %nocallbr, label %callbr
nocallbr:
br label %callbr
callbr:
callbr void asm "", "!i"() to label %nocallbr [label %ret]
ret:
ret void
}
; Fix an irreducible loop with two callbr blocks, one as header and one as regular block.
define void @callbr_header_and_regular(i1 %c) {
; CHECK-LABEL: define void @callbr_header_and_regular(
; CHECK-SAME: i1 [[C:%.*]]) {
; CHECK-NEXT: br label %[[CALLBR_HEADER:.*]]
; CHECK: [[CALLBR_HEADER]]:
; CHECK-NEXT: callbr void asm "", "!i"()
; CHECK-NEXT: to label %[[CALLBR_HEADER_TARGET_MID:.*]] [label %callbr_header.target.callbr_regular]
; CHECK: [[MID:.*]]:
; CHECK-NEXT: br i1 [[C]], label %[[IRR_GUARD:.*]], label %[[RET:.*]]
; CHECK: [[CALLBR_REGULAR:.*]]:
; CHECK-NEXT: callbr void asm "", "!i"()
; CHECK-NEXT: to label %[[CALLBR_HEADER]] [label %mid]
; CHECK: [[RET]]:
; CHECK-NEXT: ret void
; CHECK: [[CALLBR_HEADER_TARGET_MID]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[CALLBR_HEADER_TARGET_CALLBR_REGULAR:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[GUARD_CALLBR_REGULAR:%.*]] = phi i1 [ true, %[[MID]] ], [ false, %[[CALLBR_HEADER_TARGET_MID]] ], [ true, %[[CALLBR_HEADER_TARGET_CALLBR_REGULAR]] ]
; CHECK-NEXT: br i1 [[GUARD_CALLBR_REGULAR]], label %[[CALLBR_REGULAR]], label %[[MID]]
;
br label %callbr_header
callbr_header:
callbr void asm "", "!i"() to label %mid [label %callbr_regular]
mid:
br i1 %c, label %callbr_regular, label %ret
callbr_regular:
callbr void asm "", "!i"() to label %callbr_header [label %mid]
ret:
ret void
}
; Fix an irreducible loop consisting only of callbr blocks (and ret). See the
; example at the top of FixIrreducible.cpp.
define void @callbr_only(i1 %c) {
; CHECK-LABEL: define void @callbr_only(
; CHECK-SAME: i1 [[C:%.*]]) {
; CHECK-NEXT: [[CALLBR:.*:]]
; CHECK-NEXT: callbr void asm "", "!i"()
; CHECK-NEXT: to label %[[CALLBR_ENTRY_TARGET_CALLBR_HEADER:.*]] [label %callbr_entry.target.callbr_block]
; CHECK: [[CALLBR_HEADER:.*]]:
; CHECK-NEXT: callbr void asm "", ""()
; CHECK-NEXT: to label %[[CALLBR_HEADER_TARGET_CALLBR_BLOCK:.*]] []
; CHECK: [[CALLBR_BLOCK:.*]]:
; CHECK-NEXT: callbr void asm "", "!i"()
; CHECK-NEXT: to label %[[CALLBR_HEADER]] [label %ret]
; CHECK: [[RET:.*:]]
; CHECK-NEXT: ret void
; CHECK: [[CALLBR_HEADER_TARGET_CALLBR_BLOCK]]:
; CHECK-NEXT: br label %[[IRR_GUARD:.*]]
; CHECK: [[CALLBR_ENTRY_TARGET_CALLBR_HEADER]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[CALLBR_ENTRY_TARGET_CALLBR_BLOCK:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[GUARD_CALLBR_BLOCK:%.*]] = phi i1 [ true, %[[CALLBR_HEADER_TARGET_CALLBR_BLOCK]] ], [ false, %[[CALLBR_ENTRY_TARGET_CALLBR_HEADER]] ], [ true, %[[CALLBR_ENTRY_TARGET_CALLBR_BLOCK]] ]
; CHECK-NEXT: br i1 [[GUARD_CALLBR_BLOCK]], label %[[CALLBR_BLOCK]], label %[[CALLBR_HEADER]]
;
callbr_entry:
callbr void asm "", "!i"() to label %callbr_header [label %callbr_block]
callbr_header:
callbr void asm "", ""() to label %callbr_block []
callbr_block:
callbr void asm "", "!i"() to label %callbr_header [label %ret]
ret:
ret void
}
; Irreducible loop: entry leading to multiple callbr blocks.
define void @entry_multiple_callbr(i1 %a, i1 %b, i1 %c) {
; CHECK-LABEL: define void @entry_multiple_callbr(
; CHECK-SAME: i1 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br i1 [[A]], label %[[CB1:.*]], label %[[IRR_GUARD:.*]]
; CHECK: [[CB1]]:
; CHECK-NEXT: callbr void asm "", "!i,!i"()
; CHECK-NEXT: to label %[[CB1_TARGET_BLOCK:.*]] [label %[[CB1_TARGET_CB2:.*]], label %cb1.target.block1]
; CHECK: [[BLOCK:.*]]:
; CHECK-NEXT: br i1 [[B]], label %[[IRR_GUARD]], label %[[BLOCK1:.*]]
; CHECK: [[CB2:.*]]:
; CHECK-NEXT: callbr void asm "", "!i"()
; CHECK-NEXT: to label %[[CB2_TARGET_BLOCK1:.*]] [label %cb2.target.block]
; CHECK: [[BLOCK1]]:
; CHECK-NEXT: br i1 [[C]], label %[[IRR_GUARD2:.*]], label %[[EXIT:.*]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
; CHECK: [[CB1_TARGET_BLOCK]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[CB1_TARGET_CB2]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[CB1_TARGET_BLOCK1:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[GUARD_CB2:%.*]] = phi i1 [ true, %[[BLOCK]] ], [ false, %[[CB1_TARGET_BLOCK]] ], [ true, %[[CB1_TARGET_CB2]] ], [ false, %[[CB1_TARGET_BLOCK1]] ], [ true, %[[ENTRY]] ]
; CHECK-NEXT: [[GUARD_BLOCK:%.*]] = phi i1 [ false, %[[BLOCK]] ], [ true, %[[CB1_TARGET_BLOCK]] ], [ false, %[[CB1_TARGET_CB2]] ], [ false, %[[CB1_TARGET_BLOCK1]] ], [ false, %[[ENTRY]] ]
; CHECK-NEXT: br i1 [[GUARD_CB2]], label %[[CB2]], label %[[IRR_GUARD1:.*]]
; CHECK: [[IRR_GUARD1]]:
; CHECK-NEXT: br label %[[IRR_GUARD2]]
; CHECK: [[CB2_TARGET_BLOCK1]]:
; CHECK-NEXT: br label %[[IRR_GUARD2]]
; CHECK: [[CB2_TARGET_BLOCK:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD2]]
; CHECK: [[IRR_GUARD2]]:
; CHECK-NEXT: [[GUARD_BLOCK3:%.*]] = phi i1 [ true, %[[BLOCK1]] ], [ [[GUARD_BLOCK]], %[[IRR_GUARD1]] ], [ false, %[[CB2_TARGET_BLOCK1]] ], [ true, %[[CB2_TARGET_BLOCK]] ]
; CHECK-NEXT: br i1 [[GUARD_BLOCK3]], label %[[BLOCK]], label %[[BLOCK1]]
;
entry:
br i1 %a, label %cb1, label %cb2
cb1:
callbr void asm "", "!i,!i"() to label %block [label %cb2, label %block1]
block:
br i1 %b, label %cb2, label %block1
cb2:
callbr void asm "", "!i"() to label %block1 [label %block]
block1:
br i1 %c, label %block, label %exit
exit:
ret void
}
; Irreducible loop: callbr as loop exit, with multiple entries
define void @callbr_exit_with_separate_entries(i1 %a, i1 %b, i1 %c) {
; CHECK-LABEL: define void @callbr_exit_with_separate_entries(
; CHECK-SAME: i1 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[C_INV:%.*]] = xor i1 [[C]], true
; CHECK-NEXT: [[A_INV:%.*]] = xor i1 [[A]], true
; CHECK-NEXT: br label %[[IRR_GUARD:.*]]
; CHECK: [[L1:.*]]:
; CHECK-NEXT: br i1 [[B]], label %[[CB:.*]], label %[[IRR_GUARD]]
; CHECK: [[L2:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD1:.*]]
; CHECK: [[CB]]:
; CHECK-NEXT: callbr void asm "", "!i"()
; CHECK-NEXT: to label %[[EXIT:.*]] [label %cb.target.l1]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[GUARD_L2:%.*]] = phi i1 [ true, %[[L1]] ], [ [[A_INV]], %[[ENTRY]] ]
; CHECK-NEXT: br i1 [[GUARD_L2]], label %[[L2]], label %[[IRR_GUARD1]]
; CHECK: [[CB_TARGET_L1:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD1]]
; CHECK: [[IRR_GUARD1]]:
; CHECK-NEXT: [[GUARD_L1:%.*]] = phi i1 [ true, %[[CB_TARGET_L1]] ], [ true, %[[IRR_GUARD]] ], [ [[C_INV]], %[[L2]] ]
; CHECK-NEXT: br i1 [[GUARD_L1]], label %[[L1]], label %[[CB]]
;
entry:
br i1 %a, label %l1, label %l2
l1:
br i1 %b, label %cb, label %l2
l2:
br i1 %c, label %cb, label %l1
cb:
callbr void asm "", "!i"() to label %exit [label %l1]
exit:
ret void
}
define void @callbr_exit_with_separate_entries1(i1 %a, i1 %b) {
; CHECK-LABEL: define void @callbr_exit_with_separate_entries1(
; CHECK-SAME: i1 [[A:%.*]], i1 [[B:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[A_INV:%.*]] = xor i1 [[A]], true
; CHECK-NEXT: br label %[[IRR_GUARD:.*]]
; CHECK: [[LOOP1:.*]]:
; CHECK-NEXT: br i1 [[B]], label %[[CB:.*]], label %[[IRR_GUARD]]
; CHECK: [[LOOP2:.*]]:
; CHECK-NEXT: br label %[[LOOP1]]
; CHECK: [[CB]]:
; CHECK-NEXT: callbr void asm "", "!i"()
; CHECK-NEXT: to label %[[EXIT:.*]] [label %cb.target.loop2]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
; CHECK: [[CB_TARGET_LOOP2:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[GUARD_LOOP2:%.*]] = phi i1 [ true, %[[CB_TARGET_LOOP2]] ], [ true, %[[LOOP1]] ], [ [[A_INV]], %[[ENTRY]] ]
; CHECK-NEXT: br i1 [[GUARD_LOOP2]], label %[[LOOP2]], label %[[LOOP1]]
;
entry:
br i1 %a, label %loop1, label %loop2
loop1:
br i1 %b, label %cb, label %loop2
loop2:
br label %loop1
cb:
callbr void asm "", "!i"() to label %exit [label %loop2]
exit:
ret void
}
; Irreducible loop: all blocks are callbrs, with cross-edges
define void @callbr_only_multiple(i1 %a, i1 %b, i1 %c) {
; CHECK-LABEL: define void @callbr_only_multiple(
; CHECK-SAME: i1 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: callbr void asm "", "!i,!i"()
; CHECK-NEXT: to label %[[ENTRY_TARGET_CB1:.*]] [label %[[ENTRY_TARGET_CB2:.*]], label %entry.target.cb3]
; CHECK: [[CB1:.*]]:
; CHECK-NEXT: callbr void asm "", "!i"()
; CHECK-NEXT: to label %[[CB2:.*]] [label %cb1.target.cb3]
; CHECK: [[CB2]]:
; CHECK-NEXT: callbr void asm "", "!i"()
; CHECK-NEXT: to label %[[CB2_TARGET_CB3:.*]] [label %cb2.target.cb1]
; CHECK: [[CB3:.*]]:
; CHECK-NEXT: callbr void asm "", "!i"()
; CHECK-NEXT: to label %[[CB3_TARGET_CB1:.*]] [label %exit]
; CHECK: [[EXIT:.*:]]
; CHECK-NEXT: ret void
; CHECK: [[CB2_TARGET_CB3]]:
; CHECK-NEXT: br label %[[IRR_GUARD:.*]]
; CHECK: [[CB1_TARGET_CB3:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[ENTRY_TARGET_CB1]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[ENTRY_TARGET_CB2]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[ENTRY_TARGET_CB3:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[GUARD_CB3:%.*]] = phi i1 [ true, %[[CB2_TARGET_CB3]] ], [ true, %[[CB1_TARGET_CB3]] ], [ false, %[[ENTRY_TARGET_CB1]] ], [ false, %[[ENTRY_TARGET_CB2]] ], [ true, %[[ENTRY_TARGET_CB3]] ]
; CHECK-NEXT: [[GUARD_CB1:%.*]] = phi i1 [ false, %[[CB2_TARGET_CB3]] ], [ false, %[[CB1_TARGET_CB3]] ], [ true, %[[ENTRY_TARGET_CB1]] ], [ false, %[[ENTRY_TARGET_CB2]] ], [ false, %[[ENTRY_TARGET_CB3]] ]
; CHECK-NEXT: br i1 [[GUARD_CB3]], label %[[CB3]], label %[[IRR_GUARD1:.*]]
; CHECK: [[IRR_GUARD1]]:
; CHECK-NEXT: br label %[[IRR_GUARD2:.*]]
; CHECK: [[CB2_TARGET_CB1:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD2]]
; CHECK: [[CB3_TARGET_CB1]]:
; CHECK-NEXT: br label %[[IRR_GUARD2]]
; CHECK: [[IRR_GUARD2]]:
; CHECK-NEXT: [[GUARD_CB13:%.*]] = phi i1 [ true, %[[CB2_TARGET_CB1]] ], [ [[GUARD_CB1]], %[[IRR_GUARD1]] ], [ true, %[[CB3_TARGET_CB1]] ]
; CHECK-NEXT: br i1 [[GUARD_CB13]], label %[[CB1]], label %[[CB2]]
;
entry:
callbr void asm "", "!i,!i"() to label %cb1 [label %cb2, label %cb3]
cb1:
callbr void asm "", "!i"() to label %cb2 [label %cb3]
cb2:
callbr void asm "", "!i"() to label %cb3 [label %cb1]
cb3:
callbr void asm "", "!i"() to label %cb1 [label %exit]
exit:
ret void
}
; Irreducible loop: callbr as a "bypass" block
define void @callbr_bypass(i1 %a, i1 %b, i1 %c) {
; CHECK-LABEL: define void @callbr_bypass(
; CHECK-SAME: i1 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[B_INV:%.*]] = xor i1 [[B]], true
; CHECK-NEXT: [[A_INV:%.*]] = xor i1 [[A]], true
; CHECK-NEXT: br label %[[IRR_GUARD:.*]]
; CHECK: [[CB:.*]]:
; CHECK-NEXT: callbr void asm "", "!i"()
; CHECK-NEXT: to label %[[L2:.*]] [label %cb.target.l1]
; CHECK: [[L1:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD1:.*]]
; CHECK: [[L2]]:
; CHECK-NEXT: br i1 [[C]], label %[[IRR_GUARD1]], label %[[EXIT:.*]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
; CHECK: [[CB_TARGET_L1:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[GUARD_L1:%.*]] = phi i1 [ true, %[[CB_TARGET_L1]] ], [ [[A_INV]], %[[ENTRY]] ]
; CHECK-NEXT: br i1 [[GUARD_L1]], label %[[L1]], label %[[IRR_GUARD1]]
; CHECK: [[IRR_GUARD1]]:
; CHECK-NEXT: [[GUARD_CB:%.*]] = phi i1 [ true, %[[L2]] ], [ true, %[[IRR_GUARD]] ], [ [[B_INV]], %[[L1]] ]
; CHECK-NEXT: br i1 [[GUARD_CB]], label %[[CB]], label %[[L2]]
;
entry:
br i1 %a, label %cb, label %l1
cb:
callbr void asm "", "!i"() to label %l2 [label %l1]
l1:
br i1 %b, label %l2, label %cb
l2:
br i1 %c, label %cb, label %exit
exit:
ret void
}
; Irreducible loop: callbr with multiple indirect targets, some looping, some exiting
define void @callbr_multiple_with_exit(i1 %a, i1 %b, i1 %c) {
; CHECK-LABEL: define void @callbr_multiple_with_exit(
; CHECK-SAME: i1 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: callbr void asm "", "!i,!i,!i"()
; CHECK-NEXT: to label %[[ENTRY_TARGET_L1:.*]] [label %[[ENTRY_TARGET_L2:.*]], label %[[EXIT:.*]], label %entry.target.l3]
; CHECK: [[L1:.*]]:
; CHECK-NEXT: br i1 [[A]], label %[[L2:.*]], label %[[IRR_GUARD:.*]]
; CHECK: [[L2]]:
; CHECK-NEXT: br i1 [[B]], label %[[IRR_GUARD2:.*]], label %[[EXIT]]
; CHECK: [[L3:.*]]:
; CHECK-NEXT: br i1 [[C]], label %[[IRR_GUARD2]], label %[[EXIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
; CHECK: [[ENTRY_TARGET_L1]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[ENTRY_TARGET_L2]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[ENTRY_TARGET_L3:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[GUARD_L3:%.*]] = phi i1 [ true, %[[L1]] ], [ false, %[[ENTRY_TARGET_L1]] ], [ false, %[[ENTRY_TARGET_L2]] ], [ true, %[[ENTRY_TARGET_L3]] ]
; CHECK-NEXT: [[GUARD_L1:%.*]] = phi i1 [ false, %[[L1]] ], [ true, %[[ENTRY_TARGET_L1]] ], [ false, %[[ENTRY_TARGET_L2]] ], [ false, %[[ENTRY_TARGET_L3]] ]
; CHECK-NEXT: br i1 [[GUARD_L3]], label %[[L3]], label %[[IRR_GUARD1:.*]]
; CHECK: [[IRR_GUARD1]]:
; CHECK-NEXT: br label %[[IRR_GUARD2]]
; CHECK: [[IRR_GUARD2]]:
; CHECK-NEXT: [[GUARD_L13:%.*]] = phi i1 [ true, %[[L2]] ], [ [[GUARD_L1]], %[[IRR_GUARD1]] ], [ true, %[[L3]] ]
; CHECK-NEXT: br i1 [[GUARD_L13]], label %[[L1]], label %[[L2]]
;
entry:
callbr void asm "", "!i,!i,!i"() to label %l1 [label %l2, label %exit, label %l3]
l1:
br i1 %a, label %l2, label %l3
l2:
br i1 %b, label %l1, label %exit
l3:
br i1 %c, label %l1, label %exit
exit:
ret void
}
define void @callbr_nested(i1 %c, i1 %d) {
; CHECK-LABEL: define void @callbr_nested(
; CHECK-SAME: i1 [[C:%.*]], i1 [[D:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: callbr void asm "", "!i"()
; CHECK-NEXT: to label %[[ENTRY_TARGET_H:.*]] [label %entry.target.b]
; CHECK: [[H:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD1:.*]]
; CHECK: [[B:.*]]:
; CHECK-NEXT: callbr void asm "", "!i,!i"()
; CHECK-NEXT: to label %[[H]] [label %[[B_TARGET_BH:.*]], label %b.target.bb]
; CHECK: [[BH:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD:.*]]
; CHECK: [[BB:.*]]:
; CHECK-NEXT: br i1 [[C]], label %[[BH]], label %[[RET:.*]]
; CHECK: [[RET]]:
; CHECK-NEXT: ret void
; CHECK: [[B_TARGET_BH]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[B_TARGET_BB:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD]]
; CHECK: [[IRR_GUARD]]:
; CHECK-NEXT: [[GUARD_BB:%.*]] = phi i1 [ true, %[[BH]] ], [ false, %[[B_TARGET_BH]] ], [ true, %[[B_TARGET_BB]] ]
; CHECK-NEXT: br i1 [[GUARD_BB]], label %[[BB]], label %[[BH]]
; CHECK: [[ENTRY_TARGET_H]]:
; CHECK-NEXT: br label %[[IRR_GUARD1]]
; CHECK: [[ENTRY_TARGET_B:.*]]:
; CHECK-NEXT: br label %[[IRR_GUARD1]]
; CHECK: [[IRR_GUARD1]]:
; CHECK-NEXT: [[GUARD_B:%.*]] = phi i1 [ true, %[[H]] ], [ false, %[[ENTRY_TARGET_H]] ], [ true, %[[ENTRY_TARGET_B]] ]
; CHECK-NEXT: br i1 [[GUARD_B]], label %[[B]], label %[[H]]
;
entry:
callbr void asm "","!i"() to label %h [label %b]
h:
br label %b
b:
callbr void asm "","!i,!i"() to label %h [label %bh, label %bb]
bh:
br label %bb
bb:
br i1 %c, label %bh, label %ret
ret:
ret void
}
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; LOOPS-AFTER: {{.*}}
; LOOPS-BEFORE: {{.*}}