blob: a9f066b4657adcc181dbddbcb6f688cb6bba7641 [file]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -S -passes=loop-fusion < %s 2>&1 | FileCheck %s
; Verify that LoopFusion can fuse two double-loop nests with guarded inner
; loops. Loops are in canonical form.
@a = common global [10 x [10 x i32]] zeroinitializer
@b = common global [10 x [10 x i32]] zeroinitializer
@c = common global [10 x [10 x i32]] zeroinitializer
define i32 @double_loop_nest_inner_guard(i32 %m, i32 %n) {
; CHECK-LABEL: define i32 @double_loop_nest_inner_guard(
; CHECK-SAME: i32 [[M:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[CMP63:%.*]] = icmp sgt i32 [[M]], 0
; CHECK-NEXT: br i1 [[CMP63]], label %[[OUTER1_PH:.*]], label %[[FUNC_EXIT:.*]]
; CHECK: [[OUTER1_PH]]:
; CHECK-NEXT: [[CMP261:%.*]] = icmp sgt i32 [[N]], 0
; CHECK-NEXT: [[WIDE_TRIP_COUNT76:%.*]] = zext i32 [[M]] to i64
; CHECK-NEXT: [[WIDE_TRIP_COUNT72:%.*]] = zext i32 [[N]] to i64
; CHECK-NEXT: br label %[[OUTER1_BODY_INNER_GUARD:.*]]
; CHECK: [[OUTER1_BODY_INNER_GUARD]]:
; CHECK-NEXT: [[IV74:%.*]] = phi i64 [ 0, %[[OUTER1_PH]] ], [ [[IV_NEXT75:%.*]], %[[OUTER2_LATCH:.*]] ]
; CHECK-NEXT: [[IV66:%.*]] = phi i64 [ [[IV_NEXT67:%.*]], %[[OUTER2_LATCH]] ], [ 0, %[[OUTER1_PH]] ]
; CHECK-NEXT: br i1 [[CMP261]], label %[[INNER1_PH:.*]], label %[[OUTER2_LATCH]]
; CHECK: [[INNER1_PH]]:
; CHECK-NEXT: br label %[[INNER1_BODY:.*]]
; CHECK: [[INNER1_BODY]]:
; CHECK-NEXT: [[IV70:%.*]] = phi i64 [ [[IV_NEXT71:%.*]], %[[INNER1_BODY]] ], [ 0, %[[INNER1_PH]] ]
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], %[[INNER1_BODY]] ], [ 0, %[[INNER1_PH]] ]
; CHECK-NEXT: [[IDX6:%.*]] = getelementptr inbounds [10 x [10 x i32]], ptr @a, i64 0, i64 [[IV74]], i64 [[IV70]]
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[IDX6]], align 4
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], 2
; CHECK-NEXT: [[IDX10:%.*]] = getelementptr inbounds [10 x [10 x i32]], ptr @b, i64 0, i64 [[IV74]], i64 [[IV70]]
; CHECK-NEXT: store i32 [[ADD]], ptr [[IDX10]], align 4
; CHECK-NEXT: [[IV_NEXT71]] = add nuw nsw i64 [[IV70]], 1
; CHECK-NEXT: [[EXITCOND73:%.*]] = icmp eq i64 [[IV_NEXT71]], [[WIDE_TRIP_COUNT72]]
; CHECK-NEXT: [[IDX27:%.*]] = getelementptr inbounds [10 x [10 x i32]], ptr @a, i64 0, i64 [[IV66]], i64 [[IV]]
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[IDX27]], align 4
; CHECK-NEXT: [[MUL:%.*]] = shl nsw i32 [[TMP1]], 1
; CHECK-NEXT: [[IDX31:%.*]] = getelementptr inbounds [10 x [10 x i32]], ptr @c, i64 0, i64 [[IV66]], i64 [[IV]]
; CHECK-NEXT: store i32 [[MUL]], ptr [[IDX31]], align 4
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], [[WIDE_TRIP_COUNT72]]
; CHECK-NEXT: br i1 [[EXITCOND]], label %[[INNER2_EXIT:.*]], label %[[INNER1_BODY]]
; CHECK: [[INNER2_EXIT]]:
; CHECK-NEXT: br label %[[OUTER2_LATCH]]
; CHECK: [[OUTER2_LATCH]]:
; CHECK-NEXT: [[IV_NEXT75]] = add nuw nsw i64 [[IV74]], 1
; CHECK-NEXT: [[EXITCOND77:%.*]] = icmp eq i64 [[IV_NEXT75]], [[WIDE_TRIP_COUNT76]]
; CHECK-NEXT: [[IV_NEXT67]] = add nuw nsw i64 [[IV66]], 1
; CHECK-NEXT: [[EXITCOND69:%.*]] = icmp eq i64 [[IV_NEXT67]], [[WIDE_TRIP_COUNT76]]
; CHECK-NEXT: br i1 [[EXITCOND69]], label %[[OUTER2_EXIT:.*]], label %[[OUTER1_BODY_INNER_GUARD]]
; CHECK: [[OUTER2_EXIT]]:
; CHECK-NEXT: br label %[[FUNC_EXIT]]
; CHECK: [[FUNC_EXIT]]:
; CHECK-NEXT: ret i32 0
;
entry:
%cmp63 = icmp sgt i32 %m, 0
br i1 %cmp63, label %outer1.ph, label %func_exit
outer1.ph:
%cmp261 = icmp sgt i32 %n, 0
%wide.trip.count76 = zext i32 %m to i64
%wide.trip.count72 = zext i32 %n to i64
br label %outer1.body.inner.guard
outer1.body.inner.guard:
%iv74 = phi i64 [ 0, %outer1.ph ], [ %iv.next75, %outer1.latch ]
br i1 %cmp261, label %inner1.ph, label %outer1.latch
inner1.ph:
br label %inner1.body
inner1.body:
%iv70 = phi i64 [ %iv.next71, %inner1.body ], [ 0, %inner1.ph ]
%idx6 = getelementptr inbounds [10 x [10 x i32]], ptr @a, i64 0, i64 %iv74, i64 %iv70
%0 = load i32, ptr %idx6
%add = add nsw i32 %0, 2
%idx10 = getelementptr inbounds [10 x [10 x i32]], ptr @b, i64 0, i64 %iv74, i64 %iv70
store i32 %add, ptr %idx10
%iv.next71 = add nuw nsw i64 %iv70, 1
%exitcond73 = icmp eq i64 %iv.next71, %wide.trip.count72
br i1 %exitcond73, label %inner1.exit, label %inner1.body
inner1.exit:
br label %outer1.latch
outer1.latch:
%iv.next75 = add nuw nsw i64 %iv74, 1
%exitcond77 = icmp eq i64 %iv.next75, %wide.trip.count76
br i1 %exitcond77, label %outer2.ph, label %outer1.body.inner.guard
outer2.ph:
br label %outer2.body.inner.guard
outer2.body.inner.guard:
%iv66 = phi i64 [ %iv.next67, %outer2.latch ], [ 0, %outer2.ph ]
br i1 %cmp261, label %inner2.ph, label %outer2.latch
inner2.ph:
br label %inner2.body
inner2.body:
%iv = phi i64 [ %iv.next, %inner2.body ], [ 0, %inner2.ph ]
%idx27 = getelementptr inbounds [10 x [10 x i32]], ptr @a, i64 0, i64 %iv66, i64 %iv
%1 = load i32, ptr %idx27
%mul = shl nsw i32 %1, 1
%idx31 = getelementptr inbounds [10 x [10 x i32]], ptr @c, i64 0, i64 %iv66, i64 %iv
store i32 %mul, ptr %idx31
%iv.next = add nuw nsw i64 %iv, 1
%exitcond = icmp eq i64 %iv.next, %wide.trip.count72
br i1 %exitcond, label %inner2.exit, label %inner2.body
inner2.exit:
br label %outer2.latch
outer2.latch:
%iv.next67 = add nuw nsw i64 %iv66, 1
%exitcond69 = icmp eq i64 %iv.next67, %wide.trip.count76
br i1 %exitcond69, label %outer2.exit, label %outer2.body.inner.guard
outer2.exit:
br label %func_exit
func_exit:
ret i32 0
}