diff --git a/llvm/test/Transforms/LoopInterchange/call-instructions-remarks.ll b/llvm/test/Transforms/LoopInterchange/call-instructions-remarks.ll new file mode 100644 index 0000000000000..4ed3e7e0f5d00 --- /dev/null +++ b/llvm/test/Transforms/LoopInterchange/call-instructions-remarks.ll @@ -0,0 +1,63 @@ +; REQUIRES: asserts +; RUN: opt < %s -passes=loop-interchange -pass-remarks-missed='loop-interchange' -pass-remarks-output=%t -S \ +; RUN: -verify-dom-info -verify-loop-info 2>&1 +; RUN: FileCheck --input-file=%t %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +@A = common global [100 x [100 x i32]] zeroinitializer + +declare void @foo(i64 %a) +declare void @bar(i64 %a) readnone + +;;--------------------------------------Test case 01------------------------------------ +;; Not safe to interchange, because the called function `foo` is not marked as +;; readnone, so it could introduce dependences. +;; +;; for(int i=0;i<100;i++) { +;; for(int j=1;j<100;j++) { +;; foo(i); +;; A[j][i] = A[j][i]+k; +;; } +;; } + +; CHECK: --- !Missed +; CHECK-NEXT: Pass: loop-interchange +; CHECK-NEXT: Name: CallInst +; CHECK-NEXT: Function: interchange_01 +; CHECK-NEXT: Args: +; CHECK-NEXT: - String: Cannot interchange loops due to call instruction. + +define void @interchange_01(i32 %k) { +entry: + br label %for1.header + +for1.header: + %indvars.iv23 = phi i64 [ 0, %entry ], [ %indvars.iv.next24, %for1.inc10 ] + br label %for2 + +for2: + %indvars.iv = phi i64 [ %indvars.iv.next, %for2 ], [ 1, %for1.header ] + call void @foo(i64 %indvars.iv23) + %arrayidx5 = getelementptr inbounds [100 x [100 x i32]], ptr @A, i64 0, i64 %indvars.iv, i64 %indvars.iv23 + %lv = load i32, ptr %arrayidx5 + %add = add nsw i32 %lv, %k + store i32 %add, ptr %arrayidx5 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %exitcond = icmp eq i64 %indvars.iv, 99 + br i1 %exitcond, label %for2.loopexit , label %for2 + +for2.loopexit: + br label %for1.inc10 + +for1.inc10: + %indvars.iv.next24 = add nuw nsw i64 %indvars.iv23, 1 + %exitcond26 = icmp eq i64 %indvars.iv23, 99 + br i1 %exitcond26, label %for1.loopexit, label %for1.header + +for1.loopexit: + br label %exit + +exit: + ret void +} diff --git a/llvm/test/Transforms/LoopInterchange/call-instructions.ll b/llvm/test/Transforms/LoopInterchange/call-instructions.ll index 49e877aa0d36e..b207166302d21 100644 --- a/llvm/test/Transforms/LoopInterchange/call-instructions.ll +++ b/llvm/test/Transforms/LoopInterchange/call-instructions.ll @@ -1,7 +1,5 @@ -; REQUIRES: asserts -; RUN: opt < %s -passes=loop-interchange -cache-line-size=64 -pass-remarks-missed='loop-interchange' -pass-remarks-output=%t -S \ -; RUN: -verify-dom-info -verify-loop-info -stats 2>&1 | FileCheck -check-prefix=STATS %s -; RUN: FileCheck --input-file=%t %s +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -passes=loop-interchange -S -verify-dom-info -verify-loop-info 2>&1 | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @@ -10,58 +8,6 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" declare void @foo(i64 %a) declare void @bar(i64 %a) readnone -;;--------------------------------------Test case 01------------------------------------ -;; Not safe to interchange, because the called function `foo` is not marked as -;; readnone, so it could introduce dependences. -;; -;; for(int i=0;i<100;i++) { -;; for(int j=1;j<100;j++) { -;; foo(i); -;; A[j][i] = A[j][i]+k; -;; } -;; } - -; CHECK: --- !Missed -; CHECK-NEXT: Pass: loop-interchange -; CHECK-NEXT: Name: CallInst -; CHECK-NEXT: Function: interchange_01 -; CHECK-NEXT: Args: -; CHECK-NEXT: - String: Cannot interchange loops due to call instruction. - -define void @interchange_01(i32 %k) { -entry: - br label %for1.header - -for1.header: - %indvars.iv23 = phi i64 [ 0, %entry ], [ %indvars.iv.next24, %for1.inc10 ] - br label %for2 - -for2: - %indvars.iv = phi i64 [ %indvars.iv.next, %for2 ], [ 1, %for1.header ] - call void @foo(i64 %indvars.iv23) - %arrayidx5 = getelementptr inbounds [100 x [100 x i32]], ptr @A, i64 0, i64 %indvars.iv, i64 %indvars.iv23 - %lv = load i32, ptr %arrayidx5 - %add = add nsw i32 %lv, %k - store i32 %add, ptr %arrayidx5 - %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 - %exitcond = icmp eq i64 %indvars.iv, 99 - br i1 %exitcond, label %for2.loopexit , label %for2 - -for2.loopexit: - br label %for1.inc10 - -for1.inc10: - %indvars.iv.next24 = add nuw nsw i64 %indvars.iv23, 1 - %exitcond26 = icmp eq i64 %indvars.iv23, 99 - br i1 %exitcond26, label %for1.loopexit, label %for1.header - -for1.loopexit: - br label %exit - -exit: - ret void -} - ;;--------------------------------------Test case 02------------------------------------ ;; Safe to interchange, because the called function `bar` is marked as readnone, ;; so it cannot introduce dependences. @@ -72,16 +18,46 @@ exit: ;; A[j][i] = A[j][i]+k; ;; } ;; } - -; CHECK: --- !Passed -; CHECK-NEXT: Pass: loop-interchange -; CHECK-NEXT: Name: Interchanged -; CHECK-NEXT: Function: interchange_02 -; CHECK-NEXT: Args: -; CHECK-NEXT: - String: Loop interchanged with enclosing loop. -; CHECK-NEXT: ... - +; define void @interchange_02(i32 %k) { +; CHECK-LABEL: define void @interchange_02( +; CHECK-SAME: i32 [[K:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: br label %[[FOR2_PREHEADER:.*]] +; CHECK: [[FOR1_HEADER_PREHEADER:.*]]: +; CHECK-NEXT: br label %[[FOR1_HEADER:.*]] +; CHECK: [[FOR1_HEADER]]: +; CHECK-NEXT: [[INDVARS_IV23:%.*]] = phi i64 [ [[INDVARS_IV_NEXT24:%.*]], %[[FOR1_INC10:.*]] ], [ 0, %[[FOR1_HEADER_PREHEADER]] ] +; CHECK-NEXT: br label %[[FOR2_SPLIT1:.*]] +; CHECK: [[FOR2_PREHEADER]]: +; CHECK-NEXT: br label %[[FOR2:.*]] +; CHECK: [[FOR2]]: +; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[TMP0:%.*]], %[[FOR2_SPLIT:.*]] ], [ 1, %[[FOR2_PREHEADER]] ] +; CHECK-NEXT: br label %[[FOR1_HEADER_PREHEADER]] +; CHECK: [[FOR2_SPLIT1]]: +; CHECK-NEXT: call void @bar(i64 [[INDVARS_IV23]]) +; CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds [100 x [100 x i32]], ptr @A, i64 0, i64 [[INDVARS_IV]], i64 [[INDVARS_IV23]] +; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[ARRAYIDX5]], align 4 +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[LV]], [[K]] +; CHECK-NEXT: store i32 [[ADD]], ptr [[ARRAYIDX5]], align 4 +; CHECK-NEXT: [[INDVARS_IV_NEXT:%.*]] = add nuw nsw i64 [[INDVARS_IV]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[INDVARS_IV]], 99 +; CHECK-NEXT: br label %[[FOR2_LOOPEXIT:.*]] +; CHECK: [[FOR2_SPLIT]]: +; CHECK-NEXT: [[TMP0]] = add nuw nsw i64 [[INDVARS_IV]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[INDVARS_IV]], 99 +; CHECK-NEXT: br i1 [[TMP1]], label %[[FOR1_LOOPEXIT:.*]], label %[[FOR2]] +; CHECK: [[FOR2_LOOPEXIT]]: +; CHECK-NEXT: br label %[[FOR1_INC10]] +; CHECK: [[FOR1_INC10]]: +; CHECK-NEXT: [[INDVARS_IV_NEXT24]] = add nuw nsw i64 [[INDVARS_IV23]], 1 +; CHECK-NEXT: [[EXITCOND26:%.*]] = icmp eq i64 [[INDVARS_IV23]], 99 +; CHECK-NEXT: br i1 [[EXITCOND26]], label %[[FOR2_SPLIT]], label %[[FOR1_HEADER]] +; CHECK: [[FOR1_LOOPEXIT]]: +; CHECK-NEXT: br label %[[EXIT:.*]] +; CHECK: [[EXIT]]: +; CHECK-NEXT: ret void +; entry: br label %for1.header @@ -114,6 +90,3 @@ for1.loopexit: exit: ret void } - -; Check stats, we interchanged 1 out of 2 loops. -; STATS: 1 loop-interchange - Number of loops interchanged diff --git a/llvm/test/Transforms/LoopInterchange/inner-indvar-depend-on-outer-indvar-remark.ll b/llvm/test/Transforms/LoopInterchange/inner-indvar-depend-on-outer-indvar-remark.ll new file mode 100644 index 0000000000000..51fa6469cdbbb --- /dev/null +++ b/llvm/test/Transforms/LoopInterchange/inner-indvar-depend-on-outer-indvar-remark.ll @@ -0,0 +1,117 @@ +; REQUIRES: asserts +; RUN: opt < %s -passes=loop-interchange -verify-dom-info -verify-loop-info -S -debug 2>&1 | FileCheck %s + +@A = common global [100 x [100 x i64]] zeroinitializer +@N = dso_local local_unnamed_addr global i64 100, align 8 + +; for(int i=0;i<100;i++) +; for(int j=0;jj;j++) +; A[j][i] = A[j][i]+k; +; +; Inner loop induction variable exit condition depends on the +; outer loop induction variable, i.e., triangular loops. +; CHECK: Loop structure not understood by pass +; CHECK: Not interchanging loops. Cannot prove legality. +; +define void @interchange_03(i64 %k) { +entry: + br label %for1.header + +for1.header: + %i = phi i64 [ 0, %entry ], [ %i.next, %for1.inc10 ] + br label %for2 + +for2: + %j = phi i64 [ %j.next, %for2 ], [ 0, %for1.header ] + %arrayidx5 = getelementptr inbounds [100 x [100 x i64]], ptr @A, i64 0, i64 %j, i64 %i + %lv = load i64, ptr %arrayidx5 + %add = add nsw i64 %lv, %k + store i64 %add, ptr %arrayidx5 + %j.next = add nuw nsw i64 %j, 1 + %exitcond = icmp ne i64 %i, %j + br i1 %exitcond, label %for2, label %for1.inc10 + +for1.inc10: + %i.next = add nuw nsw i64 %i, 1 + %exitcond26 = icmp eq i64 %i, 99 + br i1 %exitcond26, label %for.end12, label %for1.header + +for.end12: + ret void +} diff --git a/llvm/test/Transforms/LoopInterchange/inner-indvar-depend-on-outer-indvar.ll b/llvm/test/Transforms/LoopInterchange/inner-indvar-depend-on-outer-indvar.ll index 0a1d1e5250799..ff88375e31856 100644 --- a/llvm/test/Transforms/LoopInterchange/inner-indvar-depend-on-outer-indvar.ll +++ b/llvm/test/Transforms/LoopInterchange/inner-indvar-depend-on-outer-indvar.ll @@ -1,130 +1,47 @@ -; REQUIRES: asserts -; RUN: opt < %s -passes=loop-interchange -cache-line-size=64 -verify-dom-info -verify-loop-info \ -; RUN: -S -debug 2>&1 | FileCheck %s +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -passes=loop-interchange -verify-dom-info -verify-loop-info -S 2>&1 | FileCheck %s @A = common global [100 x [100 x i64]] zeroinitializer @N = dso_local local_unnamed_addr global i64 100, align 8 - -;; for(int i=0;i<100;i++) -;; for(int j=0;jj;j++) -;; A[j][i] = A[j][i]+k; - -;; Inner loop induction variable exit condition depends on the -;; outer loop induction variable, i.e., triangular loops. -; CHECK: Loop structure not understood by pass -; CHECK: Not interchanging loops. Cannot prove legality. - -define void @interchange_03(i64 %k) { -entry: - br label %for1.header - -for1.header: - %i = phi i64 [ 0, %entry ], [ %i.next, %for1.inc10 ] - br label %for2 - -for2: - %j = phi i64 [ %j.next, %for2 ], [ 0, %for1.header ] - %arrayidx5 = getelementptr inbounds [100 x [100 x i64]], ptr @A, i64 0, i64 %j, i64 %i - %lv = load i64, ptr %arrayidx5 - %add = add nsw i64 %lv, %k - store i64 %add, ptr %arrayidx5 - %j.next = add nuw nsw i64 %j, 1 - %exitcond = icmp ne i64 %i, %j - br i1 %exitcond, label %for2, label %for1.inc10 - -for1.inc10: - %i.next = add nuw nsw i64 %i, 1 - %exitcond26 = icmp eq i64 %i, 99 - br i1 %exitcond26, label %for.end12, label %for1.header - -for.end12: - ret void -} - -;; for(int i=0;i<100;i++) -;; for(int j=0;N>j;j++) -;; A[j][i] = A[j][i]+k; - -;; Inner loop induction variable exit condition depends on -;; an outer loop invariant, can do interchange. -; CHECK: Loops interchanged - +; Inner loop induction variable exit condition depends on +; an outer loop invariant, can do interchange. +; define void @interchange_04(i64 %k) { +; CHECK-LABEL: define void @interchange_04( +; CHECK-SAME: i64 [[K:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @N, align 4 +; CHECK-NEXT: br label %[[FOR2_PREHEADER:.*]] +; CHECK: [[FOR1_HEADER_PREHEADER:.*]]: +; CHECK-NEXT: br label %[[FOR1_HEADER:.*]] +; CHECK: [[FOR1_HEADER]]: +; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], %[[FOR1_INC10:.*]] ], [ 0, %[[FOR1_HEADER_PREHEADER]] ] +; CHECK-NEXT: br label %[[FOR2_SPLIT1:.*]] +; CHECK: [[FOR2_PREHEADER]]: +; CHECK-NEXT: br label %[[FOR2:.*]] +; CHECK: [[FOR2]]: +; CHECK-NEXT: [[J:%.*]] = phi i64 [ [[TMP1:%.*]], %[[FOR2_SPLIT:.*]] ], [ 0, %[[FOR2_PREHEADER]] ] +; CHECK-NEXT: br label %[[FOR1_HEADER_PREHEADER]] +; CHECK: [[FOR2_SPLIT1]]: +; CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds [100 x [100 x i64]], ptr @A, i64 0, i64 [[J]], i64 [[I]] +; CHECK-NEXT: [[LV:%.*]] = load i64, ptr [[ARRAYIDX5]], align 4 +; CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[LV]], [[K]] +; CHECK-NEXT: store i64 [[ADD]], ptr [[ARRAYIDX5]], align 4 +; CHECK-NEXT: [[J_NEXT:%.*]] = add nuw nsw i64 [[J]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[TMP0]], [[J]] +; CHECK-NEXT: br label %[[FOR1_INC10]] +; CHECK: [[FOR2_SPLIT]]: +; CHECK-NEXT: [[TMP1]] = add nuw nsw i64 [[J]], 1 +; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[TMP0]], [[J]] +; CHECK-NEXT: br i1 [[TMP2]], label %[[FOR2]], label %[[FOR_END12:.*]] +; CHECK: [[FOR1_INC10]]: +; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i64 [[I]], 1 +; CHECK-NEXT: [[EXITCOND26:%.*]] = icmp eq i64 [[I]], 99 +; CHECK-NEXT: br i1 [[EXITCOND26]], label %[[FOR2_SPLIT]], label %[[FOR1_HEADER]] +; CHECK: [[FOR_END12]]: +; CHECK-NEXT: ret void +; entry: %0 = load i64, ptr @N, align 4 br label %for1.header diff --git a/llvm/test/Transforms/LoopInterchange/innermost-latch-uses-values-in-middle-header.ll b/llvm/test/Transforms/LoopInterchange/innermost-latch-uses-values-in-middle-header.ll index 11e59c6db9f32..bad84224d445a 100644 --- a/llvm/test/Transforms/LoopInterchange/innermost-latch-uses-values-in-middle-header.ll +++ b/llvm/test/Transforms/LoopInterchange/innermost-latch-uses-values-in-middle-header.ll @@ -1,19 +1,61 @@ -; REQUIRES: asserts -; RUN: opt < %s -passes=loop-interchange -cache-line-size=64 -verify-dom-info -verify-loop-info \ -; RUN: -S -debug 2>&1 | FileCheck %s +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -passes=loop-interchange -verify-dom-info -verify-loop-info -S 2>&1 | FileCheck %s @a = common global i32 0, align 4 @d = common dso_local local_unnamed_addr global [1 x [6 x i32]] zeroinitializer, align 4 -;; After interchanging the innermost and the middle loop, we should not continue -;; doing interchange for the (new) middle loop and the outermost loop, because of -;; values defined in the new innermost loop not available in the exiting block of -;; the entire loop nest. -; CHECK: Loops are legal to interchange -; CHECK: Loops interchanged. -; CHECK: Found unsupported PHI nodes in inner loop latch. -; CHECK: Not interchanging loops. Cannot prove legality. +; After interchanging the innermost and the middle loop, we should not continue +; doing interchange for the (new) middle loop and the outermost loop, because of +; values defined in the new innermost loop not available in the exiting block of +; the entire loop nest. +; define void @innermost_latch_uses_values_in_middle_header() { +; CHECK-LABEL: define void @innermost_latch_uses_values_in_middle_header() { +; CHECK-NEXT: [[ENTRY:.*]]: +; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr @a, align 4 +; CHECK-NEXT: [[B:%.*]] = add i32 80, 1 +; CHECK-NEXT: br label %[[OUTERMOST_HEADER:.*]] +; CHECK: [[OUTERMOST_HEADER]]: +; CHECK-NEXT: [[INDVAR_OUTERMOST:%.*]] = phi i32 [ 10, %[[ENTRY]] ], [ [[INDVAR_OUTERMOST_NEXT:%.*]], %[[OUTERMOST_LATCH:.*]] ] +; CHECK-NEXT: [[TOBOOL71_I:%.*]] = icmp eq i32 [[TMP0]], 0 +; CHECK-NEXT: br i1 [[TOBOOL71_I]], label %[[INNERMOST_HEADER_PREHEADER:.*]], label %[[OUTERMOST_LATCH]] +; CHECK: [[MIDDLE_HEADER_PREHEADER:.*]]: +; CHECK-NEXT: br label %[[MIDDLE_HEADER:.*]] +; CHECK: [[MIDDLE_HEADER]]: +; CHECK-NEXT: [[INDVAR_MIDDLE:%.*]] = phi i64 [ [[INDVAR_MIDDLE_NEXT:%.*]], %[[MIDDLE_LATCH:.*]] ], [ 4, %[[MIDDLE_HEADER_PREHEADER]] ] +; CHECK-NEXT: [[INDVAR_MIDDLE_WIDE:%.*]] = zext i32 [[B]] to i64 +; CHECK-NEXT: br label %[[INNERMOST_BODY:.*]] +; CHECK: [[INNERMOST_HEADER_PREHEADER]]: +; CHECK-NEXT: br label %[[INNERMOST_HEADER:.*]] +; CHECK: [[INNERMOST_HEADER]]: +; CHECK-NEXT: [[INDVAR_INNERMOST:%.*]] = phi i64 [ [[TMP1:%.*]], %[[INNERMOST_LATCH_SPLIT:.*]] ], [ 4, %[[INNERMOST_HEADER_PREHEADER]] ] +; CHECK-NEXT: br label %[[MIDDLE_HEADER_PREHEADER]] +; CHECK: [[INNERMOST_BODY]]: +; CHECK-NEXT: [[ARRAYIDX9_I:%.*]] = getelementptr inbounds [1 x [6 x i32]], ptr @d, i64 0, i64 [[INDVAR_INNERMOST]], i64 [[INDVAR_MIDDLE]] +; CHECK-NEXT: store i32 0, ptr [[ARRAYIDX9_I]], align 4 +; CHECK-NEXT: br label %[[INNERMOST_LATCH:.*]] +; CHECK: [[INNERMOST_LATCH]]: +; CHECK-NEXT: [[INDVAR_INNERMOST_NEXT:%.*]] = add nsw i64 [[INDVAR_INNERMOST]], 1 +; CHECK-NEXT: [[TOBOOL5_I:%.*]] = icmp eq i64 [[INDVAR_INNERMOST_NEXT]], [[INDVAR_MIDDLE_WIDE]] +; CHECK-NEXT: br label %[[MIDDLE_LATCH]] +; CHECK: [[INNERMOST_LATCH_SPLIT]]: +; CHECK-NEXT: [[INDVAR_MIDDLE_WIDE_LCSSA:%.*]] = phi i64 [ [[INDVAR_MIDDLE_WIDE]], %[[MIDDLE_LATCH]] ] +; CHECK-NEXT: [[TMP1]] = add nsw i64 [[INDVAR_INNERMOST]], 1 +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], [[INDVAR_MIDDLE_WIDE_LCSSA]] +; CHECK-NEXT: br i1 [[TMP2]], label %[[OUTERMOST_LATCH_LOOPEXIT:.*]], label %[[INNERMOST_HEADER]] +; CHECK: [[MIDDLE_LATCH]]: +; CHECK-NEXT: [[INDVAR_MIDDLE_NEXT]] = add nsw i64 [[INDVAR_MIDDLE]], -1 +; CHECK-NEXT: [[TOBOOL2_I:%.*]] = icmp eq i64 [[INDVAR_MIDDLE_NEXT]], 0 +; CHECK-NEXT: br i1 [[TOBOOL2_I]], label %[[INNERMOST_LATCH_SPLIT]], label %[[MIDDLE_HEADER]] +; CHECK: [[OUTERMOST_LATCH_LOOPEXIT]]: +; CHECK-NEXT: br label %[[OUTERMOST_LATCH]] +; CHECK: [[OUTERMOST_LATCH]]: +; CHECK-NEXT: [[INDVAR_OUTERMOST_NEXT]] = add nsw i32 [[INDVAR_OUTERMOST]], -5 +; CHECK-NEXT: [[TOBOOL_I:%.*]] = icmp eq i32 [[INDVAR_OUTERMOST_NEXT]], 0 +; CHECK-NEXT: br i1 [[TOBOOL_I]], label %[[OUTERMOST_EXIT:.*]], label %[[OUTERMOST_HEADER]] +; CHECK: [[OUTERMOST_EXIT]]: +; CHECK-NEXT: ret void +; entry: %0 = load i32, ptr @a, align 4 %b = add i32 80, 1 diff --git a/llvm/test/Transforms/LoopInterchange/interchange-flow-dep-outer.ll b/llvm/test/Transforms/LoopInterchange/interchange-flow-dep-outer.ll index 010118370bc01..6daf61a4ec007 100644 --- a/llvm/test/Transforms/LoopInterchange/interchange-flow-dep-outer.ll +++ b/llvm/test/Transforms/LoopInterchange/interchange-flow-dep-outer.ll @@ -1,6 +1,5 @@ -; REQUIRES: asserts -; RUN: opt < %s -passes=loop-interchange -cache-line-size=64 -verify-dom-info -verify-loop-info \ -; RUN: -S -debug 2>&1 | FileCheck %s +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -passes=loop-interchange -cache-line-size=64 -verify-dom-info -verify-loop-info -S 2>&1 | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @@ -8,28 +7,70 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @B = common global [100 x i32] zeroinitializer @C = common global [100 x [100 x i32]] zeroinitializer @D = common global [100 x [100 x [100 x i32]]] zeroinitializer - -;; Test that a flow dependency in outer loop doesn't prevent interchange in -;; loops i and j. -;; -;; for (int k = 0; k < 100; ++k) { -;; T[k] = fn1(); -;; for (int i = 0; i < 1000; ++i) -;; for(int j = 1; j < 1000; ++j) -;; Arr[j][i] = Arr[j][i]+k; -;; fn2(T[k]); -;; } - -; CHECK: Processing InnerLoopId = 2 and OuterLoopId = 1 -; CHECK: Loops interchanged. - -; CHECK: Processing InnerLoopId = 1 and OuterLoopId = 0 -; CHECK: Not interchanging loops. Cannot prove legality. - @T = internal global [100 x double] zeroinitializer, align 4 @Arr = internal global [1000 x [1000 x i32]] zeroinitializer, align 4 +; Test that a flow dependency in outer loop doesn't prevent interchange in +; loops i and j. +; +; for (int k = 0; k < 100; ++k) { +; T[k] = fn1(); +; for (int i = 0; i < 1000; ++i) +; for(int j = 1; j < 1000; ++j) +; Arr[j][i] = Arr[j][i]+k; +; fn2(T[k]); +; } +; +; So, loops InnerLoopId = 2 and OuterLoopId = 1 should be interchanged, +; but not InnerLoopId = 1 and OuterLoopId = 0. +; define void @interchange_09(i32 %k) { +; CHECK-LABEL: define void @interchange_09( +; CHECK-SAME: i32 [[K:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*]]: +; CHECK-NEXT: br label %[[FOR_BODY:.*]] +; CHECK: [[FOR_COND_CLEANUP:.*]]: +; CHECK-NEXT: ret void +; CHECK: [[FOR_BODY]]: +; CHECK-NEXT: [[INDVARS_IV45:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[INDVARS_IV_NEXT46:%.*]], %[[FOR_COND_CLEANUP4:.*]] ] +; CHECK-NEXT: [[CALL:%.*]] = call double @fn1() +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [100 x double], ptr @T, i64 0, i64 [[INDVARS_IV45]] +; CHECK-NEXT: store double [[CALL]], ptr [[ARRAYIDX]], align 8 +; CHECK-NEXT: br label %[[FOR_BODY9_PREHEADER:.*]] +; CHECK: [[FOR_COND6_PREHEADER_PREHEADER:.*]]: +; CHECK-NEXT: br label %[[FOR_COND6_PREHEADER:.*]] +; CHECK: [[FOR_COND6_PREHEADER]]: +; CHECK-NEXT: [[INDVARS_IV42:%.*]] = phi i64 [ [[INDVARS_IV_NEXT43:%.*]], %[[FOR_COND_CLEANUP8:.*]] ], [ 0, %[[FOR_COND6_PREHEADER_PREHEADER]] ] +; CHECK-NEXT: br label %[[FOR_BODY9_SPLIT1:.*]] +; CHECK: [[FOR_BODY9_PREHEADER]]: +; CHECK-NEXT: br label %[[FOR_BODY9:.*]] +; CHECK: [[FOR_COND_CLEANUP4]]: +; CHECK-NEXT: [[TMP:%.*]] = load double, ptr [[ARRAYIDX]], align 8 +; CHECK-NEXT: call void @fn2(double [[TMP]]) +; CHECK-NEXT: [[INDVARS_IV_NEXT46]] = add nuw nsw i64 [[INDVARS_IV45]], 1 +; CHECK-NEXT: [[EXITCOND47:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT46]], 100 +; CHECK-NEXT: br i1 [[EXITCOND47]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP]] +; CHECK: [[FOR_COND_CLEANUP8]]: +; CHECK-NEXT: [[INDVARS_IV_NEXT43]] = add nuw nsw i64 [[INDVARS_IV42]], 1 +; CHECK-NEXT: [[EXITCOND44:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT43]], 1000 +; CHECK-NEXT: br i1 [[EXITCOND44]], label %[[FOR_COND6_PREHEADER]], label %[[FOR_BODY9_SPLIT:.*]] +; CHECK: [[FOR_BODY9]]: +; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[TMP0:%.*]], %[[FOR_BODY9_SPLIT]] ], [ 1, %[[FOR_BODY9_PREHEADER]] ] +; CHECK-NEXT: br label %[[FOR_COND6_PREHEADER_PREHEADER]] +; CHECK: [[FOR_BODY9_SPLIT1]]: +; CHECK-NEXT: [[ARRAYIDX13:%.*]] = getelementptr inbounds [1000 x [1000 x i32]], ptr @Arr, i64 0, i64 [[INDVARS_IV]], i64 [[INDVARS_IV42]] +; CHECK-NEXT: [[T1:%.*]] = load i32, ptr [[ARRAYIDX13]], align 4 +; CHECK-NEXT: [[T2:%.*]] = trunc i64 [[INDVARS_IV45]] to i32 +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[T1]], [[T2]] +; CHECK-NEXT: store i32 [[ADD]], ptr [[ARRAYIDX13]], align 4 +; CHECK-NEXT: [[INDVARS_IV_NEXT:%.*]] = add nuw nsw i64 [[INDVARS_IV]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], 1000 +; CHECK-NEXT: br label %[[FOR_COND_CLEANUP8]] +; CHECK: [[FOR_BODY9_SPLIT]]: +; CHECK-NEXT: [[TMP0]] = add nuw nsw i64 [[INDVARS_IV]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[TMP0]], 1000 +; CHECK-NEXT: br i1 [[TMP1]], label %[[FOR_BODY9]], label %[[FOR_COND_CLEANUP4]] +; entry: br label %for.body @@ -62,9 +103,9 @@ for.cond.cleanup8: ; preds = %for.body9 for.body9: ; preds = %for.body9, %for.cond6.preheader %indvars.iv = phi i64 [ 1, %for.cond6.preheader ], [ %indvars.iv.next, %for.body9 ] %arrayidx13 = getelementptr inbounds [1000 x [1000 x i32]], ptr @Arr, i64 0, i64 %indvars.iv, i64 %indvars.iv42 - %tmp1 = load i32, ptr %arrayidx13, align 4 - %tmp2 = trunc i64 %indvars.iv45 to i32 - %add = add nsw i32 %tmp1, %tmp2 + %t1 = load i32, ptr %arrayidx13, align 4 + %t2 = trunc i64 %indvars.iv45 to i32 + %add = add nsw i32 %t1, %t2 store i32 %add, ptr %arrayidx13, align 4 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 %exitcond = icmp ne i64 %indvars.iv.next, 1000 diff --git a/llvm/test/Transforms/LoopInterchange/interchange-no-deps.ll b/llvm/test/Transforms/LoopInterchange/interchange-no-deps.ll index 718e9a8bbd3f5..9e8e30d670c51 100644 --- a/llvm/test/Transforms/LoopInterchange/interchange-no-deps.ll +++ b/llvm/test/Transforms/LoopInterchange/interchange-no-deps.ll @@ -1,22 +1,42 @@ -; REQUIRES: asserts -; RUN: opt < %s -passes='loop(loop-interchange),simplifycfg' -cache-line-size=64 -simplifycfg-require-and-preserve-domtree=1 -pass-remarks-output=%t \ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -passes='loop(loop-interchange),simplifycfg' -simplifycfg-require-and-preserve-domtree=1 \ ; RUN: -pass-remarks=loop-interchange -pass-remarks-missed=loop-interchange -stats -S 2>&1 \ ; RUN: | FileCheck -check-prefix=STATS %s -; RUN: FileCheck -input-file %t %s - ; no_deps_interchange just accesses a single nested array and can be interchange. -; CHECK: Name: Interchanged -; CHECK-NEXT: Function: no_deps_interchange -define i32 @no_deps_interchange(ptr nocapture %Arr) local_unnamed_addr #0 { +; +define i32 @no_deps_interchange(ptr nocapture %Arr) { +; STATS-LABEL: define i32 @no_deps_interchange( +; STATS-SAME: ptr nocapture [[ARR:%.*]]) { +; STATS-NEXT: [[ENTRY:.*]]: +; STATS-NEXT: br label %[[FOR2:.*]] +; STATS: [[FOR1_HEADER:.*]]: +; STATS-NEXT: [[INDVARS_IV19:%.*]] = phi i64 [ [[INDVARS_IV_NEXT20:%.*]], %[[FOR1_HEADER]] ], [ 0, %[[FOR2]] ] +; STATS-NEXT: [[ARRAYIDX6:%.*]] = getelementptr inbounds [1024 x i32], ptr [[ARR]], i64 [[INDVARS_IV:%.*]], i64 [[INDVARS_IV19]] +; STATS-NEXT: store i32 0, ptr [[ARRAYIDX6]], align 4 +; STATS-NEXT: [[INDVARS_IV_NEXT:%.*]] = add nuw nsw i64 [[INDVARS_IV]], 1 +; STATS-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], 1024 +; STATS-NEXT: [[INDVARS_IV_NEXT20]] = add nuw nsw i64 [[INDVARS_IV19]], 1 +; STATS-NEXT: [[EXITCOND21:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT20]], 1024 +; STATS-NEXT: br i1 [[EXITCOND21]], label %[[FOR1_HEADER]], label %[[FOR2_SPLIT:.*]] +; STATS: [[FOR2]]: +; STATS-NEXT: [[INDVARS_IV]] = phi i64 [ [[TMP0:%.*]], %[[FOR2_SPLIT]] ], [ 0, %[[ENTRY]] ] +; STATS-NEXT: br label %[[FOR1_HEADER]] +; STATS: [[FOR2_SPLIT]]: +; STATS-NEXT: [[TMP0]] = add nuw nsw i64 [[INDVARS_IV]], 1 +; STATS-NEXT: [[TMP1:%.*]] = icmp ne i64 [[TMP0]], 1024 +; STATS-NEXT: br i1 [[TMP1]], label %[[FOR2]], label %[[EXIT:.*]] +; STATS: [[EXIT]]: +; STATS-NEXT: ret i32 0 +; entry: br label %for1.header -for1.header: ; preds = %entry, %for1.inc +for1.header: %indvars.iv19 = phi i64 [ 0, %entry ], [ %indvars.iv.next20, %for1.inc ] br label %for2 -for2: ; preds = %for1.header, %for2 +for2: %indvars.iv = phi i64 [ 0, %for1.header ], [ %indvars.iv.next, %for2 ] %arrayidx6 = getelementptr inbounds [1024 x i32], ptr %Arr, i64 %indvars.iv, i64 %indvars.iv19 store i32 0, ptr %arrayidx6, align 4 @@ -29,23 +49,42 @@ for1.inc: %exitcond21 = icmp ne i64 %indvars.iv.next20, 1024 br i1 %exitcond21, label %for1.header, label %exit -exit: ; preds = %for1.inc +exit: ret i32 0 } ; No memory access using any induction variables, interchanging not beneficial. -; CHECK: Name: InterchangeNotProfitable -; CHECK-NEXT: Function: no_mem_instrs +; define i32 @no_mem_instrs(ptr %ptr) { +; STATS-LABEL: define i32 @no_mem_instrs( +; STATS-SAME: ptr [[PTR:%.*]]) { +; STATS-NEXT: [[ENTRY:.*]]: +; STATS-NEXT: br label %[[FOR1_HEADER:.*]] +; STATS: [[FOR1_HEADER]]: +; STATS-NEXT: [[INDVARS_IV19:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[INDVARS_IV_NEXT20:%.*]], %[[FOR1_INC:.*]] ] +; STATS-NEXT: br label %[[FOR2:.*]] +; STATS: [[FOR2]]: +; STATS-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ 0, %[[FOR1_HEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], %[[FOR2]] ] +; STATS-NEXT: store i64 [[INDVARS_IV]], ptr [[PTR]], align 4 +; STATS-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 +; STATS-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], 1024 +; STATS-NEXT: br i1 [[EXITCOND]], label %[[FOR2]], label %[[FOR1_INC]] +; STATS: [[FOR1_INC]]: +; STATS-NEXT: [[INDVARS_IV_NEXT20]] = add nuw nsw i64 [[INDVARS_IV19]], 1 +; STATS-NEXT: [[EXITCOND21:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT20]], 1024 +; STATS-NEXT: br i1 [[EXITCOND21]], label %[[FOR1_HEADER]], label %[[EXIT:.*]] +; STATS: [[EXIT]]: +; STATS-NEXT: ret i32 0 +; entry: br label %for1.header -for1.header: ; preds = %entry, %for1.inc +for1.header: %indvars.iv19 = phi i64 [ 0, %entry ], [ %indvars.iv.next20, %for1.inc ] br label %for2 -for2: ; preds = %for1.header, %for2 +for2: %indvars.iv = phi i64 [ 0, %for1.header ], [ %indvars.iv.next, %for2 ] store i64 %indvars.iv, ptr %ptr, align 4 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 @@ -60,7 +99,3 @@ for1.inc: exit: ; preds = %for1.inc ret i32 0 } - - -; Check stats, we interchanged 1 out of 3 loops. -; STATS: 1 loop-interchange - Number of loops interchanged diff --git a/llvm/test/Transforms/LoopInterchange/interchanged-loop-nest-3.ll b/llvm/test/Transforms/LoopInterchange/interchanged-loop-nest-3.ll index 18832933b8841..6be86f1a8fdcf 100644 --- a/llvm/test/Transforms/LoopInterchange/interchanged-loop-nest-3.ll +++ b/llvm/test/Transforms/LoopInterchange/interchanged-loop-nest-3.ll @@ -1,24 +1,66 @@ -; REQUIRES: asserts -; RUN: opt < %s -passes=loop-interchange -cache-line-size=64 -verify-dom-info -verify-loop-info \ -; RUN: -S -debug 2>&1 | FileCheck %s +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -passes=loop-interchange -verify-dom-info -verify-loop-info -S 2>&1 | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @D = common global [100 x [100 x [100 x i32]]] zeroinitializer -;; Test for interchange in loop nest greater than 2. -;; for(int i=0;i<100;i++) -;; for(int j=0;j<100;j++) -;; for(int k=0;k<100;k++) -;; D[k][j][i] = D[k][j][i]+t; - -; CHECK: Processing InnerLoopId = 2 and OuterLoopId = 1 -; CHECK: Loops interchanged. - -; CHECK: Processing InnerLoopId = 1 and OuterLoopId = 0 -; CHECK: Loops interchanged. - +; Test for interchange in loop nest greater than 2. +; for(int i=0;i<100;i++) +; for(int j=0;j<100;j++) +; for(int k=0;k<100;k++) +; D[k][j][i] = D[k][j][i]+t; +; +; Loops InnerLoopId = 2 and OuterLoopId = 1 should be interchanged, and then +; also InnerLoopId = 1 and OuterLoopId = 0. +; define void @interchange_08(i32 %t){ +; CHECK-LABEL: define void @interchange_08( +; CHECK-SAME: i32 [[T:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: br label %[[FOR_BODY6_PREHEADER:.*]] +; CHECK: [[FOR_COND1_PREHEADER_PREHEADER:.*]]: +; CHECK-NEXT: br label %[[FOR_COND1_PREHEADER:.*]] +; CHECK: [[FOR_COND1_PREHEADER]]: +; CHECK-NEXT: [[I_028:%.*]] = phi i64 [ [[INC16:%.*]], %[[FOR_INC15:.*]] ], [ 0, %[[FOR_COND1_PREHEADER_PREHEADER]] ] +; CHECK-NEXT: br label %[[FOR_BODY6_SPLIT1:.*]] +; CHECK: [[FOR_COND4_PREHEADER_PREHEADER:.*]]: +; CHECK-NEXT: br label %[[FOR_COND4_PREHEADER:.*]] +; CHECK: [[FOR_COND4_PREHEADER]]: +; CHECK-NEXT: [[J_027:%.*]] = phi i64 [ [[TMP3:%.*]], %[[FOR_INC12_SPLIT:.*]] ], [ 0, %[[FOR_COND4_PREHEADER_PREHEADER]] ] +; CHECK-NEXT: br label %[[FOR_COND1_PREHEADER_PREHEADER]] +; CHECK: [[FOR_BODY6_PREHEADER]]: +; CHECK-NEXT: br label %[[FOR_BODY6:.*]] +; CHECK: [[FOR_BODY6]]: +; CHECK-NEXT: [[K_026:%.*]] = phi i64 [ [[TMP1:%.*]], %[[FOR_BODY6_SPLIT:.*]] ], [ 0, %[[FOR_BODY6_PREHEADER]] ] +; CHECK-NEXT: br label %[[FOR_COND4_PREHEADER_PREHEADER]] +; CHECK: [[FOR_BODY6_SPLIT1]]: +; CHECK-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds [100 x [100 x [100 x i32]]], ptr @D, i64 0, i64 [[K_026]], i64 [[J_027]], i64 [[I_028]] +; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX8]], align 4 +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], [[T]] +; CHECK-NEXT: store i32 [[ADD]], ptr [[ARRAYIDX8]], align 4 +; CHECK-NEXT: [[INC:%.*]] = add nuw nsw i64 [[K_026]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[INC]], 100 +; CHECK-NEXT: br label %[[FOR_INC12:.*]] +; CHECK: [[FOR_BODY6_SPLIT]]: +; CHECK-NEXT: [[TMP1]] = add nuw nsw i64 [[K_026]], 1 +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 100 +; CHECK-NEXT: br i1 [[TMP2]], label %[[FOR_END17:.*]], label %[[FOR_BODY6]] +; CHECK: [[FOR_INC12]]: +; CHECK-NEXT: [[INC13:%.*]] = add nuw nsw i64 [[J_027]], 1 +; CHECK-NEXT: [[EXITCOND29:%.*]] = icmp eq i64 [[INC13]], 100 +; CHECK-NEXT: br label %[[FOR_INC15]] +; CHECK: [[FOR_INC12_SPLIT]]: +; CHECK-NEXT: [[TMP3]] = add nuw nsw i64 [[J_027]], 1 +; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i64 [[TMP3]], 100 +; CHECK-NEXT: br i1 [[TMP4]], label %[[FOR_BODY6_SPLIT]], label %[[FOR_COND4_PREHEADER]] +; CHECK: [[FOR_INC15]]: +; CHECK-NEXT: [[INC16]] = add nuw nsw i64 [[I_028]], 1 +; CHECK-NEXT: [[EXITCOND30:%.*]] = icmp eq i64 [[INC16]], 100 +; CHECK-NEXT: br i1 [[EXITCOND30]], label %[[FOR_INC12_SPLIT]], label %[[FOR_COND1_PREHEADER]] +; CHECK: [[FOR_END17]]: +; CHECK-NEXT: ret void +; entry: br label %for.cond1.preheader diff --git a/llvm/test/Transforms/LoopInterchange/not-interchanged-dependencies-1.ll b/llvm/test/Transforms/LoopInterchange/not-interchanged-dependencies-1.ll index ffb9f106c2880..529ebeb646690 100644 --- a/llvm/test/Transforms/LoopInterchange/not-interchanged-dependencies-1.ll +++ b/llvm/test/Transforms/LoopInterchange/not-interchanged-dependencies-1.ll @@ -1,20 +1,42 @@ -; REQUIRES: asserts -; RUN: opt < %s -passes=loop-interchange -cache-line-size=64 -verify-dom-info -verify-loop-info \ -; RUN: -S -debug 2>&1 | FileCheck %s +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -passes=loop-interchange -cache-line-size=64 -verify-dom-info -verify-loop-info -S 2>&1 | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @A = common global [100 x [100 x i32]] zeroinitializer @B = common global [100 x i32] zeroinitializer -;; Loops should not be interchanged in this case as it is not legal due to dependency. -;; for(int j=0;j<99;j++) -;; for(int i=0;i<99;i++) -;; A[j][i+1] = A[j+1][i]+k; - -; CHECK: Not interchanging loops. Cannot prove legality. - +; Loops should not be interchanged in this case as it is not legal due to dependency. +; +; for(int j=0;j<99;j++) +; for(int i=0;i<99;i++) +; A[j][i+1] = A[j+1][i]+k; +; define void @interchange_04(i32 %k){ +; CHECK-LABEL: define void @interchange_04( +; CHECK-SAME: i32 [[K:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*]]: +; CHECK-NEXT: br label %[[FOR_COND1_PREHEADER:.*]] +; CHECK: [[FOR_COND1_PREHEADER]]: +; CHECK-NEXT: [[INDVARS_IV23:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[INDVARS_IV_NEXT24:%.*]], %[[FOR_INC12:.*]] ] +; CHECK-NEXT: [[INDVARS_IV_NEXT24]] = add nuw nsw i64 [[INDVARS_IV23]], 1 +; CHECK-NEXT: br label %[[FOR_BODY3:.*]] +; CHECK: [[FOR_BODY3]]: +; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ 0, %[[FOR_COND1_PREHEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], %[[FOR_BODY3]] ] +; CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds [100 x [100 x i32]], ptr @A, i64 0, i64 [[INDVARS_IV_NEXT24]], i64 [[INDVARS_IV]] +; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX5]], align 4 +; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP0]], [[K]] +; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 +; CHECK-NEXT: [[ARRAYIDX11:%.*]] = getelementptr inbounds [100 x [100 x i32]], ptr @A, i64 0, i64 [[INDVARS_IV23]], i64 [[INDVARS_IV_NEXT]] +; CHECK-NEXT: store i32 [[ADD6]], ptr [[ARRAYIDX11]], align 4 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], 99 +; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_INC12]], label %[[FOR_BODY3]] +; CHECK: [[FOR_INC12]]: +; CHECK-NEXT: [[EXITCOND25:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT24]], 99 +; CHECK-NEXT: br i1 [[EXITCOND25]], label %[[FOR_END14:.*]], label %[[FOR_COND1_PREHEADER]] +; CHECK: [[FOR_END14]]: +; CHECK-NEXT: ret void +; entry: br label %for.cond1.preheader diff --git a/llvm/test/Transforms/LoopInterchange/not-interchanged-loop-nest-3.ll b/llvm/test/Transforms/LoopInterchange/not-interchanged-loop-nest-3.ll index ada8fb3f33eb5..6a7f43d19eaf2 100644 --- a/llvm/test/Transforms/LoopInterchange/not-interchanged-loop-nest-3.ll +++ b/llvm/test/Transforms/LoopInterchange/not-interchanged-loop-nest-3.ll @@ -1,24 +1,61 @@ -; REQUIRES: asserts -; RUN: opt < %s -passes=loop-interchange -cache-line-size=64 -verify-dom-info -verify-loop-info \ -; RUN: -S -debug 2>&1 | FileCheck %s +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -passes=loop-interchange -cache-line-size=64 -verify-dom-info -verify-loop-info -S 2>&1 | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @D = common global [100 x [100 x [100 x i32]]] zeroinitializer -;; Test for interchange in loop nest greater than 2. -;; for(int i=0;i<100;i++) -;; for(int j=0;j<100;j++) -;; for(int k=0;k<100;k++) -;; D[i][k][j] = D[i][k][j]+t; - -; CHECK: Processing InnerLoopId = 2 and OuterLoopId = 1 -; CHECK: Loops interchanged. - -; CHECK: Processing InnerLoopId = 1 and OuterLoopId = 0 -; CHECK: Interchanging loops not profitable. - +; Test for interchange in loop nest greater than 2. +; +; for(int i=0;i<100;i++) +; for(int j=0;j<100;j++) +; for(int k=0;k<100;k++) +; D[i][k][j] = D[i][k][j]+t; +; +; Loops InnerLoopId = 2 and OuterLoopId = 1 should be interchanged, but not +; loops InnerLoopId = 1 and OuterLoopId = 0 as that is not profitable. +; define void @interchange_08(i32 %t){ +; CHECK-LABEL: define void @interchange_08( +; CHECK-SAME: i32 [[T:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*]]: +; CHECK-NEXT: br label %[[FOR_COND1_PREHEADER:.*]] +; CHECK: [[FOR_COND1_PREHEADER]]: +; CHECK-NEXT: [[I_028:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[INC16:%.*]], %[[FOR_INC15:.*]] ] +; CHECK-NEXT: br label %[[FOR_BODY6_PREHEADER:.*]] +; CHECK: [[FOR_COND4_PREHEADER_PREHEADER:.*]]: +; CHECK-NEXT: br label %[[FOR_COND4_PREHEADER:.*]] +; CHECK: [[FOR_COND4_PREHEADER]]: +; CHECK-NEXT: [[J_027:%.*]] = phi i64 [ [[INC13:%.*]], %[[FOR_INC12:.*]] ], [ 0, %[[FOR_COND4_PREHEADER_PREHEADER]] ] +; CHECK-NEXT: br label %[[FOR_BODY6_SPLIT1:.*]] +; CHECK: [[FOR_BODY6_PREHEADER]]: +; CHECK-NEXT: br label %[[FOR_BODY6:.*]] +; CHECK: [[FOR_BODY6]]: +; CHECK-NEXT: [[K_026:%.*]] = phi i64 [ [[TMP1:%.*]], %[[FOR_BODY6_SPLIT:.*]] ], [ 0, %[[FOR_BODY6_PREHEADER]] ] +; CHECK-NEXT: br label %[[FOR_COND4_PREHEADER_PREHEADER]] +; CHECK: [[FOR_BODY6_SPLIT1]]: +; CHECK-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds [100 x [100 x [100 x i32]]], ptr @D, i32 0, i64 [[I_028]], i64 [[K_026]], i64 [[J_027]] +; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX8]], align 4 +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], [[T]] +; CHECK-NEXT: store i32 [[ADD]], ptr [[ARRAYIDX8]], align 4 +; CHECK-NEXT: [[INC:%.*]] = add nuw nsw i64 [[K_026]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[INC]], 100 +; CHECK-NEXT: br label %[[FOR_INC12]] +; CHECK: [[FOR_BODY6_SPLIT]]: +; CHECK-NEXT: [[TMP1]] = add nuw nsw i64 [[K_026]], 1 +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 100 +; CHECK-NEXT: br i1 [[TMP2]], label %[[FOR_INC15]], label %[[FOR_BODY6]] +; CHECK: [[FOR_INC12]]: +; CHECK-NEXT: [[INC13]] = add nuw nsw i64 [[J_027]], 1 +; CHECK-NEXT: [[EXITCOND29:%.*]] = icmp eq i64 [[INC13]], 100 +; CHECK-NEXT: br i1 [[EXITCOND29]], label %[[FOR_BODY6_SPLIT]], label %[[FOR_COND4_PREHEADER]] +; CHECK: [[FOR_INC15]]: +; CHECK-NEXT: [[INC16]] = add nuw nsw i64 [[I_028]], 1 +; CHECK-NEXT: [[EXITCOND30:%.*]] = icmp eq i64 [[INC16]], 100 +; CHECK-NEXT: br i1 [[EXITCOND30]], label %[[FOR_END17:.*]], label %[[FOR_COND1_PREHEADER]] +; CHECK: [[FOR_END17]]: +; CHECK-NEXT: ret void +; entry: br label %for.cond1.preheader diff --git a/llvm/test/Transforms/LoopInterchange/not-interchanged-tightly-nested.ll b/llvm/test/Transforms/LoopInterchange/not-interchanged-tightly-nested.ll index b8e569afe8645..d8b47682bbadc 100644 --- a/llvm/test/Transforms/LoopInterchange/not-interchanged-tightly-nested.ll +++ b/llvm/test/Transforms/LoopInterchange/not-interchanged-tightly-nested.ll @@ -1,6 +1,5 @@ -; REQUIRES: asserts -; RUN: opt < %s -passes=loop-interchange -cache-line-size=64 -verify-dom-info -verify-loop-info \ -; RUN: -S -debug 2>&1 | FileCheck %s +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -passes=loop-interchange -verify-dom-info -verify-loop-info -S 2>&1 | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @@ -9,16 +8,51 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @C = common global [100 x [100 x i32]] zeroinitializer @D = common global [100 x [100 x [100 x i32]]] zeroinitializer -;; Loops not tightly nested are not interchanged -;; for(int j=0;j