blob: 17316ee451d7318d76c764368631f87ef98f7f10 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -passes=loop-interchange -loop-interchange-profitabilities=ignore -S %s | FileCheck %s
; choice = freeze(poison);
; sum = 0.0;
; for (i = 0; i < 4; i++)
; for (j = 0; j < 4; j++)
; sum += choice ? A[j][i] : 0.0;
; Interchange is allowed because the outer preheader keeps its loop depth and
; execution count.
define void @outer_preheader_freeze(ptr noalias %A, ptr noalias %R) {
; CHECK-LABEL: define void @outer_preheader_freeze(
; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[R:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: br label %[[INNER_HEADER_PREHEADER:.*]]
; CHECK: [[OUTER_PREHEADER:.*]]:
; CHECK-NEXT: br label %[[OUTER_HEADER:.*]]
; CHECK: [[OUTER_HEADER]]:
; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, %[[OUTER_PREHEADER]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ]
; CHECK-NEXT: [[SUM_J:%.*]] = phi double [ [[SUM_NEXT_J:%.*]], %[[OUTER_LATCH]] ], [ [[SUM_I:%.*]], %[[OUTER_PREHEADER]] ]
; CHECK-NEXT: br label %[[INNER_HEADER_SPLIT1:.*]]
; CHECK: [[INNER_HEADER_PREHEADER]]:
; CHECK-NEXT: [[CHOICE:%.*]] = freeze i1 poison
; CHECK-NEXT: br label %[[INNER_HEADER:.*]]
; CHECK: [[INNER_HEADER]]:
; CHECK-NEXT: [[J:%.*]] = phi i64 [ [[TMP0:%.*]], %[[INNER_HEADER_SPLIT:.*]] ], [ 0, %[[INNER_HEADER_PREHEADER]] ]
; CHECK-NEXT: [[SUM_I]] = phi double [ 0.000000e+00, %[[INNER_HEADER_PREHEADER]] ], [ [[SUM_NEXT:%.*]], %[[INNER_HEADER_SPLIT]] ]
; CHECK-NEXT: br label %[[OUTER_PREHEADER]]
; CHECK: [[INNER_HEADER_SPLIT1]]:
; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]]
; CHECK-NEXT: [[VALUE:%.*]] = load double, ptr [[IDX]], align 8
; CHECK-NEXT: [[SELECTED:%.*]] = select i1 [[CHOICE]], double [[VALUE]], double 0.000000e+00
; CHECK-NEXT: [[SUM_NEXT_J]] = fadd reassoc double [[SUM_J]], [[SELECTED]]
; CHECK-NEXT: [[J_NEXT:%.*]] = add i64 [[J]], 1
; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], 4
; CHECK-NEXT: br label %[[OUTER_LATCH]]
; CHECK: [[INNER_HEADER_SPLIT]]:
; CHECK-NEXT: [[SUM_NEXT]] = phi double [ [[SUM_NEXT_J]], %[[OUTER_LATCH]] ]
; CHECK-NEXT: [[TMP0]] = add i64 [[J]], 1
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], 4
; CHECK-NEXT: br i1 [[TMP1]], label %[[EXIT:.*]], label %[[INNER_HEADER]]
; CHECK: [[OUTER_LATCH]]:
; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1
; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4
; CHECK-NEXT: br i1 [[I_EC]], label %[[INNER_HEADER_SPLIT]], label %[[OUTER_HEADER]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[SUM_RESULT:%.*]] = phi double [ [[SUM_NEXT]], %[[INNER_HEADER_SPLIT]] ]
; CHECK-NEXT: store double [[SUM_RESULT]], ptr [[R]], align 8
; CHECK-NEXT: ret void
;
entry:
br label %outer.preheader
outer.preheader:
%choice = freeze i1 poison
br label %outer.header
outer.header:
%i = phi i64 [ 0, %outer.preheader ], [ %i.next, %outer.latch ]
%sum.i = phi double [ 0.000000e+00, %outer.preheader ], [ %sum.next, %outer.latch ]
br label %inner.header
inner.header:
%j = phi i64 [ 0, %outer.header ], [ %j.next, %inner.header ]
%sum.j = phi double [ %sum.i, %outer.header ], [ %sum.next.j, %inner.header ]
%idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i
%value = load double, ptr %idx, align 8
%selected = select i1 %choice, double %value, double 0.000000e+00
%sum.next.j = fadd reassoc double %sum.j, %selected
%j.next = add i64 %j, 1
%j.ec = icmp eq i64 %j.next, 4
br i1 %j.ec, label %outer.latch, label %inner.header
outer.latch:
%sum.next = phi double [ %sum.next.j, %inner.header ]
%i.next = add i64 %i, 1
%i.ec = icmp eq i64 %i.next, 4
br i1 %i.ec, label %exit, label %outer.header
exit:
%sum.result = phi double [ %sum.next, %outer.latch ]
store double %sum.result, ptr %R, align 8
ret void
}
; sum = 0.0;
; for (i = 0; i < 4; i++)
; for (j = 0; j < 4; j++) {
; choice = freeze(poison);
; sum += choice ? A[j][i] : 0.0;
; }
; Interchange is allowed because the freeze in the inner-loop body keeps its
; loop depth and is not cloned.
define void @inner_body_freeze(ptr noalias %A, ptr noalias %R) {
; CHECK-LABEL: define void @inner_body_freeze(
; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[R:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: br label %[[INNER_HEADER_PREHEADER:.*]]
; CHECK: [[OUTER_HEADER_PREHEADER:.*]]:
; CHECK-NEXT: br label %[[OUTER_HEADER:.*]]
; CHECK: [[OUTER_HEADER]]:
; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ], [ 0, %[[OUTER_HEADER_PREHEADER]] ]
; CHECK-NEXT: [[SUM_J:%.*]] = phi double [ [[SUM_NEXT_J:%.*]], %[[OUTER_LATCH]] ], [ [[SUM_I:%.*]], %[[OUTER_HEADER_PREHEADER]] ]
; CHECK-NEXT: br label %[[INNER_HEADER_SPLIT1:.*]]
; CHECK: [[INNER_HEADER_PREHEADER]]:
; CHECK-NEXT: br label %[[INNER_HEADER:.*]]
; CHECK: [[INNER_HEADER]]:
; CHECK-NEXT: [[J:%.*]] = phi i64 [ [[TMP0:%.*]], %[[INNER_HEADER_SPLIT:.*]] ], [ 0, %[[INNER_HEADER_PREHEADER]] ]
; CHECK-NEXT: [[SUM_I]] = phi double [ [[SUM_NEXT:%.*]], %[[INNER_HEADER_SPLIT]] ], [ 0.000000e+00, %[[INNER_HEADER_PREHEADER]] ]
; CHECK-NEXT: br label %[[OUTER_HEADER_PREHEADER]]
; CHECK: [[INNER_HEADER_SPLIT1]]:
; CHECK-NEXT: [[CHOICE:%.*]] = freeze i1 poison
; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]]
; CHECK-NEXT: [[VALUE:%.*]] = load double, ptr [[IDX]], align 8
; CHECK-NEXT: [[SELECTED:%.*]] = select i1 [[CHOICE]], double [[VALUE]], double 0.000000e+00
; CHECK-NEXT: [[SUM_NEXT_J]] = fadd reassoc double [[SUM_J]], [[SELECTED]]
; CHECK-NEXT: [[J_NEXT:%.*]] = add i64 [[J]], 1
; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], 4
; CHECK-NEXT: br label %[[OUTER_LATCH]]
; CHECK: [[INNER_HEADER_SPLIT]]:
; CHECK-NEXT: [[SUM_NEXT]] = phi double [ [[SUM_NEXT_J]], %[[OUTER_LATCH]] ]
; CHECK-NEXT: [[TMP0]] = add i64 [[J]], 1
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], 4
; CHECK-NEXT: br i1 [[TMP1]], label %[[EXIT:.*]], label %[[INNER_HEADER]]
; CHECK: [[OUTER_LATCH]]:
; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1
; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4
; CHECK-NEXT: br i1 [[I_EC]], label %[[INNER_HEADER_SPLIT]], label %[[OUTER_HEADER]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[SUM_RESULT:%.*]] = phi double [ [[SUM_NEXT]], %[[INNER_HEADER_SPLIT]] ]
; CHECK-NEXT: store double [[SUM_RESULT]], ptr [[R]], align 8
; CHECK-NEXT: ret void
;
entry:
br label %outer.header
outer.header:
%i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ]
%sum.i = phi double [ 0.000000e+00, %entry ], [ %sum.next, %outer.latch ]
br label %inner.header
inner.header:
%j = phi i64 [ 0, %outer.header ], [ %j.next, %inner.header ]
%sum.j = phi double [ %sum.i, %outer.header ], [ %sum.next.j, %inner.header ]
%choice = freeze i1 poison
%idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i
%value = load double, ptr %idx, align 8
%selected = select i1 %choice, double %value, double 0.000000e+00
%sum.next.j = fadd reassoc double %sum.j, %selected
%j.next = add i64 %j, 1
%j.ec = icmp eq i64 %j.next, 4
br i1 %j.ec, label %outer.latch, label %inner.header
outer.latch:
%sum.next = phi double [ %sum.next.j, %inner.header ]
%i.next = add i64 %i, 1
%i.ec = icmp eq i64 %i.next, 4
br i1 %i.ec, label %exit, label %outer.header
exit:
%sum.result = phi double [ %sum.next, %outer.latch ]
store double %sum.result, ptr %R, align 8
ret void
}
; Interchange is allowed because the distinct outer-header and inner-preheader
; blocks contain no freeze.
define void @header_preheader_control(ptr noalias %A, i1 %choice) {
; CHECK-LABEL: define void @header_preheader_control(
; CHECK-SAME: ptr noalias [[A:%.*]], i1 [[CHOICE:%.*]]) {
; 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_NEXT:%.*]], %[[OUTER_LATCH:.*]] ], [ 0, %[[OUTER_HEADER_PREHEADER]] ]
; CHECK-NEXT: [[HEADER_BIT:%.*]] = xor i1 [[CHOICE]], true
; CHECK-NEXT: [[PREHEADER_BIT:%.*]] = xor i1 [[CHOICE]], false
; CHECK-NEXT: [[SELECTED_BIT:%.*]] = and i1 [[HEADER_BIT]], [[PREHEADER_BIT]]
; CHECK-NEXT: br label %[[INNER_HEADER_SPLIT1:.*]]
; CHECK: [[INNER_PREHEADER]]:
; CHECK-NEXT: br label %[[INNER_HEADER:.*]]
; CHECK: [[INNER_HEADER]]:
; CHECK-NEXT: [[J:%.*]] = phi i64 [ 0, %[[INNER_PREHEADER]] ], [ [[TMP0:%.*]], %[[INNER_HEADER_SPLIT:.*]] ]
; CHECK-NEXT: br label %[[OUTER_HEADER_PREHEADER]]
; CHECK: [[INNER_HEADER_SPLIT1]]:
; CHECK-NEXT: [[SELECTED:%.*]] = select i1 [[SELECTED_BIT]], double 1.000000e+00, double 0.000000e+00
; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]]
; CHECK-NEXT: store double [[SELECTED]], ptr [[IDX]], align 8
; CHECK-NEXT: [[J_NEXT:%.*]] = add i64 [[J]], 1
; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], 4
; CHECK-NEXT: br label %[[OUTER_LATCH]]
; CHECK: [[INNER_HEADER_SPLIT]]:
; CHECK-NEXT: [[TMP0]] = add i64 [[J]], 1
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], 4
; CHECK-NEXT: br i1 [[TMP1]], label %[[EXIT:.*]], label %[[INNER_HEADER]]
; CHECK: [[OUTER_LATCH]]:
; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1
; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4
; CHECK-NEXT: br i1 [[I_EC]], label %[[INNER_HEADER_SPLIT]], label %[[OUTER_HEADER]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
entry:
br label %outer.header
outer.header:
%i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ]
%header.bit = xor i1 %choice, true
br label %inner.preheader
inner.preheader:
%preheader.bit = xor i1 %choice, false
%selected.bit = and i1 %header.bit, %preheader.bit
br label %inner.header
inner.header:
%j = phi i64 [ 0, %inner.preheader ], [ %j.next, %inner.header ]
%selected = select i1 %selected.bit, double 1.000000e+00, double 0.000000e+00
%idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i
store double %selected, ptr %idx, align 8
%j.next = add i64 %j, 1
%j.ec = icmp eq i64 %j.next, 4
br i1 %j.ec, label %outer.latch, label %inner.header
outer.latch:
%i.next = add i64 %i, 1
%i.ec = icmp eq i64 %i.next, 4
br i1 %i.ec, label %exit, label %outer.header
exit:
ret void
}
; choice = freeze(poison) in the outer header, before a distinct inner
; preheader.
; Interchange is rejected because the freeze in the outer header would move to
; a different loop depth.
define void @outer_header_freeze(ptr noalias %A, i1 %choice) {
; CHECK-LABEL: define void @outer_header_freeze(
; CHECK-SAME: ptr noalias [[A:%.*]], i1 [[CHOICE:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[OUTER_HEADER:.*]]
; CHECK: [[OUTER_HEADER]]:
; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ]
; CHECK-NEXT: [[HEADER_BIT:%.*]] = freeze i1 poison
; CHECK-NEXT: br label %[[INNER_PREHEADER:.*]]
; CHECK: [[INNER_PREHEADER]]:
; CHECK-NEXT: [[PREHEADER_BIT:%.*]] = xor i1 [[CHOICE]], false
; CHECK-NEXT: [[SELECTED_BIT:%.*]] = and i1 [[HEADER_BIT]], [[PREHEADER_BIT]]
; CHECK-NEXT: br label %[[INNER_HEADER:.*]]
; CHECK: [[INNER_HEADER]]:
; CHECK-NEXT: [[J:%.*]] = phi i64 [ 0, %[[INNER_PREHEADER]] ], [ [[J_NEXT:%.*]], %[[INNER_HEADER]] ]
; CHECK-NEXT: [[SELECTED:%.*]] = select i1 [[SELECTED_BIT]], double 1.000000e+00, double 0.000000e+00
; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]]
; CHECK-NEXT: store double [[SELECTED]], ptr [[IDX]], align 8
; CHECK-NEXT: [[J_NEXT]] = add i64 [[J]], 1
; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], 4
; CHECK-NEXT: br i1 [[J_EC]], label %[[OUTER_LATCH]], label %[[INNER_HEADER]]
; CHECK: [[OUTER_LATCH]]:
; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1
; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4
; CHECK-NEXT: br i1 [[I_EC]], label %[[EXIT:.*]], label %[[OUTER_HEADER]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
entry:
br label %outer.header
outer.header:
%i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ]
%header.bit = freeze i1 poison
br label %inner.preheader
inner.preheader:
%preheader.bit = xor i1 %choice, false
%selected.bit = and i1 %header.bit, %preheader.bit
br label %inner.header
inner.header:
%j = phi i64 [ 0, %inner.preheader ], [ %j.next, %inner.header ]
%selected = select i1 %selected.bit, double 1.000000e+00, double 0.000000e+00
%idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i
store double %selected, ptr %idx, align 8
%j.next = add i64 %j, 1
%j.ec = icmp eq i64 %j.next, 4
br i1 %j.ec, label %outer.latch, label %inner.header
outer.latch:
%i.next = add i64 %i, 1
%i.ec = icmp eq i64 %i.next, 4
br i1 %i.ec, label %exit, label %outer.header
exit:
ret void
}
; choice = freeze(poison) in the inner preheader, after a distinct outer
; header.
; Interchange is rejected because the freeze in the inner preheader would move
; to a different loop depth.
define void @inner_preheader_freeze(ptr noalias %A, i1 %choice) {
; CHECK-LABEL: define void @inner_preheader_freeze(
; CHECK-SAME: ptr noalias [[A:%.*]], i1 [[CHOICE:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[OUTER_HEADER:.*]]
; CHECK: [[OUTER_HEADER]]:
; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ]
; CHECK-NEXT: [[HEADER_BIT:%.*]] = xor i1 [[CHOICE]], true
; CHECK-NEXT: br label %[[INNER_PREHEADER:.*]]
; CHECK: [[INNER_PREHEADER]]:
; CHECK-NEXT: [[PREHEADER_BIT:%.*]] = freeze i1 poison
; CHECK-NEXT: [[SELECTED_BIT:%.*]] = and i1 [[HEADER_BIT]], [[PREHEADER_BIT]]
; CHECK-NEXT: br label %[[INNER_HEADER:.*]]
; CHECK: [[INNER_HEADER]]:
; CHECK-NEXT: [[J:%.*]] = phi i64 [ 0, %[[INNER_PREHEADER]] ], [ [[J_NEXT:%.*]], %[[INNER_HEADER]] ]
; CHECK-NEXT: [[SELECTED:%.*]] = select i1 [[SELECTED_BIT]], double 1.000000e+00, double 0.000000e+00
; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]]
; CHECK-NEXT: store double [[SELECTED]], ptr [[IDX]], align 8
; CHECK-NEXT: [[J_NEXT]] = add i64 [[J]], 1
; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], 4
; CHECK-NEXT: br i1 [[J_EC]], label %[[OUTER_LATCH]], label %[[INNER_HEADER]]
; CHECK: [[OUTER_LATCH]]:
; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1
; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4
; CHECK-NEXT: br i1 [[I_EC]], label %[[EXIT:.*]], label %[[OUTER_HEADER]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
entry:
br label %outer.header
outer.header:
%i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ]
%header.bit = xor i1 %choice, true
br label %inner.preheader
inner.preheader:
%preheader.bit = freeze i1 poison
%selected.bit = and i1 %header.bit, %preheader.bit
br label %inner.header
inner.header:
%j = phi i64 [ 0, %inner.preheader ], [ %j.next, %inner.header ]
%selected = select i1 %selected.bit, double 1.000000e+00, double 0.000000e+00
%idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i
store double %selected, ptr %idx, align 8
%j.next = add i64 %j, 1
%j.ec = icmp eq i64 %j.next, 4
br i1 %j.ec, label %outer.latch, label %inner.header
outer.latch:
%i.next = add i64 %i, 1
%i.ec = icmp eq i64 %i.next, 4
br i1 %i.ec, label %exit, label %outer.header
exit:
ret void
}
; Interchange is allowed because the distinct inner-exit and outer-latch blocks
; contain no freeze.
define void @exit_latch_control(ptr noalias %A, ptr noalias %R, i1 %choice) {
; CHECK-LABEL: define void @exit_latch_control(
; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[R:%.*]], i1 [[CHOICE:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: br label %[[OUTER_HEADER:.*]]
; CHECK: [[OUTER_HEADER_PREHEADER:.*]]:
; CHECK-NEXT: br label %[[INNER_HEADER:.*]]
; CHECK: [[INNER_HEADER]]:
; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ], [ 0, %[[OUTER_HEADER_PREHEADER]] ]
; CHECK-NEXT: br label %[[INNER_HEADER_SPLIT1:.*]]
; CHECK: [[OUTER_HEADER]]:
; CHECK-NEXT: br label %[[INNER_HEADER1:.*]]
; CHECK: [[INNER_HEADER1]]:
; CHECK-NEXT: [[J:%.*]] = phi i64 [ [[TMP2:%.*]], %[[INNER_HEADER_SPLIT:.*]] ], [ 0, %[[OUTER_HEADER]] ]
; CHECK-NEXT: br label %[[OUTER_HEADER_PREHEADER]]
; CHECK: [[INNER_HEADER_SPLIT1]]:
; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]]
; CHECK-NEXT: store double 1.000000e+00, ptr [[IDX]], align 8
; CHECK-NEXT: [[J_NEXT:%.*]] = add i64 [[J]], 1
; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], 4
; CHECK-NEXT: br label %[[INNER_EXIT:.*]]
; CHECK: [[INNER_HEADER_SPLIT]]:
; CHECK-NEXT: [[TMP0:%.*]] = phi i1 [ [[EXIT_BIT:%.*]], %[[OUTER_LATCH]] ]
; CHECK-NEXT: [[TMP1:%.*]] = phi i1 [ [[LATCH_BIT:%.*]], %[[OUTER_LATCH]] ]
; CHECK-NEXT: [[TMP2]] = add i64 [[J]], 1
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i64 [[TMP2]], 4
; CHECK-NEXT: br i1 [[TMP3]], label %[[EXIT:.*]], label %[[INNER_HEADER1]]
; CHECK: [[INNER_EXIT]]:
; CHECK-NEXT: [[EXIT_BIT]] = xor i1 [[CHOICE]], true
; CHECK-NEXT: br label %[[OUTER_LATCH]]
; CHECK: [[OUTER_LATCH]]:
; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1
; CHECK-NEXT: [[LATCH_BIT]] = xor i1 [[CHOICE]], false
; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4
; CHECK-NEXT: br i1 [[I_EC]], label %[[INNER_HEADER_SPLIT]], label %[[INNER_HEADER]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[EXIT_OUT:%.*]] = phi i1 [ [[TMP0]], %[[INNER_HEADER_SPLIT]] ]
; CHECK-NEXT: [[LATCH_OUT:%.*]] = phi i1 [ [[TMP1]], %[[INNER_HEADER_SPLIT]] ]
; CHECK-NEXT: [[SELECTED_OUT:%.*]] = and i1 [[EXIT_OUT]], [[LATCH_OUT]]
; CHECK-NEXT: [[VALUE:%.*]] = select i1 [[SELECTED_OUT]], double 1.000000e+00, double 0.000000e+00
; CHECK-NEXT: store double [[VALUE]], ptr [[R]], align 8
; CHECK-NEXT: ret void
;
entry:
br label %outer.header
outer.header:
%i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ]
br label %inner.header
inner.header:
%j = phi i64 [ 0, %outer.header ], [ %j.next, %inner.header ]
%idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i
store double 1.000000e+00, ptr %idx, align 8
%j.next = add i64 %j, 1
%j.ec = icmp eq i64 %j.next, 4
br i1 %j.ec, label %inner.exit, label %inner.header
inner.exit:
%exit.bit = xor i1 %choice, true
br label %outer.latch
outer.latch:
%exit.bit.lcssa = phi i1 [ %exit.bit, %inner.exit ]
%i.next = add i64 %i, 1
%latch.bit = xor i1 %choice, false
%i.ec = icmp eq i64 %i.next, 4
br i1 %i.ec, label %exit, label %outer.header
exit:
%exit.out = phi i1 [ %exit.bit.lcssa, %outer.latch ]
%latch.out = phi i1 [ %latch.bit, %outer.latch ]
%selected.out = and i1 %exit.out, %latch.out
%value = select i1 %selected.out, double 1.000000e+00, double 0.000000e+00
store double %value, ptr %R, align 8
ret void
}
; choice = freeze(poison) in the inner exit, before a distinct outer latch.
; Interchange is rejected because the freeze in the inner exit would move to a
; different loop depth.
define void @inner_exit_freeze(ptr noalias %A, ptr noalias %R, i1 %choice) {
; CHECK-LABEL: define void @inner_exit_freeze(
; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[R:%.*]], i1 [[CHOICE:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[OUTER_HEADER:.*]]
; CHECK: [[OUTER_HEADER]]:
; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ]
; CHECK-NEXT: br label %[[INNER_HEADER:.*]]
; CHECK: [[INNER_HEADER]]:
; CHECK-NEXT: [[J:%.*]] = phi i64 [ 0, %[[OUTER_HEADER]] ], [ [[J_NEXT:%.*]], %[[INNER_HEADER]] ]
; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]]
; CHECK-NEXT: store double 1.000000e+00, ptr [[IDX]], align 8
; CHECK-NEXT: [[J_NEXT]] = add i64 [[J]], 1
; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], 4
; CHECK-NEXT: br i1 [[J_EC]], label %[[INNER_EXIT:.*]], label %[[INNER_HEADER]]
; CHECK: [[INNER_EXIT]]:
; CHECK-NEXT: [[EXIT_BIT:%.*]] = freeze i1 poison
; CHECK-NEXT: br label %[[OUTER_LATCH]]
; CHECK: [[OUTER_LATCH]]:
; CHECK-NEXT: [[EXIT_BIT_LCSSA:%.*]] = phi i1 [ [[EXIT_BIT]], %[[INNER_EXIT]] ]
; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1
; CHECK-NEXT: [[LATCH_BIT:%.*]] = xor i1 [[CHOICE]], false
; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4
; CHECK-NEXT: br i1 [[I_EC]], label %[[EXIT:.*]], label %[[OUTER_HEADER]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[EXIT_OUT:%.*]] = phi i1 [ [[EXIT_BIT_LCSSA]], %[[OUTER_LATCH]] ]
; CHECK-NEXT: [[LATCH_OUT:%.*]] = phi i1 [ [[LATCH_BIT]], %[[OUTER_LATCH]] ]
; CHECK-NEXT: [[SELECTED_OUT:%.*]] = and i1 [[EXIT_OUT]], [[LATCH_OUT]]
; CHECK-NEXT: [[VALUE:%.*]] = select i1 [[SELECTED_OUT]], double 1.000000e+00, double 0.000000e+00
; CHECK-NEXT: store double [[VALUE]], ptr [[R]], align 8
; CHECK-NEXT: ret void
;
entry:
br label %outer.header
outer.header:
%i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ]
br label %inner.header
inner.header:
%j = phi i64 [ 0, %outer.header ], [ %j.next, %inner.header ]
%idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i
store double 1.000000e+00, ptr %idx, align 8
%j.next = add i64 %j, 1
%j.ec = icmp eq i64 %j.next, 4
br i1 %j.ec, label %inner.exit, label %inner.header
inner.exit:
%exit.bit = freeze i1 poison
br label %outer.latch
outer.latch:
%exit.bit.lcssa = phi i1 [ %exit.bit, %inner.exit ]
%i.next = add i64 %i, 1
%latch.bit = xor i1 %choice, false
%i.ec = icmp eq i64 %i.next, 4
br i1 %i.ec, label %exit, label %outer.header
exit:
%exit.out = phi i1 [ %exit.bit.lcssa, %outer.latch ]
%latch.out = phi i1 [ %latch.bit, %outer.latch ]
%selected.out = and i1 %exit.out, %latch.out
%value = select i1 %selected.out, double 1.000000e+00, double 0.000000e+00
store double %value, ptr %R, align 8
ret void
}
; choice = freeze(poison) in the outer latch, after a distinct inner exit.
; Interchange is rejected because the freeze in the outer latch would move to a
; different loop depth.
define void @outer_latch_freeze(ptr noalias %A, ptr noalias %R, i1 %choice) {
; CHECK-LABEL: define void @outer_latch_freeze(
; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[R:%.*]], i1 [[CHOICE:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[OUTER_HEADER:.*]]
; CHECK: [[OUTER_HEADER]]:
; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ]
; CHECK-NEXT: br label %[[INNER_HEADER:.*]]
; CHECK: [[INNER_HEADER]]:
; CHECK-NEXT: [[J:%.*]] = phi i64 [ 0, %[[OUTER_HEADER]] ], [ [[J_NEXT:%.*]], %[[INNER_HEADER]] ]
; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]]
; CHECK-NEXT: store double 1.000000e+00, ptr [[IDX]], align 8
; CHECK-NEXT: [[J_NEXT]] = add i64 [[J]], 1
; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], 4
; CHECK-NEXT: br i1 [[J_EC]], label %[[INNER_EXIT:.*]], label %[[INNER_HEADER]]
; CHECK: [[INNER_EXIT]]:
; CHECK-NEXT: [[EXIT_BIT:%.*]] = xor i1 [[CHOICE]], true
; CHECK-NEXT: br label %[[OUTER_LATCH]]
; CHECK: [[OUTER_LATCH]]:
; CHECK-NEXT: [[EXIT_BIT_LCSSA:%.*]] = phi i1 [ [[EXIT_BIT]], %[[INNER_EXIT]] ]
; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1
; CHECK-NEXT: [[LATCH_BIT:%.*]] = freeze i1 poison
; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4
; CHECK-NEXT: br i1 [[I_EC]], label %[[EXIT:.*]], label %[[OUTER_HEADER]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[EXIT_OUT:%.*]] = phi i1 [ [[EXIT_BIT_LCSSA]], %[[OUTER_LATCH]] ]
; CHECK-NEXT: [[LATCH_OUT:%.*]] = phi i1 [ [[LATCH_BIT]], %[[OUTER_LATCH]] ]
; CHECK-NEXT: [[SELECTED_OUT:%.*]] = and i1 [[EXIT_OUT]], [[LATCH_OUT]]
; CHECK-NEXT: [[VALUE:%.*]] = select i1 [[SELECTED_OUT]], double 1.000000e+00, double 0.000000e+00
; CHECK-NEXT: store double [[VALUE]], ptr [[R]], align 8
; CHECK-NEXT: ret void
;
entry:
br label %outer.header
outer.header:
%i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ]
br label %inner.header
inner.header:
%j = phi i64 [ 0, %outer.header ], [ %j.next, %inner.header ]
%idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i
store double 1.000000e+00, ptr %idx, align 8
%j.next = add i64 %j, 1
%j.ec = icmp eq i64 %j.next, 4
br i1 %j.ec, label %inner.exit, label %inner.header
inner.exit:
%exit.bit = xor i1 %choice, true
br label %outer.latch
outer.latch:
%exit.bit.lcssa = phi i1 [ %exit.bit, %inner.exit ]
%i.next = add i64 %i, 1
%latch.bit = freeze i1 poison
%i.ec = icmp eq i64 %i.next, 4
br i1 %i.ec, label %exit, label %outer.header
exit:
%exit.out = phi i1 [ %exit.bit.lcssa, %outer.latch ]
%latch.out = phi i1 [ %latch.bit, %outer.latch ]
%selected.out = and i1 %exit.out, %latch.out
%value = select i1 %selected.out, double 1.000000e+00, double 0.000000e+00
store double %value, ptr %R, align 8
ret void
}
; Interchange is allowed because neither cloned operand set contains a freeze.
define void @inner_latch_clone_control(ptr noalias %A, ptr noalias %R,
; CHECK-LABEL: define void @inner_latch_clone_control(
; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[R:%.*]], i1 [[CONDITION_ARG:%.*]], i1 [[STEP_ARG:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: br label %[[INNER_HEADER_PREHEADER:.*]]
; CHECK: [[OUTER_HEADER_PREHEADER:.*]]:
; CHECK-NEXT: br label %[[OUTER_HEADER:.*]]
; CHECK: [[OUTER_HEADER]]:
; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ], [ 0, %[[OUTER_HEADER_PREHEADER]] ]
; CHECK-NEXT: br label %[[INNER_HEADER_SPLIT1:.*]]
; CHECK: [[INNER_HEADER_PREHEADER]]:
; CHECK-NEXT: br label %[[INNER_HEADER:.*]]
; CHECK: [[INNER_HEADER]]:
; CHECK-NEXT: [[J:%.*]] = phi i64 [ [[TMP9:%.*]], %[[INNER_HEADER_SPLIT:.*]] ], [ 0, %[[INNER_HEADER_PREHEADER]] ]
; CHECK-NEXT: [[K:%.*]] = phi i64 [ [[TMP4:%.*]], %[[INNER_HEADER_SPLIT]] ], [ 0, %[[INNER_HEADER_PREHEADER]] ]
; CHECK-NEXT: br label %[[OUTER_HEADER_PREHEADER]]
; CHECK: [[INNER_HEADER_SPLIT1]]:
; CHECK-NEXT: [[CONDITION_CHOICE:%.*]] = xor i1 [[CONDITION_ARG]], true
; CHECK-NEXT: [[STEP_CHOICE:%.*]] = xor i1 [[STEP_ARG]], true
; CHECK-NEXT: [[CONDITION_EXT:%.*]] = zext i1 [[CONDITION_CHOICE]] to i64
; CHECK-NEXT: [[CONDITION_ZERO:%.*]] = mul i64 [[CONDITION_EXT]], 0
; CHECK-NEXT: [[BOUND:%.*]] = add i64 4, [[CONDITION_ZERO]]
; CHECK-NEXT: [[STEP_EXT:%.*]] = zext i1 [[STEP_CHOICE]] to i64
; CHECK-NEXT: [[STEP_ZERO:%.*]] = mul i64 [[STEP_EXT]], 0
; CHECK-NEXT: [[STEP:%.*]] = add i64 1, [[STEP_ZERO]]
; CHECK-NEXT: [[K_NEXT:%.*]] = add i64 [[K]], [[STEP]]
; CHECK-NEXT: [[K_FP:%.*]] = sitofp i64 [[K]] to double
; CHECK-NEXT: [[SELECTED_BIT:%.*]] = and i1 [[CONDITION_CHOICE]], [[STEP_CHOICE]]
; CHECK-NEXT: [[SELECTED:%.*]] = select i1 [[SELECTED_BIT]], double 1.000000e+00, double 0.000000e+00
; CHECK-NEXT: [[VALUE:%.*]] = fadd double [[SELECTED]], [[K_FP]]
; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]]
; CHECK-NEXT: store double [[VALUE]], ptr [[IDX]], align 8
; CHECK-NEXT: [[J_NEXT:%.*]] = add i64 [[J]], 1
; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], [[BOUND]]
; CHECK-NEXT: br label %[[OUTER_LATCH]]
; CHECK: [[INNER_HEADER_SPLIT]]:
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[STEP_ARG]], true
; CHECK-NEXT: [[TMP1:%.*]] = zext i1 [[TMP0]] to i64
; CHECK-NEXT: [[TMP2:%.*]] = mul i64 [[TMP1]], 0
; CHECK-NEXT: [[TMP3:%.*]] = add i64 1, [[TMP2]]
; CHECK-NEXT: [[TMP4]] = add i64 [[K]], [[TMP3]]
; CHECK-NEXT: [[TMP5:%.*]] = xor i1 [[CONDITION_ARG]], true
; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i64
; CHECK-NEXT: [[TMP7:%.*]] = mul i64 [[TMP6]], 0
; CHECK-NEXT: [[TMP8:%.*]] = add i64 4, [[TMP7]]
; CHECK-NEXT: [[TMP9]] = add i64 [[J]], 1
; CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], [[TMP8]]
; CHECK-NEXT: br i1 [[TMP10]], label %[[EXIT:.*]], label %[[INNER_HEADER]]
; CHECK: [[OUTER_LATCH]]:
; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1
; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4
; CHECK-NEXT: br i1 [[I_EC]], label %[[INNER_HEADER_SPLIT]], label %[[OUTER_HEADER]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[CONDITION_OUT:%.*]] = phi i1 [ [[TMP5]], %[[INNER_HEADER_SPLIT]] ]
; CHECK-NEXT: [[STEP_OUT:%.*]] = phi i1 [ [[TMP0]], %[[INNER_HEADER_SPLIT]] ]
; CHECK-NEXT: [[SELECTED_OUT:%.*]] = and i1 [[CONDITION_OUT]], [[STEP_OUT]]
; CHECK-NEXT: [[RESULT:%.*]] = select i1 [[SELECTED_OUT]], double 2.000000e+00, double 3.000000e+00
; CHECK-NEXT: store double [[RESULT]], ptr [[R]], align 8
; CHECK-NEXT: ret void
;
i1 %condition.arg, i1 %step.arg) {
entry:
br label %outer.header
outer.header:
%i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ]
br label %inner.header
inner.header:
%j = phi i64 [ 0, %outer.header ], [ %j.next, %inner.header ]
%k = phi i64 [ 0, %outer.header ], [ %k.next, %inner.header ]
%condition.choice = xor i1 %condition.arg, true
%step.choice = xor i1 %step.arg, true
%condition.ext = zext i1 %condition.choice to i64
%condition.zero = mul i64 %condition.ext, 0
%bound = add i64 4, %condition.zero
%step.ext = zext i1 %step.choice to i64
%step.zero = mul i64 %step.ext, 0
%step = add i64 1, %step.zero
%k.next = add i64 %k, %step
%k.fp = sitofp i64 %k to double
%selected.bit = and i1 %condition.choice, %step.choice
%selected = select i1 %selected.bit, double 1.000000e+00, double 0.000000e+00
%value = fadd double %selected, %k.fp
%idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i
store double %value, ptr %idx, align 8
%j.next = add i64 %j, 1
%j.ec = icmp eq i64 %j.next, %bound
br i1 %j.ec, label %outer.latch, label %inner.header
outer.latch:
%condition.lcssa = phi i1 [ %condition.choice, %inner.header ]
%step.lcssa = phi i1 [ %step.choice, %inner.header ]
%i.next = add i64 %i, 1
%i.ec = icmp eq i64 %i.next, 4
br i1 %i.ec, label %exit, label %outer.header
exit:
%condition.out = phi i1 [ %condition.lcssa, %outer.latch ]
%step.out = phi i1 [ %step.lcssa, %outer.latch ]
%selected.out = and i1 %condition.out, %step.out
%result = select i1 %selected.out, double 2.000000e+00, double 3.000000e+00
store double %result, ptr %R, align 8
ret void
}
; Interchange is rejected because the latch-condition computation would clone
; the freeze.
define void @inner_latch_condition_freeze(ptr noalias %A, ptr noalias %R,
; CHECK-LABEL: define void @inner_latch_condition_freeze(
; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[R:%.*]], i1 [[STEP_ARG:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[OUTER_HEADER:.*]]
; CHECK: [[OUTER_HEADER]]:
; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ]
; CHECK-NEXT: br label %[[INNER_HEADER:.*]]
; CHECK: [[INNER_HEADER]]:
; CHECK-NEXT: [[J:%.*]] = phi i64 [ 0, %[[OUTER_HEADER]] ], [ [[J_NEXT:%.*]], %[[INNER_HEADER]] ]
; CHECK-NEXT: [[K:%.*]] = phi i64 [ 0, %[[OUTER_HEADER]] ], [ [[K_NEXT:%.*]], %[[INNER_HEADER]] ]
; CHECK-NEXT: [[CONDITION_CHOICE:%.*]] = freeze i1 poison
; CHECK-NEXT: [[STEP_CHOICE:%.*]] = xor i1 [[STEP_ARG]], true
; CHECK-NEXT: [[CONDITION_EXT:%.*]] = zext i1 [[CONDITION_CHOICE]] to i64
; CHECK-NEXT: [[CONDITION_ZERO:%.*]] = mul i64 [[CONDITION_EXT]], 0
; CHECK-NEXT: [[BOUND:%.*]] = add i64 4, [[CONDITION_ZERO]]
; CHECK-NEXT: [[STEP_EXT:%.*]] = zext i1 [[STEP_CHOICE]] to i64
; CHECK-NEXT: [[STEP_ZERO:%.*]] = mul i64 [[STEP_EXT]], 0
; CHECK-NEXT: [[STEP:%.*]] = add i64 1, [[STEP_ZERO]]
; CHECK-NEXT: [[K_NEXT]] = add i64 [[K]], [[STEP]]
; CHECK-NEXT: [[K_FP:%.*]] = sitofp i64 [[K]] to double
; CHECK-NEXT: [[SELECTED_BIT:%.*]] = and i1 [[CONDITION_CHOICE]], [[STEP_CHOICE]]
; CHECK-NEXT: [[SELECTED:%.*]] = select i1 [[SELECTED_BIT]], double 1.000000e+00, double 0.000000e+00
; CHECK-NEXT: [[VALUE:%.*]] = fadd double [[SELECTED]], [[K_FP]]
; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]]
; CHECK-NEXT: store double [[VALUE]], ptr [[IDX]], align 8
; CHECK-NEXT: [[J_NEXT]] = add i64 [[J]], 1
; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], [[BOUND]]
; CHECK-NEXT: br i1 [[J_EC]], label %[[OUTER_LATCH]], label %[[INNER_HEADER]]
; CHECK: [[OUTER_LATCH]]:
; CHECK-NEXT: [[CONDITION_LCSSA:%.*]] = phi i1 [ [[CONDITION_CHOICE]], %[[INNER_HEADER]] ]
; CHECK-NEXT: [[STEP_LCSSA:%.*]] = phi i1 [ [[STEP_CHOICE]], %[[INNER_HEADER]] ]
; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1
; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4
; CHECK-NEXT: br i1 [[I_EC]], label %[[EXIT:.*]], label %[[OUTER_HEADER]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[CONDITION_OUT:%.*]] = phi i1 [ [[CONDITION_LCSSA]], %[[OUTER_LATCH]] ]
; CHECK-NEXT: [[STEP_OUT:%.*]] = phi i1 [ [[STEP_LCSSA]], %[[OUTER_LATCH]] ]
; CHECK-NEXT: [[SELECTED_OUT:%.*]] = and i1 [[CONDITION_OUT]], [[STEP_OUT]]
; CHECK-NEXT: [[RESULT:%.*]] = select i1 [[SELECTED_OUT]], double 2.000000e+00, double 3.000000e+00
; CHECK-NEXT: store double [[RESULT]], ptr [[R]], align 8
; CHECK-NEXT: ret void
;
i1 %step.arg) {
entry:
br label %outer.header
outer.header:
%i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ]
br label %inner.header
inner.header:
%j = phi i64 [ 0, %outer.header ], [ %j.next, %inner.header ]
%k = phi i64 [ 0, %outer.header ], [ %k.next, %inner.header ]
%condition.choice = freeze i1 poison
%step.choice = xor i1 %step.arg, true
%condition.ext = zext i1 %condition.choice to i64
%condition.zero = mul i64 %condition.ext, 0
%bound = add i64 4, %condition.zero
%step.ext = zext i1 %step.choice to i64
%step.zero = mul i64 %step.ext, 0
%step = add i64 1, %step.zero
%k.next = add i64 %k, %step
%k.fp = sitofp i64 %k to double
%selected.bit = and i1 %condition.choice, %step.choice
%selected = select i1 %selected.bit, double 1.000000e+00, double 0.000000e+00
%value = fadd double %selected, %k.fp
%idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i
store double %value, ptr %idx, align 8
%j.next = add i64 %j, 1
%j.ec = icmp eq i64 %j.next, %bound
br i1 %j.ec, label %outer.latch, label %inner.header
outer.latch:
%condition.lcssa = phi i1 [ %condition.choice, %inner.header ]
%step.lcssa = phi i1 [ %step.choice, %inner.header ]
%i.next = add i64 %i, 1
%i.ec = icmp eq i64 %i.next, 4
br i1 %i.ec, label %exit, label %outer.header
exit:
%condition.out = phi i1 [ %condition.lcssa, %outer.latch ]
%step.out = phi i1 [ %step.lcssa, %outer.latch ]
%selected.out = and i1 %condition.out, %step.out
%result = select i1 %selected.out, double 2.000000e+00, double 3.000000e+00
store double %result, ptr %R, align 8
ret void
}
; Interchange is rejected because the second induction update would clone the
; freeze.
define void @inner_latch_induction_freeze(ptr noalias %A, ptr noalias %R,
; CHECK-LABEL: define void @inner_latch_induction_freeze(
; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[R:%.*]], i1 [[CONDITION_ARG:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[OUTER_HEADER:.*]]
; CHECK: [[OUTER_HEADER]]:
; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ]
; CHECK-NEXT: br label %[[INNER_HEADER:.*]]
; CHECK: [[INNER_HEADER]]:
; CHECK-NEXT: [[J:%.*]] = phi i64 [ 0, %[[OUTER_HEADER]] ], [ [[J_NEXT:%.*]], %[[INNER_HEADER]] ]
; CHECK-NEXT: [[K:%.*]] = phi i64 [ 0, %[[OUTER_HEADER]] ], [ [[K_NEXT:%.*]], %[[INNER_HEADER]] ]
; CHECK-NEXT: [[CONDITION_CHOICE:%.*]] = xor i1 [[CONDITION_ARG]], true
; CHECK-NEXT: [[STEP_CHOICE:%.*]] = freeze i1 poison
; CHECK-NEXT: [[CONDITION_EXT:%.*]] = zext i1 [[CONDITION_CHOICE]] to i64
; CHECK-NEXT: [[CONDITION_ZERO:%.*]] = mul i64 [[CONDITION_EXT]], 0
; CHECK-NEXT: [[BOUND:%.*]] = add i64 4, [[CONDITION_ZERO]]
; CHECK-NEXT: [[STEP_EXT:%.*]] = zext i1 [[STEP_CHOICE]] to i64
; CHECK-NEXT: [[STEP_ZERO:%.*]] = mul i64 [[STEP_EXT]], 0
; CHECK-NEXT: [[STEP:%.*]] = add i64 1, [[STEP_ZERO]]
; CHECK-NEXT: [[K_NEXT]] = add i64 [[K]], [[STEP]]
; CHECK-NEXT: [[K_FP:%.*]] = sitofp i64 [[K]] to double
; CHECK-NEXT: [[SELECTED_BIT:%.*]] = and i1 [[CONDITION_CHOICE]], [[STEP_CHOICE]]
; CHECK-NEXT: [[SELECTED:%.*]] = select i1 [[SELECTED_BIT]], double 1.000000e+00, double 0.000000e+00
; CHECK-NEXT: [[VALUE:%.*]] = fadd double [[SELECTED]], [[K_FP]]
; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [4 x double], ptr [[A]], i64 [[J]], i64 [[I]]
; CHECK-NEXT: store double [[VALUE]], ptr [[IDX]], align 8
; CHECK-NEXT: [[J_NEXT]] = add i64 [[J]], 1
; CHECK-NEXT: [[J_EC:%.*]] = icmp eq i64 [[J_NEXT]], [[BOUND]]
; CHECK-NEXT: br i1 [[J_EC]], label %[[OUTER_LATCH]], label %[[INNER_HEADER]]
; CHECK: [[OUTER_LATCH]]:
; CHECK-NEXT: [[CONDITION_LCSSA:%.*]] = phi i1 [ [[CONDITION_CHOICE]], %[[INNER_HEADER]] ]
; CHECK-NEXT: [[STEP_LCSSA:%.*]] = phi i1 [ [[STEP_CHOICE]], %[[INNER_HEADER]] ]
; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1
; CHECK-NEXT: [[I_EC:%.*]] = icmp eq i64 [[I_NEXT]], 4
; CHECK-NEXT: br i1 [[I_EC]], label %[[EXIT:.*]], label %[[OUTER_HEADER]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[CONDITION_OUT:%.*]] = phi i1 [ [[CONDITION_LCSSA]], %[[OUTER_LATCH]] ]
; CHECK-NEXT: [[STEP_OUT:%.*]] = phi i1 [ [[STEP_LCSSA]], %[[OUTER_LATCH]] ]
; CHECK-NEXT: [[SELECTED_OUT:%.*]] = and i1 [[CONDITION_OUT]], [[STEP_OUT]]
; CHECK-NEXT: [[RESULT:%.*]] = select i1 [[SELECTED_OUT]], double 2.000000e+00, double 3.000000e+00
; CHECK-NEXT: store double [[RESULT]], ptr [[R]], align 8
; CHECK-NEXT: ret void
;
i1 %condition.arg) {
entry:
br label %outer.header
outer.header:
%i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ]
br label %inner.header
inner.header:
%j = phi i64 [ 0, %outer.header ], [ %j.next, %inner.header ]
%k = phi i64 [ 0, %outer.header ], [ %k.next, %inner.header ]
%condition.choice = xor i1 %condition.arg, true
%step.choice = freeze i1 poison
%condition.ext = zext i1 %condition.choice to i64
%condition.zero = mul i64 %condition.ext, 0
%bound = add i64 4, %condition.zero
%step.ext = zext i1 %step.choice to i64
%step.zero = mul i64 %step.ext, 0
%step = add i64 1, %step.zero
%k.next = add i64 %k, %step
%k.fp = sitofp i64 %k to double
%selected.bit = and i1 %condition.choice, %step.choice
%selected = select i1 %selected.bit, double 1.000000e+00, double 0.000000e+00
%value = fadd double %selected, %k.fp
%idx = getelementptr inbounds [4 x double], ptr %A, i64 %j, i64 %i
store double %value, ptr %idx, align 8
%j.next = add i64 %j, 1
%j.ec = icmp eq i64 %j.next, %bound
br i1 %j.ec, label %outer.latch, label %inner.header
outer.latch:
%condition.lcssa = phi i1 [ %condition.choice, %inner.header ]
%step.lcssa = phi i1 [ %step.choice, %inner.header ]
%i.next = add i64 %i, 1
%i.ec = icmp eq i64 %i.next, 4
br i1 %i.ec, label %exit, label %outer.header
exit:
%condition.out = phi i1 [ %condition.lcssa, %outer.latch ]
%step.out = phi i1 [ %step.lcssa, %outer.latch ]
%selected.out = and i1 %condition.out, %step.out
%result = select i1 %selected.out, double 2.000000e+00, double 3.000000e+00
store double %result, ptr %R, align 8
ret void
}