Sameer Sahasrabuddhe | 3cbbded | 2020-03-28 07:13:35 -0400 | [diff] [blame] | 1 | ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
Arthur Eubanks | 89df0fd | 2020-09-21 16:52:07 -0700 | [diff] [blame] | 2 | ; RUN: opt < %s -unify-loop-exits -enable-new-pm=0 -S | FileCheck %s |
Ta-Wei Tu | 529ecd1 | 2020-10-20 10:41:38 -0700 | [diff] [blame] | 3 | ; RUN: opt < %s -passes='lowerswitch,unify-loop-exits' -S | FileCheck %s |
Sameer Sahasrabuddhe | 3cbbded | 2020-03-28 07:13:35 -0400 | [diff] [blame] | 4 | |
| 5 | ; Loop consists of A and B: |
| 6 | ; - A is the header |
| 7 | ; - A and B are exiting blocks |
| 8 | ; - C and return are exit blocks. |
| 9 | ; Pattern: Value (%mytmp42) defined in exiting block (A) and used in |
| 10 | ; exit block (return). |
| 11 | ; The relevant code uses DT::dominates(Value, |
| 12 | ; BasicBlock). This is misnamed because it actually checks |
| 13 | ; strict dominance, causing the pattern to be miscompiled |
| 14 | ; (the use receives an undef value). |
| 15 | define i32 @exiting-used-in-exit(i32* %arg1, i32* %arg2) local_unnamed_addr align 2 { |
| 16 | ; CHECK-LABEL: @exiting-used-in-exit( |
| 17 | ; CHECK-NEXT: entry: |
| 18 | ; CHECK-NEXT: br label [[A:%.*]] |
| 19 | ; CHECK: A: |
| 20 | ; CHECK-NEXT: [[MYTMP42:%.*]] = load i32, i32* [[ARG1:%.*]], align 4 |
| 21 | ; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0 |
| 22 | ; CHECK-NEXT: br i1 [[CMP1]], label [[B:%.*]], label [[LOOP_EXIT_GUARD:%.*]] |
| 23 | ; CHECK: B: |
| 24 | ; CHECK-NEXT: [[MYTMP41:%.*]] = load i32, i32* [[ARG2:%.*]], align 4 |
| 25 | ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[MYTMP41]], 0 |
| 26 | ; CHECK-NEXT: br i1 [[CMP]], label [[A]], label [[LOOP_EXIT_GUARD]] |
| 27 | ; CHECK: C: |
| 28 | ; CHECK-NEXT: [[INC:%.*]] = add i32 [[MYTMP41_MOVED:%.*]], 1 |
| 29 | ; CHECK-NEXT: br label [[RETURN:%.*]] |
| 30 | ; CHECK: return: |
| 31 | ; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[INC]], [[C:%.*]] ], [ [[PHI_MOVED:%.*]], [[LOOP_EXIT_GUARD]] ] |
| 32 | ; CHECK-NEXT: ret i32 [[PHI]] |
| 33 | ; CHECK: loop.exit.guard: |
| 34 | ; CHECK-NEXT: [[GUARD_RETURN:%.*]] = phi i1 [ true, [[A]] ], [ false, [[B]] ] |
| 35 | ; CHECK-NEXT: [[PHI_MOVED]] = phi i32 [ [[MYTMP42]], [[A]] ], [ undef, [[B]] ] |
| 36 | ; CHECK-NEXT: [[MYTMP41_MOVED]] = phi i32 [ undef, [[A]] ], [ [[MYTMP41]], [[B]] ] |
| 37 | ; CHECK-NEXT: br i1 [[GUARD_RETURN]], label [[RETURN]], label [[C]] |
| 38 | ; |
| 39 | entry: |
| 40 | br label %A |
| 41 | |
| 42 | A: |
| 43 | %mytmp42 = load i32, i32* %arg1, align 4 |
| 44 | %cmp1 = icmp slt i32 %mytmp42, 0 |
| 45 | br i1 %cmp1, label %B, label %return |
| 46 | |
| 47 | B: |
| 48 | %mytmp41 = load i32, i32* %arg2, align 4 |
| 49 | %cmp = icmp slt i32 %mytmp41, 0 |
| 50 | br i1 %cmp, label %A, label %C |
| 51 | |
| 52 | C: |
| 53 | %inc = add i32 %mytmp41, 1 |
| 54 | br label %return |
| 55 | |
| 56 | return: |
| 57 | %phi = phi i32 [ %inc, %C ], [ %mytmp42, %A ] |
| 58 | ret i32 %phi |
| 59 | } |
| 60 | |
| 61 | ; Loop consists of A, B and C: |
| 62 | ; - A is the header |
| 63 | ; - A and C are exiting blocks |
| 64 | ; - B is an "internal" block that dominates exiting block C |
| 65 | ; - D and return are exit blocks. |
| 66 | ; Pattern: Value (%mytmp41) defined in internal block (B) and used in an |
| 67 | ; exit block (D). |
| 68 | define i32 @internal-used-in-exit(i32* %arg1, i32* %arg2) local_unnamed_addr align 2 { |
| 69 | ; CHECK-LABEL: @internal-used-in-exit( |
| 70 | ; CHECK-NEXT: entry: |
| 71 | ; CHECK-NEXT: [[MYTMP42:%.*]] = load i32, i32* [[ARG1:%.*]], align 4 |
| 72 | ; CHECK-NEXT: br label [[A:%.*]] |
| 73 | ; CHECK: A: |
| 74 | ; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0 |
| 75 | ; CHECK-NEXT: br i1 [[CMP1]], label [[B:%.*]], label [[LOOP_EXIT_GUARD:%.*]] |
| 76 | ; CHECK: B: |
| 77 | ; CHECK-NEXT: [[MYTMP41:%.*]] = load i32, i32* [[ARG2:%.*]], align 4 |
| 78 | ; CHECK-NEXT: br label [[C:%.*]] |
| 79 | ; CHECK: C: |
| 80 | ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[MYTMP42]], 0 |
| 81 | ; CHECK-NEXT: br i1 [[CMP]], label [[A]], label [[LOOP_EXIT_GUARD]] |
| 82 | ; CHECK: D: |
| 83 | ; CHECK-NEXT: [[INC:%.*]] = add i32 [[MYTMP41_MOVED:%.*]], 1 |
| 84 | ; CHECK-NEXT: br label [[RETURN:%.*]] |
| 85 | ; CHECK: return: |
| 86 | ; CHECK-NEXT: ret i32 0 |
| 87 | ; CHECK: loop.exit.guard: |
| 88 | ; CHECK-NEXT: [[GUARD_RETURN:%.*]] = phi i1 [ true, [[A]] ], [ false, [[C]] ] |
| 89 | ; CHECK-NEXT: [[MYTMP41_MOVED]] = phi i32 [ undef, [[A]] ], [ [[MYTMP41]], [[C]] ] |
| 90 | ; CHECK-NEXT: br i1 [[GUARD_RETURN]], label [[RETURN]], label [[D:%.*]] |
| 91 | ; |
| 92 | entry: |
| 93 | %mytmp42 = load i32, i32* %arg1, align 4 |
| 94 | br label %A |
| 95 | |
| 96 | A: |
| 97 | %cmp1 = icmp slt i32 %mytmp42, 0 |
| 98 | br i1 %cmp1, label %B, label %return |
| 99 | |
| 100 | B: |
| 101 | %mytmp41 = load i32, i32* %arg2, align 4 |
| 102 | br label %C |
| 103 | |
| 104 | C: |
| 105 | %cmp = icmp slt i32 %mytmp42, 0 |
| 106 | br i1 %cmp, label %A, label %D |
| 107 | |
| 108 | D: |
| 109 | %inc = add i32 %mytmp41, 1 |
| 110 | br label %return |
| 111 | |
| 112 | return: |
| 113 | ret i32 0 |
| 114 | } |
| 115 | |
| 116 | ; Loop consists of A, B and C: |
| 117 | ; - A is the header |
| 118 | ; - A and C are exiting blocks |
| 119 | ; - B is an "internal" block that dominates exiting block C |
| 120 | ; - D and return are exit blocks. |
| 121 | ; Pattern: %return contains a phi node that receives values from |
| 122 | ; %entry, %A and %D. This mixes all the special cases in a single phi. |
| 123 | define i32 @mixed-use-in-exit(i32* %arg1, i32* %arg2) local_unnamed_addr align 2 { |
| 124 | ; CHECK-LABEL: @mixed-use-in-exit( |
| 125 | ; CHECK-NEXT: entry: |
| 126 | ; CHECK-NEXT: [[MYTMP42:%.*]] = load i32, i32* [[ARG1:%.*]], align 4 |
| 127 | ; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[MYTMP42]], 0 |
| 128 | ; CHECK-NEXT: br i1 [[CMP2]], label [[A:%.*]], label [[RETURN:%.*]] |
| 129 | ; CHECK: A: |
| 130 | ; CHECK-NEXT: [[MYTMP43:%.*]] = add i32 [[MYTMP42]], 1 |
| 131 | ; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0 |
| 132 | ; CHECK-NEXT: br i1 [[CMP1]], label [[B:%.*]], label [[LOOP_EXIT_GUARD:%.*]] |
| 133 | ; CHECK: B: |
| 134 | ; CHECK-NEXT: [[MYTMP41:%.*]] = load i32, i32* [[ARG2:%.*]], align 4 |
| 135 | ; CHECK-NEXT: br label [[C:%.*]] |
| 136 | ; CHECK: C: |
| 137 | ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[MYTMP42]], 0 |
| 138 | ; CHECK-NEXT: br i1 [[CMP]], label [[A]], label [[LOOP_EXIT_GUARD]] |
| 139 | ; CHECK: D: |
| 140 | ; CHECK-NEXT: br label [[RETURN]] |
| 141 | ; CHECK: return: |
| 142 | ; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[MYTMP41_MOVED:%.*]], [[D:%.*]] ], [ [[MYTMP42]], [[ENTRY:%.*]] ], [ [[PHI_MOVED:%.*]], [[LOOP_EXIT_GUARD]] ] |
| 143 | ; CHECK-NEXT: ret i32 [[PHI]] |
| 144 | ; CHECK: loop.exit.guard: |
| 145 | ; CHECK-NEXT: [[GUARD_RETURN:%.*]] = phi i1 [ true, [[A]] ], [ false, [[C]] ] |
| 146 | ; CHECK-NEXT: [[PHI_MOVED]] = phi i32 [ [[MYTMP43]], [[A]] ], [ undef, [[C]] ] |
| 147 | ; CHECK-NEXT: [[MYTMP41_MOVED]] = phi i32 [ undef, [[A]] ], [ [[MYTMP41]], [[C]] ] |
| 148 | ; CHECK-NEXT: br i1 [[GUARD_RETURN]], label [[RETURN]], label [[D]] |
| 149 | ; |
| 150 | entry: |
| 151 | %mytmp42 = load i32, i32* %arg1, align 4 |
| 152 | %cmp2 = icmp slt i32 %mytmp42, 0 |
| 153 | br i1 %cmp2, label %A, label %return |
| 154 | |
| 155 | A: |
| 156 | %mytmp43 = add i32 %mytmp42, 1 |
| 157 | %cmp1 = icmp slt i32 %mytmp42, 0 |
| 158 | br i1 %cmp1, label %B, label %return |
| 159 | |
| 160 | B: |
| 161 | %mytmp41 = load i32, i32* %arg2, align 4 |
| 162 | br label %C |
| 163 | |
| 164 | C: |
| 165 | %cmp = icmp slt i32 %mytmp42, 0 |
| 166 | br i1 %cmp, label %A, label %D |
| 167 | |
| 168 | D: |
| 169 | br label %return |
| 170 | |
| 171 | return: |
| 172 | %phi = phi i32 [ %mytmp41, %D ], [ %mytmp43, %A ], [%mytmp42, %entry] |
| 173 | ret i32 %phi |
| 174 | } |
| 175 | |
| 176 | ; Loop consists of A, B and C: |
| 177 | ; - A is the header |
| 178 | ; - A and C are exiting blocks |
| 179 | ; - B is an "internal" block that dominates exiting block C |
| 180 | ; - D and E are exit blocks. |
| 181 | ; Pattern: Value (%mytmp41) defined in internal block (B) and used in a |
| 182 | ; downstream block not related to the loop (return). The use |
| 183 | ; is a phi where the incoming block for %mytmp41 is not related |
| 184 | ; to the loop (D). |
| 185 | ; This pattern does not involve either the exiting blocks or |
| 186 | ; the exit blocks, which catches any such assumptions built |
| 187 | ; into the SSA reconstruction phase. |
| 188 | define i32 @phi-via-external-block(i32* %arg1, i32* %arg2) local_unnamed_addr align 2 { |
| 189 | ; CHECK-LABEL: @phi-via-external-block( |
| 190 | ; CHECK-NEXT: entry: |
| 191 | ; CHECK-NEXT: [[MYTMP42:%.*]] = load i32, i32* [[ARG1:%.*]], align 4 |
| 192 | ; CHECK-NEXT: br label [[A:%.*]] |
| 193 | ; CHECK: A: |
| 194 | ; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0 |
| 195 | ; CHECK-NEXT: br i1 [[CMP1]], label [[B:%.*]], label [[LOOP_EXIT_GUARD:%.*]] |
| 196 | ; CHECK: B: |
| 197 | ; CHECK-NEXT: [[MYTMP41:%.*]] = load i32, i32* [[ARG2:%.*]], align 4 |
| 198 | ; CHECK-NEXT: br label [[C:%.*]] |
| 199 | ; CHECK: C: |
| 200 | ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[MYTMP42]], 0 |
| 201 | ; CHECK-NEXT: br i1 [[CMP]], label [[A]], label [[LOOP_EXIT_GUARD]] |
| 202 | ; CHECK: D: |
| 203 | ; CHECK-NEXT: br label [[RETURN:%.*]] |
| 204 | ; CHECK: E: |
| 205 | ; CHECK-NEXT: br label [[RETURN]] |
| 206 | ; CHECK: return: |
| 207 | ; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[MYTMP41_MOVED:%.*]], [[D:%.*]] ], [ [[MYTMP42]], [[E:%.*]] ] |
| 208 | ; CHECK-NEXT: ret i32 [[PHI]] |
| 209 | ; CHECK: loop.exit.guard: |
| 210 | ; CHECK-NEXT: [[GUARD_E:%.*]] = phi i1 [ true, [[A]] ], [ false, [[C]] ] |
| 211 | ; CHECK-NEXT: [[MYTMP41_MOVED]] = phi i32 [ undef, [[A]] ], [ [[MYTMP41]], [[C]] ] |
| 212 | ; CHECK-NEXT: br i1 [[GUARD_E]], label [[E]], label [[D]] |
| 213 | ; |
| 214 | entry: |
| 215 | %mytmp42 = load i32, i32* %arg1, align 4 |
| 216 | br label %A |
| 217 | |
| 218 | A: |
| 219 | %cmp1 = icmp slt i32 %mytmp42, 0 |
| 220 | br i1 %cmp1, label %B, label %E |
| 221 | |
| 222 | B: |
| 223 | %mytmp41 = load i32, i32* %arg2, align 4 |
| 224 | br label %C |
| 225 | |
| 226 | C: |
| 227 | %cmp = icmp slt i32 %mytmp42, 0 |
| 228 | br i1 %cmp, label %A, label %D |
| 229 | |
| 230 | D: |
| 231 | br label %return |
| 232 | |
| 233 | E: |
| 234 | br label %return |
| 235 | |
| 236 | return: |
| 237 | %phi = phi i32 [ %mytmp41, %D ], [ %mytmp42, %E ] |
| 238 | ret i32 %phi |
| 239 | } |