Files
clang-p2996/llvm/test/Transforms/DFAJumpThreading/negative.ll
Alex Zhikhartsev 8b0d763474 [DFAJumpThreading] Relax analysis to handle unpredictable initial values
Responding to a feature request from the Rust community:

https://github.com/rust-lang/rust/issues/80630

    void foo(X) {
      for (...)
	switch (X)
	  case A
	    X = B
	  case B
	    X = C
    }

Even though the initial switch value is non-constant, the switch
statement can still be threaded: the initial value will hit the switch
statement but the rest of the state changes will proceed by jumping
unconditionally.

The early predictability check is relaxed to allow unpredictable values
anywhere, but later, after the paths through the switch statement have
been enumerated, no non-constant state values are allowed along the
paths. Any state value not along a path will be an initial switch value,
which can be safely ignored.

Differential Revision: https://reviews.llvm.org/D124394
2022-05-26 11:29:54 -04:00

266 lines
6.4 KiB
LLVM

; RUN: opt -dfa-jump-threading -dfa-cost-threshold=25 -pass-remarks-missed='dfa-jump-threading' -pass-remarks-output=%t -disable-output %s
; RUN: FileCheck --input-file %t --check-prefix=REMARK %s
; RUN: opt -S -dfa-jump-threading %s | FileCheck %s
; This negative test case checks that the optimization doesn't trigger
; when the code size cost is too high.
define i32 @negative1(i32 %num) {
; REMARK: NotProfitable
; REMARK-NEXT: negative1
entry:
br label %for.body
for.body:
%count = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
%state = phi i32 [ 1, %entry ], [ %state.next, %for.inc ]
switch i32 %state, label %for.inc [
i32 1, label %case1
i32 2, label %case2
]
case1:
br label %for.inc
case2:
%cmp = icmp eq i32 %count, 50
%sel = select i1 %cmp, i32 1, i32 2
br label %for.inc
for.inc:
%state.next = phi i32 [ %sel, %case2 ], [ 1, %for.body ], [ 2, %case1 ]
%add1 = add i32 %num, %num
%add2 = add i32 %add1, %add1
%add3 = add i32 %add2, %add2
%add4 = add i32 %add3, %add3
%add5 = add i32 %add4, %add4
%add6 = add i32 %add5, %add5
%add7 = add i32 %add6, %add6
%add8 = add i32 %add7, %add7
%add9 = add i32 %add8, %add8
%add10 = add i32 %add9, %add9
%add11 = add i32 %add10, %add10
%add12 = add i32 %add11, %add11
%add13 = add i32 %add12, %add12
%add14 = add i32 %add13, %add13
%add15 = add i32 %add14, %add14
%add16 = add i32 %add15, %add15
%add17 = add i32 %add16, %add16
%add18 = add i32 %add17, %add17
%add19 = add i32 %add18, %add18
%add20 = add i32 %add19, %add19
%add21 = add i32 %add20, %add20
%add22 = add i32 %add21, %add21
%inc = add nsw i32 %count, 1
%cmp.exit = icmp slt i32 %inc, %num
br i1 %cmp.exit, label %for.body, label %for.end
for.end:
ret i32 %add22
}
declare void @func()
define i32 @negative2(i32 %num) {
; REMARK: NonDuplicatableInst
; REMARK-NEXT: negative2
entry:
br label %for.body
for.body:
%count = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
%state = phi i32 [ 1, %entry ], [ %state.next, %for.inc ]
switch i32 %state, label %for.inc [
i32 1, label %case1
i32 2, label %case2
]
case1:
br label %for.inc
case2:
%cmp = icmp eq i32 %count, 50
%sel = select i1 %cmp, i32 1, i32 2
br label %for.inc
for.inc:
%state.next = phi i32 [ %sel, %case2 ], [ 1, %for.body ], [ 2, %case1 ]
call void @func() noduplicate
%inc = add nsw i32 %count, 1
%cmp.exit = icmp slt i32 %inc, %num
br i1 %cmp.exit, label %for.body, label %for.end
for.end:
ret i32 0
}
define i32 @negative3(i32 %num) {
; REMARK: ConvergentInst
; REMARK-NEXT: negative3
entry:
br label %for.body
for.body:
%count = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
%state = phi i32 [ 1, %entry ], [ %state.next, %for.inc ]
switch i32 %state, label %for.inc [
i32 1, label %case1
i32 2, label %case2
]
case1:
br label %for.inc
case2:
%cmp = icmp eq i32 %count, 50
%sel = select i1 %cmp, i32 1, i32 2
br label %for.inc
for.inc:
%state.next = phi i32 [ %sel, %case2 ], [ 1, %for.body ], [ 2, %case1 ]
call void @func() convergent
%inc = add nsw i32 %count, 1
%cmp.exit = icmp slt i32 %inc, %num
br i1 %cmp.exit, label %for.body, label %for.end
for.end:
ret i32 0
}
define i32 @negative4(i32 %num) {
; REMARK: SwitchNotPredictable
; REMARK-NEXT: negative4
entry:
br label %for.body
for.body:
%count = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
%state = phi i32 [ 1, %entry ], [ %state.next, %for.inc ]
switch i32 %state, label %for.inc [
i32 1, label %case1
i32 2, label %case2
]
case1:
br label %for.inc
case2:
%cmp = icmp eq i32 %count, 50
%sel = select i1 %cmp, i32 1, i32 2
br label %for.inc
for.inc:
; the switch variable is not predictable since the exit value for %case1
; is defined through a non-instruction (function argument).
%state.next = phi i32 [ %sel, %case2 ], [ 1, %for.body ], [ %num, %case1 ]
%inc = add nsw i32 %count, 1
%cmp.exit = icmp slt i32 %inc, %num
br i1 %cmp.exit, label %for.body, label %for.end
for.end:
ret i32 0
}
; Do not optimize if marked minsize.
define i32 @negative5(i32 %num) minsize {
; CHECK-LABEL: @negative5(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[COUNT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: [[STATE:%.*]] = phi i32 [ 1, [[ENTRY]] ], [ [[STATE_NEXT:%.*]], [[FOR_INC]] ]
; CHECK-NEXT: switch i32 [[STATE]], label [[FOR_INC]] [
; CHECK-NEXT: i32 1, label [[CASE1:%.*]]
; CHECK-NEXT: i32 2, label [[CASE2:%.*]]
; CHECK-NEXT: ]
; CHECK: case1:
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: case2:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[COUNT]], 50
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 1, i32 2
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[STATE_NEXT]] = phi i32 [ [[SEL]], [[CASE2]] ], [ 1, [[FOR_BODY]] ], [ 2, [[CASE1]] ]
; CHECK-NEXT: [[INC]] = add nsw i32 [[COUNT]], 1
; CHECK-NEXT: [[CMP_EXIT:%.*]] = icmp slt i32 [[INC]], [[NUM:%.*]]
; CHECK-NEXT: br i1 [[CMP_EXIT]], label [[FOR_BODY]], label [[FOR_END:%.*]]
; CHECK: for.end:
; CHECK-NEXT: ret i32 0
;
entry:
br label %for.body
for.body:
%count = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
%state = phi i32 [ 1, %entry ], [ %state.next, %for.inc ]
switch i32 %state, label %for.inc [
i32 1, label %case1
i32 2, label %case2
]
case1:
br label %for.inc
case2:
%cmp = icmp eq i32 %count, 50
%sel = select i1 %cmp, i32 1, i32 2
br label %for.inc
for.inc:
%state.next = phi i32 [ %sel, %case2 ], [ 1, %for.body ], [ 2, %case1 ]
%inc = add nsw i32 %count, 1
%cmp.exit = icmp slt i32 %inc, %num
br i1 %cmp.exit, label %for.body, label %for.end
for.end:
ret i32 0
}
declare i32 @arbitrary_function()
; Don't confuse %state.2 for the initial switch value.
define i32 @negative6(i32 %init) {
; REMARK: SwitchNotPredictable
; REMARK-NEXT: negative6
entry:
%cmp = icmp eq i32 %init, 0
br label %loop.2
loop.2:
%state.2 = call i32 @arbitrary_function()
br label %loop.3
loop.3:
%state = phi i32 [ %state.2, %loop.2 ], [ 3, %case2 ]
switch i32 %state, label %infloop.i [
i32 2, label %case2
i32 3, label %case3
i32 4, label %case4
i32 0, label %case0
i32 1, label %case1
]
case2:
br label %loop.3
case3:
br i1 %cmp, label %loop.2.backedge, label %case4
case4:
br label %loop.2.backedge
loop.2.backedge:
br label %loop.2
case0:
br label %exit
case1:
br label %exit
infloop.i:
br label %infloop.i
exit:
ret i32 0
}