1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -unify-loop-exits -enable-new-pm=0 -S | FileCheck %s 3; RUN: opt < %s -passes='lowerswitch,unify-loop-exits' -S | FileCheck %s 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). 15define 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; 39entry: 40 br label %A 41 42A: 43 %mytmp42 = load i32, i32* %arg1, align 4 44 %cmp1 = icmp slt i32 %mytmp42, 0 45 br i1 %cmp1, label %B, label %return 46 47B: 48 %mytmp41 = load i32, i32* %arg2, align 4 49 %cmp = icmp slt i32 %mytmp41, 0 50 br i1 %cmp, label %A, label %C 51 52C: 53 %inc = add i32 %mytmp41, 1 54 br label %return 55 56return: 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). 68define 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; 92entry: 93 %mytmp42 = load i32, i32* %arg1, align 4 94 br label %A 95 96A: 97 %cmp1 = icmp slt i32 %mytmp42, 0 98 br i1 %cmp1, label %B, label %return 99 100B: 101 %mytmp41 = load i32, i32* %arg2, align 4 102 br label %C 103 104C: 105 %cmp = icmp slt i32 %mytmp42, 0 106 br i1 %cmp, label %A, label %D 107 108D: 109 %inc = add i32 %mytmp41, 1 110 br label %return 111 112return: 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. 123define 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; 150entry: 151 %mytmp42 = load i32, i32* %arg1, align 4 152 %cmp2 = icmp slt i32 %mytmp42, 0 153 br i1 %cmp2, label %A, label %return 154 155A: 156 %mytmp43 = add i32 %mytmp42, 1 157 %cmp1 = icmp slt i32 %mytmp42, 0 158 br i1 %cmp1, label %B, label %return 159 160B: 161 %mytmp41 = load i32, i32* %arg2, align 4 162 br label %C 163 164C: 165 %cmp = icmp slt i32 %mytmp42, 0 166 br i1 %cmp, label %A, label %D 167 168D: 169 br label %return 170 171return: 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. 188define 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; 214entry: 215 %mytmp42 = load i32, i32* %arg1, align 4 216 br label %A 217 218A: 219 %cmp1 = icmp slt i32 %mytmp42, 0 220 br i1 %cmp1, label %B, label %E 221 222B: 223 %mytmp41 = load i32, i32* %arg2, align 4 224 br label %C 225 226C: 227 %cmp = icmp slt i32 %mytmp42, 0 228 br i1 %cmp, label %A, label %D 229 230D: 231 br label %return 232 233E: 234 br label %return 235 236return: 237 %phi = phi i32 [ %mytmp41, %D ], [ %mytmp42, %E ] 238 ret i32 %phi 239} 240