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
870 lines
38 KiB
LLVM
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: {{.*}}
|