llvm-project/llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch-select.ll
Joshua Cao 2f171b275f [SimpleLoopUnswitch] Unswitch AND/OR conditions of selects
If a select's condition is a AND/OR, we can unswitch invariant operands.
This patch uses existing logic from unswitching AND/OR's for branch
conditions.

This patch fixes the Cost computation for unswitching selects to have
the cost of the entire loop, since unswitching selects do not remove
branches. This is required for this patch because otherwise, there are
cases where unswitching selects of AND/OR is beating out unswitching of
branches.

This patch also prevents unswitching of logical AND/OR selects. This
should instead be done by unswitching of AND/OR branch conditions.

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D151677
2023-06-14 00:52:45 -07:00

1085 lines
53 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
; RUN: opt -passes='simple-loop-unswitch<nontrivial>' -S < %s | FileCheck %s
; Non-trivial loop unswitching of select instruction.
declare i1 @foo()
declare i1 @bar(i32)
declare i32 @llvm.vector.reduce.add.v2i32(<2 x i32>)
define i32 @basic(i32 %N, i1 %cond, i32 %select_input) {
; CHECK-LABEL: define i32 @basic
; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND:%.*]], i32 [[SELECT_INPUT:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND]]
; CHECK-NEXT: br i1 [[COND_FR]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
; CHECK: entry.split.us:
; CHECK-NEXT: br label [[FOR_COND_US:%.*]]
; CHECK: for.cond.us:
; CHECK-NEXT: [[RES_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[ADD_US:%.*]], [[TMP1:%.*]] ]
; CHECK-NEXT: [[I_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[INC_US:%.*]], [[TMP1]] ]
; CHECK-NEXT: [[CMP_US:%.*]] = icmp slt i32 [[I_US]], [[N]]
; CHECK-NEXT: br i1 [[CMP_US]], label [[FOR_BODY_US:%.*]], label [[FOR_COND_CLEANUP_SPLIT_US:%.*]]
; CHECK: for.body.us:
; CHECK-NEXT: br label [[TMP0:%.*]]
; CHECK: 0:
; CHECK-NEXT: br label [[TMP1]]
; CHECK: 1:
; CHECK-NEXT: [[UNSWITCHED_SELECT_US:%.*]] = phi i32 [ [[SELECT_INPUT]], [[TMP0]] ]
; CHECK-NEXT: [[ADD_US]] = add nuw nsw i32 [[UNSWITCHED_SELECT_US]], [[RES_US]]
; CHECK-NEXT: [[INC_US]] = add nuw nsw i32 [[I_US]], 1
; CHECK-NEXT: br label [[FOR_COND_US]]
; CHECK: for.cond.cleanup.split.us:
; CHECK-NEXT: [[RES_LCSSA_US:%.*]] = phi i32 [ [[RES_US]], [[FOR_COND_US]] ]
; CHECK-NEXT: br label [[FOR_COND_CLEANUP:%.*]]
; CHECK: entry.split:
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[ADD:%.*]], [[TMP2:%.*]] ]
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[INC:%.*]], [[TMP2]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I]], [[N]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP_SPLIT:%.*]]
; CHECK: for.body:
; CHECK-NEXT: br label [[TMP2]]
; CHECK: 2:
; CHECK-NEXT: [[ADD]] = add nuw nsw i32 42, [[RES]]
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I]], 1
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.cond.cleanup.split:
; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi i32 [ [[RES]], [[FOR_COND]] ]
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: [[DOTUS_PHI:%.*]] = phi i32 [ [[RES_LCSSA]], [[FOR_COND_CLEANUP_SPLIT]] ], [ [[RES_LCSSA_US]], [[FOR_COND_CLEANUP_SPLIT_US]] ]
; CHECK-NEXT: ret i32 [[DOTUS_PHI]]
;
entry:
br label %for.cond
for.cond: ; preds = %for.body, %entry
%res = phi i32 [ 0, %entry ], [ %add, %for.body ]
%i = phi i32 [ 0, %entry ], [ %inc, %for.body ]
%cmp = icmp slt i32 %i, %N
br i1 %cmp, label %for.body, label %for.cond.cleanup
for.body: ; preds = %for.cond
%cond1 = select i1 %cond, i32 %select_input, i32 42
%add = add nuw nsw i32 %cond1, %res
%inc = add nuw nsw i32 %i, 1
br label %for.cond
for.cond.cleanup: ; preds = %for.cond
ret i32 %res
}
define i32 @basic_veccond(i32 %N, <2 x i1> %cond, <2 x i32> %select_input) {
; CHECK-LABEL: define i32 @basic_veccond
; CHECK-SAME: (i32 [[N:%.*]], <2 x i1> [[COND:%.*]], <2 x i32> [[SELECT_INPUT:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[ADD:%.*]], [[FOR_BODY:%.*]] ]
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I]], [[N]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[COND1:%.*]] = select <2 x i1> [[COND]], <2 x i32> [[SELECT_INPUT]], <2 x i32> <i32 42, i32 42>
; CHECK-NEXT: [[VREDUCE:%.*]] = call i32 @llvm.vector.reduce.add.v2i32(<2 x i32> [[COND1]])
; CHECK-NEXT: [[ADD]] = add nuw nsw i32 [[VREDUCE]], [[RES]]
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I]], 1
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi i32 [ [[RES]], [[FOR_COND]] ]
; CHECK-NEXT: ret i32 [[RES_LCSSA]]
;
entry:
br label %for.cond
for.cond: ; preds = %for.body, %entry
%res = phi i32 [ 0, %entry ], [ %add, %for.body ]
%i = phi i32 [ 0, %entry ], [ %inc, %for.body ]
%cmp = icmp slt i32 %i, %N
br i1 %cmp, label %for.body, label %for.cond.cleanup
for.body: ; preds = %for.cond
%cond1 = select <2 x i1> %cond, <2 x i32> %select_input, <2 x i32> <i32 42, i32 42>
%vreduce = call i32 @llvm.vector.reduce.add.v2i32(<2 x i32> %cond1)
%add = add nuw nsw i32 %vreduce, %res
%inc = add nuw nsw i32 %i, 1
br label %for.cond
for.cond.cleanup: ; preds = %for.cond
ret i32 %res
}
define i32 @select_phi_input(i32 %N, i1 %cond) {
; CHECK-LABEL: define i32 @select_phi_input
; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND]]
; CHECK-NEXT: br i1 [[COND_FR]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
; CHECK: entry.split.us:
; CHECK-NEXT: br label [[FOR_COND_US:%.*]]
; CHECK: for.cond.us:
; CHECK-NEXT: [[RES_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[ADD_US:%.*]], [[TMP1:%.*]] ]
; CHECK-NEXT: [[I_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[INC_US:%.*]], [[TMP1]] ]
; CHECK-NEXT: [[CMP_US:%.*]] = icmp slt i32 [[I_US]], [[N]]
; CHECK-NEXT: br i1 [[CMP_US]], label [[FOR_BODY_US:%.*]], label [[FOR_COND_CLEANUP_SPLIT_US:%.*]]
; CHECK: for.body.us:
; CHECK-NEXT: br label [[TMP0:%.*]]
; CHECK: 0:
; CHECK-NEXT: br label [[TMP1]]
; CHECK: 1:
; CHECK-NEXT: [[UNSWITCHED_SELECT_US:%.*]] = phi i32 [ [[I_US]], [[TMP0]] ]
; CHECK-NEXT: [[ADD_US]] = add nuw nsw i32 [[UNSWITCHED_SELECT_US]], [[RES_US]]
; CHECK-NEXT: [[INC_US]] = add nuw nsw i32 [[I_US]], 1
; CHECK-NEXT: br label [[FOR_COND_US]]
; CHECK: for.cond.cleanup.split.us:
; CHECK-NEXT: [[RES_LCSSA_US:%.*]] = phi i32 [ [[RES_US]], [[FOR_COND_US]] ]
; CHECK-NEXT: br label [[FOR_COND_CLEANUP:%.*]]
; CHECK: entry.split:
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[ADD:%.*]], [[TMP2:%.*]] ]
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[INC:%.*]], [[TMP2]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I]], [[N]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP_SPLIT:%.*]]
; CHECK: for.body:
; CHECK-NEXT: br label [[TMP2]]
; CHECK: 2:
; CHECK-NEXT: [[ADD]] = add nuw nsw i32 42, [[RES]]
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I]], 1
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.cond.cleanup.split:
; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi i32 [ [[RES]], [[FOR_COND]] ]
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: [[DOTUS_PHI:%.*]] = phi i32 [ [[RES_LCSSA]], [[FOR_COND_CLEANUP_SPLIT]] ], [ [[RES_LCSSA_US]], [[FOR_COND_CLEANUP_SPLIT_US]] ]
; CHECK-NEXT: ret i32 [[DOTUS_PHI]]
;
entry:
br label %for.cond
for.cond: ; preds = %for.body, %entry
%res = phi i32 [ 0, %entry ], [ %add, %for.body ]
%i = phi i32 [ 0, %entry ], [ %inc, %for.body ]
%cmp = icmp slt i32 %i, %N
br i1 %cmp, label %for.body, label %for.cond.cleanup
for.body: ; preds = %for.cond
%cond1 = select i1 %cond, i32 %i, i32 42
%add = add nuw nsw i32 %cond1, %res
%inc = add nuw nsw i32 %i, 1
br label %for.cond
for.cond.cleanup: ; preds = %for.cond
ret i32 %res
}
define i32 @basic_cond_noundef(i32 %N, i1 noundef %cond) {
; CHECK-LABEL: define i32 @basic_cond_noundef
; CHECK-SAME: (i32 [[N:%.*]], i1 noundef [[COND:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[COND]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
; CHECK: entry.split.us:
; CHECK-NEXT: br label [[FOR_COND_US:%.*]]
; CHECK: for.cond.us:
; CHECK-NEXT: [[RES_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[ADD_US:%.*]], [[TMP1:%.*]] ]
; CHECK-NEXT: [[I_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[INC_US:%.*]], [[TMP1]] ]
; CHECK-NEXT: [[CMP_US:%.*]] = icmp slt i32 [[I_US]], [[N]]
; CHECK-NEXT: br i1 [[CMP_US]], label [[FOR_BODY_US:%.*]], label [[FOR_COND_CLEANUP_SPLIT_US:%.*]]
; CHECK: for.body.us:
; CHECK-NEXT: br label [[TMP0:%.*]]
; CHECK: 0:
; CHECK-NEXT: br label [[TMP1]]
; CHECK: 1:
; CHECK-NEXT: [[UNSWITCHED_SELECT_US:%.*]] = phi i32 [ [[I_US]], [[TMP0]] ]
; CHECK-NEXT: [[ADD_US]] = add nuw nsw i32 [[UNSWITCHED_SELECT_US]], [[RES_US]]
; CHECK-NEXT: [[INC_US]] = add nuw nsw i32 [[I_US]], 1
; CHECK-NEXT: br label [[FOR_COND_US]]
; CHECK: for.cond.cleanup.split.us:
; CHECK-NEXT: [[RES_LCSSA_US:%.*]] = phi i32 [ [[RES_US]], [[FOR_COND_US]] ]
; CHECK-NEXT: br label [[FOR_COND_CLEANUP:%.*]]
; CHECK: entry.split:
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[ADD:%.*]], [[TMP2:%.*]] ]
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[INC:%.*]], [[TMP2]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I]], [[N]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP_SPLIT:%.*]]
; CHECK: for.body:
; CHECK-NEXT: br label [[TMP2]]
; CHECK: 2:
; CHECK-NEXT: [[ADD]] = add nuw nsw i32 42, [[RES]]
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I]], 1
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.cond.cleanup.split:
; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi i32 [ [[RES]], [[FOR_COND]] ]
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: [[DOTUS_PHI:%.*]] = phi i32 [ [[RES_LCSSA]], [[FOR_COND_CLEANUP_SPLIT]] ], [ [[RES_LCSSA_US]], [[FOR_COND_CLEANUP_SPLIT_US]] ]
; CHECK-NEXT: ret i32 [[DOTUS_PHI]]
;
entry:
br label %for.cond
for.cond: ; preds = %for.body, %entry
%res = phi i32 [ 0, %entry ], [ %add, %for.body ]
%i = phi i32 [ 0, %entry ], [ %inc, %for.body ]
%cmp = icmp slt i32 %i, %N
br i1 %cmp, label %for.body, label %for.cond.cleanup
for.body: ; preds = %for.cond
%cond1 = select i1 %cond, i32 %i, i32 42
%add = add nuw nsw i32 %cond1, %res
%inc = add nuw nsw i32 %i, 1
br label %for.cond
for.cond.cleanup: ; preds = %for.cond
ret i32 %res
}
define i32 @cond_invariant(i32 %N) {
; CHECK-LABEL: define i32 @cond_invariant
; CHECK-SAME: (i32 [[N:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[ADD:%.*]], [[FOR_BODY:%.*]] ]
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I]], [[N]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[COND:%.*]] = call i1 @foo()
; CHECK-NEXT: [[COND1:%.*]] = select i1 [[COND]], i32 [[I]], i32 42
; CHECK-NEXT: [[ADD]] = add nuw nsw i32 [[COND1]], [[RES]]
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I]], 1
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi i32 [ [[RES]], [[FOR_COND]] ]
; CHECK-NEXT: ret i32 [[RES_LCSSA]]
;
entry:
br label %for.cond
for.cond: ; preds = %for.body, %entry
%res = phi i32 [ 0, %entry ], [ %add, %for.body ]
%i = phi i32 [ 0, %entry ], [ %inc, %for.body ]
%cmp = icmp slt i32 %i, %N
br i1 %cmp, label %for.body, label %for.cond.cleanup
for.body: ; preds = %for.cond
%cond = call i1 @foo()
%cond1 = select i1 %cond, i32 %i, i32 42
%add = add nuw nsw i32 %cond1, %res
%inc = add nuw nsw i32 %i, 1
br label %for.cond
for.cond.cleanup: ; preds = %for.cond
ret i32 %res
}
define i32 @chained_select(i32 %N, i1 %cond, i1 %cond2) {
; CHECK-LABEL: define i32 @chained_select
; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND:%.*]], i1 [[COND2:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND]]
; CHECK-NEXT: br i1 [[COND_FR]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
; CHECK: entry.split.us:
; CHECK-NEXT: [[COND2_FR13:%.*]] = freeze i1 [[COND2]]
; CHECK-NEXT: br i1 [[COND2_FR13]], label [[ENTRY_SPLIT_US_SPLIT_US:%.*]], label [[ENTRY_SPLIT_US_SPLIT:%.*]]
; CHECK: entry.split.us.split.us:
; CHECK-NEXT: br label [[FOR_COND_US_US:%.*]]
; CHECK: for.cond.us.us:
; CHECK-NEXT: [[RES_US_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US_SPLIT_US]] ], [ [[ADD_US_US:%.*]], [[TMP3:%.*]] ]
; CHECK-NEXT: [[I_US_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US_SPLIT_US]] ], [ [[INC_US_US:%.*]], [[TMP3]] ]
; CHECK-NEXT: [[CMP_US_US:%.*]] = icmp slt i32 [[I_US_US]], [[N]]
; CHECK-NEXT: br i1 [[CMP_US_US]], label [[FOR_BODY_US_US:%.*]], label [[FOR_COND_CLEANUP_SPLIT_US_SPLIT_US:%.*]]
; CHECK: for.body.us.us:
; CHECK-NEXT: br label [[TMP0:%.*]]
; CHECK: 0:
; CHECK-NEXT: br label [[TMP1:%.*]]
; CHECK: 1:
; CHECK-NEXT: [[UNSWITCHED_SELECT_US_US:%.*]] = phi i32 [ [[I_US_US]], [[TMP0]] ]
; CHECK-NEXT: br label [[TMP2:%.*]]
; CHECK: 2:
; CHECK-NEXT: br label [[TMP3]]
; CHECK: 3:
; CHECK-NEXT: [[UNSWITCHED_SELECT_US11:%.*]] = phi i32 [ [[UNSWITCHED_SELECT_US_US]], [[TMP2]] ]
; CHECK-NEXT: [[ADD_US_US]] = add nuw nsw i32 [[UNSWITCHED_SELECT_US11]], [[RES_US_US]]
; CHECK-NEXT: [[INC_US_US]] = add nuw nsw i32 [[I_US_US]], 1
; CHECK-NEXT: br label [[FOR_COND_US_US]]
; CHECK: for.cond.cleanup.split.us.split.us:
; CHECK-NEXT: [[RES_LCSSA_US_US:%.*]] = phi i32 [ [[RES_US_US]], [[FOR_COND_US_US]] ]
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_SPLIT_US:%.*]]
; CHECK: entry.split.us.split:
; CHECK-NEXT: br label [[FOR_COND_US:%.*]]
; CHECK: for.cond.us:
; CHECK-NEXT: [[RES_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US_SPLIT]] ], [ [[ADD_US:%.*]], [[TMP6:%.*]] ]
; CHECK-NEXT: [[I_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US_SPLIT]] ], [ [[INC_US:%.*]], [[TMP6]] ]
; CHECK-NEXT: [[CMP_US:%.*]] = icmp slt i32 [[I_US]], [[N]]
; CHECK-NEXT: br i1 [[CMP_US]], label [[FOR_BODY_US:%.*]], label [[FOR_COND_CLEANUP_SPLIT_US_SPLIT:%.*]]
; CHECK: for.body.us:
; CHECK-NEXT: br label [[TMP4:%.*]]
; CHECK: 4:
; CHECK-NEXT: br label [[TMP5:%.*]]
; CHECK: 5:
; CHECK-NEXT: [[UNSWITCHED_SELECT_US:%.*]] = phi i32 [ [[I_US]], [[TMP4]] ]
; CHECK-NEXT: br label [[TMP6]]
; CHECK: 6:
; CHECK-NEXT: [[ADD_US]] = add nuw nsw i32 24, [[RES_US]]
; CHECK-NEXT: [[INC_US]] = add nuw nsw i32 [[I_US]], 1
; CHECK-NEXT: br label [[FOR_COND_US]]
; CHECK: for.cond.cleanup.split.us.split:
; CHECK-NEXT: [[RES_LCSSA_US:%.*]] = phi i32 [ [[RES_US]], [[FOR_COND_US]] ]
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_SPLIT_US]]
; CHECK: for.cond.cleanup.split.us:
; CHECK-NEXT: [[DOTUS_PHI12:%.*]] = phi i32 [ [[RES_LCSSA_US]], [[FOR_COND_CLEANUP_SPLIT_US_SPLIT]] ], [ [[RES_LCSSA_US_US]], [[FOR_COND_CLEANUP_SPLIT_US_SPLIT_US]] ]
; CHECK-NEXT: br label [[FOR_COND_CLEANUP:%.*]]
; CHECK: entry.split:
; CHECK-NEXT: [[COND2_FR:%.*]] = freeze i1 [[COND2]]
; CHECK-NEXT: br i1 [[COND2_FR]], label [[ENTRY_SPLIT_SPLIT_US:%.*]], label [[ENTRY_SPLIT_SPLIT:%.*]]
; CHECK: entry.split.split.us:
; CHECK-NEXT: br label [[FOR_COND_US1:%.*]]
; CHECK: for.cond.us1:
; CHECK-NEXT: [[RES_US2:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_SPLIT_US]] ], [ [[ADD_US7:%.*]], [[TMP9:%.*]] ]
; CHECK-NEXT: [[I_US3:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_SPLIT_US]] ], [ [[INC_US8:%.*]], [[TMP9]] ]
; CHECK-NEXT: [[CMP_US4:%.*]] = icmp slt i32 [[I_US3]], [[N]]
; CHECK-NEXT: br i1 [[CMP_US4]], label [[FOR_BODY_US5:%.*]], label [[FOR_COND_CLEANUP_SPLIT_SPLIT_US:%.*]]
; CHECK: for.body.us5:
; CHECK-NEXT: br label [[TMP7:%.*]]
; CHECK: 7:
; CHECK-NEXT: br label [[TMP8:%.*]]
; CHECK: 8:
; CHECK-NEXT: br label [[TMP9]]
; CHECK: 9:
; CHECK-NEXT: [[UNSWITCHED_SELECT_US6:%.*]] = phi i32 [ 42, [[TMP8]] ]
; CHECK-NEXT: [[ADD_US7]] = add nuw nsw i32 [[UNSWITCHED_SELECT_US6]], [[RES_US2]]
; CHECK-NEXT: [[INC_US8]] = add nuw nsw i32 [[I_US3]], 1
; CHECK-NEXT: br label [[FOR_COND_US1]]
; CHECK: for.cond.cleanup.split.split.us:
; CHECK-NEXT: [[RES_LCSSA_US9:%.*]] = phi i32 [ [[RES_US2]], [[FOR_COND_US1]] ]
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_SPLIT:%.*]]
; CHECK: entry.split.split:
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_SPLIT]] ], [ [[ADD:%.*]], [[TMP11:%.*]] ]
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_SPLIT]] ], [ [[INC:%.*]], [[TMP11]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I]], [[N]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP_SPLIT_SPLIT:%.*]]
; CHECK: for.body:
; CHECK-NEXT: br label [[TMP10:%.*]]
; CHECK: 10:
; CHECK-NEXT: br label [[TMP11]]
; CHECK: 11:
; CHECK-NEXT: [[ADD]] = add nuw nsw i32 24, [[RES]]
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I]], 1
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.cond.cleanup.split.split:
; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi i32 [ [[RES]], [[FOR_COND]] ]
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_SPLIT]]
; CHECK: for.cond.cleanup.split:
; CHECK-NEXT: [[DOTUS_PHI10:%.*]] = phi i32 [ [[RES_LCSSA]], [[FOR_COND_CLEANUP_SPLIT_SPLIT]] ], [ [[RES_LCSSA_US9]], [[FOR_COND_CLEANUP_SPLIT_SPLIT_US]] ]
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: [[DOTUS_PHI:%.*]] = phi i32 [ [[DOTUS_PHI10]], [[FOR_COND_CLEANUP_SPLIT]] ], [ [[DOTUS_PHI12]], [[FOR_COND_CLEANUP_SPLIT_US]] ]
; CHECK-NEXT: ret i32 [[DOTUS_PHI]]
;
entry:
br label %for.cond
for.cond: ; preds = %for.body, %entry
%res = phi i32 [ 0, %entry ], [ %add, %for.body ]
%i = phi i32 [ 0, %entry ], [ %inc, %for.body ]
%cmp = icmp slt i32 %i, %N
br i1 %cmp, label %for.body, label %for.cond.cleanup
for.body: ; preds = %for.cond
%select1 = select i1 %cond, i32 %i, i32 42
%select2 = select i1 %cond2, i32 %select1, i32 24
%add = add nuw nsw i32 %select2, %res
%inc = add nuw nsw i32 %i, 1
br label %for.cond
for.cond.cleanup: ; preds = %for.cond
ret i32 %res
}
define i32 @select_in_if(i32 %N, i1 %cond) {
; CHECK-LABEL: define i32 @select_in_if
; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND]]
; CHECK-NEXT: br i1 [[COND_FR]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
; CHECK: entry.split.us:
; CHECK-NEXT: br label [[FOR_COND_US:%.*]]
; CHECK: for.cond.us:
; CHECK-NEXT: [[RES_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[ADD_US:%.*]], [[FOR_BODY_END_US:%.*]] ]
; CHECK-NEXT: [[I_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[INC_US:%.*]], [[FOR_BODY_END_US]] ]
; CHECK-NEXT: [[CMP_US:%.*]] = icmp slt i32 [[I_US]], [[N]]
; CHECK-NEXT: br i1 [[CMP_US]], label [[FOR_BODY_US:%.*]], label [[FOR_COND_CLEANUP_SPLIT_US:%.*]]
; CHECK: for.body.us:
; CHECK-NEXT: [[UREM_US:%.*]] = urem i32 [[I_US]], 2
; CHECK-NEXT: [[IF_COND_US:%.*]] = icmp eq i32 [[UREM_US]], 0
; CHECK-NEXT: br i1 [[IF_COND_US]], label [[FOR_BODY_IF_US:%.*]], label [[FOR_BODY_END_US]]
; CHECK: for.body.if.us:
; CHECK-NEXT: br label [[TMP0:%.*]]
; CHECK: for.body.end.us:
; CHECK-NEXT: [[P_US:%.*]] = phi i32 [ [[UNSWITCHED_SELECT_US:%.*]], [[TMP1:%.*]] ], [ 24, [[FOR_BODY_US]] ]
; CHECK-NEXT: [[ADD_US]] = add nuw nsw i32 [[P_US]], [[RES_US]]
; CHECK-NEXT: [[INC_US]] = add nuw nsw i32 [[I_US]], 1
; CHECK-NEXT: br label [[FOR_COND_US]]
; CHECK: 0:
; CHECK-NEXT: br label [[TMP1]]
; CHECK: 1:
; CHECK-NEXT: [[UNSWITCHED_SELECT_US]] = phi i32 [ [[I_US]], [[TMP0]] ]
; CHECK-NEXT: br label [[FOR_BODY_END_US]]
; CHECK: for.cond.cleanup.split.us:
; CHECK-NEXT: [[RES_LCSSA_US:%.*]] = phi i32 [ [[RES_US]], [[FOR_COND_US]] ]
; CHECK-NEXT: br label [[FOR_COND_CLEANUP:%.*]]
; CHECK: entry.split:
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[ADD:%.*]], [[FOR_BODY_END:%.*]] ]
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[INC:%.*]], [[FOR_BODY_END]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I]], [[N]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP_SPLIT:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[UREM:%.*]] = urem i32 [[I]], 2
; CHECK-NEXT: [[IF_COND:%.*]] = icmp eq i32 [[UREM]], 0
; CHECK-NEXT: br i1 [[IF_COND]], label [[FOR_BODY_IF:%.*]], label [[FOR_BODY_END]]
; CHECK: for.body.if:
; CHECK-NEXT: br label [[TMP2:%.*]]
; CHECK: 2:
; CHECK-NEXT: br label [[FOR_BODY_END]]
; CHECK: for.body.end:
; CHECK-NEXT: [[P:%.*]] = phi i32 [ 42, [[TMP2]] ], [ 24, [[FOR_BODY]] ]
; CHECK-NEXT: [[ADD]] = add nuw nsw i32 [[P]], [[RES]]
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I]], 1
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.cond.cleanup.split:
; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi i32 [ [[RES]], [[FOR_COND]] ]
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: [[DOTUS_PHI:%.*]] = phi i32 [ [[RES_LCSSA]], [[FOR_COND_CLEANUP_SPLIT]] ], [ [[RES_LCSSA_US]], [[FOR_COND_CLEANUP_SPLIT_US]] ]
; CHECK-NEXT: ret i32 [[DOTUS_PHI]]
;
entry:
br label %for.cond
for.cond: ; preds = %for.body.end, %entry
%res = phi i32 [ 0, %entry ], [ %add, %for.body.end ]
%i = phi i32 [ 0, %entry ], [ %inc, %for.body.end ]
%cmp = icmp slt i32 %i, %N
br i1 %cmp, label %for.body, label %for.cond.cleanup
for.body: ; preds = %for.cond
%urem = urem i32 %i, 2
%if.cond = icmp eq i32 %urem, 0
br i1 %if.cond, label %for.body.if, label %for.body.end
for.body.if: ; preds = %for.body
%cond1 = select i1 %cond, i32 %i, i32 42
br label %for.body.end
for.body.end: ; preds = %for.body, %for.body.if
%p = phi i32 [ %cond1, %for.body.if ], [ 24, %for.body ]
%add = add nuw nsw i32 %p, %res
%inc = add nuw nsw i32 %i, 1
br label %for.cond
for.cond.cleanup: ; preds = %for.cond
ret i32 %res
}
define i32 @select_in_if_else(i32 %N, i1 %cond) {
; CHECK-LABEL: define i32 @select_in_if_else
; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND]]
; CHECK-NEXT: br i1 [[COND_FR]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
; CHECK: entry.split.us:
; CHECK-NEXT: br label [[FOR_COND_US:%.*]]
; CHECK: for.cond.us:
; CHECK-NEXT: [[RES_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[ADD_US:%.*]], [[FOR_BODY_END_US:%.*]] ]
; CHECK-NEXT: [[I_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[INC_US:%.*]], [[FOR_BODY_END_US]] ]
; CHECK-NEXT: [[CMP_US:%.*]] = icmp slt i32 [[I_US]], [[N]]
; CHECK-NEXT: br i1 [[CMP_US]], label [[FOR_BODY_US:%.*]], label [[FOR_COND_CLEANUP_SPLIT_US:%.*]]
; CHECK: for.body.us:
; CHECK-NEXT: [[UREM_US:%.*]] = urem i32 [[I_US]], 2
; CHECK-NEXT: [[IF_COND_US:%.*]] = icmp eq i32 [[UREM_US]], 0
; CHECK-NEXT: br i1 [[IF_COND_US]], label [[FOR_BODY_IF_US:%.*]], label [[FOR_BODY_ELSE_US:%.*]]
; CHECK: for.body.else.us:
; CHECK-NEXT: br label [[TMP0:%.*]]
; CHECK: for.body.if.us:
; CHECK-NEXT: [[COND1A_US:%.*]] = select i1 true, i32 [[I_US]], i32 42
; CHECK-NEXT: br label [[FOR_BODY_END_US]]
; CHECK: for.body.end.us:
; CHECK-NEXT: [[P_US:%.*]] = phi i32 [ [[COND1A_US]], [[FOR_BODY_IF_US]] ], [ [[UNSWITCHED_SELECT_US:%.*]], [[TMP1:%.*]] ]
; CHECK-NEXT: [[ADD_US]] = add nuw nsw i32 [[P_US]], [[RES_US]]
; CHECK-NEXT: [[INC_US]] = add nuw nsw i32 [[I_US]], 1
; CHECK-NEXT: br label [[FOR_COND_US]]
; CHECK: 0:
; CHECK-NEXT: br label [[TMP1]]
; CHECK: 1:
; CHECK-NEXT: [[UNSWITCHED_SELECT_US]] = phi i32 [ 24, [[TMP0]] ]
; CHECK-NEXT: br label [[FOR_BODY_END_US]]
; CHECK: for.cond.cleanup.split.us:
; CHECK-NEXT: [[RES_LCSSA_US:%.*]] = phi i32 [ [[RES_US]], [[FOR_COND_US]] ]
; CHECK-NEXT: br label [[FOR_COND_CLEANUP:%.*]]
; CHECK: entry.split:
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[ADD:%.*]], [[FOR_BODY_END:%.*]] ]
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[INC:%.*]], [[FOR_BODY_END]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I]], [[N]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP_SPLIT:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[UREM:%.*]] = urem i32 [[I]], 2
; CHECK-NEXT: [[IF_COND:%.*]] = icmp eq i32 [[UREM]], 0
; CHECK-NEXT: br i1 [[IF_COND]], label [[FOR_BODY_IF:%.*]], label [[FOR_BODY_ELSE:%.*]]
; CHECK: for.body.if:
; CHECK-NEXT: [[COND1A:%.*]] = select i1 false, i32 [[I]], i32 42
; CHECK-NEXT: br label [[FOR_BODY_END]]
; CHECK: for.body.else:
; CHECK-NEXT: br label [[TMP2:%.*]]
; CHECK: 2:
; CHECK-NEXT: br label [[FOR_BODY_END]]
; CHECK: for.body.end:
; CHECK-NEXT: [[P:%.*]] = phi i32 [ [[COND1A]], [[FOR_BODY_IF]] ], [ [[I]], [[TMP2]] ]
; CHECK-NEXT: [[ADD]] = add nuw nsw i32 [[P]], [[RES]]
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I]], 1
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.cond.cleanup.split:
; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi i32 [ [[RES]], [[FOR_COND]] ]
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: [[DOTUS_PHI:%.*]] = phi i32 [ [[RES_LCSSA]], [[FOR_COND_CLEANUP_SPLIT]] ], [ [[RES_LCSSA_US]], [[FOR_COND_CLEANUP_SPLIT_US]] ]
; CHECK-NEXT: ret i32 [[DOTUS_PHI]]
;
entry:
br label %for.cond
for.cond: ; preds = %for.body.end, %entry
%res = phi i32 [ 0, %entry ], [ %add, %for.body.end ]
%i = phi i32 [ 0, %entry ], [ %inc, %for.body.end ]
%cmp = icmp slt i32 %i, %N
br i1 %cmp, label %for.body, label %for.cond.cleanup
for.body: ; preds = %for.cond
%urem = urem i32 %i, 2
%if.cond = icmp eq i32 %urem, 0
br i1 %if.cond, label %for.body.if, label %for.body.else
for.body.if: ; preds = %for.body
%cond1a = select i1 %cond, i32 %i, i32 42
br label %for.body.end
for.body.else: ; preds = %for.body
%cond1b = select i1 %cond, i32 24, i32 %i
br label %for.body.end
for.body.end: ; preds = %for.body.if, %for.body.else
%p = phi i32 [ %cond1a, %for.body.if ], [ %cond1b, %for.body.else ]
%add = add nuw nsw i32 %p, %res
%inc = add nuw nsw i32 %i, 1
br label %for.cond
for.cond.cleanup: ; preds = %for.cond
ret i32 %res
}
define dso_local void @select_nested_loop(i1 noundef zeroext %cond, i32 noundef %n, i32 noundef %m) {
; CHECK-LABEL: define dso_local void @select_nested_loop
; CHECK-SAME: (i1 noundef zeroext [[COND:%.*]], i32 noundef [[N:%.*]], i32 noundef [[M:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP17_NOT:%.*]] = icmp eq i32 [[N]], 0
; CHECK-NEXT: [[CMP215_NOT:%.*]] = icmp eq i32 [[M]], 0
; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[CMP17_NOT]], [[CMP215_NOT]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_COND1_PREHEADER_US_PREHEADER:%.*]]
; CHECK: for.cond1.preheader.us.preheader:
; CHECK-NEXT: br i1 [[COND]], label [[FOR_COND1_PREHEADER_US_PREHEADER_SPLIT_US:%.*]], label [[FOR_COND1_PREHEADER_US_PREHEADER_SPLIT:%.*]]
; CHECK: for.cond1.preheader.us.preheader.split.us:
; CHECK-NEXT: br label [[FOR_COND1_PREHEADER_US_US:%.*]]
; CHECK: for.cond1.preheader.us.us:
; CHECK-NEXT: [[I_018_US_US:%.*]] = phi i32 [ [[INC7_US_US:%.*]], [[FOR_COND1_FOR_COND_CLEANUP3_CRIT_EDGE_US_US:%.*]] ], [ 0, [[FOR_COND1_PREHEADER_US_PREHEADER_SPLIT_US]] ]
; CHECK-NEXT: br label [[FOR_COND1_PREHEADER_US_SPLIT_US_US:%.*]]
; CHECK: for.cond1.for.cond.cleanup3_crit_edge.us.us:
; CHECK-NEXT: [[INC7_US_US]] = add nuw i32 [[I_018_US_US]], 1
; CHECK-NEXT: [[EXITCOND21_NOT_US:%.*]] = icmp eq i32 [[INC7_US_US]], [[N]]
; CHECK-NEXT: br i1 [[EXITCOND21_NOT_US]], label [[FOR_COND_CLEANUP_LOOPEXIT_SPLIT_US:%.*]], label [[FOR_COND1_PREHEADER_US_US]]
; CHECK: for.cond1.preheader.us.split.us.us:
; CHECK-NEXT: br label [[FOR_BODY4_US_US_US:%.*]]
; CHECK: for.body4.us.us.us:
; CHECK-NEXT: [[J_016_US_US_US:%.*]] = phi i32 [ 0, [[FOR_COND1_PREHEADER_US_SPLIT_US_US]] ], [ [[INC_US_US_US:%.*]], [[TMP1:%.*]] ]
; CHECK-NEXT: br label [[TMP0:%.*]]
; CHECK: 0:
; CHECK-NEXT: br label [[TMP1]]
; CHECK: 1:
; CHECK-NEXT: [[UNSWITCHED_SELECT_US_US:%.*]] = phi i32 [ [[I_018_US_US]], [[TMP0]] ]
; CHECK-NEXT: tail call void @bar(i32 noundef [[UNSWITCHED_SELECT_US_US]])
; CHECK-NEXT: [[INC_US_US_US]] = add nuw i32 [[J_016_US_US_US]], 1
; CHECK-NEXT: [[EXITCOND_NOT_US_US:%.*]] = icmp eq i32 [[INC_US_US_US]], [[M]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT_US_US]], label [[FOR_COND1_FOR_COND_CLEANUP3_CRIT_EDGE_US_SPLIT_US_US:%.*]], label [[FOR_BODY4_US_US_US]]
; CHECK: for.cond1.for.cond.cleanup3_crit_edge.us.split.us.us:
; CHECK-NEXT: br label [[FOR_COND1_FOR_COND_CLEANUP3_CRIT_EDGE_US_US]]
; CHECK: for.cond.cleanup.loopexit.split.us:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]]
; CHECK: for.cond1.preheader.us.preheader.split:
; CHECK-NEXT: br label [[FOR_COND1_PREHEADER_US:%.*]]
; CHECK: for.cond1.preheader.us:
; CHECK-NEXT: [[I_018_US:%.*]] = phi i32 [ [[INC7_US:%.*]], [[FOR_COND1_FOR_COND_CLEANUP3_CRIT_EDGE_US:%.*]] ], [ 0, [[FOR_COND1_PREHEADER_US_PREHEADER_SPLIT]] ]
; CHECK-NEXT: br label [[FOR_COND1_PREHEADER_US_SPLIT:%.*]]
; CHECK: for.cond1.preheader.us.split:
; CHECK-NEXT: br label [[FOR_BODY4_US:%.*]]
; CHECK: for.body4.us:
; CHECK-NEXT: [[J_016_US:%.*]] = phi i32 [ 0, [[FOR_COND1_PREHEADER_US_SPLIT]] ], [ [[INC_US:%.*]], [[TMP2:%.*]] ]
; CHECK-NEXT: br label [[TMP2]]
; CHECK: 2:
; CHECK-NEXT: tail call void @bar(i32 noundef [[J_016_US]])
; CHECK-NEXT: [[INC_US]] = add nuw i32 [[J_016_US]], 1
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INC_US]], [[M]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND1_FOR_COND_CLEANUP3_CRIT_EDGE_US_SPLIT:%.*]], label [[FOR_BODY4_US]]
; CHECK: for.cond1.for.cond.cleanup3_crit_edge.us.split:
; CHECK-NEXT: br label [[FOR_COND1_FOR_COND_CLEANUP3_CRIT_EDGE_US]]
; CHECK: for.cond1.for.cond.cleanup3_crit_edge.us:
; CHECK-NEXT: [[INC7_US]] = add nuw i32 [[I_018_US]], 1
; CHECK-NEXT: [[EXITCOND21_NOT:%.*]] = icmp eq i32 [[INC7_US]], [[N]]
; CHECK-NEXT: br i1 [[EXITCOND21_NOT]], label [[FOR_COND_CLEANUP_LOOPEXIT_SPLIT:%.*]], label [[FOR_COND1_PREHEADER_US]]
; CHECK: for.cond.cleanup.loopexit.split:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT]]
; CHECK: for.cond.cleanup.loopexit:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: ret void
;
entry:
%cmp17.not = icmp eq i32 %n, 0
%cmp215.not = icmp eq i32 %m, 0
%or.cond = or i1 %cmp17.not, %cmp215.not
br i1 %or.cond, label %for.cond.cleanup, label %for.cond1.preheader.us
for.cond1.preheader.us: ; preds = %entry, %for.cond1.for.cond.cleanup3_crit_edge.us
%i.018.us = phi i32 [ %inc7.us, %for.cond1.for.cond.cleanup3_crit_edge.us ], [ 0, %entry ]
br label %for.body4.us
for.body4.us: ; preds = %for.cond1.preheader.us, %for.body4.us
%j.016.us = phi i32 [ 0, %for.cond1.preheader.us ], [ %inc.us, %for.body4.us ]
%cond5.us = select i1 %cond, i32 %i.018.us, i32 %j.016.us
tail call void @bar(i32 noundef %cond5.us) #2
%inc.us = add nuw i32 %j.016.us, 1
%exitcond.not = icmp eq i32 %inc.us, %m
br i1 %exitcond.not, label %for.cond1.for.cond.cleanup3_crit_edge.us, label %for.body4.us
for.cond1.for.cond.cleanup3_crit_edge.us: ; preds = %for.body4.us
%inc7.us = add nuw i32 %i.018.us, 1
%exitcond21.not = icmp eq i32 %inc7.us, %n
br i1 %exitcond21.not, label %for.cond.cleanup, label %for.cond1.preheader.us
for.cond.cleanup: ; preds = %for.cond1.for.cond.cleanup3_crit_edge.us, %entry
ret void
}
define dso_local void @select_invariant_outer_loop(i1 noundef zeroext %cond, i32 noundef %n, i32 noundef %m) {
; CHECK-LABEL: define dso_local void @select_invariant_outer_loop
; CHECK-SAME: (i1 noundef zeroext [[COND:%.*]], i32 noundef [[N:%.*]], i32 noundef [[M:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP20_NOT:%.*]] = icmp eq i32 [[N]], 0
; CHECK-NEXT: [[CMP218_NOT:%.*]] = icmp eq i32 [[M]], 0
; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[CMP20_NOT]], [[CMP218_NOT]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_COND1_PREHEADER_US_PREHEADER:%.*]]
; CHECK: for.cond1.preheader.us.preheader:
; CHECK-NEXT: br label [[FOR_COND1_PREHEADER_US:%.*]]
; CHECK: for.cond1.preheader.us:
; CHECK-NEXT: [[I_021_US:%.*]] = phi i32 [ [[INC9_US:%.*]], [[FOR_COND1_FOR_COND_CLEANUP3_CRIT_EDGE_US:%.*]] ], [ 0, [[FOR_COND1_PREHEADER_US_PREHEADER]] ]
; CHECK-NEXT: [[REM_US:%.*]] = and i32 [[I_021_US]], 1
; CHECK-NEXT: [[CMP5_US:%.*]] = icmp eq i32 [[REM_US]], 0
; CHECK-NEXT: [[CMP5_US_FR:%.*]] = freeze i1 [[CMP5_US]]
; CHECK-NEXT: br i1 [[CMP5_US_FR]], label [[FOR_COND1_PREHEADER_US_SPLIT_US:%.*]], label [[FOR_COND1_PREHEADER_US_SPLIT:%.*]]
; CHECK: for.cond1.preheader.us.split.us:
; CHECK-NEXT: br label [[FOR_BODY4_US_US:%.*]]
; CHECK: for.body4.us.us:
; CHECK-NEXT: [[J_019_US_US:%.*]] = phi i32 [ 0, [[FOR_COND1_PREHEADER_US_SPLIT_US]] ], [ [[INC_US_US:%.*]], [[TMP1:%.*]] ]
; CHECK-NEXT: br label [[TMP0:%.*]]
; CHECK: 0:
; CHECK-NEXT: br label [[TMP1]]
; CHECK: 1:
; CHECK-NEXT: [[UNSWITCHED_SELECT_US:%.*]] = phi i32 [ [[I_021_US]], [[TMP0]] ]
; CHECK-NEXT: tail call void @bar(i32 noundef [[UNSWITCHED_SELECT_US]])
; CHECK-NEXT: [[INC_US_US]] = add nuw i32 [[J_019_US_US]], 1
; CHECK-NEXT: [[EXITCOND_NOT_US:%.*]] = icmp eq i32 [[INC_US_US]], [[M]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT_US]], label [[FOR_COND1_FOR_COND_CLEANUP3_CRIT_EDGE_US_SPLIT_US:%.*]], label [[FOR_BODY4_US_US]]
; CHECK: for.cond1.for.cond.cleanup3_crit_edge.us.split.us:
; CHECK-NEXT: br label [[FOR_COND1_FOR_COND_CLEANUP3_CRIT_EDGE_US]]
; CHECK: for.cond1.preheader.us.split:
; CHECK-NEXT: br label [[FOR_BODY4_US:%.*]]
; CHECK: for.body4.us:
; CHECK-NEXT: [[J_019_US:%.*]] = phi i32 [ 0, [[FOR_COND1_PREHEADER_US_SPLIT]] ], [ [[INC_US:%.*]], [[TMP2:%.*]] ]
; CHECK-NEXT: br label [[TMP2]]
; CHECK: 2:
; CHECK-NEXT: tail call void @bar(i32 noundef [[J_019_US]])
; CHECK-NEXT: [[INC_US]] = add nuw i32 [[J_019_US]], 1
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INC_US]], [[M]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND1_FOR_COND_CLEANUP3_CRIT_EDGE_US_SPLIT:%.*]], label [[FOR_BODY4_US]]
; CHECK: for.cond1.for.cond.cleanup3_crit_edge.us.split:
; CHECK-NEXT: br label [[FOR_COND1_FOR_COND_CLEANUP3_CRIT_EDGE_US]]
; CHECK: for.cond1.for.cond.cleanup3_crit_edge.us:
; CHECK-NEXT: [[INC9_US]] = add nuw i32 [[I_021_US]], 1
; CHECK-NEXT: [[EXITCOND24_NOT:%.*]] = icmp eq i32 [[INC9_US]], [[N]]
; CHECK-NEXT: br i1 [[EXITCOND24_NOT]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_COND1_PREHEADER_US]]
; CHECK: for.cond.cleanup.loopexit:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: ret void
;
entry:
%cmp20.not = icmp eq i32 %n, 0
%cmp218.not = icmp eq i32 %m, 0
%or.cond = or i1 %cmp20.not, %cmp218.not
br i1 %or.cond, label %for.cond.cleanup, label %for.cond1.preheader.us
for.cond1.preheader.us: ; preds = %entry, %for.cond1.for.cond.cleanup3_crit_edge.us
%i.021.us = phi i32 [ %inc9.us, %for.cond1.for.cond.cleanup3_crit_edge.us ], [ 0, %entry ]
%rem.us = and i32 %i.021.us, 1
%cmp5.us = icmp eq i32 %rem.us, 0
br label %for.body4.us
for.body4.us: ; preds = %for.cond1.preheader.us, %for.body4.us
%j.019.us = phi i32 [ 0, %for.cond1.preheader.us ], [ %inc.us, %for.body4.us ]
%cond7.us = select i1 %cmp5.us, i32 %i.021.us, i32 %j.019.us
tail call void @bar(i32 noundef %cond7.us) #2
%inc.us = add nuw i32 %j.019.us, 1
%exitcond.not = icmp eq i32 %inc.us, %m
br i1 %exitcond.not, label %for.cond1.for.cond.cleanup3_crit_edge.us, label %for.body4.us
for.cond1.for.cond.cleanup3_crit_edge.us: ; preds = %for.body4.us
%inc9.us = add nuw i32 %i.021.us, 1
%exitcond24.not = icmp eq i32 %inc9.us, %n
br i1 %exitcond24.not, label %for.cond.cleanup, label %for.cond1.preheader.us
for.cond.cleanup: ; preds = %for.cond1.for.cond.cleanup3_crit_edge.us, %entry
ret void
}
; Unswitch %val should look through the trivial select and unswitch on %cond
define dso_local i32 @trivial_select_cond(i32 noundef %n, i32 noundef %a, i32 noundef %b, i1 noundef %cond) {
; CHECK-LABEL: define dso_local i32 @trivial_select_cond
; CHECK-SAME: (i32 noundef [[N:%.*]], i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], i1 noundef [[COND:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[N]], 0
; CHECK-NEXT: [[TRIVIAL_COND:%.*]] = select i1 [[COND]], i1 true, i1 false
; CHECK-NEXT: br i1 [[CMP2]], label [[FOR_BODY_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]]
; CHECK: for.body.preheader:
; CHECK-NEXT: br i1 [[COND]], label [[FOR_BODY_PREHEADER_SPLIT_US:%.*]], label [[FOR_BODY_PREHEADER_SPLIT:%.*]]
; CHECK: for.body.preheader.split.us:
; CHECK-NEXT: br label [[FOR_BODY_US:%.*]]
; CHECK: for.body.us:
; CHECK-NEXT: [[I_03_US:%.*]] = phi i32 [ [[INC_US:%.*]], [[TMP1:%.*]] ], [ 0, [[FOR_BODY_PREHEADER_SPLIT_US]] ]
; CHECK-NEXT: br label [[TMP0:%.*]]
; CHECK: 0:
; CHECK-NEXT: br label [[TMP1]]
; CHECK: 1:
; CHECK-NEXT: [[UNSWITCHED_SELECT_US:%.*]] = phi i32 [ [[A]], [[TMP0]] ]
; CHECK-NEXT: tail call void @bar(i32 noundef [[UNSWITCHED_SELECT_US]])
; CHECK-NEXT: [[INC_US]] = add nuw nsw i32 [[I_03_US]], 1
; CHECK-NEXT: [[EXITCOND_NOT_US:%.*]] = icmp eq i32 [[INC_US]], [[N]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT_US]], label [[FOR_COND_CLEANUP_LOOPEXIT_SPLIT_US:%.*]], label [[FOR_BODY_US]]
; CHECK: for.cond.cleanup.loopexit.split.us:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]]
; CHECK: for.body.preheader.split:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.cond.cleanup.loopexit.split:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT]]
; CHECK: for.cond.cleanup.loopexit:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: ret i32 undef
; CHECK: for.body:
; CHECK-NEXT: [[I_03:%.*]] = phi i32 [ [[INC:%.*]], [[TMP2:%.*]] ], [ 0, [[FOR_BODY_PREHEADER_SPLIT]] ]
; CHECK-NEXT: br label [[TMP2]]
; CHECK: 2:
; CHECK-NEXT: tail call void @bar(i32 noundef [[B]])
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_03]], 1
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INC]], [[N]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP_LOOPEXIT_SPLIT:%.*]], label [[FOR_BODY]]
;
entry:
%cmp2 = icmp sgt i32 %n, 0
%trivial_cond = select i1 %cond, i1 true, i1 false
br i1 %cmp2, label %for.body, label %for.cond.cleanup
for.cond.cleanup: ; preds = %for.body, %entry
ret i32 undef
for.body: ; preds = %entry, %for.body
%i.03 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
%val = select i1 %trivial_cond, i32 %a, i32 %b
tail call void @bar(i32 noundef %val)
%inc = add nuw nsw i32 %i.03, 1
%exitcond.not = icmp eq i32 %inc, %n
br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
}
; Test unswitch select when the condition is an AND whose LHS is invariant
define i32 @and_lhs_invariant(i32 %num, i1 %cond) {
; CHECK-LABEL: define i32 @and_lhs_invariant
; CHECK-SAME: (i32 [[NUM:%.*]], i1 [[COND:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[NUM]], 0
; CHECK-NEXT: br i1 [[CMP6]], label [[FOR_BODY_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]]
; CHECK: for.body.preheader:
; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND]]
; CHECK-NEXT: br i1 [[COND_FR]], label [[FOR_BODY_PREHEADER_SPLIT:%.*]], label [[FOR_BODY_PREHEADER_SPLIT_US:%.*]]
; CHECK: for.body.preheader.split.us:
; CHECK-NEXT: br label [[FOR_BODY_US:%.*]]
; CHECK: for.body.us:
; CHECK-NEXT: [[I_07_US:%.*]] = phi i32 [ [[INC_US:%.*]], [[TMP0:%.*]] ], [ 0, [[FOR_BODY_PREHEADER_SPLIT_US]] ]
; CHECK-NEXT: br label [[TMP0]]
; CHECK: 0:
; CHECK-NEXT: [[UNSWITCHED_SELECT_US:%.*]] = phi i32 [ 0, [[FOR_BODY_US]] ]
; CHECK-NEXT: tail call void @bar(i32 noundef [[UNSWITCHED_SELECT_US]])
; CHECK-NEXT: [[INC_US]] = add nuw nsw i32 [[I_07_US]], 1
; CHECK-NEXT: [[EXITCOND_NOT_US:%.*]] = icmp eq i32 [[INC_US]], [[NUM]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT_US]], label [[FOR_COND_CLEANUP_LOOPEXIT_SPLIT_US:%.*]], label [[FOR_BODY_US]]
; CHECK: for.cond.cleanup.loopexit.split.us:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]]
; CHECK: for.body.preheader.split:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.cond.cleanup.loopexit.split:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT]]
; CHECK: for.cond.cleanup.loopexit:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: ret i32 undef
; CHECK: for.body:
; CHECK-NEXT: [[I_07:%.*]] = phi i32 [ [[INC:%.*]], [[TMP3:%.*]] ], [ 0, [[FOR_BODY_PREHEADER_SPLIT]] ]
; CHECK-NEXT: [[REM:%.*]] = and i32 [[I_07]], 1
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[REM]], 0
; CHECK-NEXT: [[TMP1:%.*]] = and i1 true, [[CMP1]]
; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3]]
; CHECK: 2:
; CHECK-NEXT: br label [[TMP3]]
; CHECK: 3:
; CHECK-NEXT: [[UNSWITCHED_SELECT:%.*]] = phi i32 [ [[I_07]], [[TMP2]] ], [ 0, [[FOR_BODY]] ]
; CHECK-NEXT: tail call void @bar(i32 noundef [[UNSWITCHED_SELECT]])
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_07]], 1
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INC]], [[NUM]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP_LOOPEXIT_SPLIT:%.*]], label [[FOR_BODY]]
;
entry:
%cmp6 = icmp sgt i32 %num, 0
br i1 %cmp6, label %for.body, label %for.cond.cleanup
for.cond.cleanup: ; preds = %for.body, %entry
ret i32 undef
for.body: ; preds = %entry, %for.body
%i.07 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
%rem = and i32 %i.07, 1
%cmp1 = icmp eq i32 %rem, 0
%0 = and i1 %cond, %cmp1
%cond2 = select i1 %0, i32 %i.07, i32 0
tail call void @bar(i32 noundef %cond2)
%inc = add nuw nsw i32 %i.07, 1
%exitcond.not = icmp eq i32 %inc, %num
br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
}
; Test unswitch select when the condition is an AND whose RHS is invariant
define i32 @and_rhs_invariant(i32 %num, i1 %cond) {
; CHECK-LABEL: define i32 @and_rhs_invariant
; CHECK-SAME: (i32 [[NUM:%.*]], i1 [[COND:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[NUM]], 0
; CHECK-NEXT: br i1 [[CMP6]], label [[FOR_BODY_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]]
; CHECK: for.body.preheader:
; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND]]
; CHECK-NEXT: br i1 [[COND_FR]], label [[FOR_BODY_PREHEADER_SPLIT:%.*]], label [[FOR_BODY_PREHEADER_SPLIT_US:%.*]]
; CHECK: for.body.preheader.split.us:
; CHECK-NEXT: br label [[FOR_BODY_US:%.*]]
; CHECK: for.body.us:
; CHECK-NEXT: [[I_07_US:%.*]] = phi i32 [ [[INC_US:%.*]], [[TMP0:%.*]] ], [ 0, [[FOR_BODY_PREHEADER_SPLIT_US]] ]
; CHECK-NEXT: br label [[TMP0]]
; CHECK: 0:
; CHECK-NEXT: [[UNSWITCHED_SELECT_US:%.*]] = phi i32 [ 0, [[FOR_BODY_US]] ]
; CHECK-NEXT: tail call void @bar(i32 noundef [[UNSWITCHED_SELECT_US]])
; CHECK-NEXT: [[INC_US]] = add nuw nsw i32 [[I_07_US]], 1
; CHECK-NEXT: [[EXITCOND_NOT_US:%.*]] = icmp eq i32 [[INC_US]], [[NUM]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT_US]], label [[FOR_COND_CLEANUP_LOOPEXIT_SPLIT_US:%.*]], label [[FOR_BODY_US]]
; CHECK: for.cond.cleanup.loopexit.split.us:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]]
; CHECK: for.body.preheader.split:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.cond.cleanup.loopexit.split:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT]]
; CHECK: for.cond.cleanup.loopexit:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: ret i32 undef
; CHECK: for.body:
; CHECK-NEXT: [[I_07:%.*]] = phi i32 [ [[INC:%.*]], [[TMP3:%.*]] ], [ 0, [[FOR_BODY_PREHEADER_SPLIT]] ]
; CHECK-NEXT: [[REM:%.*]] = and i32 [[I_07]], 1
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[REM]], 0
; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[CMP1]], true
; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3]]
; CHECK: 2:
; CHECK-NEXT: br label [[TMP3]]
; CHECK: 3:
; CHECK-NEXT: [[UNSWITCHED_SELECT:%.*]] = phi i32 [ [[I_07]], [[TMP2]] ], [ 0, [[FOR_BODY]] ]
; CHECK-NEXT: tail call void @bar(i32 noundef [[UNSWITCHED_SELECT]])
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_07]], 1
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INC]], [[NUM]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP_LOOPEXIT_SPLIT:%.*]], label [[FOR_BODY]]
;
entry:
%cmp6 = icmp sgt i32 %num, 0
br i1 %cmp6, label %for.body, label %for.cond.cleanup
for.cond.cleanup: ; preds = %for.body, %entry
ret i32 undef
for.body: ; preds = %entry, %for.body
%i.07 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
%rem = and i32 %i.07, 1
%cmp1 = icmp eq i32 %rem, 0
%0 = and i1 %cmp1, %cond
%cond2 = select i1 %0, i32 %i.07, i32 0
tail call void @bar(i32 noundef %cond2)
%inc = add nuw nsw i32 %i.07, 1
%exitcond.not = icmp eq i32 %inc, %num
br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
}
; Test unswitch select when the condition is an OR whose LHS is invariant
define i32 @or_lhs_invariant(i32 %num, i1 %cond) {
; CHECK-LABEL: define i32 @or_lhs_invariant
; CHECK-SAME: (i32 [[NUM:%.*]], i1 [[COND:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[NUM]], 0
; CHECK-NEXT: br i1 [[CMP6]], label [[FOR_BODY_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]]
; CHECK: for.body.preheader:
; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND]]
; CHECK-NEXT: br i1 [[COND_FR]], label [[FOR_BODY_PREHEADER_SPLIT_US:%.*]], label [[FOR_BODY_PREHEADER_SPLIT:%.*]]
; CHECK: for.body.preheader.split.us:
; CHECK-NEXT: br label [[FOR_BODY_US:%.*]]
; CHECK: for.body.us:
; CHECK-NEXT: [[I_07_US:%.*]] = phi i32 [ [[INC_US:%.*]], [[TMP1:%.*]] ], [ 0, [[FOR_BODY_PREHEADER_SPLIT_US]] ]
; CHECK-NEXT: br label [[TMP0:%.*]]
; CHECK: 0:
; CHECK-NEXT: br label [[TMP1]]
; CHECK: 1:
; CHECK-NEXT: [[UNSWITCHED_SELECT_US:%.*]] = phi i32 [ [[I_07_US]], [[TMP0]] ]
; CHECK-NEXT: tail call void @bar(i32 noundef [[UNSWITCHED_SELECT_US]])
; CHECK-NEXT: [[INC_US]] = add nuw nsw i32 [[I_07_US]], 1
; CHECK-NEXT: [[EXITCOND_NOT_US:%.*]] = icmp eq i32 [[INC_US]], [[NUM]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT_US]], label [[FOR_COND_CLEANUP_LOOPEXIT_SPLIT_US:%.*]], label [[FOR_BODY_US]]
; CHECK: for.cond.cleanup.loopexit.split.us:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]]
; CHECK: for.body.preheader.split:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.cond.cleanup.loopexit.split:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT]]
; CHECK: for.cond.cleanup.loopexit:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: ret i32 undef
; CHECK: for.body:
; CHECK-NEXT: [[I_07:%.*]] = phi i32 [ [[INC:%.*]], [[TMP4:%.*]] ], [ 0, [[FOR_BODY_PREHEADER_SPLIT]] ]
; CHECK-NEXT: [[REM:%.*]] = and i32 [[I_07]], 1
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[REM]], 0
; CHECK-NEXT: [[TMP2:%.*]] = or i1 false, [[CMP1]]
; CHECK-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP4]]
; CHECK: 3:
; CHECK-NEXT: br label [[TMP4]]
; CHECK: 4:
; CHECK-NEXT: [[UNSWITCHED_SELECT:%.*]] = phi i32 [ [[I_07]], [[TMP3]] ], [ 0, [[FOR_BODY]] ]
; CHECK-NEXT: tail call void @bar(i32 noundef [[UNSWITCHED_SELECT]])
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_07]], 1
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INC]], [[NUM]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP_LOOPEXIT_SPLIT:%.*]], label [[FOR_BODY]]
;
entry:
%cmp6 = icmp sgt i32 %num, 0
br i1 %cmp6, label %for.body, label %for.cond.cleanup
for.cond.cleanup: ; preds = %for.body, %entry
ret i32 undef
for.body: ; preds = %entry, %for.body
%i.07 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
%rem = and i32 %i.07, 1
%cmp1 = icmp eq i32 %rem, 0
%0 = or i1 %cond, %cmp1
%cond2 = select i1 %0, i32 %i.07, i32 0
tail call void @bar(i32 noundef %cond2)
%inc = add nuw nsw i32 %i.07, 1
%exitcond.not = icmp eq i32 %inc, %num
br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
}
; Test unswitch select when the condition is an OR whose RHS is invariant
define i32 @or_rhs_invariant(i32 %num, i1 %cond) {
; CHECK-LABEL: define i32 @or_rhs_invariant
; CHECK-SAME: (i32 [[NUM:%.*]], i1 [[COND:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[NUM]], 0
; CHECK-NEXT: br i1 [[CMP6]], label [[FOR_BODY_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]]
; CHECK: for.body.preheader:
; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND]]
; CHECK-NEXT: br i1 [[COND_FR]], label [[FOR_BODY_PREHEADER_SPLIT_US:%.*]], label [[FOR_BODY_PREHEADER_SPLIT:%.*]]
; CHECK: for.body.preheader.split.us:
; CHECK-NEXT: br label [[FOR_BODY_US:%.*]]
; CHECK: for.body.us:
; CHECK-NEXT: [[I_07_US:%.*]] = phi i32 [ [[INC_US:%.*]], [[TMP1:%.*]] ], [ 0, [[FOR_BODY_PREHEADER_SPLIT_US]] ]
; CHECK-NEXT: br label [[TMP0:%.*]]
; CHECK: 0:
; CHECK-NEXT: br label [[TMP1]]
; CHECK: 1:
; CHECK-NEXT: [[UNSWITCHED_SELECT_US:%.*]] = phi i32 [ [[I_07_US]], [[TMP0]] ]
; CHECK-NEXT: tail call void @bar(i32 noundef [[UNSWITCHED_SELECT_US]])
; CHECK-NEXT: [[INC_US]] = add nuw nsw i32 [[I_07_US]], 1
; CHECK-NEXT: [[EXITCOND_NOT_US:%.*]] = icmp eq i32 [[INC_US]], [[NUM]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT_US]], label [[FOR_COND_CLEANUP_LOOPEXIT_SPLIT_US:%.*]], label [[FOR_BODY_US]]
; CHECK: for.cond.cleanup.loopexit.split.us:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]]
; CHECK: for.body.preheader.split:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.cond.cleanup.loopexit.split:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT]]
; CHECK: for.cond.cleanup.loopexit:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: ret i32 undef
; CHECK: for.body:
; CHECK-NEXT: [[I_07:%.*]] = phi i32 [ [[INC:%.*]], [[TMP4:%.*]] ], [ 0, [[FOR_BODY_PREHEADER_SPLIT]] ]
; CHECK-NEXT: [[REM:%.*]] = and i32 [[I_07]], 1
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[REM]], 0
; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[CMP1]], false
; CHECK-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP4]]
; CHECK: 3:
; CHECK-NEXT: br label [[TMP4]]
; CHECK: 4:
; CHECK-NEXT: [[UNSWITCHED_SELECT:%.*]] = phi i32 [ [[I_07]], [[TMP3]] ], [ 0, [[FOR_BODY]] ]
; CHECK-NEXT: tail call void @bar(i32 noundef [[UNSWITCHED_SELECT]])
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_07]], 1
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INC]], [[NUM]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP_LOOPEXIT_SPLIT:%.*]], label [[FOR_BODY]]
;
entry:
%cmp6 = icmp sgt i32 %num, 0
br i1 %cmp6, label %for.body, label %for.cond.cleanup
for.cond.cleanup: ; preds = %for.body, %entry
ret i32 undef
for.body: ; preds = %entry, %for.body
%i.07 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
%rem = and i32 %i.07, 1
%cmp1 = icmp eq i32 %rem, 0
%0 = or i1 %cmp1, %cond
%cond2 = select i1 %0, i32 %i.07, i32 0
tail call void @bar(i32 noundef %cond2)
%inc = add nuw nsw i32 %i.07, 1
%exitcond.not = icmp eq i32 %inc, %num
br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
}