1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4 2; RUN: opt -passes="default<O3>" -S %s | FileCheck %s 3 4target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 5target triple = "arm64-apple-macosx11.0.0" 6 7define void @partial_unroll_forced(i32 %N, ptr %src, ptr noalias %dst) { 8; CHECK-LABEL: define void @partial_unroll_forced( 9; CHECK-SAME: i32 [[N:%.*]], ptr readonly captures(none) [[SRC:%.*]], ptr noalias writeonly captures(none) [[DST:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { 10; CHECK-NEXT: entry: 11; CHECK-NEXT: [[CMP141:%.*]] = icmp sgt i32 [[N]], 0 12; CHECK-NEXT: br i1 [[CMP141]], label [[LOOP_LATCH_PREHEADER:%.*]], label [[EXIT:%.*]] 13; CHECK: loop.latch.preheader: 14; CHECK-NEXT: [[WIDE_TRIP_COUNT:%.*]] = zext nneg i32 [[N]] to i64 15; CHECK-NEXT: [[XTRAITER:%.*]] = and i64 [[WIDE_TRIP_COUNT]], 1 16; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i32 [[N]], 1 17; CHECK-NEXT: br i1 [[TMP0]], label [[EXIT_LOOPEXIT_UNR_LCSSA:%.*]], label [[LOOP_LATCH_PREHEADER_NEW:%.*]] 18; CHECK: loop.latch.preheader.new: 19; CHECK-NEXT: [[UNROLL_ITER:%.*]] = and i64 [[WIDE_TRIP_COUNT]], 2147483646 20; CHECK-NEXT: br label [[LOOP_LATCH:%.*]] 21; CHECK: loop.latch: 22; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ 0, [[LOOP_LATCH_PREHEADER_NEW]] ], [ [[INDVARS_IV_NEXT_1:%.*]], [[LOOP_LATCH]] ] 23; CHECK-NEXT: [[NITER:%.*]] = phi i64 [ 0, [[LOOP_LATCH_PREHEADER_NEW]] ], [ [[NITER_NEXT_1:%.*]], [[LOOP_LATCH]] ] 24; CHECK-NEXT: [[SRC_IDX:%.*]] = getelementptr <8 x half>, ptr [[SRC]], i64 [[INDVARS_IV]] 25; CHECK-NEXT: [[L:%.*]] = load <8 x half>, ptr [[SRC_IDX]], align 16 26; CHECK-NEXT: [[DST_IDX:%.*]] = getelementptr <8 x half>, ptr [[DST]], i64 [[INDVARS_IV]] 27; CHECK-NEXT: [[ADD:%.*]] = fadd <8 x half> [[L]], [[L]] 28; CHECK-NEXT: store <8 x half> [[ADD]], ptr [[DST_IDX]], align 16 29; CHECK-NEXT: [[INDVARS_IV_NEXT:%.*]] = or disjoint i64 [[INDVARS_IV]], 1 30; CHECK-NEXT: [[SRC_IDX_1:%.*]] = getelementptr <8 x half>, ptr [[SRC]], i64 [[INDVARS_IV_NEXT]] 31; CHECK-NEXT: [[L_1:%.*]] = load <8 x half>, ptr [[SRC_IDX_1]], align 16 32; CHECK-NEXT: [[DST_IDX_1:%.*]] = getelementptr <8 x half>, ptr [[DST]], i64 [[INDVARS_IV_NEXT]] 33; CHECK-NEXT: [[ADD_1:%.*]] = fadd <8 x half> [[L_1]], [[L_1]] 34; CHECK-NEXT: store <8 x half> [[ADD_1]], ptr [[DST_IDX_1]], align 16 35; CHECK-NEXT: [[INDVARS_IV_NEXT_1]] = add nuw nsw i64 [[INDVARS_IV]], 2 36; CHECK-NEXT: [[NITER_NEXT_1]] = add i64 [[NITER]], 2 37; CHECK-NEXT: [[NITER_NCMP_1:%.*]] = icmp eq i64 [[NITER_NEXT_1]], [[UNROLL_ITER]] 38; CHECK-NEXT: br i1 [[NITER_NCMP_1]], label [[EXIT_LOOPEXIT_UNR_LCSSA]], label [[LOOP_LATCH]], !llvm.loop [[LOOP0:![0-9]+]] 39; CHECK: exit.loopexit.unr-lcssa: 40; CHECK-NEXT: [[INDVARS_IV_UNR:%.*]] = phi i64 [ 0, [[LOOP_LATCH_PREHEADER]] ], [ [[INDVARS_IV_NEXT_1]], [[LOOP_LATCH]] ] 41; CHECK-NEXT: [[LCMP_MOD_NOT:%.*]] = icmp eq i64 [[XTRAITER]], 0 42; CHECK-NEXT: br i1 [[LCMP_MOD_NOT]], label [[EXIT]], label [[LOOP_LATCH_EPIL:%.*]] 43; CHECK: loop.latch.epil: 44; CHECK-NEXT: [[SRC_IDX_EPIL:%.*]] = getelementptr <8 x half>, ptr [[SRC]], i64 [[INDVARS_IV_UNR]] 45; CHECK-NEXT: [[L_EPIL:%.*]] = load <8 x half>, ptr [[SRC_IDX_EPIL]], align 16 46; CHECK-NEXT: [[DST_IDX_EPIL:%.*]] = getelementptr <8 x half>, ptr [[DST]], i64 [[INDVARS_IV_UNR]] 47; CHECK-NEXT: [[ADD_EPIL:%.*]] = fadd <8 x half> [[L_EPIL]], [[L_EPIL]] 48; CHECK-NEXT: store <8 x half> [[ADD_EPIL]], ptr [[DST_IDX_EPIL]], align 16 49; CHECK-NEXT: br label [[EXIT]] 50; CHECK: exit: 51; CHECK-NEXT: ret void 52; 53entry: 54 br label %loop.header 55 56loop.header: 57 %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ] 58 %cmp14 = icmp slt i32 %iv, %N 59 br i1 %cmp14, label %loop.latch, label %exit 60 61loop.latch: 62 %iv.ext = zext i32 %iv to i64 63 %src.idx = getelementptr <8 x half>, ptr %src, i64 %iv.ext 64 %l = load <8 x half>, ptr %src.idx, align 16 65 %dst.idx = getelementptr <8 x half>, ptr %dst, i64 %iv.ext 66 %add = fadd <8 x half> %l, %l 67 store <8 x half> %add, ptr %dst.idx, align 16 68 %iv.next = add i32 %iv, 1 69 br label %loop.header, !llvm.loop !0 70 71exit: 72 ret void 73} 74 75define void @cse_matching_load_from_previous_unrolled_iteration(i32 %N, ptr %src, ptr noalias %dst) { 76; CHECK-LABEL: define void @cse_matching_load_from_previous_unrolled_iteration( 77; CHECK-SAME: i32 [[N:%.*]], ptr readonly captures(none) [[SRC:%.*]], ptr noalias writeonly captures(none) [[DST:%.*]]) local_unnamed_addr #[[ATTR0]] { 78; CHECK-NEXT: entry: 79; CHECK-NEXT: [[SRC_4:%.*]] = getelementptr i8, ptr [[SRC]], i64 4 80; CHECK-NEXT: [[SRC_12:%.*]] = getelementptr i8, ptr [[SRC]], i64 12 81; CHECK-NEXT: [[CMP141:%.*]] = icmp sgt i32 [[N]], 0 82; CHECK-NEXT: br i1 [[CMP141]], label [[LOOP_LATCH_PREHEADER:%.*]], label [[EXIT:%.*]] 83; CHECK: loop.latch.preheader: 84; CHECK-NEXT: [[WIDE_TRIP_COUNT:%.*]] = zext nneg i32 [[N]] to i64 85; CHECK-NEXT: [[XTRAITER:%.*]] = and i64 [[WIDE_TRIP_COUNT]], 1 86; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i32 [[N]], 1 87; CHECK-NEXT: br i1 [[TMP0]], label [[EXIT_LOOPEXIT_UNR_LCSSA:%.*]], label [[LOOP_LATCH_PREHEADER_NEW:%.*]] 88; CHECK: loop.latch.preheader.new: 89; CHECK-NEXT: [[UNROLL_ITER:%.*]] = and i64 [[WIDE_TRIP_COUNT]], 2147483646 90; CHECK-NEXT: br label [[LOOP_LATCH:%.*]] 91; CHECK: loop.latch: 92; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ 0, [[LOOP_LATCH_PREHEADER_NEW]] ], [ [[INDVARS_IV_NEXT_1:%.*]], [[LOOP_LATCH]] ] 93; CHECK-NEXT: [[NITER:%.*]] = phi i64 [ 0, [[LOOP_LATCH_PREHEADER_NEW]] ], [ [[NITER_NEXT_1:%.*]], [[LOOP_LATCH]] ] 94; CHECK-NEXT: [[GEP_SRC_12:%.*]] = getelementptr <2 x i32>, ptr [[SRC_12]], i64 [[INDVARS_IV]] 95; CHECK-NEXT: [[L_12:%.*]] = load <2 x i32>, ptr [[GEP_SRC_12]], align 8 96; CHECK-NEXT: [[GEP_SRC_4:%.*]] = getelementptr <2 x i32>, ptr [[SRC_4]], i64 [[INDVARS_IV]] 97; CHECK-NEXT: [[L_4:%.*]] = load <2 x i32>, ptr [[GEP_SRC_4]], align 8 98; CHECK-NEXT: [[MUL:%.*]] = mul <2 x i32> [[L_4]], [[L_12]] 99; CHECK-NEXT: [[GEP_DST:%.*]] = getelementptr <2 x i32>, ptr [[DST]], i64 [[INDVARS_IV]] 100; CHECK-NEXT: store <2 x i32> [[MUL]], ptr [[GEP_DST]], align 8 101; CHECK-NEXT: [[INDVARS_IV_NEXT:%.*]] = or disjoint i64 [[INDVARS_IV]], 1 102; CHECK-NEXT: [[GEP_SRC_12_1:%.*]] = getelementptr <2 x i32>, ptr [[SRC_12]], i64 [[INDVARS_IV_NEXT]] 103; CHECK-NEXT: [[L_12_1:%.*]] = load <2 x i32>, ptr [[GEP_SRC_12_1]], align 8 104; CHECK-NEXT: [[MUL_1:%.*]] = mul <2 x i32> [[L_12]], [[L_12_1]] 105; CHECK-NEXT: [[GEP_DST_1:%.*]] = getelementptr <2 x i32>, ptr [[DST]], i64 [[INDVARS_IV_NEXT]] 106; CHECK-NEXT: store <2 x i32> [[MUL_1]], ptr [[GEP_DST_1]], align 8 107; CHECK-NEXT: [[INDVARS_IV_NEXT_1]] = add nuw nsw i64 [[INDVARS_IV]], 2 108; CHECK-NEXT: [[NITER_NEXT_1]] = add i64 [[NITER]], 2 109; CHECK-NEXT: [[NITER_NCMP_1:%.*]] = icmp eq i64 [[NITER_NEXT_1]], [[UNROLL_ITER]] 110; CHECK-NEXT: br i1 [[NITER_NCMP_1]], label [[EXIT_LOOPEXIT_UNR_LCSSA]], label [[LOOP_LATCH]], !llvm.loop [[LOOP3:![0-9]+]] 111; CHECK: exit.loopexit.unr-lcssa: 112; CHECK-NEXT: [[INDVARS_IV_UNR:%.*]] = phi i64 [ 0, [[LOOP_LATCH_PREHEADER]] ], [ [[INDVARS_IV_NEXT_1]], [[LOOP_LATCH]] ] 113; CHECK-NEXT: [[LCMP_MOD_NOT:%.*]] = icmp eq i64 [[XTRAITER]], 0 114; CHECK-NEXT: br i1 [[LCMP_MOD_NOT]], label [[EXIT]], label [[LOOP_LATCH_EPIL:%.*]] 115; CHECK: loop.latch.epil: 116; CHECK-NEXT: [[GEP_SRC_12_EPIL:%.*]] = getelementptr <2 x i32>, ptr [[SRC_12]], i64 [[INDVARS_IV_UNR]] 117; CHECK-NEXT: [[L_12_EPIL:%.*]] = load <2 x i32>, ptr [[GEP_SRC_12_EPIL]], align 8 118; CHECK-NEXT: [[GEP_SRC_4_EPIL:%.*]] = getelementptr <2 x i32>, ptr [[SRC_4]], i64 [[INDVARS_IV_UNR]] 119; CHECK-NEXT: [[L_4_EPIL:%.*]] = load <2 x i32>, ptr [[GEP_SRC_4_EPIL]], align 8 120; CHECK-NEXT: [[MUL_EPIL:%.*]] = mul <2 x i32> [[L_4_EPIL]], [[L_12_EPIL]] 121; CHECK-NEXT: [[GEP_DST_EPIL:%.*]] = getelementptr <2 x i32>, ptr [[DST]], i64 [[INDVARS_IV_UNR]] 122; CHECK-NEXT: store <2 x i32> [[MUL_EPIL]], ptr [[GEP_DST_EPIL]], align 8 123; CHECK-NEXT: br label [[EXIT]] 124; CHECK: exit: 125; CHECK-NEXT: ret void 126; 127entry: 128 %src.4 = getelementptr i8, ptr %src, i64 4 129 %src.12 = getelementptr i8, ptr %src, i64 12 130 br label %loop.header 131 132loop.header: 133 %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ] 134 %cmp14 = icmp slt i32 %iv, %N 135 br i1 %cmp14, label %loop.latch, label %exit 136 137loop.latch: 138 %iv.ext = zext i32 %iv to i64 139 %gep.src.12 = getelementptr <2 x i32>, ptr %src.12, i64 %iv.ext 140 %l.12 = load <2 x i32>, ptr %gep.src.12, align 8 141 %gep.src.4 = getelementptr <2 x i32>, ptr %src.4, i64 %iv.ext 142 %l.4 = load <2 x i32>, ptr %gep.src.4, align 8 143 %mul = mul <2 x i32> %l.12, %l.4 144 %gep.dst = getelementptr <2 x i32>, ptr %dst, i64 %iv.ext 145 store <2 x i32> %mul, ptr %gep.dst 146 %iv.next = add nuw nsw i32 %iv, 1 147 br label %loop.header, !llvm.loop !0 148 149exit: 150 ret void 151} 152 153!0 = distinct !{!0, !1, !2} 154!1 = !{!"llvm.loop.mustprogress"} 155!2 = !{!"llvm.loop.unroll.count", i32 2} 156;. 157; CHECK: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]], [[META2:![0-9]+]]} 158; CHECK: [[META1]] = !{!"llvm.loop.mustprogress"} 159; CHECK: [[META2]] = !{!"llvm.loop.unroll.disable"} 160; CHECK: [[LOOP3]] = distinct !{[[LOOP3]], [[META1]], [[META2]]} 161;. 162