
When updating the branch instruction outside the loopduring non-trivial unswitching, always skip trivial selects and update the condition. Otherwise we might create invalid IR, because the trivial select is inside the loop, while the condition is outside the loop. Fixes #55697.
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
|
|
}
|