| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt -passes=loop-bound-split -S < %s | FileCheck %s |
| |
| ; The transformation is failed with this test because we can not guarantee the |
| ; split condition is always true in pre-loop after transformation. |
| define void @variable_split_loop_bound_and_exit_cond_inc_with_sgt(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) { |
| ; CHECK-LABEL: @variable_split_loop_bound_and_exit_cond_inc_with_sgt( |
| ; CHECK-NEXT: loop.ph: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]] |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[IV]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i64 [[INC]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| loop.ph: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ] |
| %cmp = icmp ult i64 %iv, %a |
| br i1 %cmp, label %if.then, label %if.else |
| |
| if.then: |
| %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv |
| %val = load i64, i64* %src.arrayidx |
| %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv |
| store i64 %val, i64* %dst.arrayidx |
| br label %for.inc |
| |
| if.else: |
| br label %for.inc |
| |
| for.inc: |
| %inc = add nuw nsw i64 %iv, 1 |
| %cond = icmp sgt i64 %inc, %n |
| br i1 %cond, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| ; The transformation works with this test because we can guarantee the split |
| ; condition is always true in pre-loop after transformation. |
| define void @umax_variable_split_loop_bound_and_exit_cond_inc_with_sgt(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) { |
| ; CHECK-LABEL: @umax_variable_split_loop_bound_and_exit_cond_inc_with_sgt( |
| ; CHECK-NEXT: loop.ph: |
| ; CHECK-NEXT: [[B:%.*]] = call i64 @llvm.umax.i64(i64 [[A:%.*]], i64 1) |
| ; CHECK-NEXT: br label [[LOOP_PH_SPLIT:%.*]] |
| ; CHECK: loop.ph.split: |
| ; CHECK-NEXT: [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[N:%.*]], i64 0) |
| ; CHECK-NEXT: [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[SMAX]], i64 [[B]]) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH_SPLIT]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IV]], [[B]] |
| ; CHECK-NEXT: br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[IV]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i64 [[INC]], [[NEW_BOUND]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[LOOP_PH_SPLIT_SPLIT:%.*]], label [[LOOP]] |
| ; CHECK: loop.ph.split.split: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i64 [ [[INC]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[TMP0:%.*]] = icmp ne i64 [[IV_LCSSA]], [[N]] |
| ; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP_SPLIT_PREHEADER:%.*]], label [[EXIT:%.*]] |
| ; CHECK: loop.split.preheader: |
| ; CHECK-NEXT: br label [[LOOP_SPLIT:%.*]] |
| ; CHECK: loop.split: |
| ; CHECK-NEXT: [[IV_SPLIT:%.*]] = phi i64 [ [[INC_SPLIT:%.*]], [[FOR_INC_SPLIT:%.*]] ], [ [[IV_LCSSA]], [[LOOP_SPLIT_PREHEADER]] ] |
| ; CHECK-NEXT: [[CMP_SPLIT:%.*]] = icmp ult i64 [[IV_SPLIT]], [[B]] |
| ; CHECK-NEXT: br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]] |
| ; CHECK: if.else.split: |
| ; CHECK-NEXT: br label [[FOR_INC_SPLIT]] |
| ; CHECK: if.then.split: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, i64* [[SRC]], i64 [[IV_SPLIT]] |
| ; CHECK-NEXT: [[VAL_SPLIT:%.*]] = load i64, i64* [[SRC_ARRAYIDX_SPLIT]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, i64* [[DST]], i64 [[IV_SPLIT]] |
| ; CHECK-NEXT: store i64 [[VAL_SPLIT]], i64* [[DST_ARRAYIDX_SPLIT]], align 4 |
| ; CHECK-NEXT: br label [[FOR_INC_SPLIT]] |
| ; CHECK: for.inc.split: |
| ; CHECK-NEXT: [[INC_SPLIT]] = add nuw nsw i64 [[IV_SPLIT]], 1 |
| ; CHECK-NEXT: [[COND_SPLIT:%.*]] = icmp sgt i64 [[INC_SPLIT]], [[N]] |
| ; CHECK-NEXT: br i1 [[COND_SPLIT]], label [[EXIT_LOOPEXIT:%.*]], label [[LOOP_SPLIT]] |
| ; CHECK: exit.loopexit: |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| loop.ph: |
| %b = call i64 @llvm.umax.i64(i64 %a, i64 1) |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ] |
| %cmp = icmp ult i64 %iv, %b |
| br i1 %cmp, label %if.then, label %if.else |
| |
| if.then: |
| %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv |
| %val = load i64, i64* %src.arrayidx |
| %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv |
| store i64 %val, i64* %dst.arrayidx |
| br label %for.inc |
| |
| if.else: |
| br label %for.inc |
| |
| for.inc: |
| %inc = add nuw nsw i64 %iv, 1 |
| %cond = icmp sgt i64 %inc, %n |
| br i1 %cond, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| ; The transformation works with this test because we can guarantee the split |
| ; condition is always true in pre-loop after transformation. |
| define void @constant_split_loop_bound_and_exit_cond_inc_with_sgt(i64* noalias %src, i64* noalias %dst, i64 %n) { |
| ; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_inc_with_sgt( |
| ; CHECK-NEXT: loop.ph: |
| ; CHECK-NEXT: br label [[LOOP_PH_SPLIT:%.*]] |
| ; CHECK: loop.ph.split: |
| ; CHECK-NEXT: [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[N:%.*]], i64 0) |
| ; CHECK-NEXT: [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[SMAX]], i64 10) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH_SPLIT]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IV]], 10 |
| ; CHECK-NEXT: br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[IV]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i64 [[INC]], [[NEW_BOUND]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[LOOP_PH_SPLIT_SPLIT:%.*]], label [[LOOP]] |
| ; CHECK: loop.ph.split.split: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i64 [ [[INC]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[TMP0:%.*]] = icmp ne i64 [[IV_LCSSA]], [[N]] |
| ; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP_SPLIT_PREHEADER:%.*]], label [[EXIT:%.*]] |
| ; CHECK: loop.split.preheader: |
| ; CHECK-NEXT: br label [[LOOP_SPLIT:%.*]] |
| ; CHECK: loop.split: |
| ; CHECK-NEXT: [[IV_SPLIT:%.*]] = phi i64 [ [[INC_SPLIT:%.*]], [[FOR_INC_SPLIT:%.*]] ], [ [[IV_LCSSA]], [[LOOP_SPLIT_PREHEADER]] ] |
| ; CHECK-NEXT: [[CMP_SPLIT:%.*]] = icmp ult i64 [[IV_SPLIT]], 10 |
| ; CHECK-NEXT: br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]] |
| ; CHECK: if.else.split: |
| ; CHECK-NEXT: br label [[FOR_INC_SPLIT]] |
| ; CHECK: if.then.split: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, i64* [[SRC]], i64 [[IV_SPLIT]] |
| ; CHECK-NEXT: [[VAL_SPLIT:%.*]] = load i64, i64* [[SRC_ARRAYIDX_SPLIT]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, i64* [[DST]], i64 [[IV_SPLIT]] |
| ; CHECK-NEXT: store i64 [[VAL_SPLIT]], i64* [[DST_ARRAYIDX_SPLIT]], align 4 |
| ; CHECK-NEXT: br label [[FOR_INC_SPLIT]] |
| ; CHECK: for.inc.split: |
| ; CHECK-NEXT: [[INC_SPLIT]] = add nuw nsw i64 [[IV_SPLIT]], 1 |
| ; CHECK-NEXT: [[COND_SPLIT:%.*]] = icmp sgt i64 [[INC_SPLIT]], [[N]] |
| ; CHECK-NEXT: br i1 [[COND_SPLIT]], label [[EXIT_LOOPEXIT:%.*]], label [[LOOP_SPLIT]] |
| ; CHECK: exit.loopexit: |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| loop.ph: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ] |
| %cmp = icmp ult i64 %iv, 10 |
| br i1 %cmp, label %if.then, label %if.else |
| |
| if.then: |
| %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv |
| %val = load i64, i64* %src.arrayidx |
| %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv |
| store i64 %val, i64* %dst.arrayidx |
| br label %for.inc |
| |
| if.else: |
| br label %for.inc |
| |
| for.inc: |
| %inc = add nuw nsw i64 %iv, 1 |
| %cond = icmp sgt i64 %inc, %n |
| br i1 %cond, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| define void @variable_split_loop_bound_and_exit_cond_inc_with_eq(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) { |
| ; CHECK-LABEL: @variable_split_loop_bound_and_exit_cond_inc_with_eq( |
| ; CHECK-NEXT: loop.ph: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]] |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[IV]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i64 [[INC]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| loop.ph: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ] |
| %cmp = icmp ult i64 %iv, %a |
| br i1 %cmp, label %if.then, label %if.else |
| |
| if.then: |
| %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv |
| %val = load i64, i64* %src.arrayidx |
| %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv |
| store i64 %val, i64* %dst.arrayidx |
| br label %for.inc |
| |
| if.else: |
| br label %for.inc |
| |
| for.inc: |
| %inc = add nuw nsw i64 %iv, 1 |
| %cond = icmp eq i64 %inc, %n |
| br i1 %cond, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| define void @constant_split_loop_bound_and_exit_cond_inc_with_eq(i64* noalias %src, i64* noalias %dst, i64 %n) { |
| ; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_inc_with_eq( |
| ; CHECK-NEXT: loop.ph: |
| ; CHECK-NEXT: br label [[LOOP_PH_SPLIT:%.*]] |
| ; CHECK: loop.ph.split: |
| ; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[N:%.*]], -1 |
| ; CHECK-NEXT: [[NEW_BOUND:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP0]], i64 10) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH_SPLIT]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IV]], 10 |
| ; CHECK-NEXT: br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[IV]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i64 [[INC]], [[NEW_BOUND]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[LOOP_PH_SPLIT_SPLIT:%.*]], label [[LOOP]] |
| ; CHECK: loop.ph.split.split: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i64 [ [[INC]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[IV_LCSSA]], [[N]] |
| ; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP_SPLIT_PREHEADER:%.*]], label [[EXIT:%.*]] |
| ; CHECK: loop.split.preheader: |
| ; CHECK-NEXT: br label [[LOOP_SPLIT:%.*]] |
| ; CHECK: loop.split: |
| ; CHECK-NEXT: [[IV_SPLIT:%.*]] = phi i64 [ [[INC_SPLIT:%.*]], [[FOR_INC_SPLIT:%.*]] ], [ [[IV_LCSSA]], [[LOOP_SPLIT_PREHEADER]] ] |
| ; CHECK-NEXT: [[CMP_SPLIT:%.*]] = icmp ult i64 [[IV_SPLIT]], 10 |
| ; CHECK-NEXT: br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]] |
| ; CHECK: if.else.split: |
| ; CHECK-NEXT: br label [[FOR_INC_SPLIT]] |
| ; CHECK: if.then.split: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, i64* [[SRC]], i64 [[IV_SPLIT]] |
| ; CHECK-NEXT: [[VAL_SPLIT:%.*]] = load i64, i64* [[SRC_ARRAYIDX_SPLIT]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, i64* [[DST]], i64 [[IV_SPLIT]] |
| ; CHECK-NEXT: store i64 [[VAL_SPLIT]], i64* [[DST_ARRAYIDX_SPLIT]], align 4 |
| ; CHECK-NEXT: br label [[FOR_INC_SPLIT]] |
| ; CHECK: for.inc.split: |
| ; CHECK-NEXT: [[INC_SPLIT]] = add nuw nsw i64 [[IV_SPLIT]], 1 |
| ; CHECK-NEXT: [[COND_SPLIT:%.*]] = icmp eq i64 [[INC_SPLIT]], [[N]] |
| ; CHECK-NEXT: br i1 [[COND_SPLIT]], label [[EXIT_LOOPEXIT:%.*]], label [[LOOP_SPLIT]] |
| ; CHECK: exit.loopexit: |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| loop.ph: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ] |
| %cmp = icmp ult i64 %iv, 10 |
| br i1 %cmp, label %if.then, label %if.else |
| |
| if.then: |
| %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv |
| %val = load i64, i64* %src.arrayidx |
| %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv |
| store i64 %val, i64* %dst.arrayidx |
| br label %for.inc |
| |
| if.else: |
| br label %for.inc |
| |
| for.inc: |
| %inc = add nuw nsw i64 %iv, 1 |
| %cond = icmp eq i64 %inc, %n |
| br i1 %cond, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| define void @variable_split_loop_bound_and_exit_cond_inc_with_sge(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) { |
| ; CHECK-LABEL: @variable_split_loop_bound_and_exit_cond_inc_with_sge( |
| ; CHECK-NEXT: loop.ph: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]] |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[IV]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp sge i64 [[INC]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| loop.ph: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ] |
| %cmp = icmp ult i64 %iv, %a |
| br i1 %cmp, label %if.then, label %if.else |
| |
| if.then: |
| %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv |
| %val = load i64, i64* %src.arrayidx |
| %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv |
| store i64 %val, i64* %dst.arrayidx |
| br label %for.inc |
| |
| if.else: |
| br label %for.inc |
| |
| for.inc: |
| %inc = add nuw nsw i64 %iv, 1 |
| %cond = icmp sge i64 %inc, %n |
| br i1 %cond, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| define void @constant_split_loop_bound_and_exit_cond_inc_with_sge(i64* noalias %src, i64* noalias %dst, i64 %n) { |
| ; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_inc_with_sge( |
| ; CHECK-NEXT: loop.ph: |
| ; CHECK-NEXT: br label [[LOOP_PH_SPLIT:%.*]] |
| ; CHECK: loop.ph.split: |
| ; CHECK-NEXT: [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[N:%.*]], i64 1) |
| ; CHECK-NEXT: [[TMP0:%.*]] = add nsw i64 [[SMAX]], -1 |
| ; CHECK-NEXT: [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[TMP0]], i64 10) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH_SPLIT]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IV]], 10 |
| ; CHECK-NEXT: br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[IV]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp sge i64 [[INC]], [[NEW_BOUND]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[LOOP_PH_SPLIT_SPLIT:%.*]], label [[LOOP]] |
| ; CHECK: loop.ph.split.split: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i64 [ [[INC]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[IV_LCSSA]], [[N]] |
| ; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP_SPLIT_PREHEADER:%.*]], label [[EXIT:%.*]] |
| ; CHECK: loop.split.preheader: |
| ; CHECK-NEXT: br label [[LOOP_SPLIT:%.*]] |
| ; CHECK: loop.split: |
| ; CHECK-NEXT: [[IV_SPLIT:%.*]] = phi i64 [ [[INC_SPLIT:%.*]], [[FOR_INC_SPLIT:%.*]] ], [ [[IV_LCSSA]], [[LOOP_SPLIT_PREHEADER]] ] |
| ; CHECK-NEXT: [[CMP_SPLIT:%.*]] = icmp ult i64 [[IV_SPLIT]], 10 |
| ; CHECK-NEXT: br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]] |
| ; CHECK: if.else.split: |
| ; CHECK-NEXT: br label [[FOR_INC_SPLIT]] |
| ; CHECK: if.then.split: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, i64* [[SRC]], i64 [[IV_SPLIT]] |
| ; CHECK-NEXT: [[VAL_SPLIT:%.*]] = load i64, i64* [[SRC_ARRAYIDX_SPLIT]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, i64* [[DST]], i64 [[IV_SPLIT]] |
| ; CHECK-NEXT: store i64 [[VAL_SPLIT]], i64* [[DST_ARRAYIDX_SPLIT]], align 4 |
| ; CHECK-NEXT: br label [[FOR_INC_SPLIT]] |
| ; CHECK: for.inc.split: |
| ; CHECK-NEXT: [[INC_SPLIT]] = add nuw nsw i64 [[IV_SPLIT]], 1 |
| ; CHECK-NEXT: [[COND_SPLIT:%.*]] = icmp sge i64 [[INC_SPLIT]], [[N]] |
| ; CHECK-NEXT: br i1 [[COND_SPLIT]], label [[EXIT_LOOPEXIT:%.*]], label [[LOOP_SPLIT]] |
| ; CHECK: exit.loopexit: |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| loop.ph: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ] |
| %cmp = icmp ult i64 %iv, 10 |
| br i1 %cmp, label %if.then, label %if.else |
| |
| if.then: |
| %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv |
| %val = load i64, i64* %src.arrayidx |
| %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv |
| store i64 %val, i64* %dst.arrayidx |
| br label %for.inc |
| |
| if.else: |
| br label %for.inc |
| |
| for.inc: |
| %inc = add nuw nsw i64 %iv, 1 |
| %cond = icmp sge i64 %inc, %n |
| br i1 %cond, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| define void @variable_split_loop_bound_and_exit_cond_inc_with_step_is_not_one(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) { |
| ; CHECK-LABEL: @variable_split_loop_bound_and_exit_cond_inc_with_step_is_not_one( |
| ; CHECK-NEXT: loop.ph: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]] |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[IV]], 2 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i64 [[INC]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| loop.ph: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ] |
| %cmp = icmp ult i64 %iv, %a |
| br i1 %cmp, label %if.then, label %if.else |
| |
| if.then: |
| %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv |
| %val = load i64, i64* %src.arrayidx |
| %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv |
| store i64 %val, i64* %dst.arrayidx |
| br label %for.inc |
| |
| if.else: |
| br label %for.inc |
| |
| for.inc: |
| %inc = add nuw nsw i64 %iv, 2 |
| %cond = icmp sgt i64 %inc, %n |
| br i1 %cond, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| define void @constant_split_loop_bound_and_exit_cond_inc_with_step_is_not_one(i64* noalias %src, i64* noalias %dst, i64 %n) { |
| ; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_inc_with_step_is_not_one( |
| ; CHECK-NEXT: loop.ph: |
| ; CHECK-NEXT: br label [[LOOP_PH_SPLIT:%.*]] |
| ; CHECK: loop.ph.split: |
| ; CHECK-NEXT: [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[N:%.*]], i64 1) |
| ; CHECK-NEXT: [[TMP0:%.*]] = lshr i64 [[SMAX]], 1 |
| ; CHECK-NEXT: [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[TMP0]], i64 10) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH_SPLIT]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IV]], 10 |
| ; CHECK-NEXT: br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[IV]], 2 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i64 [[INC]], [[NEW_BOUND]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[LOOP_PH_SPLIT_SPLIT:%.*]], label [[LOOP]] |
| ; CHECK: loop.ph.split.split: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i64 [ [[INC]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[IV_LCSSA]], [[N]] |
| ; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP_SPLIT_PREHEADER:%.*]], label [[EXIT:%.*]] |
| ; CHECK: loop.split.preheader: |
| ; CHECK-NEXT: br label [[LOOP_SPLIT:%.*]] |
| ; CHECK: loop.split: |
| ; CHECK-NEXT: [[IV_SPLIT:%.*]] = phi i64 [ [[INC_SPLIT:%.*]], [[FOR_INC_SPLIT:%.*]] ], [ [[IV_LCSSA]], [[LOOP_SPLIT_PREHEADER]] ] |
| ; CHECK-NEXT: [[CMP_SPLIT:%.*]] = icmp ult i64 [[IV_SPLIT]], 10 |
| ; CHECK-NEXT: br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]] |
| ; CHECK: if.else.split: |
| ; CHECK-NEXT: br label [[FOR_INC_SPLIT]] |
| ; CHECK: if.then.split: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, i64* [[SRC]], i64 [[IV_SPLIT]] |
| ; CHECK-NEXT: [[VAL_SPLIT:%.*]] = load i64, i64* [[SRC_ARRAYIDX_SPLIT]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, i64* [[DST]], i64 [[IV_SPLIT]] |
| ; CHECK-NEXT: store i64 [[VAL_SPLIT]], i64* [[DST_ARRAYIDX_SPLIT]], align 4 |
| ; CHECK-NEXT: br label [[FOR_INC_SPLIT]] |
| ; CHECK: for.inc.split: |
| ; CHECK-NEXT: [[INC_SPLIT]] = add nuw nsw i64 [[IV_SPLIT]], 2 |
| ; CHECK-NEXT: [[COND_SPLIT:%.*]] = icmp sgt i64 [[INC_SPLIT]], [[N]] |
| ; CHECK-NEXT: br i1 [[COND_SPLIT]], label [[EXIT_LOOPEXIT:%.*]], label [[LOOP_SPLIT]] |
| ; CHECK: exit.loopexit: |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| loop.ph: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ] |
| %cmp = icmp ult i64 %iv, 10 |
| br i1 %cmp, label %if.then, label %if.else |
| |
| if.then: |
| %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv |
| %val = load i64, i64* %src.arrayidx |
| %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv |
| store i64 %val, i64* %dst.arrayidx |
| br label %for.inc |
| |
| if.else: |
| br label %for.inc |
| |
| for.inc: |
| %inc = add nuw nsw i64 %iv, 2 |
| %cond = icmp sgt i64 %inc, %n |
| br i1 %cond, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| define void @variable_split_loop_bound_and_exit_cond_inc_with_ne(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) { |
| ; CHECK-LABEL: @variable_split_loop_bound_and_exit_cond_inc_with_ne( |
| ; CHECK-NEXT: loop.ph: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]] |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[FOR_INC]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[IV]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp ne i64 [[INC]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| loop.ph: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ] |
| %cmp = icmp ult i64 %iv, %a |
| br i1 %cmp, label %if.then, label %for.inc |
| |
| if.then: |
| %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv |
| %val = load i64, i64* %src.arrayidx |
| %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv |
| store i64 %val, i64* %dst.arrayidx |
| br label %for.inc |
| |
| for.inc: |
| %inc = add nuw nsw i64 %iv, 1 |
| %cond = icmp ne i64 %inc, %n |
| br i1 %cond, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| define void @constant_split_loop_bound_and_exit_cond_inc_with_ne(i64* noalias %src, i64* noalias %dst, i64 %n) { |
| ; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_inc_with_ne( |
| ; CHECK-NEXT: loop.ph: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IV]], 10 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[FOR_INC]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[IV]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp ne i64 [[INC]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| loop.ph: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ] |
| %cmp = icmp ult i64 %iv, 10 |
| br i1 %cmp, label %if.then, label %for.inc |
| |
| if.then: |
| %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv |
| %val = load i64, i64* %src.arrayidx |
| %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv |
| store i64 %val, i64* %dst.arrayidx |
| br label %for.inc |
| |
| for.inc: |
| %inc = add nuw nsw i64 %iv, 1 |
| %cond = icmp ne i64 %inc, %n |
| br i1 %cond, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| define void @varialbe_split_loop_bound_and_exit_cond_dec_with_slt(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) { |
| ; CHECK-LABEL: @varialbe_split_loop_bound_and_exit_cond_dec_with_slt( |
| ; CHECK-NEXT: loop.ph: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[DEC:%.*]], [[FOR_DEC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]] |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[FOR_DEC]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: br label [[FOR_DEC]] |
| ; CHECK: for.dec: |
| ; CHECK-NEXT: [[DEC]] = sub nuw nsw i64 [[IV]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp slt i64 [[DEC]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| loop.ph: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ %dec, %for.dec ], [ 0, %loop.ph ] |
| %cmp = icmp ult i64 %iv, %a |
| br i1 %cmp, label %if.then, label %for.dec |
| |
| if.then: |
| %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv |
| %val = load i64, i64* %src.arrayidx |
| %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv |
| store i64 %val, i64* %dst.arrayidx |
| br label %for.dec |
| |
| for.dec: |
| %dec = sub nuw nsw i64 %iv, 1 |
| %cond = icmp slt i64 %dec, %n |
| br i1 %cond, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| define void @constant_split_loop_bound_and_exit_cond_dec_with_slt(i64* noalias %src, i64* noalias %dst, i64 %n) { |
| ; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_dec_with_slt( |
| ; CHECK-NEXT: loop.ph: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[DEC:%.*]], [[FOR_DEC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IV]], 10 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[FOR_DEC]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: br label [[FOR_DEC]] |
| ; CHECK: for.dec: |
| ; CHECK-NEXT: [[DEC]] = sub nuw nsw i64 [[IV]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp slt i64 [[DEC]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| loop.ph: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ %dec, %for.dec ], [ 0, %loop.ph ] |
| %cmp = icmp ult i64 %iv, 10 |
| br i1 %cmp, label %if.then, label %for.dec |
| |
| if.then: |
| %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv |
| %val = load i64, i64* %src.arrayidx |
| %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv |
| store i64 %val, i64* %dst.arrayidx |
| br label %for.dec |
| |
| for.dec: |
| %dec = sub nuw nsw i64 %iv, 1 |
| %cond = icmp slt i64 %dec, %n |
| br i1 %cond, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| define void @variable_split_loop_bound_and_exit_cond_dec_with_sle(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) { |
| ; CHECK-LABEL: @variable_split_loop_bound_and_exit_cond_dec_with_sle( |
| ; CHECK-NEXT: loop.ph: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[DEC:%.*]], [[FOR_DEC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]] |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[FOR_DEC]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: br label [[FOR_DEC]] |
| ; CHECK: for.dec: |
| ; CHECK-NEXT: [[DEC]] = sub nuw nsw i64 [[IV]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp sle i64 [[DEC]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| loop.ph: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ %dec, %for.dec ], [ 0, %loop.ph ] |
| %cmp = icmp ult i64 %iv, %a |
| br i1 %cmp, label %if.then, label %for.dec |
| |
| if.then: |
| %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv |
| %val = load i64, i64* %src.arrayidx |
| %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv |
| store i64 %val, i64* %dst.arrayidx |
| br label %for.dec |
| |
| for.dec: |
| %dec = sub nuw nsw i64 %iv, 1 |
| %cond = icmp sle i64 %dec, %n |
| br i1 %cond, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| define void @constant_split_loop_bound_and_exit_cond_dec_with_sle(i64* noalias %src, i64* noalias %dst, i64 %n) { |
| ; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_dec_with_sle( |
| ; CHECK-NEXT: loop.ph: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[DEC:%.*]], [[FOR_DEC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IV]], 10 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[FOR_DEC]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: br label [[FOR_DEC]] |
| ; CHECK: for.dec: |
| ; CHECK-NEXT: [[DEC]] = sub nuw nsw i64 [[IV]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp sle i64 [[DEC]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| loop.ph: |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ %dec, %for.dec ], [ 0, %loop.ph ] |
| %cmp = icmp ult i64 %iv, 10 |
| br i1 %cmp, label %if.then, label %for.dec |
| |
| if.then: |
| %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv |
| %val = load i64, i64* %src.arrayidx |
| %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv |
| store i64 %val, i64* %dst.arrayidx |
| br label %for.dec |
| |
| for.dec: |
| %dec = sub nuw nsw i64 %iv, 1 |
| %cond = icmp sle i64 %dec, %n |
| br i1 %cond, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| ; LoopBoundSplit pass should ignore phi which is not scevable phi. |
| define void @constant_split_loop_bound_and_exit_cond_inc_with_sgt_and_is_not_scevable_phi(i64* noalias %src, i64* noalias %dst, i64 %n) { |
| ; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_inc_with_sgt_and_is_not_scevable_phi( |
| ; CHECK-NEXT: loop.ph: |
| ; CHECK-NEXT: br label [[LOOP_PH_SPLIT:%.*]] |
| ; CHECK: loop.ph.split: |
| ; CHECK-NEXT: [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[N:%.*]], i64 0) |
| ; CHECK-NEXT: [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[SMAX]], i64 10) |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IS_NOT_SCEVABLE_PHI:%.*]] = phi double [ 1.000000e+00, [[FOR_INC:%.*]] ], [ 2.000000e+00, [[LOOP_PH_SPLIT]] ] |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC]] ], [ 0, [[LOOP_PH_SPLIT]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IV]], 10 |
| ; CHECK-NEXT: br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]] |
| ; CHECK-NEXT: store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4 |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[IV]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i64 [[INC]], [[NEW_BOUND]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[LOOP_PH_SPLIT_SPLIT:%.*]], label [[LOOP]] |
| ; CHECK: loop.ph.split.split: |
| ; CHECK-NEXT: [[IS_NOT_SCEVABLE_PHI_LCSSA:%.*]] = phi double [ 1.000000e+00, [[FOR_INC]] ] |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i64 [ [[INC]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[TMP0:%.*]] = icmp ne i64 [[IV_LCSSA]], [[N]] |
| ; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP_SPLIT_PREHEADER:%.*]], label [[EXIT:%.*]] |
| ; CHECK: loop.split.preheader: |
| ; CHECK-NEXT: br label [[LOOP_SPLIT:%.*]] |
| ; CHECK: loop.split: |
| ; CHECK-NEXT: [[IS_NOT_SCEVABLE_PHI_SPLIT:%.*]] = phi double [ 1.000000e+00, [[FOR_INC_SPLIT:%.*]] ], [ [[IS_NOT_SCEVABLE_PHI_LCSSA]], [[LOOP_SPLIT_PREHEADER]] ] |
| ; CHECK-NEXT: [[IV_SPLIT:%.*]] = phi i64 [ [[INC_SPLIT:%.*]], [[FOR_INC_SPLIT]] ], [ [[IV_LCSSA]], [[LOOP_SPLIT_PREHEADER]] ] |
| ; CHECK-NEXT: [[CMP_SPLIT:%.*]] = icmp ult i64 [[IV_SPLIT]], 10 |
| ; CHECK-NEXT: br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]] |
| ; CHECK: if.else.split: |
| ; CHECK-NEXT: br label [[FOR_INC_SPLIT]] |
| ; CHECK: if.then.split: |
| ; CHECK-NEXT: [[SRC_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, i64* [[SRC]], i64 [[IV_SPLIT]] |
| ; CHECK-NEXT: [[VAL_SPLIT:%.*]] = load i64, i64* [[SRC_ARRAYIDX_SPLIT]], align 4 |
| ; CHECK-NEXT: [[DST_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, i64* [[DST]], i64 [[IV_SPLIT]] |
| ; CHECK-NEXT: store i64 [[VAL_SPLIT]], i64* [[DST_ARRAYIDX_SPLIT]], align 4 |
| ; CHECK-NEXT: br label [[FOR_INC_SPLIT]] |
| ; CHECK: for.inc.split: |
| ; CHECK-NEXT: [[INC_SPLIT]] = add nuw nsw i64 [[IV_SPLIT]], 1 |
| ; CHECK-NEXT: [[COND_SPLIT:%.*]] = icmp sgt i64 [[INC_SPLIT]], [[N]] |
| ; CHECK-NEXT: br i1 [[COND_SPLIT]], label [[EXIT_LOOPEXIT:%.*]], label [[LOOP_SPLIT]] |
| ; CHECK: exit.loopexit: |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| loop.ph: |
| br label %loop |
| |
| loop: |
| %is_not_scevable_phi = phi double [ 1.0, %for.inc ], [ 2.0, %loop.ph ] |
| %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ] |
| %cmp = icmp ult i64 %iv, 10 |
| br i1 %cmp, label %if.then, label %if.else |
| |
| if.then: |
| %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv |
| %val = load i64, i64* %src.arrayidx |
| %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv |
| store i64 %val, i64* %dst.arrayidx |
| br label %for.inc |
| |
| if.else: |
| br label %for.inc |
| |
| for.inc: |
| %inc = add nuw nsw i64 %iv, 1 |
| %cond = icmp sgt i64 %inc, %n |
| br i1 %cond, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| declare i64 @llvm.umax.i64(i64, i64) |