1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
; This test checks that nested loops are revisited in various scenarios when
; unrolling. Note that if we ever start doing outer loop peeling a test case
; for that should be added here that will look essentially like a hybrid of the
; current two cases.
;
; RUN: opt < %s -disable-output -debug-pass-manager 2>&1 \
; RUN: -passes='require<opt-remark-emit>,loop(loop-unroll-full)' \
; RUN: | FileCheck %s
;
; Also run in a special mode that visits children.
; RUN: opt < %s -disable-output -debug-pass-manager -unroll-revisit-child-loops 2>&1 \
; RUN: -passes='require<opt-remark-emit>,loop(loop-unroll-full)' \
; RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-CHILDREN
; Basic test is fully unrolled and we revisit the post-unroll new sibling
; loops, including the ones that used to be child loops.
define void @full_unroll(i1* %ptr) {
; CHECK-LABEL: OptimizationRemarkEmitterAnalysis on full_unroll
; CHECK-NOT: LoopFullUnrollPass
entry:
br label %l0
l0:
%cond.0 = load volatile i1, i1* %ptr
br i1 %cond.0, label %l0.0.ph, label %exit
l0.0.ph:
br label %l0.0
l0.0:
%iv = phi i32 [ %iv.next, %l0.0.latch ], [ 0, %l0.0.ph ]
%iv.next = add i32 %iv, 1
br label %l0.0.0.ph
l0.0.0.ph:
br label %l0.0.0
l0.0.0:
%cond.0.0.0 = load volatile i1, i1* %ptr
br i1 %cond.0.0.0, label %l0.0.0, label %l0.0.1.ph
; CHECK: LoopFullUnrollPass on Loop at depth 3 containing: %l0.0.0<header>
; CHECK-NOT: LoopFullUnrollPass
l0.0.1.ph:
br label %l0.0.1
l0.0.1:
%cond.0.0.1 = load volatile i1, i1* %ptr
br i1 %cond.0.0.1, label %l0.0.1, label %l0.0.latch
; CHECK: LoopFullUnrollPass on Loop at depth 3 containing: %l0.0.1<header>
; CHECK-NOT: LoopFullUnrollPass
l0.0.latch:
%cmp = icmp slt i32 %iv.next, 2
br i1 %cmp, label %l0.0, label %l0.latch
; CHECK: LoopFullUnrollPass on Loop at depth 2 containing: %l0.0
; CHECK-NOT: LoopFullUnrollPass
;
; Unrolling occurs, so we visit what were the inner loops twice over. First we
; visit their clones, and then we visit the original loops re-parented.
; CHECK: LoopFullUnrollPass on Loop at depth 2 containing: %l0.0.1.1<header>
; CHECK-NOT: LoopFullUnrollPass
; CHECK: LoopFullUnrollPass on Loop at depth 2 containing: %l0.0.0.1<header>
; CHECK-NOT: LoopFullUnrollPass
; CHECK: LoopFullUnrollPass on Loop at depth 2 containing: %l0.0.1<header>
; CHECK-NOT: LoopFullUnrollPass
; CHECK: LoopFullUnrollPass on Loop at depth 2 containing: %l0.0.0<header>
; CHECK-NOT: LoopFullUnrollPass
l0.latch:
br label %l0
; CHECK: LoopFullUnrollPass on Loop at depth 1 containing: %l0<header>
; CHECK-NOT: LoopFullUnrollPass
exit:
ret void
}
; Now we test forced runtime partial unrolling with metadata. Here we end up
; duplicating child loops without changing their structure and so they aren't by
; default visited, but will be visited with a special parameter.
define void @partial_unroll(i32 %count, i1* %ptr) {
; CHECK-LABEL: OptimizationRemarkEmitterAnalysis on partial_unroll
; CHECK-NOT: LoopFullUnrollPass
entry:
br label %l0
l0:
%cond.0 = load volatile i1, i1* %ptr
br i1 %cond.0, label %l0.0.ph, label %exit
l0.0.ph:
br label %l0.0
l0.0:
%iv = phi i32 [ %iv.next, %l0.0.latch ], [ 0, %l0.0.ph ]
%iv.next = add i32 %iv, 1
br label %l0.0.0.ph
l0.0.0.ph:
br label %l0.0.0
l0.0.0:
%cond.0.0.0 = load volatile i1, i1* %ptr
br i1 %cond.0.0.0, label %l0.0.0, label %l0.0.1.ph
; CHECK: LoopFullUnrollPass on Loop at depth 3 containing: %l0.0.0<header>
; CHECK-NOT: LoopFullUnrollPass
l0.0.1.ph:
br label %l0.0.1
l0.0.1:
%cond.0.0.1 = load volatile i1, i1* %ptr
br i1 %cond.0.0.1, label %l0.0.1, label %l0.0.latch
; CHECK: LoopFullUnrollPass on Loop at depth 3 containing: %l0.0.1<header>
; CHECK-NOT: LoopFullUnrollPass
l0.0.latch:
%cmp = icmp slt i32 %iv.next, %count
br i1 %cmp, label %l0.0, label %l0.latch, !llvm.loop !1
; CHECK: LoopFullUnrollPass on Loop at depth 2 containing: %l0.0
; CHECK-NOT: LoopFullUnrollPass
;
; Partial unrolling occurs which introduces both new child loops and new sibling
; loops. We only visit the child loops in a special mode, not by default.
; CHECK-CHILDREN: LoopFullUnrollPass on Loop at depth 3 containing: %l0.0.0<header>
; CHECK-CHILDREN-NOT: LoopFullUnrollPass
; CHECK-CHILDREN: LoopFullUnrollPass on Loop at depth 3 containing: %l0.0.1<header>
; CHECK-CHILDREN-NOT: LoopFullUnrollPass
; CHECK-CHILDREN: LoopFullUnrollPass on Loop at depth 3 containing: %l0.0.0.1<header>
; CHECK-CHILDREN-NOT: LoopFullUnrollPass
; CHECK-CHILDREN: LoopFullUnrollPass on Loop at depth 3 containing: %l0.0.1.1<header>
; CHECK-CHILDREN-NOT: LoopFullUnrollPass
;
; When we revisit children, we also revisit the current loop.
; CHECK-CHILDREN: LoopFullUnrollPass on Loop at depth 2 containing: %l0.0<header>
; CHECK-CHILDREN-NOT: LoopFullUnrollPass
;
; Revisit the children of the outer loop that are part of the epilogue.
;
; CHECK: LoopFullUnrollPass on Loop at depth 2 containing: %l0.0.1.epil<header>
; CHECK-NOT: LoopFullUnrollPass
; CHECK: LoopFullUnrollPass on Loop at depth 2 containing: %l0.0.0.epil<header>
; CHECK-NOT: LoopFullUnrollPass
l0.latch:
br label %l0
; CHECK: LoopFullUnrollPass on Loop at depth 1 containing: %l0<header>
; CHECK-NOT: LoopFullUnrollPass
exit:
ret void
}
!1 = !{!1, !2}
!2 = !{!"llvm.loop.unroll.count", i32 2}
|