258 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt -passes=loop-unroll -S %s -verify-loop-info -verify-dom-info -verify-loop-lcssa | FileCheck %s3 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 412; CHECK-NEXT: br label [[FOR_LATCH:%.*]]13; CHECK: for.latch:14; CHECK-NEXT: store volatile i64 0, ptr [[OUT:%.*]], align 415; CHECK-NEXT: [[PTR_1:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 116; CHECK-NEXT: store i32 0, ptr [[PTR_1]], align 417; CHECK-NEXT: br label [[FOR_LATCH_1:%.*]]18; CHECK: for.latch.1:19; CHECK-NEXT: store volatile i64 1, ptr [[OUT]], align 420; CHECK-NEXT: [[PTR_2:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 221; CHECK-NEXT: store i32 0, ptr [[PTR_2]], align 422; CHECK-NEXT: br label [[FOR_LATCH_2:%.*]]23; CHECK: for.latch.2:24; CHECK-NEXT: store volatile i64 2, ptr [[OUT]], align 425; CHECK-NEXT: [[PTR_3:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 326; CHECK-NEXT: store i32 0, ptr [[PTR_3]], align 427; 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 430; CHECK-NEXT: unreachable31; CHECK: if.end.loopexit:32; CHECK-NEXT: ret void33;34 35entry:36 br label %for.header37 38for.header: ; preds = %for.latch, %entry39 %indvars.iv800 = phi i64 [ 0, %entry ], [ %indvars.iv.next801, %for.latch ]40 %ptr = getelementptr inbounds i32, ptr %arg, i64 %indvars.iv80041 store i32 0, ptr %ptr, align 442 %indvars.iv.next801 = add nuw nsw i64 %indvars.iv800, 143 %exitcond802 = icmp eq i64 %indvars.iv.next801, 444 br i1 %exitcond802, label %if.end.loopexit, label %for.latch45 46for.latch: ; preds = %for.header47 store volatile i64 %indvars.iv800, ptr %out48 br label %for.header49 50if.end.loopexit: ; preds = %for.header51 ret void52}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+0060; CHECK-NEXT: br label [[LOOP_LATCH:%.*]]61; CHECK: loop.latch:62; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds double, ptr [[ARG2:%.*]], i64 163; CHECK-NEXT: [[LV:%.*]] = load double, ptr [[PTR]], align 864; 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: unreachable68; 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.header75 76loop.header: ; preds = %entry, %loop.latch77 %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, %d281 %iv.next = add nuw nsw i64 %iv, 182 %cond = icmp eq i64 %iv.next, 283 br i1 %cond, label %loop.exit, label %loop.latch84 85loop.latch: ; preds = %bb36686 %ptr = getelementptr inbounds double, ptr %arg2, i64 %iv.next87 %lv = load double, ptr %ptr, align 888 br label %loop.header89 90loop.exit: ; preds = %bb36691 %res.lcssa = phi double [ %res, %loop.header ]92 ret double %res.lcssa93}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 4108; CHECK-NEXT: [[J_IV_NEXT]] = add nuw nsw i64 [[J_IV]], 1109; CHECK-NEXT: [[INNER_COND:%.*]] = icmp eq i64 [[J_IV_NEXT]], 40000110; 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 4120; CHECK-NEXT: [[J_IV_NEXT_1]] = add nuw nsw i64 [[J_IV_1]], 1121; CHECK-NEXT: [[INNER_COND_1:%.*]] = icmp eq i64 [[J_IV_NEXT_1]], 40000122; 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 4132; CHECK-NEXT: [[J_IV_NEXT_2]] = add nuw nsw i64 [[J_IV_2]], 1133; CHECK-NEXT: [[INNER_COND_2:%.*]] = icmp eq i64 [[J_IV_NEXT_2]], 40000134; CHECK-NEXT: br i1 [[INNER_COND_2]], label [[OUTER_LATCH_2:%.*]], label [[INNER_BODY_2]]135; CHECK: outer.latch.2:136; CHECK-NEXT: unreachable137; CHECK: exit:138; CHECK-NEXT: ret void139;140 141entry:142 br label %outer.header143 144outer.header: ; preds = %outer.latch, %entry145 %outer.iv = phi i64 [ 0, %entry ], [ %outer.iv.next, %outer.latch ]146 %outer.iv.next = add nuw nsw i64 %outer.iv, 1147 %outer.cond = icmp eq i64 %outer.iv, 2148 br i1 %outer.cond, label %exit, label %inner.body149 150inner.body:151 %j.iv = phi i64 [ 0, %outer.header ], [ %j.iv.next, %inner.body ]152 %idx = add i64 %outer.iv, %j.iv153 %ptr = getelementptr inbounds i32, ptr %arg, i64 %idx154 store i32 0, ptr %ptr, align 4155 %j.iv.next = add nuw nsw i64 %j.iv, 1156 %inner.cond = icmp eq i64 %j.iv.next, 40000157 br i1 %inner.cond, label %outer.latch, label %inner.body158 159outer.latch: ; preds = %inner.body160 br label %outer.header161 162exit: ; preds = %outer.header163 ret void164}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]], 1174; CHECK-NEXT: [[OUTER_COND:%.*]] = icmp eq i64 [[OUTER_IV]], 40000175; 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 4181; CHECK-NEXT: [[IDX_1:%.*]] = add i64 [[OUTER_IV]], 1182; CHECK-NEXT: [[PTR_1:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 [[IDX_1]]183; CHECK-NEXT: store i32 0, ptr [[PTR_1]], align 4184; CHECK-NEXT: br label [[OUTER_HEADER]]185; CHECK: exit:186; CHECK-NEXT: ret void187;188 189entry:190 br label %outer.header191 192outer.header: ; preds = %outer.latch, %entry193 %outer.iv = phi i64 [ 0, %entry ], [ %outer.iv.next, %outer.latch ]194 %outer.iv.next = add nuw nsw i64 %outer.iv, 1195 %outer.cond = icmp eq i64 %outer.iv, 40000196 br i1 %outer.cond, label %exit, label %inner.body197 198inner.body:199 %j.iv = phi i64 [ 0, %outer.header ], [ %j.iv.next, %inner.body ]200 %idx = add i64 %outer.iv, %j.iv201 %ptr = getelementptr inbounds i32, ptr %arg, i64 %idx202 store i32 0, ptr %ptr, align 4203 %j.iv.next = add nuw nsw i64 %j.iv, 1204 %inner.cond = icmp eq i64 %j.iv.next, 2205 br i1 %inner.cond, label %outer.latch, label %inner.body206 207outer.latch: ; preds = %inner.body208 br label %outer.header209 210exit: ; preds = %outer.header211 ret void212}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: unreachable229; 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 void235;236 237entry:238 br label %while.header239 240while.header: ; preds = %while.latch, %entry241 switch i32 undef, label %exit [242 i32 11, label %while.body1243 i32 5, label %while.body2244 ]245 246while.body1: ; preds = %while.header247 unreachable248 249while.body2: ; preds = %while.header250 br label %while.latch251 252while.latch: ; preds = %while.body2253 br label %while.header254 255exit: ; preds = %while.header256 ret void257}258