llvm-project/llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch-trivial-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

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
}