1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -loop-unroll -unroll-runtime -unroll-count=4 -S | FileCheck %s 3; RUN: opt < %s -passes='require<opt-remark-emit>,loop-unroll' -unroll-runtime -unroll-count=4 -S | FileCheck %s 4 5; Check that loop unroll pass correctly handle loops with 6; single exiting block not the loop header or latch. 7 8define void @test1(i32* noalias %A) { 9; CHECK-LABEL: @test1( 10; CHECK-NEXT: entry: 11; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[A:%.*]], align 4 12; CHECK-NEXT: call void @bar(i32 [[TMP0]]) 13; CHECK-NEXT: br label [[FOR_HEADER:%.*]] 14; CHECK: for.header: 15; CHECK-NEXT: call void @bar(i32 [[TMP0]]) 16; CHECK-NEXT: br label [[FOR_BODY:%.*]] 17; CHECK: for.body: 18; CHECK-NEXT: br label [[FOR_BODY_FOR_BODY_CRIT_EDGE:%.*]] 19; CHECK: for.body.for.body_crit_edge: 20; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 1 21; CHECK-NEXT: [[DOTPRE:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT]], align 4 22; CHECK-NEXT: call void @bar(i32 [[DOTPRE]]) 23; CHECK-NEXT: br label [[FOR_BODY_1:%.*]] 24; CHECK: for.body.1: 25; CHECK-NEXT: br label [[FOR_BODY_FOR_BODY_CRIT_EDGE_1:%.*]] 26; CHECK: for.body.for.body_crit_edge.1: 27; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_1:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 2 28; CHECK-NEXT: [[DOTPRE_1:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT_1]], align 4 29; CHECK-NEXT: call void @bar(i32 [[DOTPRE_1]]) 30; CHECK-NEXT: br label [[FOR_BODY_2:%.*]] 31; CHECK: for.body.2: 32; CHECK-NEXT: br label [[FOR_BODY_FOR_BODY_CRIT_EDGE_2:%.*]] 33; CHECK: for.body.for.body_crit_edge.2: 34; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_2:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 3 35; CHECK-NEXT: [[DOTPRE_2:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT_2]], align 4 36; CHECK-NEXT: call void @bar(i32 [[DOTPRE_2]]) 37; CHECK-NEXT: br label [[FOR_BODY_3:%.*]] 38; CHECK: for.body.3: 39; CHECK-NEXT: br i1 false, label [[FOR_BODY_FOR_BODY_CRIT_EDGE_3:%.*]], label [[FOR_END:%.*]] 40; CHECK: for.body.for.body_crit_edge.3: 41; CHECK-NEXT: unreachable 42; CHECK: for.end: 43; CHECK-NEXT: ret void 44; 45entry: 46 %0 = load i32, i32* %A, align 4 47 call void @bar(i32 %0) 48 br label %for.header 49 50for.header: 51 %1 = phi i32 [ %0, %entry ], [ %.pre, %for.body.for.body_crit_edge ] 52 %i = phi i64 [ 0, %entry ], [ %inc, %for.body.for.body_crit_edge ] 53 %arrayidx = getelementptr inbounds i32, i32* %A, i64 %i 54 call void @bar(i32 %1) 55 br label %for.body 56 57for.body: 58 %inc = add nsw i64 %i, 1 59 %cmp = icmp slt i64 %inc, 4 60 br i1 %cmp, label %for.body.for.body_crit_edge, label %for.end 61 62for.body.for.body_crit_edge: 63 %arrayidx.phi.trans.insert = getelementptr inbounds i32, i32* %A, i64 %inc 64 %.pre = load i32, i32* %arrayidx.phi.trans.insert, align 4 65 br label %for.header 66 67for.end: 68 ret void 69} 70 71; Check that loop unroll pass correctly handle loops with 72; (1) exiting block not dominating the loop latch; and 73; (2) exiting terminator instructions cannot be simplified to unconditional. 74 75define void @test2(i32* noalias %A) { 76; CHECK-LABEL: @test2( 77; CHECK-NEXT: entry: 78; CHECK-NEXT: br i1 true, label [[FOR_PREHEADER:%.*]], label [[FOR_END:%.*]] 79; CHECK: for.preheader: 80; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[A:%.*]], align 4 81; CHECK-NEXT: call void @bar(i32 [[TMP0]]) 82; CHECK-NEXT: br label [[FOR_HEADER:%.*]] 83; CHECK: for.header: 84; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[TMP0]], [[FOR_PREHEADER]] ], [ [[DOTPRE_3:%.*]], [[FOR_BODY_FOR_BODY_CRIT_EDGE_3:%.*]] ] 85; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, [[FOR_PREHEADER]] ], [ [[INC_3:%.*]], [[FOR_BODY_FOR_BODY_CRIT_EDGE_3]] ] 86; CHECK-NEXT: call void @bar(i32 [[TMP1]]) 87; CHECK-NEXT: [[INC:%.*]] = add nuw nsw i64 [[I]], 1 88; CHECK-NEXT: br i1 true, label [[FOR_BODY:%.*]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE:%.*]] 89; CHECK: for.body: 90; CHECK-NEXT: [[CMP:%.*]] = call i1 @foo(i64 [[I]]) 91; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE]], label [[FOR_END_LOOPEXIT:%.*]] 92; CHECK: for.body.for.body_crit_edge: 93; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[INC]] 94; CHECK-NEXT: [[DOTPRE:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT]], align 4 95; CHECK-NEXT: call void @bar(i32 [[DOTPRE]]) 96; CHECK-NEXT: [[INC_1:%.*]] = add nuw nsw i64 [[INC]], 1 97; CHECK-NEXT: br i1 true, label [[FOR_BODY_1:%.*]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE_1:%.*]] 98; CHECK: for.body.1: 99; CHECK-NEXT: [[CMP_1:%.*]] = call i1 @foo(i64 [[INC]]) 100; CHECK-NEXT: br i1 [[CMP_1]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE_1]], label [[FOR_END_LOOPEXIT]] 101; CHECK: for.body.for.body_crit_edge.1: 102; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_1:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[INC_1]] 103; CHECK-NEXT: [[DOTPRE_1:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT_1]], align 4 104; CHECK-NEXT: call void @bar(i32 [[DOTPRE_1]]) 105; CHECK-NEXT: [[INC_2:%.*]] = add nuw nsw i64 [[INC_1]], 1 106; CHECK-NEXT: br i1 true, label [[FOR_BODY_2:%.*]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE_2:%.*]] 107; CHECK: for.body.2: 108; CHECK-NEXT: [[CMP_2:%.*]] = call i1 @foo(i64 [[INC_1]]) 109; CHECK-NEXT: br i1 [[CMP_2]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE_2]], label [[FOR_END_LOOPEXIT]] 110; CHECK: for.body.for.body_crit_edge.2: 111; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_2:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[INC_2]] 112; CHECK-NEXT: [[DOTPRE_2:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT_2]], align 4 113; CHECK-NEXT: call void @bar(i32 [[DOTPRE_2]]) 114; CHECK-NEXT: [[INC_3]] = add nsw i64 [[INC_2]], 1 115; CHECK-NEXT: br i1 true, label [[FOR_BODY_3:%.*]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE_3]] 116; CHECK: for.body.3: 117; CHECK-NEXT: [[CMP_3:%.*]] = call i1 @foo(i64 [[INC_2]]) 118; CHECK-NEXT: br i1 [[CMP_3]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE_3]], label [[FOR_END_LOOPEXIT]] 119; CHECK: for.body.for.body_crit_edge.3: 120; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_3:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[INC_3]] 121; CHECK-NEXT: [[DOTPRE_3]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT_3]], align 4 122; CHECK-NEXT: br label [[FOR_HEADER]], !llvm.loop [[LOOP0:![0-9]+]] 123; CHECK: for.end.loopexit: 124; CHECK-NEXT: br label [[FOR_END]] 125; CHECK: for.end: 126; CHECK-NEXT: ret void 127; 128entry: 129 br i1 true, label %for.preheader, label %for.end 130 131for.preheader: 132 %0 = load i32, i32* %A, align 4 133 call void @bar(i32 %0) 134 br label %for.header 135 136for.header: 137 %1 = phi i32 [ %0, %for.preheader ], [ %.pre, %for.body.for.body_crit_edge ] 138 %i = phi i64 [ 0, %for.preheader ], [ %inc, %for.body.for.body_crit_edge ] 139 %arrayidx = getelementptr inbounds i32, i32* %A, i64 %i 140 call void @bar(i32 %1) 141 %inc = add nsw i64 %i, 1 142 br i1 true, label %for.body, label %for.body.for.body_crit_edge 143 144for.body: 145 %cmp = call i1 @foo(i64 %i) 146 br i1 %cmp, label %for.body.for.body_crit_edge, label %for.end 147 148for.body.for.body_crit_edge: 149 %arrayidx.phi.trans.insert = getelementptr inbounds i32, i32* %A, i64 %inc 150 %.pre = load i32, i32* %arrayidx.phi.trans.insert, align 4 151 br label %for.header 152 153for.end: 154 ret void 155} 156 157; Check that loop unroll pass correctly handle loops with 158; (1) multiple exiting blocks; and 159; (2) loop latch is not an exiting block. 160 161define void @test3(i32* noalias %A, i1 %cond) { 162; CHECK-LABEL: @test3( 163; CHECK-NEXT: entry: 164; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[A:%.*]], align 4 165; CHECK-NEXT: call void @bar(i32 [[TMP0]]) 166; CHECK-NEXT: br label [[FOR_HEADER:%.*]] 167; CHECK: for.header: 168; CHECK-NEXT: call void @bar(i32 [[TMP0]]) 169; CHECK-NEXT: br i1 [[COND:%.*]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] 170; CHECK: for.body: 171; CHECK-NEXT: br label [[FOR_BODY_FOR_BODY_CRIT_EDGE:%.*]] 172; CHECK: for.body.for.body_crit_edge: 173; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 1 174; CHECK-NEXT: [[DOTPRE:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT]], align 4 175; CHECK-NEXT: call void @bar(i32 [[DOTPRE]]) 176; CHECK-NEXT: br i1 [[COND]], label [[FOR_BODY_1:%.*]], label [[FOR_END]] 177; CHECK: for.body.1: 178; CHECK-NEXT: br label [[FOR_BODY_FOR_BODY_CRIT_EDGE_1:%.*]] 179; CHECK: for.body.for.body_crit_edge.1: 180; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_1:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 2 181; CHECK-NEXT: [[DOTPRE_1:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT_1]], align 4 182; CHECK-NEXT: call void @bar(i32 [[DOTPRE_1]]) 183; CHECK-NEXT: br i1 [[COND]], label [[FOR_BODY_2:%.*]], label [[FOR_END]] 184; CHECK: for.body.2: 185; CHECK-NEXT: br label [[FOR_BODY_FOR_BODY_CRIT_EDGE_2:%.*]] 186; CHECK: for.body.for.body_crit_edge.2: 187; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_2:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 3 188; CHECK-NEXT: [[DOTPRE_2:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT_2]], align 4 189; CHECK-NEXT: call void @bar(i32 [[DOTPRE_2]]) 190; CHECK-NEXT: br i1 [[COND]], label [[FOR_BODY_3:%.*]], label [[FOR_END]] 191; CHECK: for.body.3: 192; CHECK-NEXT: br i1 false, label [[FOR_BODY_FOR_BODY_CRIT_EDGE_3:%.*]], label [[FOR_END]] 193; CHECK: for.body.for.body_crit_edge.3: 194; CHECK-NEXT: unreachable 195; CHECK: for.end: 196; CHECK-NEXT: ret void 197; 198entry: 199 %0 = load i32, i32* %A, align 4 200 call void @bar(i32 %0) 201 br label %for.header 202 203for.header: 204 %1 = phi i32 [ %0, %entry ], [ %.pre, %for.body.for.body_crit_edge ] 205 %i = phi i64 [ 0, %entry ], [ %inc, %for.body.for.body_crit_edge ] 206 %arrayidx = getelementptr inbounds i32, i32* %A, i64 %i 207 call void @bar(i32 %1) 208 br i1 %cond, label %for.body, label %for.end 209 210for.body: 211 %inc = add nsw i64 %i, 1 212 %cmp = icmp slt i64 %inc, 4 213 br i1 %cmp, label %for.body.for.body_crit_edge, label %for.end 214 215for.body.for.body_crit_edge: 216 %arrayidx.phi.trans.insert = getelementptr inbounds i32, i32* %A, i64 %inc 217 %.pre = load i32, i32* %arrayidx.phi.trans.insert, align 4 218 br label %for.header 219 220for.end: 221 ret void 222} 223 224; Test it doesn't crash. 225define void @test4(i32 %arg) { 226; CHECK-LABEL: @test4( 227; CHECK-NEXT: bb: 228; CHECK-NEXT: br label [[BB1:%.*]] 229; CHECK: bb1: 230; CHECK-NEXT: br i1 false, label [[BB4:%.*]], label [[BB1_1:%.*]] 231; CHECK: bb1.1: 232; CHECK-NEXT: br i1 false, label [[BB4]], label [[BB1_2:%.*]] 233; CHECK: bb1.2: 234; CHECK-NEXT: br i1 false, label [[BB4]], label [[BB1_3:%.*]] 235; CHECK: bb1.3: 236; CHECK-NEXT: br i1 false, label [[BB4]], label [[BB1]], !llvm.loop [[LOOP2:![0-9]+]] 237; CHECK: bb4: 238; CHECK-NEXT: unreachable 239; 240bb: 241 br label %bb1 242 243bb1: ; preds = %bb1, %bb 244 %tmp = phi i64 [ 0, %bb ], [ 65, %bb1 ] 245 %tmp2 = phi i32 [ %arg, %bb ], [ %tmp3, %bb1 ] 246 %tmp3 = add i32 0, -1880031232 247 br i1 false, label %bb4, label %bb1 248 249bb4: ; preds = %bb1 250 unreachable 251} 252 253 254declare void @bar(i32) 255declare i1 @foo(i64) 256