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.end: 25; CHECK-NEXT: ret void 26; CHECK: for.body.1: 27; CHECK-NEXT: br label [[FOR_BODY_FOR_BODY_CRIT_EDGE_1:%.*]] 28; CHECK: for.body.for.body_crit_edge.1: 29; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_1:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 2 30; CHECK-NEXT: [[DOTPRE_1:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT_1]], align 4 31; CHECK-NEXT: call void @bar(i32 [[DOTPRE_1]]) 32; CHECK-NEXT: br label [[FOR_BODY_2:%.*]] 33; CHECK: for.body.2: 34; CHECK-NEXT: br label [[FOR_BODY_FOR_BODY_CRIT_EDGE_2:%.*]] 35; CHECK: for.body.for.body_crit_edge.2: 36; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_2:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 3 37; CHECK-NEXT: [[DOTPRE_2:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT_2]], align 4 38; CHECK-NEXT: call void @bar(i32 [[DOTPRE_2]]) 39; CHECK-NEXT: br label [[FOR_BODY_3:%.*]] 40; CHECK: for.body.3: 41; CHECK-NEXT: br i1 false, label [[FOR_BODY_FOR_BODY_CRIT_EDGE_3:%.*]], label [[FOR_END:%.*]] 42; CHECK: for.body.for.body_crit_edge.3: 43; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_3:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 4 44; CHECK-NEXT: unreachable 45; 46entry: 47 %0 = load i32, i32* %A, align 4 48 call void @bar(i32 %0) 49 br label %for.header 50 51for.header: 52 %1 = phi i32 [ %0, %entry ], [ %.pre, %for.body.for.body_crit_edge ] 53 %i = phi i64 [ 0, %entry ], [ %inc, %for.body.for.body_crit_edge ] 54 %arrayidx = getelementptr inbounds i32, i32* %A, i64 %i 55 call void @bar(i32 %1) 56 br label %for.body 57 58for.body: 59 %inc = add nsw i64 %i, 1 60 %cmp = icmp slt i64 %inc, 4 61 br i1 %cmp, label %for.body.for.body_crit_edge, label %for.end 62 63for.body.for.body_crit_edge: 64 %arrayidx.phi.trans.insert = getelementptr inbounds i32, i32* %A, i64 %inc 65 %.pre = load i32, i32* %arrayidx.phi.trans.insert, align 4 66 br label %for.header 67 68for.end: 69 ret void 70} 71 72; Check that loop unroll pass correctly handle loops with 73; (1) exiting block not dominating the loop latch; and 74; (2) exiting terminator instructions cannot be simplified to unconditional. 75 76define void @test2(i32* noalias %A) { 77; CHECK-LABEL: @test2( 78; CHECK-NEXT: entry: 79; CHECK-NEXT: br i1 true, label [[FOR_PREHEADER:%.*]], label [[FOR_END:%.*]] 80; CHECK: for.preheader: 81; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[A:%.*]], align 4 82; CHECK-NEXT: call void @bar(i32 [[TMP0]]) 83; CHECK-NEXT: br label [[FOR_HEADER:%.*]] 84; CHECK: for.header: 85; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[TMP0]], [[FOR_PREHEADER]] ], [ [[DOTPRE_3:%.*]], [[FOR_BODY_FOR_BODY_CRIT_EDGE_3:%.*]] ] 86; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, [[FOR_PREHEADER]] ], [ [[INC_3:%.*]], [[FOR_BODY_FOR_BODY_CRIT_EDGE_3]] ] 87; CHECK-NEXT: call void @bar(i32 [[TMP1]]) 88; CHECK-NEXT: [[INC:%.*]] = add nuw nsw i64 [[I]], 1 89; CHECK-NEXT: br i1 true, label [[FOR_BODY:%.*]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE:%.*]] 90; CHECK: for.body: 91; CHECK-NEXT: [[CMP:%.*]] = call i1 @foo(i64 [[I]]) 92; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE]], label [[FOR_END_LOOPEXIT:%.*]] 93; CHECK: for.body.for.body_crit_edge: 94; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[INC]] 95; CHECK-NEXT: [[DOTPRE:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT]], align 4 96; CHECK-NEXT: call void @bar(i32 [[DOTPRE]]) 97; CHECK-NEXT: [[INC_1:%.*]] = add nuw nsw i64 [[INC]], 1 98; CHECK-NEXT: br i1 true, label [[FOR_BODY_1:%.*]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE_1:%.*]] 99; CHECK: for.end.loopexit: 100; CHECK-NEXT: br label [[FOR_END]] 101; CHECK: for.end: 102; CHECK-NEXT: ret void 103; CHECK: for.body.1: 104; CHECK-NEXT: [[CMP_1:%.*]] = call i1 @foo(i64 [[INC]]) 105; CHECK-NEXT: br i1 [[CMP_1]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE_1]], label [[FOR_END_LOOPEXIT]] 106; CHECK: for.body.for.body_crit_edge.1: 107; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_1:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[INC_1]] 108; CHECK-NEXT: [[DOTPRE_1:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT_1]], align 4 109; CHECK-NEXT: call void @bar(i32 [[DOTPRE_1]]) 110; CHECK-NEXT: [[INC_2:%.*]] = add nuw nsw i64 [[INC_1]], 1 111; CHECK-NEXT: br i1 true, label [[FOR_BODY_2:%.*]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE_2:%.*]] 112; CHECK: for.body.2: 113; CHECK-NEXT: [[CMP_2:%.*]] = call i1 @foo(i64 [[INC_1]]) 114; CHECK-NEXT: br i1 [[CMP_2]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE_2]], label [[FOR_END_LOOPEXIT]] 115; CHECK: for.body.for.body_crit_edge.2: 116; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_2:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[INC_2]] 117; CHECK-NEXT: [[DOTPRE_2:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT_2]], align 4 118; CHECK-NEXT: call void @bar(i32 [[DOTPRE_2]]) 119; CHECK-NEXT: [[INC_3]] = add nsw i64 [[INC_2]], 1 120; CHECK-NEXT: br i1 true, label [[FOR_BODY_3:%.*]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE_3]] 121; CHECK: for.body.3: 122; CHECK-NEXT: [[CMP_3:%.*]] = call i1 @foo(i64 [[INC_2]]) 123; CHECK-NEXT: br i1 [[CMP_3]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE_3]], label [[FOR_END_LOOPEXIT]] 124; CHECK: for.body.for.body_crit_edge.3: 125; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_3:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[INC_3]] 126; CHECK-NEXT: [[DOTPRE_3]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT_3]], align 4 127; CHECK-NEXT: br label [[FOR_HEADER]], !llvm.loop !0 128; 129entry: 130 br i1 true, label %for.preheader, label %for.end 131 132for.preheader: 133 %0 = load i32, i32* %A, align 4 134 call void @bar(i32 %0) 135 br label %for.header 136 137for.header: 138 %1 = phi i32 [ %0, %for.preheader ], [ %.pre, %for.body.for.body_crit_edge ] 139 %i = phi i64 [ 0, %for.preheader ], [ %inc, %for.body.for.body_crit_edge ] 140 %arrayidx = getelementptr inbounds i32, i32* %A, i64 %i 141 call void @bar(i32 %1) 142 %inc = add nsw i64 %i, 1 143 br i1 true, label %for.body, label %for.body.for.body_crit_edge 144 145for.body: 146 %cmp = call i1 @foo(i64 %i) 147 br i1 %cmp, label %for.body.for.body_crit_edge, label %for.end 148 149for.body.for.body_crit_edge: 150 %arrayidx.phi.trans.insert = getelementptr inbounds i32, i32* %A, i64 %inc 151 %.pre = load i32, i32* %arrayidx.phi.trans.insert, align 4 152 br label %for.header 153 154for.end: 155 ret void 156} 157 158; Check that loop unroll pass correctly handle loops with 159; (1) multiple exiting blocks; and 160; (2) loop latch is not an exiting block. 161 162define void @test3(i32* noalias %A, i1 %cond) { 163; CHECK-LABEL: @test3( 164; CHECK-NEXT: entry: 165; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[A:%.*]], align 4 166; CHECK-NEXT: call void @bar(i32 [[TMP0]]) 167; CHECK-NEXT: br label [[FOR_HEADER:%.*]] 168; CHECK: for.header: 169; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[TMP0]], [[ENTRY:%.*]] ], [ [[DOTPRE_3:%.*]], [[FOR_BODY_FOR_BODY_CRIT_EDGE_3:%.*]] ] 170; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ [[INC_3:%.*]], [[FOR_BODY_FOR_BODY_CRIT_EDGE_3]] ] 171; CHECK-NEXT: call void @bar(i32 [[TMP1]]) 172; CHECK-NEXT: br i1 [[COND:%.*]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] 173; CHECK: for.body: 174; CHECK-NEXT: [[INC:%.*]] = add nuw nsw i64 [[I]], 1 175; CHECK-NEXT: br i1 true, label [[FOR_BODY_FOR_BODY_CRIT_EDGE:%.*]], label [[FOR_END]] 176; CHECK: for.body.for.body_crit_edge: 177; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[INC]] 178; CHECK-NEXT: [[DOTPRE:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT]], align 4 179; CHECK-NEXT: call void @bar(i32 [[DOTPRE]]) 180; CHECK-NEXT: br i1 [[COND]], label [[FOR_BODY_1:%.*]], label [[FOR_END]] 181; CHECK: for.end: 182; CHECK-NEXT: ret void 183; CHECK: for.body.1: 184; CHECK-NEXT: [[INC_1:%.*]] = add nuw nsw i64 [[INC]], 1 185; CHECK-NEXT: br i1 true, label [[FOR_BODY_FOR_BODY_CRIT_EDGE_1:%.*]], label [[FOR_END]] 186; CHECK: for.body.for.body_crit_edge.1: 187; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_1:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[INC_1]] 188; CHECK-NEXT: [[DOTPRE_1:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT_1]], align 4 189; CHECK-NEXT: call void @bar(i32 [[DOTPRE_1]]) 190; CHECK-NEXT: br i1 [[COND]], label [[FOR_BODY_2:%.*]], label [[FOR_END]] 191; CHECK: for.body.2: 192; CHECK-NEXT: [[INC_2:%.*]] = add nuw nsw i64 [[INC_1]], 1 193; CHECK-NEXT: br i1 true, label [[FOR_BODY_FOR_BODY_CRIT_EDGE_2:%.*]], label [[FOR_END]] 194; CHECK: for.body.for.body_crit_edge.2: 195; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_2:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[INC_2]] 196; CHECK-NEXT: [[DOTPRE_2:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT_2]], align 4 197; CHECK-NEXT: call void @bar(i32 [[DOTPRE_2]]) 198; CHECK-NEXT: br i1 [[COND]], label [[FOR_BODY_3:%.*]], label [[FOR_END]] 199; CHECK: for.body.3: 200; CHECK-NEXT: [[INC_3]] = add nuw nsw i64 [[INC_2]], 1 201; CHECK-NEXT: br i1 false, label [[FOR_BODY_FOR_BODY_CRIT_EDGE_3]], label [[FOR_END]] 202; CHECK: for.body.for.body_crit_edge.3: 203; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_3:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[INC_3]] 204; CHECK-NEXT: [[DOTPRE_3]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT_3]], align 4 205; CHECK-NEXT: br label [[FOR_HEADER]], !llvm.loop !2 206; 207entry: 208 %0 = load i32, i32* %A, align 4 209 call void @bar(i32 %0) 210 br label %for.header 211 212for.header: 213 %1 = phi i32 [ %0, %entry ], [ %.pre, %for.body.for.body_crit_edge ] 214 %i = phi i64 [ 0, %entry ], [ %inc, %for.body.for.body_crit_edge ] 215 %arrayidx = getelementptr inbounds i32, i32* %A, i64 %i 216 call void @bar(i32 %1) 217 br i1 %cond, label %for.body, label %for.end 218 219for.body: 220 %inc = add nsw i64 %i, 1 221 %cmp = icmp slt i64 %inc, 4 222 br i1 %cmp, label %for.body.for.body_crit_edge, label %for.end 223 224for.body.for.body_crit_edge: 225 %arrayidx.phi.trans.insert = getelementptr inbounds i32, i32* %A, i64 %inc 226 %.pre = load i32, i32* %arrayidx.phi.trans.insert, align 4 227 br label %for.header 228 229for.end: 230 ret void 231} 232 233declare void @bar(i32) 234declare i1 @foo(i64) 235