
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
120 lines
3.4 KiB
LLVM
120 lines
3.4 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt -passes='simple-loop-unswitch<nontrivial>' -S < %s | FileCheck %s
|
|
|
|
; If we try to replace uses of `true` outside of `@foo`, we'll see it here.
|
|
define i1 @bar() {
|
|
; CHECK-LABEL: @bar(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
ret i1 true
|
|
}
|
|
|
|
; We shouldn't unswitch this loop.
|
|
define void @foo() {
|
|
; CHECK-LABEL: @foo(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[HEADER:%.*]]
|
|
; CHECK: header:
|
|
; CHECK-NEXT: [[VAL:%.*]] = select i1 true, i1 true, i1 false
|
|
; CHECK-NEXT: br i1 [[VAL]], label [[EXIT:%.*]], label [[HEADER]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %header
|
|
|
|
header:
|
|
%val = select i1 true, i1 true, i1 false
|
|
br i1 %val, label %exit, label %header
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @unswitch_trivial_select(i1 %c.1, i1 %c.2, i8 %a) {
|
|
; CHECK-LABEL: @unswitch_trivial_select(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[C_1:%.*]], label [[PH_1:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: ph.1:
|
|
; CHECK-NEXT: br i1 [[C_2:%.*]], label [[PH_2:%.*]], label [[EXIT]]
|
|
; CHECK: ph.2:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[A:%.*]], 30
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i1 true, i1 false
|
|
; CHECK-NEXT: [[CMP_FR:%.*]] = freeze i1 [[CMP]]
|
|
; CHECK-NEXT: br i1 [[CMP_FR]], label [[PH_2_SPLIT_US:%.*]], label [[PH_2_SPLIT:%.*]]
|
|
; CHECK: ph.2.split.us:
|
|
; CHECK-NEXT: br label [[LOOP_US:%.*]]
|
|
; CHECK: loop.us:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[EXIT_LOOPEXIT_SPLIT_US:%.*]]
|
|
; CHECK: exit.loopexit.split.us:
|
|
; CHECK-NEXT: br label [[EXIT_LOOPEXIT:%.*]]
|
|
; CHECK: ph.2.split:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[LOOP_LATCH:%.*]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: br label [[LOOP]]
|
|
; CHECK: exit.loopexit:
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br i1 %c.1, label %ph.1, label %exit
|
|
|
|
ph.1:
|
|
br i1 %c.2, label %ph.2, label %exit
|
|
|
|
ph.2:
|
|
%cmp = icmp eq i8 %a, 30
|
|
%sel = select i1 %cmp, i1 true, i1 false
|
|
br label %loop
|
|
|
|
loop:
|
|
call void @foo()
|
|
br i1 %sel, label %exit, label %loop.latch
|
|
|
|
loop.latch:
|
|
br label %loop
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Test case for PR55697.
|
|
define i32 @unswitch_trivial_select_cmp_outside(i32 %x) {
|
|
; CHECK-LABEL: @unswitch_trivial_select_cmp_outside(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[X:%.*]], 100
|
|
; CHECK-NEXT: br i1 [[C]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
|
|
; CHECK: entry.split.us:
|
|
; CHECK-NEXT: br label [[LOOP_US:%.*]]
|
|
; CHECK: loop.us:
|
|
; CHECK-NEXT: [[P_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ 35, [[LOOP_US]] ]
|
|
; CHECK-NEXT: br label [[LOOP_US]]
|
|
; CHECK: entry.split:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[P:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ]
|
|
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 false, i1 true, i1 false
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[LCSSA:%.*]] = phi i32 [ [[P]], [[LOOP]] ]
|
|
; CHECK-NEXT: ret i32 [[LCSSA]]
|
|
;
|
|
entry:
|
|
%c = icmp ult i32 %x, 100
|
|
br label %loop
|
|
|
|
loop:
|
|
%p = phi i32 [ 0, %entry ], [ 35, %loop ]
|
|
%spec.select = select i1 %c, i1 true, i1 false
|
|
br i1 %spec.select, label %loop, label %exit
|
|
|
|
exit:
|
|
%lcssa = phi i32 [ %p, %loop ]
|
|
ret i32 %lcssa
|
|
}
|