In the transformation phase, at first LoopInterchange moves several instructions in the inner loop into the new latch block. The instructions used as incoming values to the induction variables from the latch block are the targets of this movement. Previously, this process could result in an infinite loop when a PHI node refers to another PHI node, as in the following example: ``` %i = phi i64 [ 0, %entry ], [ %i.inc, %latch ] %j = phi i64 [ 0, %entry ], [ %i, %latch ] ``` The root cause was that `%i` enqueued for processing because it is used by `%j`. This patch fixes the issue by preventing induction variables from being enqueued into the movement list. Fix #193733
63 lines
2.5 KiB
LLVM
63 lines
2.5 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
|
|
; RUN: opt < %s -passes=loop-interchange -loop-interchange-profitabilities=ignore -verify-dom-info -verify-loop-info -verify-scev -verify-loop-lcssa -S | FileCheck %s
|
|
|
|
; Check that `%k`, which refers to another phi node, is processed correctly.
|
|
|
|
define void @f(ptr %A) {
|
|
; CHECK-LABEL: define void @f(
|
|
; CHECK-SAME: ptr [[A:%.*]]) {
|
|
; CHECK-NEXT: [[ENTRY:.*:]]
|
|
; CHECK-NEXT: br label %[[INNER_PREHEADER:.*]]
|
|
; CHECK: [[OUTER_HEADER_PREHEADER:.*]]:
|
|
; CHECK-NEXT: br label %[[OUTER_HEADER:.*]]
|
|
; CHECK: [[OUTER_HEADER]]:
|
|
; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_INC:%.*]], %[[OUTER_LATCH:.*]] ], [ 0, %[[OUTER_HEADER_PREHEADER]] ]
|
|
; CHECK-NEXT: br label %[[INNER_SPLIT1:.*]]
|
|
; CHECK: [[INNER_PREHEADER]]:
|
|
; CHECK-NEXT: br label %[[INNER:.*]]
|
|
; CHECK: [[INNER]]:
|
|
; CHECK-NEXT: [[J:%.*]] = phi i64 [ [[TMP0:%.*]], %[[INNER_SPLIT:.*]] ], [ 0, %[[INNER_PREHEADER]] ]
|
|
; CHECK-NEXT: [[K:%.*]] = phi i64 [ [[J]], %[[INNER_SPLIT]] ], [ -1, %[[INNER_PREHEADER]] ]
|
|
; CHECK-NEXT: br label %[[OUTER_HEADER_PREHEADER]]
|
|
; CHECK: [[INNER_SPLIT1]]:
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr [10 x i64], ptr [[A]], i64 [[I]], i64 [[J]]
|
|
; CHECK-NEXT: store i64 [[K]], ptr [[GEP]], align 4
|
|
; CHECK-NEXT: [[J_INC:%.*]] = add i64 [[J]], 1
|
|
; CHECK-NEXT: [[EC_J:%.*]] = icmp eq i64 [[J_INC]], 10
|
|
; CHECK-NEXT: br label %[[OUTER_LATCH]]
|
|
; CHECK: [[INNER_SPLIT]]:
|
|
; CHECK-NEXT: [[TMP0]] = add i64 [[J]], 1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], 10
|
|
; CHECK-NEXT: br i1 [[TMP1]], label %[[EXIT:.*]], label %[[INNER]]
|
|
; CHECK: [[OUTER_LATCH]]:
|
|
; CHECK-NEXT: [[I_INC]] = add i64 [[I]], 1
|
|
; CHECK-NEXT: [[EC_I:%.*]] = icmp eq i64 [[I_INC]], 10
|
|
; CHECK-NEXT: br i1 [[EC_I]], label %[[INNER_SPLIT]], label %[[OUTER_HEADER]]
|
|
; CHECK: [[EXIT]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %outer.header
|
|
|
|
outer.header:
|
|
%i = phi i64 [ 0, %entry ], [ %i.inc, %outer.latch ]
|
|
br label %inner
|
|
|
|
inner:
|
|
%j = phi i64 [ 0, %outer.header ], [ %j.inc, %inner ]
|
|
%k = phi i64 [ -1, %outer.header ], [ %j, %inner ]
|
|
%gep = getelementptr [10 x i64], ptr %A, i64 %i, i64 %j
|
|
store i64 %k, ptr %gep
|
|
%j.inc = add i64 %j, 1
|
|
%ec.j = icmp eq i64 %j.inc, 10
|
|
br i1 %ec.j, label %outer.latch, label %inner
|
|
|
|
outer.latch:
|
|
%i.inc = add i64 %i, 1
|
|
%ec.i = icmp eq i64 %i.inc, 10
|
|
br i1 %ec.i, label %exit, label %outer.header
|
|
|
|
exit:
|
|
ret void
|
|
}
|