1; RUN: opt -S -passes=loop-fusion < %s 2>&1 | FileCheck %s 2 3; Verify that LoopFusion can fuse two triple-loop nests with guarded inner 4; loops. Loops are in canonical form. 5 6@a = common global [10 x [10 x [10 x i32]]] zeroinitializer 7@b = common global [10 x [10 x [10 x i32]]] zeroinitializer 8@c = common global [10 x [10 x [10 x i32]]] zeroinitializer 9 10; CHECK-LABEL: @triple_loop_nest_inner_guard 11; CHECK: br i1 %{{.*}}, label %[[OUTER_PH:outer1.ph]], label %[[FUNC_EXIT:func_exit]] 12 13; CHECK: [[OUTER_PH]]: 14; CHECK: br label %[[OUTER_BODY_MIDDLE_GUARD:outer1.body.middle1.guard]] 15 16; CHECK: [[OUTER_BODY_MIDDLE_GUARD]]: 17; CHECK: br i1 %{{.*}}, label %[[MIDDLE_PH:middle1.ph]], label %[[OUTER_LATCH:outer2.latch]] 18 19; CHECK: [[MIDDLE_PH]]: 20; CHECK-NEXT: br label %[[MIDDLE_BODY_INNER_GUARD:middle1.body.inner1.guard]] 21 22; CHECK: [[MIDDLE_BODY_INNER_GUARD]]: 23; CHECK: br i1 %{{.*}}, label %[[INNER_PH:inner1.ph]], label %[[MIDDLE_LATCH:middle2.latch]] 24 25; CHECK: [[INNER_PH]]: 26; CHECK-NEXT: br label %[[INNER_BODY:inner1.body]] 27 28; CHECK: [[INNER_BODY]]: 29; First loop body. 30; CHECK: load 31; CHECK: add 32; CHECK: store 33; Second loop body. 34; CHECK: load 35; CHECK: mul 36; CHECK: store 37; CHECK: br i1 %{{.*}}, label %[[INNER_EXIT:inner2.exit]], label %[[INNER_BODY:inner1.body]] 38 39; CHECK: [[INNER_EXIT]]: 40; CHECK-NEXT: br label %[[MIDDLE_LATCH:middle2.latch]] 41 42; CHECK: [[MIDDLE_LATCH]]: 43; CHECK: br i1 %{{.*}}, label %[[MIDDLE_EXIT:middle2.exit]], label %[[MIDDLE_BODY_INNER_GUARD]] 44 45; CHECK: [[MIDDLE_EXIT]]: 46; CHECK-NEXT: br label %[[OUTER_LATCH:outer2.latch]] 47 48; CHECK: [[OUTER_LATCH]]: 49; CHECK: br i1 %{{.*}}, label %[[OUTER_EXIT:outer2.exit]], label %[[OUTER_BODY_MIDDLE_GUARD]] 50 51; CHECK: [[OUTER_EXIT]]: 52; CHECK-NEXT: br label %[[FUNC_EXIT:func_exit]] 53 54; CHECK: [[FUNC_EXIT]]: 55; CHECK-NEXT: ret 56 57define i32 @triple_loop_nest_inner_guard(i32 %m, i32 %n, i32 %M, i32 %N) { 58entry: 59 %cmp101 = icmp sgt i32 %m, 0 60 br i1 %cmp101, label %outer1.ph, label %func_exit 61 62outer1.ph: 63 %cmp298 = icmp sgt i32 %n, 0 64 %cmp696 = icmp sgt i32 %M, 0 65 %wide.trip.count122 = zext i32 %m to i64 66 %wide.trip.count118 = zext i32 %n to i64 67 %wide.trip.count114 = zext i32 %M to i64 68 br label %outer1.body.middle1.guard 69 70outer1.body.middle1.guard: 71 %iv120 = phi i64 [ 0, %outer1.ph ], [ %iv.next121, %outer1.latch ] 72 br i1 %cmp298, label %middle1.ph, label %outer1.latch 73 74middle1.ph: 75 br label %middle1.body.inner1.guard 76 77middle1.body.inner1.guard: 78 %iv116 = phi i64 [ %iv.next117, %middle1.latch ], [ 0, %middle1.ph ] 79 br i1 %cmp696, label %inner1.ph, label %middle1.latch 80 81inner1.ph: 82 br label %inner1.body 83 84inner1.body: 85 %iv112 = phi i64 [ %iv.next113, %inner1.body ], [ 0, %inner1.ph ] 86 %idx12 = getelementptr inbounds [10 x [10 x [10 x i32]]], ptr @a, i64 0, i64 %iv120, i64 %iv116, i64 %iv112 87 %0 = load i32, ptr %idx12 88 %add = add nsw i32 %0, 2 89 %idx18 = getelementptr inbounds [10 x [10 x [10 x i32]]], ptr @b, i64 0, i64 %iv120, i64 %iv116, i64 %iv112 90 store i32 %add, ptr %idx18 91 %iv.next113 = add nuw nsw i64 %iv112, 1 92 %exitcond115 = icmp eq i64 %iv.next113, %wide.trip.count114 93 br i1 %exitcond115, label %inner1.exit, label %inner1.body 94 95inner1.exit: 96 br label %middle1.latch 97 98middle1.latch: 99 %iv.next117 = add nuw nsw i64 %iv116, 1 100 %exitcond119 = icmp eq i64 %iv.next117, %wide.trip.count118 101 br i1 %exitcond119, label %middle1.exit, label %middle1.body.inner1.guard 102 103middle1.exit: 104 br label %outer1.latch 105 106outer1.latch: 107 %iv.next121 = add nuw nsw i64 %iv120, 1 108 %exitcond123 = icmp eq i64 %iv.next121, %wide.trip.count122 109 br i1 %exitcond123, label %outer2.ph, label %outer1.body.middle1.guard 110 111outer2.ph: 112 br label %outer2.middle2.guard 113 114outer2.middle2.guard: 115 %iv108 = phi i64 [ %iv.next109, %outer2.latch ], [ 0, %outer2.ph ] 116 br i1 %cmp298, label %middle2.ph, label %outer2.latch 117 118middle2.ph: 119 br label %middle2.body.inner2.guard 120 121middle2.body.inner2.guard: 122 %iv104 = phi i64 [ %iv.next105, %middle2.latch ], [ 0, %middle2.ph ] 123 br i1 %cmp696, label %inner2.ph, label %middle2.latch 124 125inner2.ph: 126 br label %inner2.body 127 128inner2.body: 129 %iv = phi i64 [ %iv.next, %inner2.body ], [ 0, %inner2.ph ] 130 %idx45 = getelementptr inbounds [10 x [10 x [10 x i32]]], ptr @a, i64 0, i64 %iv108, i64 %iv104, i64 %iv 131 %1 = load i32, ptr %idx45 132 %mul = shl nsw i32 %1, 1 133 %idx51 = getelementptr inbounds [10 x [10 x [10 x i32]]], ptr @c, i64 0, i64 %iv108, i64 %iv104, i64 %iv 134 store i32 %mul, ptr %idx51 135 %iv.next = add nuw nsw i64 %iv, 1 136 %exitcond = icmp eq i64 %iv.next, %wide.trip.count114 137 br i1 %exitcond, label %inner2.exit, label %inner2.body 138 139inner2.exit: 140 br label %middle2.latch 141 142middle2.latch: 143 %iv.next105 = add nuw nsw i64 %iv104, 1 144 %exitcond107 = icmp eq i64 %iv.next105, %wide.trip.count118 145 br i1 %exitcond107, label %middle2.exit, label %middle2.body.inner2.guard 146 147middle2.exit: 148 br label %outer2.latch 149 150outer2.latch: 151 %iv.next109 = add nuw nsw i64 %iv108, 1 152 %exitcond111 = icmp eq i64 %iv.next109, %wide.trip.count122 153 br i1 %exitcond111, label %outer2.exit, label %outer2.middle2.guard 154 155outer2.exit: 156 br label %func_exit 157 158func_exit: 159 ret i32 undef 160} 161