1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -passes=loop-idiom < %s -S | FileCheck %s 3 4define void @copy_both_noalias(ptr noalias nocapture %d, ptr noalias nocapture readonly %s, i64 %sz) { 5; CHECK-LABEL: @copy_both_noalias( 6; CHECK-NEXT: entry: 7; CHECK-NEXT: [[EXITCOND_NOT1:%.*]] = icmp eq i64 [[SZ:%.*]], 0 8; CHECK-NEXT: br i1 [[EXITCOND_NOT1]], label [[FOR_END:%.*]], label [[FOR_BODY_PREHEADER:%.*]] 9; CHECK: for.body.preheader: 10; CHECK-NEXT: [[TMP0:%.*]] = shl nuw i64 [[SZ]], 2 11; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[D:%.*]], ptr align 4 [[S:%.*]], i64 [[TMP0]], i1 false) 12; CHECK-NEXT: br label [[FOR_BODY:%.*]] 13; CHECK: for.body: 14; CHECK-NEXT: [[I_04:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_BODY]] ], [ 0, [[FOR_BODY_PREHEADER]] ] 15; CHECK-NEXT: [[D_ADDR_03:%.*]] = phi ptr [ [[INCDEC_PTR1:%.*]], [[FOR_BODY]] ], [ [[D]], [[FOR_BODY_PREHEADER]] ] 16; CHECK-NEXT: [[S_ADDR_02:%.*]] = phi ptr [ [[INCDEC_PTR:%.*]], [[FOR_BODY]] ], [ [[S]], [[FOR_BODY_PREHEADER]] ] 17; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds float, ptr [[S_ADDR_02]], i64 1 18; CHECK-NEXT: [[TMP1:%.*]] = load float, ptr [[S_ADDR_02]], align 4 19; CHECK-NEXT: [[INCDEC_PTR1]] = getelementptr inbounds float, ptr [[D_ADDR_03]], i64 1 20; CHECK-NEXT: [[INC]] = add i64 [[I_04]], 1 21; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INC]], [[SZ]] 22; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_END_LOOPEXIT:%.*]], label [[FOR_BODY]] 23; CHECK: for.end.loopexit: 24; CHECK-NEXT: br label [[FOR_END]] 25; CHECK: for.end: 26; CHECK-NEXT: ret void 27; 28entry: 29 %exitcond.not1 = icmp eq i64 %sz, 0 30 br i1 %exitcond.not1, label %for.end, label %for.body.preheader 31 32for.body.preheader: ; preds = %entry 33 br label %for.body 34 35for.body: ; preds = %for.body.preheader, %for.body 36 %i.04 = phi i64 [ %inc, %for.body ], [ 0, %for.body.preheader ] 37 %d.addr.03 = phi ptr [ %incdec.ptr1, %for.body ], [ %d, %for.body.preheader ] 38 %s.addr.02 = phi ptr [ %incdec.ptr, %for.body ], [ %s, %for.body.preheader ] 39 %incdec.ptr = getelementptr inbounds float, ptr %s.addr.02, i64 1 40 %0 = load float, ptr %s.addr.02, align 4 41 %incdec.ptr1 = getelementptr inbounds float, ptr %d.addr.03, i64 1 42 store float %0, ptr %d.addr.03, align 4 43 %inc = add i64 %i.04, 1 44 %exitcond.not = icmp eq i64 %inc, %sz 45 br i1 %exitcond.not, label %for.end.loopexit, label %for.body 46 47for.end.loopexit: ; preds = %for.body 48 br label %for.end 49 50for.end: ; preds = %for.end.loopexit, %entry 51 ret void 52} 53 54define void @copy_one_noalias(ptr nocapture %d, ptr noalias nocapture readonly %s, i64 %sz) { 55; CHECK-LABEL: @copy_one_noalias( 56; CHECK-NEXT: entry: 57; CHECK-NEXT: [[EXITCOND_NOT1:%.*]] = icmp eq i64 [[SZ:%.*]], 0 58; CHECK-NEXT: br i1 [[EXITCOND_NOT1]], label [[FOR_END:%.*]], label [[FOR_BODY_PREHEADER:%.*]] 59; CHECK: for.body.preheader: 60; CHECK-NEXT: [[TMP0:%.*]] = shl nuw i64 [[SZ]], 2 61; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[D:%.*]], ptr align 4 [[S:%.*]], i64 [[TMP0]], i1 false) 62; CHECK-NEXT: br label [[FOR_BODY:%.*]] 63; CHECK: for.body: 64; CHECK-NEXT: [[I_04:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_BODY]] ], [ 0, [[FOR_BODY_PREHEADER]] ] 65; CHECK-NEXT: [[D_ADDR_03:%.*]] = phi ptr [ [[INCDEC_PTR1:%.*]], [[FOR_BODY]] ], [ [[D]], [[FOR_BODY_PREHEADER]] ] 66; CHECK-NEXT: [[S_ADDR_02:%.*]] = phi ptr [ [[INCDEC_PTR:%.*]], [[FOR_BODY]] ], [ [[S]], [[FOR_BODY_PREHEADER]] ] 67; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds float, ptr [[S_ADDR_02]], i64 1 68; CHECK-NEXT: [[TMP1:%.*]] = load float, ptr [[S_ADDR_02]], align 4 69; CHECK-NEXT: [[INCDEC_PTR1]] = getelementptr inbounds float, ptr [[D_ADDR_03]], i64 1 70; CHECK-NEXT: [[INC]] = add i64 [[I_04]], 1 71; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INC]], [[SZ]] 72; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_END_LOOPEXIT:%.*]], label [[FOR_BODY]] 73; CHECK: for.end.loopexit: 74; CHECK-NEXT: br label [[FOR_END]] 75; CHECK: for.end: 76; CHECK-NEXT: ret void 77; 78entry: 79 %exitcond.not1 = icmp eq i64 %sz, 0 80 br i1 %exitcond.not1, label %for.end, label %for.body.preheader 81 82for.body.preheader: ; preds = %entry 83 br label %for.body 84 85for.body: ; preds = %for.body.preheader, %for.body 86 %i.04 = phi i64 [ %inc, %for.body ], [ 0, %for.body.preheader ] 87 %d.addr.03 = phi ptr [ %incdec.ptr1, %for.body ], [ %d, %for.body.preheader ] 88 %s.addr.02 = phi ptr [ %incdec.ptr, %for.body ], [ %s, %for.body.preheader ] 89 %incdec.ptr = getelementptr inbounds float, ptr %s.addr.02, i64 1 90 %0 = load float, ptr %s.addr.02, align 4 91 %incdec.ptr1 = getelementptr inbounds float, ptr %d.addr.03, i64 1 92 store float %0, ptr %d.addr.03, align 4 93 %inc = add i64 %i.04, 1 94 %exitcond.not = icmp eq i64 %inc, %sz 95 br i1 %exitcond.not, label %for.end.loopexit, label %for.body 96 97for.end.loopexit: ; preds = %for.body 98 br label %for.end 99 100for.end: ; preds = %for.end.loopexit, %entry 101 ret void 102} 103 104; PR44378 105define dso_local void @memcpy_loop(ptr noalias nocapture %p, ptr noalias nocapture readonly %q, i32 %n) { 106; CHECK-LABEL: @memcpy_loop( 107; CHECK-NEXT: entry: 108; CHECK-NEXT: [[CMP4:%.*]] = icmp sgt i32 [[N:%.*]], 0 109; CHECK-NEXT: br i1 [[CMP4]], label [[FOR_BODY_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]] 110; CHECK: for.body.preheader: 111; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[N]] to i64 112; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[P:%.*]], ptr align 1 [[Q:%.*]], i64 [[TMP0]], i1 false) 113; CHECK-NEXT: br label [[FOR_BODY:%.*]] 114; CHECK: for.cond.cleanup.loopexit: 115; CHECK-NEXT: br label [[FOR_COND_CLEANUP]] 116; CHECK: for.cond.cleanup: 117; CHECK-NEXT: ret void 118; CHECK: for.body: 119; CHECK-NEXT: [[I_07:%.*]] = phi i32 [ [[INC:%.*]], [[FOR_BODY]] ], [ 0, [[FOR_BODY_PREHEADER]] ] 120; CHECK-NEXT: [[P_ADDR_06:%.*]] = phi ptr [ [[INCDEC_PTR1:%.*]], [[FOR_BODY]] ], [ [[P]], [[FOR_BODY_PREHEADER]] ] 121; CHECK-NEXT: [[Q_ADDR_05:%.*]] = phi ptr [ [[INCDEC_PTR:%.*]], [[FOR_BODY]] ], [ [[Q]], [[FOR_BODY_PREHEADER]] ] 122; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds i8, ptr [[Q_ADDR_05]], i64 1 123; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[Q_ADDR_05]], align 1 124; CHECK-NEXT: [[INCDEC_PTR1]] = getelementptr inbounds i8, ptr [[P_ADDR_06]], i64 1 125; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_07]], 1 126; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INC]], [[N]] 127; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_BODY]] 128; 129entry: 130 %cmp4 = icmp sgt i32 %n, 0 131 br i1 %cmp4, label %for.body, label %for.cond.cleanup 132 133for.cond.cleanup: 134 ret void 135 136for.body: 137 %i.07 = phi i32 [ %inc, %for.body ], [ 0, %entry ] 138 %p.addr.06 = phi ptr [ %incdec.ptr1, %for.body ], [ %p, %entry ] 139 %q.addr.05 = phi ptr [ %incdec.ptr, %for.body ], [ %q, %entry ] 140 %incdec.ptr = getelementptr inbounds i8, ptr %q.addr.05, i64 1 141 %0 = load i8, ptr %q.addr.05, align 1 142 %incdec.ptr1 = getelementptr inbounds i8, ptr %p.addr.06, i64 1 143 store i8 %0, ptr %p.addr.06, align 1 144 %inc = add nuw nsw i32 %i.07, 1 145 %exitcond.not = icmp eq i32 %inc, %n 146 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 147} 148