| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt < %s -passes="loop-reduce" -S -lsr-term-fold | FileCheck %s |
| |
| ; There are 3 test cases here regarding the replacing the primary iv with |
| ; other affine AddRec IV. |
| ; 1. Loop with constant tripcount |
| ; 2. Loop with runtime tripcount |
| ; 3. The replacing AddRec IV is a complicated AddRec. This tests whether |
| ; the fold terminating condition transformation is writing new terminating |
| ; condition in the correct type. |
| |
| target datalayout = "e-p:32:32:32-n32" |
| |
| ; This is equivalent to the following code, loop guard is removed. |
| ; void const_tripcount(int *a) { |
| ; for (int i = 21; i < 400; i++) |
| ; a[i] = 1; |
| ; } |
| define void @const_tripcount(ptr %a) { |
| ; CHECK-LABEL: @const_tripcount( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[UGLYGEP:%.*]] = getelementptr i8, ptr [[A:%.*]], i64 84 |
| ; CHECK-NEXT: [[UGLYGEP1:%.*]] = getelementptr i8, ptr [[A]], i32 1600 |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[LSR_IV1:%.*]] = phi ptr [ [[UGLYGEP2:%.*]], [[FOR_BODY]] ], [ [[UGLYGEP]], [[ENTRY:%.*]] ] |
| ; CHECK-NEXT: store i32 1, ptr [[LSR_IV1]], align 4 |
| ; CHECK-NEXT: [[UGLYGEP2]] = getelementptr i8, ptr [[LSR_IV1]], i64 4 |
| ; CHECK-NEXT: [[LSR_FOLD_TERM_COND_REPLACED_TERM_COND:%.*]] = icmp eq ptr [[UGLYGEP2]], [[UGLYGEP1]] |
| ; CHECK-NEXT: br i1 [[LSR_FOLD_TERM_COND_REPLACED_TERM_COND]], label [[FOR_END:%.*]], label [[FOR_BODY]] |
| ; CHECK: for.end: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %uglygep = getelementptr i8, ptr %a, i64 84 |
| br label %for.body |
| |
| for.body: ; preds = %for.body, %entry |
| %lsr.iv1 = phi ptr [ %uglygep2, %for.body ], [ %uglygep, %entry ] |
| %lsr.iv = phi i64 [ %lsr.iv.next, %for.body ], [ 379, %entry ] |
| store i32 1, ptr %lsr.iv1, align 4 |
| %lsr.iv.next = add nsw i64 %lsr.iv, -1 |
| %uglygep2 = getelementptr i8, ptr %lsr.iv1, i64 4 |
| %exitcond.not = icmp eq i64 %lsr.iv.next, 0 |
| br i1 %exitcond.not, label %for.end, label %for.body |
| |
| for.end: ; preds = %for.body |
| ret void |
| } |
| |
| ; This is equivalent to the following code, loop guard is removed. |
| ; void runtime_tripcount(int *a, int N) { |
| ; for (int i = 21; i < N; i++) |
| ; a[i] = 1; |
| ; } |
| |
| define void @runtime_tripcount(ptr %a, i32 %N) { |
| ; CHECK-LABEL: @runtime_tripcount( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[UGLYGEP:%.*]] = getelementptr i8, ptr [[A:%.*]], i32 84 |
| ; CHECK-NEXT: [[TMP0:%.*]] = shl i32 [[N:%.*]], 2 |
| ; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[TMP0]], 84 |
| ; CHECK-NEXT: [[UGLYGEP1:%.*]] = getelementptr i8, ptr [[A]], i32 [[TMP1]] |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[LSR_IV1:%.*]] = phi ptr [ [[UGLYGEP2:%.*]], [[FOR_BODY]] ], [ [[UGLYGEP]], [[ENTRY:%.*]] ] |
| ; CHECK-NEXT: store i32 1, ptr [[LSR_IV1]], align 4 |
| ; CHECK-NEXT: [[UGLYGEP2]] = getelementptr i8, ptr [[LSR_IV1]], i64 4 |
| ; CHECK-NEXT: [[LSR_FOLD_TERM_COND_REPLACED_TERM_COND:%.*]] = icmp eq ptr [[UGLYGEP2]], [[UGLYGEP1]] |
| ; CHECK-NEXT: br i1 [[LSR_FOLD_TERM_COND_REPLACED_TERM_COND]], label [[FOR_END:%.*]], label [[FOR_BODY]] |
| ; CHECK: for.end: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %uglygep = getelementptr i8, ptr %a, i32 84 |
| br label %for.body |
| |
| for.body: ; preds = %for.body, %entry |
| %lsr.iv1 = phi ptr [ %uglygep2, %for.body ], [ %uglygep, %entry ] |
| %lsr.iv = phi i32 [ %lsr.iv.next, %for.body ], [ %N, %entry ] |
| store i32 1, ptr %lsr.iv1, align 4 |
| %lsr.iv.next = add nsw i32 %lsr.iv, -1 |
| %uglygep2 = getelementptr i8, ptr %lsr.iv1, i64 4 |
| %exitcond.not = icmp eq i32 %lsr.iv.next, 0 |
| br i1 %exitcond.not, label %for.end, label %for.body |
| |
| for.end: ; preds = %for.body |
| ret void |
| } |
| |
| ; This is modified from IR of the following code, loop guard is removed. |
| ; void foo(int*); |
| ; void ptr_of_ptr_addrec(int **ptrptr, int length) { |
| ; int **it = ptrptr; |
| ; for (int i = length; i; i--) { |
| ; foo(*it); |
| ; it++; |
| ; } |
| ; } |
| define void @ptr_of_ptr_addrec(ptr %ptrptr, i32 %length) { |
| ; CHECK-LABEL: @ptr_of_ptr_addrec( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[START_PTRPTR:%.*]] = getelementptr ptr, ptr [[PTRPTR:%.*]] |
| ; CHECK-NEXT: [[TMP0:%.*]] = shl i32 [[LENGTH:%.*]], 2 |
| ; CHECK-NEXT: [[UGLYGEP:%.*]] = getelementptr i8, ptr [[START_PTRPTR]], i32 [[TMP0]] |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[IT_04:%.*]] = phi ptr [ [[INCDEC_PTR:%.*]], [[FOR_BODY]] ], [ [[START_PTRPTR]], [[ENTRY:%.*]] ] |
| ; CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[IT_04]], align 8 |
| ; CHECK-NEXT: tail call void @foo(ptr [[TMP1]]) |
| ; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds ptr, ptr [[IT_04]], i64 1 |
| ; CHECK-NEXT: [[LSR_FOLD_TERM_COND_REPLACED_TERM_COND:%.*]] = icmp eq ptr [[INCDEC_PTR]], [[UGLYGEP]] |
| ; CHECK-NEXT: br i1 [[LSR_FOLD_TERM_COND_REPLACED_TERM_COND]], label [[FOR_END:%.*]], label [[FOR_BODY]] |
| ; CHECK: for.end: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %start.ptrptr = getelementptr inbounds ptr, ptr %ptrptr |
| br label %for.body |
| |
| for.body: ; preds = %entry, %for.body |
| %i.05 = phi i32 [ %dec, %for.body ], [ %length, %entry ] |
| %it.04 = phi ptr [ %incdec.ptr, %for.body ], [ %start.ptrptr, %entry ] |
| %0 = load ptr, ptr %it.04, align 8 |
| tail call void @foo(ptr %0) |
| %incdec.ptr = getelementptr inbounds ptr, ptr %it.04, i64 1 |
| %dec = add nsw i32 %i.05, -1 |
| %tobool.not = icmp eq i32 %dec, 0 |
| br i1 %tobool.not, label %for.end, label %for.body |
| |
| for.end: ; preds = %for.body |
| ret void |
| } |
| |
| declare void @foo(ptr) |
| |
| define void @iv_start_non_preheader(ptr %mark, i32 signext %length) { |
| ; CHECK-LABEL: @iv_start_non_preheader( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TOBOOL_NOT3:%.*]] = icmp eq i32 [[LENGTH:%.*]], 0 |
| ; CHECK-NEXT: br i1 [[TOBOOL_NOT3]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY_PREHEADER:%.*]] |
| ; CHECK: for.body.preheader: |
| ; CHECK-NEXT: [[TMP0:%.*]] = shl i32 [[LENGTH]], 2 |
| ; CHECK-NEXT: [[UGLYGEP:%.*]] = getelementptr i8, ptr [[MARK:%.*]], i32 [[TMP0]] |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.cond.cleanup.loopexit: |
| ; CHECK-NEXT: br label [[FOR_COND_CLEANUP]] |
| ; CHECK: for.cond.cleanup: |
| ; CHECK-NEXT: ret void |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[DST_04:%.*]] = phi ptr [ [[INCDEC_PTR:%.*]], [[FOR_BODY]] ], [ [[MARK]], [[FOR_BODY_PREHEADER]] ] |
| ; CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[DST_04]], align 8 |
| ; CHECK-NEXT: [[TMP2:%.*]] = call ptr @foo(ptr [[TMP1]]) |
| ; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds ptr, ptr [[DST_04]], i64 1 |
| ; CHECK-NEXT: [[LSR_FOLD_TERM_COND_REPLACED_TERM_COND:%.*]] = icmp eq ptr [[INCDEC_PTR]], [[UGLYGEP]] |
| ; CHECK-NEXT: br i1 [[LSR_FOLD_TERM_COND_REPLACED_TERM_COND]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_BODY]] |
| ; |
| entry: |
| %tobool.not3 = icmp eq i32 %length, 0 |
| br i1 %tobool.not3, label %for.cond.cleanup, label %for.body |
| |
| for.cond.cleanup: ; preds = %for.body, %entry |
| ret void |
| |
| for.body: ; preds = %entry, %for.body |
| %i.05 = phi i32 [ %dec, %for.body ], [ %length, %entry ] |
| %dst.04 = phi ptr [ %incdec.ptr, %for.body ], [ %mark, %entry ] |
| %0 = load ptr, ptr %dst.04, align 8 |
| call ptr @foo(ptr %0) |
| %incdec.ptr = getelementptr inbounds ptr, ptr %dst.04, i64 1 |
| %dec = add nsw i32 %i.05, -1 |
| %tobool.not = icmp eq i32 %dec, 0 |
| br i1 %tobool.not, label %for.cond.cleanup, label %for.body |
| } |