| ; 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 triple-loop nests with guarded inner |
| ; loops. Loops are in canonical form. |
| |
| @a = common global [10 x [10 x [10 x i32]]] zeroinitializer |
| @b = common global [10 x [10 x [10 x i32]]] zeroinitializer |
| @c = common global [10 x [10 x [10 x i32]]] zeroinitializer |
| |
| define i32 @triple_loop_nest_inner_guard(i32 %m, i32 %n, i32 %mm) { |
| ; CHECK-LABEL: define i32 @triple_loop_nest_inner_guard( |
| ; CHECK-SAME: i32 [[M:%.*]], i32 [[N:%.*]], i32 [[MM:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[CMP101:%.*]] = icmp sgt i32 [[M]], 0 |
| ; CHECK-NEXT: br i1 [[CMP101]], label %[[OUTER1_PH:.*]], label %[[FUNC_EXIT:.*]] |
| ; CHECK: [[OUTER1_PH]]: |
| ; CHECK-NEXT: [[CMP298:%.*]] = icmp sgt i32 [[N]], 0 |
| ; CHECK-NEXT: [[CMP696:%.*]] = icmp sgt i32 [[MM]], 0 |
| ; CHECK-NEXT: [[WIDE_TRIP_COUNT122:%.*]] = zext i32 [[M]] to i64 |
| ; CHECK-NEXT: [[WIDE_TRIP_COUNT118:%.*]] = zext i32 [[N]] to i64 |
| ; CHECK-NEXT: [[WIDE_TRIP_COUNT114:%.*]] = zext i32 [[MM]] to i64 |
| ; CHECK-NEXT: br label %[[OUTER1_BODY_MIDDLE1_GUARD:.*]] |
| ; CHECK: [[OUTER1_BODY_MIDDLE1_GUARD]]: |
| ; CHECK-NEXT: [[IV120:%.*]] = phi i64 [ 0, %[[OUTER1_PH]] ], [ [[IV_NEXT121:%.*]], %[[OUTER2_LATCH:.*]] ] |
| ; CHECK-NEXT: [[IV108:%.*]] = phi i64 [ [[IV_NEXT109:%.*]], %[[OUTER2_LATCH]] ], [ 0, %[[OUTER1_PH]] ] |
| ; CHECK-NEXT: br i1 [[CMP298]], label %[[MIDDLE1_PH:.*]], label %[[OUTER2_LATCH]] |
| ; CHECK: [[MIDDLE1_PH]]: |
| ; CHECK-NEXT: br label %[[MIDDLE1_BODY_INNER1_GUARD:.*]] |
| ; CHECK: [[MIDDLE1_BODY_INNER1_GUARD]]: |
| ; CHECK-NEXT: [[IV116:%.*]] = phi i64 [ [[IV_NEXT117:%.*]], %[[MIDDLE2_LATCH:.*]] ], [ 0, %[[MIDDLE1_PH]] ] |
| ; CHECK-NEXT: [[IV104:%.*]] = phi i64 [ [[IV_NEXT105:%.*]], %[[MIDDLE2_LATCH]] ], [ 0, %[[MIDDLE1_PH]] ] |
| ; CHECK-NEXT: br i1 [[CMP696]], label %[[INNER1_PH:.*]], label %[[MIDDLE2_LATCH]] |
| ; CHECK: [[INNER1_PH]]: |
| ; CHECK-NEXT: br label %[[INNER1_BODY:.*]] |
| ; CHECK: [[INNER1_BODY]]: |
| ; CHECK-NEXT: [[IV112:%.*]] = phi i64 [ [[IV_NEXT113:%.*]], %[[INNER1_BODY]] ], [ 0, %[[INNER1_PH]] ] |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], %[[INNER1_BODY]] ], [ 0, %[[INNER1_PH]] ] |
| ; CHECK-NEXT: [[IDX12:%.*]] = getelementptr inbounds [10 x [10 x [10 x i32]]], ptr @a, i64 0, i64 [[IV120]], i64 [[IV116]], i64 [[IV112]] |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[IDX12]], align 4 |
| ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], 2 |
| ; CHECK-NEXT: [[IDX18:%.*]] = getelementptr inbounds [10 x [10 x [10 x i32]]], ptr @b, i64 0, i64 [[IV120]], i64 [[IV116]], i64 [[IV112]] |
| ; CHECK-NEXT: store i32 [[ADD]], ptr [[IDX18]], align 4 |
| ; CHECK-NEXT: [[IV_NEXT113]] = add nuw nsw i64 [[IV112]], 1 |
| ; CHECK-NEXT: [[EXITCOND115:%.*]] = icmp eq i64 [[IV_NEXT113]], [[WIDE_TRIP_COUNT114]] |
| ; CHECK-NEXT: [[IDX45:%.*]] = getelementptr inbounds [10 x [10 x [10 x i32]]], ptr @a, i64 0, i64 [[IV108]], i64 [[IV104]], i64 [[IV]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[IDX45]], align 4 |
| ; CHECK-NEXT: [[MUL:%.*]] = shl nsw i32 [[TMP1]], 1 |
| ; CHECK-NEXT: [[IDX51:%.*]] = getelementptr inbounds [10 x [10 x [10 x i32]]], ptr @c, i64 0, i64 [[IV108]], i64 [[IV104]], i64 [[IV]] |
| ; CHECK-NEXT: store i32 [[MUL]], ptr [[IDX51]], align 4 |
| ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 |
| ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], [[WIDE_TRIP_COUNT114]] |
| ; CHECK-NEXT: br i1 [[EXITCOND]], label %[[INNER2_EXIT:.*]], label %[[INNER1_BODY]] |
| ; CHECK: [[INNER2_EXIT]]: |
| ; CHECK-NEXT: br label %[[MIDDLE2_LATCH]] |
| ; CHECK: [[MIDDLE2_LATCH]]: |
| ; CHECK-NEXT: [[IV_NEXT117]] = add nuw nsw i64 [[IV116]], 1 |
| ; CHECK-NEXT: [[EXITCOND119:%.*]] = icmp eq i64 [[IV_NEXT117]], [[WIDE_TRIP_COUNT118]] |
| ; CHECK-NEXT: [[IV_NEXT105]] = add nuw nsw i64 [[IV104]], 1 |
| ; CHECK-NEXT: [[EXITCOND107:%.*]] = icmp eq i64 [[IV_NEXT105]], [[WIDE_TRIP_COUNT118]] |
| ; CHECK-NEXT: br i1 [[EXITCOND107]], label %[[MIDDLE2_EXIT:.*]], label %[[MIDDLE1_BODY_INNER1_GUARD]] |
| ; CHECK: [[MIDDLE2_EXIT]]: |
| ; CHECK-NEXT: br label %[[OUTER2_LATCH]] |
| ; CHECK: [[OUTER2_LATCH]]: |
| ; CHECK-NEXT: [[IV_NEXT121]] = add nuw nsw i64 [[IV120]], 1 |
| ; CHECK-NEXT: [[EXITCOND123:%.*]] = icmp eq i64 [[IV_NEXT121]], [[WIDE_TRIP_COUNT122]] |
| ; CHECK-NEXT: [[IV_NEXT109]] = add nuw nsw i64 [[IV108]], 1 |
| ; CHECK-NEXT: [[EXITCOND111:%.*]] = icmp eq i64 [[IV_NEXT109]], [[WIDE_TRIP_COUNT122]] |
| ; CHECK-NEXT: br i1 [[EXITCOND111]], label %[[OUTER2_EXIT:.*]], label %[[OUTER1_BODY_MIDDLE1_GUARD]] |
| ; CHECK: [[OUTER2_EXIT]]: |
| ; CHECK-NEXT: br label %[[FUNC_EXIT]] |
| ; CHECK: [[FUNC_EXIT]]: |
| ; CHECK-NEXT: ret i32 0 |
| ; |
| entry: |
| %cmp101 = icmp sgt i32 %m, 0 |
| br i1 %cmp101, label %outer1.ph, label %func_exit |
| |
| outer1.ph: |
| %cmp298 = icmp sgt i32 %n, 0 |
| %cmp696 = icmp sgt i32 %mm, 0 |
| %wide.trip.count122 = zext i32 %m to i64 |
| %wide.trip.count118 = zext i32 %n to i64 |
| %wide.trip.count114 = zext i32 %mm to i64 |
| br label %outer1.body.middle1.guard |
| |
| outer1.body.middle1.guard: |
| %iv120 = phi i64 [ 0, %outer1.ph ], [ %iv.next121, %outer1.latch ] |
| br i1 %cmp298, label %middle1.ph, label %outer1.latch |
| |
| middle1.ph: |
| br label %middle1.body.inner1.guard |
| |
| middle1.body.inner1.guard: |
| %iv116 = phi i64 [ %iv.next117, %middle1.latch ], [ 0, %middle1.ph ] |
| br i1 %cmp696, label %inner1.ph, label %middle1.latch |
| |
| inner1.ph: |
| br label %inner1.body |
| |
| inner1.body: |
| %iv112 = phi i64 [ %iv.next113, %inner1.body ], [ 0, %inner1.ph ] |
| %idx12 = getelementptr inbounds [10 x [10 x [10 x i32]]], ptr @a, i64 0, i64 %iv120, i64 %iv116, i64 %iv112 |
| %0 = load i32, ptr %idx12 |
| %add = add nsw i32 %0, 2 |
| %idx18 = getelementptr inbounds [10 x [10 x [10 x i32]]], ptr @b, i64 0, i64 %iv120, i64 %iv116, i64 %iv112 |
| store i32 %add, ptr %idx18 |
| %iv.next113 = add nuw nsw i64 %iv112, 1 |
| %exitcond115 = icmp eq i64 %iv.next113, %wide.trip.count114 |
| br i1 %exitcond115, label %inner1.exit, label %inner1.body |
| |
| inner1.exit: |
| br label %middle1.latch |
| |
| middle1.latch: |
| %iv.next117 = add nuw nsw i64 %iv116, 1 |
| %exitcond119 = icmp eq i64 %iv.next117, %wide.trip.count118 |
| br i1 %exitcond119, label %middle1.exit, label %middle1.body.inner1.guard |
| |
| middle1.exit: |
| br label %outer1.latch |
| |
| outer1.latch: |
| %iv.next121 = add nuw nsw i64 %iv120, 1 |
| %exitcond123 = icmp eq i64 %iv.next121, %wide.trip.count122 |
| br i1 %exitcond123, label %outer2.ph, label %outer1.body.middle1.guard |
| |
| outer2.ph: |
| br label %outer2.middle2.guard |
| |
| outer2.middle2.guard: |
| %iv108 = phi i64 [ %iv.next109, %outer2.latch ], [ 0, %outer2.ph ] |
| br i1 %cmp298, label %middle2.ph, label %outer2.latch |
| |
| middle2.ph: |
| br label %middle2.body.inner2.guard |
| |
| middle2.body.inner2.guard: |
| %iv104 = phi i64 [ %iv.next105, %middle2.latch ], [ 0, %middle2.ph ] |
| br i1 %cmp696, label %inner2.ph, label %middle2.latch |
| |
| inner2.ph: |
| br label %inner2.body |
| |
| inner2.body: |
| %iv = phi i64 [ %iv.next, %inner2.body ], [ 0, %inner2.ph ] |
| %idx45 = getelementptr inbounds [10 x [10 x [10 x i32]]], ptr @a, i64 0, i64 %iv108, i64 %iv104, i64 %iv |
| %1 = load i32, ptr %idx45 |
| %mul = shl nsw i32 %1, 1 |
| %idx51 = getelementptr inbounds [10 x [10 x [10 x i32]]], ptr @c, i64 0, i64 %iv108, i64 %iv104, i64 %iv |
| store i32 %mul, ptr %idx51 |
| %iv.next = add nuw nsw i64 %iv, 1 |
| %exitcond = icmp eq i64 %iv.next, %wide.trip.count114 |
| br i1 %exitcond, label %inner2.exit, label %inner2.body |
| |
| inner2.exit: |
| br label %middle2.latch |
| |
| middle2.latch: |
| %iv.next105 = add nuw nsw i64 %iv104, 1 |
| %exitcond107 = icmp eq i64 %iv.next105, %wide.trip.count118 |
| br i1 %exitcond107, label %middle2.exit, label %middle2.body.inner2.guard |
| |
| middle2.exit: |
| br label %outer2.latch |
| |
| outer2.latch: |
| %iv.next109 = add nuw nsw i64 %iv108, 1 |
| %exitcond111 = icmp eq i64 %iv.next109, %wide.trip.count122 |
| br i1 %exitcond111, label %outer2.exit, label %outer2.middle2.guard |
| |
| outer2.exit: |
| br label %func_exit |
| |
| func_exit: |
| ret i32 0 |
| } |