1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -passes=loop-unroll -S %s -verify-loop-info -verify-dom-info -verify-loop-lcssa | FileCheck %s 3 4%struct.spam = type { double, double, double, double, double, double, double } 5 6define void @test2(ptr %arg, ptr %out) { 7; CHECK-LABEL: @test2( 8; CHECK-NEXT: entry: 9; CHECK-NEXT: br label [[FOR_HEADER:%.*]] 10; CHECK: for.header: 11; CHECK-NEXT: store i32 0, ptr [[ARG:%.*]], align 4 12; CHECK-NEXT: br label [[FOR_LATCH:%.*]] 13; CHECK: for.latch: 14; CHECK-NEXT: store volatile i64 0, ptr [[OUT:%.*]], align 4 15; CHECK-NEXT: [[PTR_1:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 1 16; CHECK-NEXT: store i32 0, ptr [[PTR_1]], align 4 17; CHECK-NEXT: br label [[FOR_LATCH_1:%.*]] 18; CHECK: for.latch.1: 19; CHECK-NEXT: store volatile i64 1, ptr [[OUT]], align 4 20; CHECK-NEXT: [[PTR_2:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 2 21; CHECK-NEXT: store i32 0, ptr [[PTR_2]], align 4 22; CHECK-NEXT: br label [[FOR_LATCH_2:%.*]] 23; CHECK: for.latch.2: 24; CHECK-NEXT: store volatile i64 2, ptr [[OUT]], align 4 25; CHECK-NEXT: [[PTR_3:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 3 26; CHECK-NEXT: store i32 0, ptr [[PTR_3]], align 4 27; CHECK-NEXT: br i1 true, label [[IF_END_LOOPEXIT:%.*]], label [[FOR_LATCH_3:%.*]] 28; CHECK: for.latch.3: 29; CHECK-NEXT: store volatile i64 3, ptr [[OUT]], align 4 30; CHECK-NEXT: unreachable 31; CHECK: if.end.loopexit: 32; CHECK-NEXT: ret void 33; 34 35entry: 36 br label %for.header 37 38for.header: ; preds = %for.latch, %entry 39 %indvars.iv800 = phi i64 [ 0, %entry ], [ %indvars.iv.next801, %for.latch ] 40 %ptr = getelementptr inbounds i32, ptr %arg, i64 %indvars.iv800 41 store i32 0, ptr %ptr, align 4 42 %indvars.iv.next801 = add nuw nsw i64 %indvars.iv800, 1 43 %exitcond802 = icmp eq i64 %indvars.iv.next801, 4 44 br i1 %exitcond802, label %if.end.loopexit, label %for.latch 45 46for.latch: ; preds = %for.header 47 store volatile i64 %indvars.iv800, ptr %out 48 br label %for.header 49 50if.end.loopexit: ; preds = %for.header 51 ret void 52} 53 54define double @test_with_lcssa(double %arg1, ptr %arg2) { 55; CHECK-LABEL: @test_with_lcssa( 56; CHECK-NEXT: entry: 57; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] 58; CHECK: loop.header: 59; CHECK-NEXT: [[RES:%.*]] = fsub double [[ARG1:%.*]], 3.000000e+00 60; CHECK-NEXT: br label [[LOOP_LATCH:%.*]] 61; CHECK: loop.latch: 62; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds double, ptr [[ARG2:%.*]], i64 1 63; CHECK-NEXT: [[LV:%.*]] = load double, ptr [[PTR]], align 8 64; CHECK-NEXT: [[RES_1:%.*]] = fsub double [[LV]], [[RES]] 65; CHECK-NEXT: br i1 true, label [[LOOP_EXIT:%.*]], label [[LOOP_LATCH_1:%.*]] 66; CHECK: loop.latch.1: 67; CHECK-NEXT: unreachable 68; CHECK: loop.exit: 69; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi double [ [[RES_1]], [[LOOP_LATCH]] ] 70; CHECK-NEXT: ret double [[RES_LCSSA]] 71; 72 73entry: 74 br label %loop.header 75 76loop.header: ; preds = %entry, %loop.latch 77 %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ] 78 %d1 = phi double [ %arg1, %entry ], [ %lv, %loop.latch ] 79 %d2 = phi double [ 3.0, %entry ], [ %res, %loop.latch ] 80 %res = fsub double %d1, %d2 81 %iv.next = add nuw nsw i64 %iv, 1 82 %cond = icmp eq i64 %iv.next, 2 83 br i1 %cond, label %loop.exit, label %loop.latch 84 85loop.latch: ; preds = %bb366 86 %ptr = getelementptr inbounds double, ptr %arg2, i64 %iv.next 87 %lv = load double, ptr %ptr, align 8 88 br label %loop.header 89 90loop.exit: ; preds = %bb366 91 %res.lcssa = phi double [ %res, %loop.header ] 92 ret double %res.lcssa 93} 94 95; We unroll the outer loop and need to preserve LI for the inner loop. 96define void @test_with_nested_loop(ptr %arg) { 97; CHECK-LABEL: @test_with_nested_loop( 98; CHECK-NEXT: entry: 99; CHECK-NEXT: br label [[OUTER_HEADER:%.*]] 100; CHECK: outer.header: 101; CHECK-NEXT: br label [[INNER_BODY_PREHEADER:%.*]] 102; CHECK: inner.body.preheader: 103; CHECK-NEXT: br label [[INNER_BODY:%.*]] 104; CHECK: inner.body: 105; CHECK-NEXT: [[J_IV:%.*]] = phi i64 [ [[J_IV_NEXT:%.*]], [[INNER_BODY]] ], [ 0, [[INNER_BODY_PREHEADER]] ] 106; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds i32, ptr [[ARG:%.*]], i64 [[J_IV]] 107; CHECK-NEXT: store i32 0, ptr [[PTR]], align 4 108; CHECK-NEXT: [[J_IV_NEXT]] = add nuw nsw i64 [[J_IV]], 1 109; CHECK-NEXT: [[INNER_COND:%.*]] = icmp eq i64 [[J_IV_NEXT]], 40000 110; CHECK-NEXT: br i1 [[INNER_COND]], label [[OUTER_LATCH:%.*]], label [[INNER_BODY]] 111; CHECK: outer.latch: 112; CHECK-NEXT: br label [[INNER_BODY_PREHEADER_1:%.*]] 113; CHECK: inner.body.preheader.1: 114; CHECK-NEXT: br label [[INNER_BODY_1:%.*]] 115; CHECK: inner.body.1: 116; CHECK-NEXT: [[J_IV_1:%.*]] = phi i64 [ [[J_IV_NEXT_1:%.*]], [[INNER_BODY_1]] ], [ 0, [[INNER_BODY_PREHEADER_1]] ] 117; CHECK-NEXT: [[IDX_1:%.*]] = add i64 1, [[J_IV_1]] 118; CHECK-NEXT: [[PTR_1:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 [[IDX_1]] 119; CHECK-NEXT: store i32 0, ptr [[PTR_1]], align 4 120; CHECK-NEXT: [[J_IV_NEXT_1]] = add nuw nsw i64 [[J_IV_1]], 1 121; CHECK-NEXT: [[INNER_COND_1:%.*]] = icmp eq i64 [[J_IV_NEXT_1]], 40000 122; CHECK-NEXT: br i1 [[INNER_COND_1]], label [[OUTER_LATCH_1:%.*]], label [[INNER_BODY_1]] 123; CHECK: outer.latch.1: 124; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[INNER_BODY_PREHEADER_2:%.*]] 125; CHECK: inner.body.preheader.2: 126; CHECK-NEXT: br label [[INNER_BODY_2:%.*]] 127; CHECK: inner.body.2: 128; CHECK-NEXT: [[J_IV_2:%.*]] = phi i64 [ [[J_IV_NEXT_2:%.*]], [[INNER_BODY_2]] ], [ 0, [[INNER_BODY_PREHEADER_2]] ] 129; CHECK-NEXT: [[IDX_2:%.*]] = add i64 2, [[J_IV_2]] 130; CHECK-NEXT: [[PTR_2:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 [[IDX_2]] 131; CHECK-NEXT: store i32 0, ptr [[PTR_2]], align 4 132; CHECK-NEXT: [[J_IV_NEXT_2]] = add nuw nsw i64 [[J_IV_2]], 1 133; CHECK-NEXT: [[INNER_COND_2:%.*]] = icmp eq i64 [[J_IV_NEXT_2]], 40000 134; CHECK-NEXT: br i1 [[INNER_COND_2]], label [[OUTER_LATCH_2:%.*]], label [[INNER_BODY_2]] 135; CHECK: outer.latch.2: 136; CHECK-NEXT: unreachable 137; CHECK: exit: 138; CHECK-NEXT: ret void 139; 140 141entry: 142 br label %outer.header 143 144outer.header: ; preds = %outer.latch, %entry 145 %outer.iv = phi i64 [ 0, %entry ], [ %outer.iv.next, %outer.latch ] 146 %outer.iv.next = add nuw nsw i64 %outer.iv, 1 147 %outer.cond = icmp eq i64 %outer.iv, 2 148 br i1 %outer.cond, label %exit, label %inner.body 149 150inner.body: 151 %j.iv = phi i64 [ 0, %outer.header ], [ %j.iv.next, %inner.body ] 152 %idx = add i64 %outer.iv, %j.iv 153 %ptr = getelementptr inbounds i32, ptr %arg, i64 %idx 154 store i32 0, ptr %ptr, align 4 155 %j.iv.next = add nuw nsw i64 %j.iv, 1 156 %inner.cond = icmp eq i64 %j.iv.next, 40000 157 br i1 %inner.cond, label %outer.latch, label %inner.body 158 159outer.latch: ; preds = %inner.body 160 br label %outer.header 161 162exit: ; preds = %outer.header 163 ret void 164} 165 166; We unroll the inner loop and need to preserve LI for the outer loop. 167define void @test_with_nested_loop_unroll_inner(ptr %arg) { 168; CHECK-LABEL: @test_with_nested_loop_unroll_inner( 169; CHECK-NEXT: entry: 170; CHECK-NEXT: br label [[OUTER_HEADER:%.*]] 171; CHECK: outer.header: 172; CHECK-NEXT: [[OUTER_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[OUTER_IV_NEXT:%.*]], [[INNER_BODY:%.*]] ] 173; CHECK-NEXT: [[OUTER_IV_NEXT]] = add nuw nsw i64 [[OUTER_IV]], 1 174; CHECK-NEXT: [[OUTER_COND:%.*]] = icmp eq i64 [[OUTER_IV]], 40000 175; CHECK-NEXT: br i1 [[OUTER_COND]], label [[EXIT:%.*]], label [[INNER_BODY_PREHEADER:%.*]] 176; CHECK: inner.body.preheader: 177; CHECK-NEXT: br label [[INNER_BODY]] 178; CHECK: inner.body: 179; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds i32, ptr [[ARG:%.*]], i64 [[OUTER_IV]] 180; CHECK-NEXT: store i32 0, ptr [[PTR]], align 4 181; CHECK-NEXT: [[IDX_1:%.*]] = add i64 [[OUTER_IV]], 1 182; CHECK-NEXT: [[PTR_1:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 [[IDX_1]] 183; CHECK-NEXT: store i32 0, ptr [[PTR_1]], align 4 184; CHECK-NEXT: br label [[OUTER_HEADER]] 185; CHECK: exit: 186; CHECK-NEXT: ret void 187; 188 189entry: 190 br label %outer.header 191 192outer.header: ; preds = %outer.latch, %entry 193 %outer.iv = phi i64 [ 0, %entry ], [ %outer.iv.next, %outer.latch ] 194 %outer.iv.next = add nuw nsw i64 %outer.iv, 1 195 %outer.cond = icmp eq i64 %outer.iv, 40000 196 br i1 %outer.cond, label %exit, label %inner.body 197 198inner.body: 199 %j.iv = phi i64 [ 0, %outer.header ], [ %j.iv.next, %inner.body ] 200 %idx = add i64 %outer.iv, %j.iv 201 %ptr = getelementptr inbounds i32, ptr %arg, i64 %idx 202 store i32 0, ptr %ptr, align 4 203 %j.iv.next = add nuw nsw i64 %j.iv, 1 204 %inner.cond = icmp eq i64 %j.iv.next, 2 205 br i1 %inner.cond, label %outer.latch, label %inner.body 206 207outer.latch: ; preds = %inner.body 208 br label %outer.header 209 210exit: ; preds = %outer.header 211 ret void 212} 213 214 215 216; Check that we do not crash for headers with non-branch instructions, e.g. 217; switch. We do not unroll in those cases. 218define void @test_switchinst_in_header() { 219; CHECK-LABEL: @test_switchinst_in_header( 220; CHECK-NEXT: entry: 221; CHECK-NEXT: br label [[WHILE_HEADER:%.*]] 222; CHECK: while.header: 223; CHECK-NEXT: switch i32 undef, label [[EXIT:%.*]] [ 224; CHECK-NEXT: i32 11, label [[WHILE_BODY1:%.*]] 225; CHECK-NEXT: i32 5, label [[WHILE_BODY2:%.*]] 226; CHECK-NEXT: ] 227; CHECK: while.body1: 228; CHECK-NEXT: unreachable 229; CHECK: while.body2: 230; CHECK-NEXT: br label [[WHILE_LATCH:%.*]] 231; CHECK: while.latch: 232; CHECK-NEXT: br label [[WHILE_HEADER]] 233; CHECK: exit: 234; CHECK-NEXT: ret void 235; 236 237entry: 238 br label %while.header 239 240while.header: ; preds = %while.latch, %entry 241 switch i32 undef, label %exit [ 242 i32 11, label %while.body1 243 i32 5, label %while.body2 244 ] 245 246while.body1: ; preds = %while.header 247 unreachable 248 249while.body2: ; preds = %while.header 250 br label %while.latch 251 252while.latch: ; preds = %while.body2 253 br label %while.header 254 255exit: ; preds = %while.header 256 ret void 257} 258