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 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
|
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -unify-loop-exits -structurizecfg -S | FileCheck %s
; The structurizer uses an RPO traversal over a region, along with a
; manual hack that is meant to sort ensure that blocks within a loop
; are all visited before visiting blocks outside the loop. But this
; does not always work as expected. For example the results are
; incorrect when multiple nested loops are involved.
; The workaround for this is to unify loop exits. Each loop now
; becomes an SESE region with a single header and a single exit. The
; structurizer is a region pass, and it no longer sees the entire loop
; nest in a single region. More importantly, for each loop, the only
; block reachable outside the loop is the region exit, which avoids
; any confusion in the hacked RPO traversal.
; In the function below, B1 is an exiting block in outer loop H1. It's
; successor inside the loop is the header of another loop H2. Due to
; the incorrect traversal, B1 dominates all the blocks in the
; structurized program, except the header H1.
define void @exiting-block(i1 %PredH1, i1 %PredB2, i1 %PredB1, i1 %PredH2) {
; CHECK-LABEL: @exiting-block(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[PREDH1_INV:%.*]] = xor i1 [[PREDH1:%.*]], true
; CHECK-NEXT: [[PREDB2_INV:%.*]] = xor i1 [[PREDB2:%.*]], true
; CHECK-NEXT: br label [[H1:%.*]]
; CHECK: H1:
; CHECK-NEXT: br i1 [[PREDH1_INV]], label [[B1:%.*]], label [[FLOW3:%.*]]
; CHECK: Flow3:
; CHECK-NEXT: [[TMP0:%.*]] = phi i1 [ true, [[B1]] ], [ undef, [[H1]] ]
; CHECK-NEXT: [[TMP1:%.*]] = phi i1 [ [[PREDB1:%.*]], [[B1]] ], [ [[PREDH1]], [[H1]] ]
; CHECK-NEXT: br i1 [[TMP1]], label [[H2:%.*]], label [[FLOW4:%.*]]
; CHECK: H2:
; CHECK-NEXT: br i1 [[PREDH2:%.*]], label [[B2:%.*]], label [[FLOW:%.*]]
; CHECK: B2:
; CHECK-NEXT: br i1 [[PREDB2_INV]], label [[L2:%.*]], label [[FLOW2:%.*]]
; CHECK: Flow:
; CHECK-NEXT: [[TMP2:%.*]] = phi i1 [ false, [[FLOW2]] ], [ true, [[H2]] ]
; CHECK-NEXT: [[TMP3:%.*]] = phi i1 [ false, [[FLOW2]] ], [ undef, [[H2]] ]
; CHECK-NEXT: [[TMP4:%.*]] = phi i1 [ [[TMP7:%.*]], [[FLOW2]] ], [ true, [[H2]] ]
; CHECK-NEXT: br i1 [[TMP4]], label [[LOOP_EXIT_GUARD1:%.*]], label [[H2]]
; CHECK: L2:
; CHECK-NEXT: br label [[FLOW2]]
; CHECK: L1:
; CHECK-NEXT: br label [[FLOW5:%.*]]
; CHECK: B1:
; CHECK-NEXT: br label [[FLOW3]]
; CHECK: C:
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
; CHECK: Flow5:
; CHECK-NEXT: [[TMP5:%.*]] = phi i1 [ undef, [[L1:%.*]] ], [ [[TMP3]], [[LOOP_EXIT_GUARD1]] ]
; CHECK-NEXT: [[TMP6:%.*]] = phi i1 [ false, [[L1]] ], [ true, [[LOOP_EXIT_GUARD1]] ]
; CHECK-NEXT: br label [[FLOW4]]
; CHECK: loop.exit.guard:
; CHECK-NEXT: br i1 [[TMP8:%.*]], label [[C:%.*]], label [[EXIT]]
; CHECK: Flow2:
; CHECK-NEXT: [[TMP7]] = phi i1 [ false, [[L2]] ], [ true, [[B2]] ]
; CHECK-NEXT: br label [[FLOW]]
; CHECK: Flow4:
; CHECK-NEXT: [[TMP8]] = phi i1 [ [[TMP5]], [[FLOW5]] ], [ [[TMP0]], [[FLOW3]] ]
; CHECK-NEXT: [[TMP9:%.*]] = phi i1 [ [[TMP6]], [[FLOW5]] ], [ true, [[FLOW3]] ]
; CHECK-NEXT: br i1 [[TMP9]], label [[LOOP_EXIT_GUARD:%.*]], label [[H1]]
; CHECK: loop.exit.guard1:
; CHECK-NEXT: br i1 [[TMP2]], label [[L1]], label [[FLOW5]]
;
entry:
br label %H1
H1: ; preds = %L1, %entry
br i1 %PredH1, label %H2, label %B1
H2: ; preds = %B1, %L2, %H1
br i1 %PredH2, label %B2, label %L1
B2: ; preds = %H2
br i1 %PredB2, label %exit, label %L2
L2: ; preds = %B2
br label %H2
L1: ; preds = %H2
br label %H1
B1: ; preds = %H1
br i1 %PredB1, label %H2, label %C
C: ; preds = %B1
br label %exit
exit: ; preds = %C, %B2
ret void
}
; The function below has three nested loops. Due to the incorrect
; traversal, H2 dominates H3 in the structurized program, and the
; backedge from L13 to H3 has no equivalent path.
define void @incorrect-backedge(i1 %PredH2, i1 %PredH3, i1 %PredL2, i1 %PredL13, i1 %PredL1)
; CHECK-LABEL: @incorrect-backedge(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[PREDH2_INV:%.*]] = xor i1 [[PREDH2:%.*]], true
; CHECK-NEXT: [[PREDL2_INV:%.*]] = xor i1 [[PREDL2:%.*]], true
; CHECK-NEXT: [[PREDH3_INV:%.*]] = xor i1 [[PREDH3:%.*]], true
; CHECK-NEXT: [[PREDL13_INV:%.*]] = xor i1 [[PREDL13:%.*]], true
; CHECK-NEXT: br label [[H1:%.*]]
; CHECK: H1:
; CHECK-NEXT: br label [[H2:%.*]]
; CHECK: H2:
; CHECK-NEXT: br i1 [[PREDH2_INV]], label [[H3:%.*]], label [[FLOW4:%.*]]
; CHECK: H3:
; CHECK-NEXT: br i1 [[PREDH3_INV]], label [[L2:%.*]], label [[FLOW:%.*]]
; CHECK: L2:
; CHECK-NEXT: br i1 [[PREDL2_INV]], label [[L13:%.*]], label [[FLOW3:%.*]]
; CHECK: Flow:
; CHECK-NEXT: [[TMP0:%.*]] = phi i1 [ [[TMP7:%.*]], [[FLOW3]] ], [ true, [[H3]] ]
; CHECK-NEXT: [[TMP1:%.*]] = phi i1 [ [[TMP8:%.*]], [[FLOW3]] ], [ false, [[H3]] ]
; CHECK-NEXT: [[TMP2:%.*]] = phi i1 [ [[TMP8]], [[FLOW3]] ], [ true, [[H3]] ]
; CHECK-NEXT: [[TMP3:%.*]] = phi i1 [ [[TMP9:%.*]], [[FLOW3]] ], [ true, [[H3]] ]
; CHECK-NEXT: br i1 [[TMP3]], label [[LOOP_EXIT_GUARD2:%.*]], label [[H3]]
; CHECK: L13:
; CHECK-NEXT: br label [[FLOW3]]
; CHECK: Flow5:
; CHECK-NEXT: [[TMP4:%.*]] = phi i1 [ [[TMP10:%.*]], [[LOOP_EXIT_GUARD1:%.*]] ], [ true, [[LOOP_EXIT_GUARD:%.*]] ]
; CHECK-NEXT: [[TMP5:%.*]] = phi i1 [ false, [[LOOP_EXIT_GUARD1]] ], [ true, [[LOOP_EXIT_GUARD]] ]
; CHECK-NEXT: br i1 [[TMP5]], label [[L1:%.*]], label [[FLOW6:%.*]]
; CHECK: L1:
; CHECK-NEXT: br label [[FLOW6]]
; CHECK: Flow6:
; CHECK-NEXT: [[TMP6:%.*]] = phi i1 [ [[PREDL1:%.*]], [[L1]] ], [ [[TMP4]], [[FLOW5:%.*]] ]
; CHECK-NEXT: br i1 [[TMP6]], label [[EXIT:%.*]], label [[H1]]
; CHECK: exit:
; CHECK-NEXT: ret void
; CHECK: loop.exit.guard:
; CHECK-NEXT: br i1 [[DOTINV:%.*]], label [[LOOP_EXIT_GUARD1]], label [[FLOW5]]
; CHECK: loop.exit.guard1:
; CHECK-NEXT: br label [[FLOW5]]
; CHECK: Flow3:
; CHECK-NEXT: [[TMP7]] = phi i1 [ true, [[L13]] ], [ false, [[L2]] ]
; CHECK-NEXT: [[TMP8]] = phi i1 [ false, [[L13]] ], [ undef, [[L2]] ]
; CHECK-NEXT: [[TMP9]] = phi i1 [ [[PREDL13_INV]], [[L13]] ], [ true, [[L2]] ]
; CHECK-NEXT: br label [[FLOW]]
; CHECK: Flow4:
; CHECK-NEXT: [[TMP10]] = phi i1 [ [[TMP2]], [[LOOP_EXIT_GUARD2]] ], [ false, [[H2]] ]
; CHECK-NEXT: [[TMP11:%.*]] = phi i1 [ [[TMP1]], [[LOOP_EXIT_GUARD2]] ], [ true, [[H2]] ]
; CHECK-NEXT: [[TMP12:%.*]] = phi i1 [ [[TMP0]], [[LOOP_EXIT_GUARD2]] ], [ true, [[H2]] ]
; CHECK-NEXT: [[DOTINV]] = xor i1 [[TMP11]], true
; CHECK-NEXT: br i1 [[TMP12]], label [[LOOP_EXIT_GUARD]], label [[H2]]
; CHECK: loop.exit.guard2:
; CHECK-NEXT: br label [[FLOW4]]
;
{
entry:
br label %H1
H1:
br label %H2
H2:
br i1 %PredH2, label %L1, label %H3
H3:
br i1 %PredH3, label %exit, label %L2
L2:
br i1 %PredL2, label %H2, label %L13
L13:
br i1 %PredL13, label %H3, label %H1
L1:
br i1 %PredL1, label %exit, label %H1
exit:
ret void
}
|