Files
clang-p2996/llvm/test/Transforms/LoopUnswitch/partial-unswitch-cost.ll
Florian Hahn b8c81fa5c7 [LoopUnswitch] Add shortcut if unswitched path is a no-op.
If we determine that the invariant path through the loop has no effects,
we can directly branch to the exit block, instead to unswitching first.

Besides avoiding some extra work (unswitching first, then deleting the
loop again) this allows to be more aggressive than regular unswitching
with respect to cost-modeling. This approach should always be be
desirable.

This is similar in spirit to D93734, just that it uses the previously
added checks for loop-unswitching.

I tried to add the required no-op checks from scratch, as we only check
a subset of the loop. There is potential to unify the checks with
LoopDeletion, at the cost of adding a predicate whether a block should
be considered.

Reviewed By: jdoerfert

Differential Revision: https://reviews.llvm.org/D95468
2021-02-01 09:03:30 +00:00

427 lines
9.9 KiB
LLVM

; RUN: opt -loop-unswitch -loop-unswitch-threshold=10 -verify-dom-info -verify-memoryssa -S -enable-new-pm=0 %s | FileCheck %s
declare void @clobber()
; Test cases for partial unswitching, where the regular cost-model overestimates
; the cost of unswitching, because it misses the fact that the unswitched paths
; are no-ops.
define i32 @no_partial_unswitch_size_too_large_no_mustprogress(i32* %ptr, i32 %N) {
; CHECK-LABEL: @no_partial_unswitch_size_too_large_no_mustprogress
; CHECK-LABEL: entry:
; CHECK-NEXT: br label %loop.header
;
entry:
br label %loop.header
loop.header:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
%lv = load i32, i32* %ptr
%sc = icmp eq i32 %lv, 100
br i1 %sc, label %noclobber, label %clobber
noclobber:
br label %loop.latch
clobber:
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
br label %loop.latch
loop.latch:
%c = icmp ult i32 %iv, %N
%iv.next = add i32 %iv, 1
br i1 %c, label %loop.header, label %exit
exit:
ret i32 10
}
define i32 @partial_unswitch_shortcut_mustprogress(i32* %ptr, i32 %N) mustprogress {
; CHECK-LABEL: @partial_unswitch_shortcut_mustprogress
; CHECK-LABEL: entry:
; CHECK-NEXT: [[LV:%[0-9]+]] = load i32, i32* %ptr, align 4
; CHECK-NEXT: [[C:%[0-9]+]] = icmp eq i32 [[LV]], 100
; CHECK-NEXT: br i1 [[C]], label %[[CRIT_TO_EXIT:[a-z._]+]], label %[[CRIT_TO_HEADER:[a-z._]+]]
;
; CHECK: [[CRIT_TO_HEADER]]:
; CHECK-NEXT: br label %loop.header
;
; CHECK: [[CRIT_TO_EXIT]]:
; CHECK-NEXT: br label %exit
;
entry:
br label %loop.header
loop.header:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
%lv = load i32, i32* %ptr
%sc = icmp eq i32 %lv, 100
br i1 %sc, label %noclobber, label %clobber
noclobber:
br label %loop.latch
clobber:
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
br label %loop.latch
loop.latch:
%c = icmp ult i32 %iv, %N
%iv.next = add i32 %iv, 1
br i1 %c, label %loop.header, label %exit
exit:
ret i32 10
}
define i32 @partial_unswitch_shortcut_mustprogress_single_exit_on_path(i32* %ptr, i32 %N) mustprogress {
; CHECK-LABEL: @partial_unswitch_shortcut_mustprogress_single_exit_on_path
; CHECK-LABEL: entry:
; CHECK-NEXT: [[LV:%[0-9]+]] = load i32, i32* %ptr, align 4
; CHECK-NEXT: [[C:%[0-9]+]] = icmp eq i32 [[LV]], 100
; CHECK-NEXT: br i1 [[C]], label %[[CRIT_TO_EXIT:.+]], label %[[CRIT_TO_HEADER:[a-z._]+]]
;
; CHECK: [[CRIT_TO_HEADER]]:
; CHECK-NEXT: br label %loop.header
;
; CHECK: [[CRIT_TO_EXIT]]:
; CHECK-NEXT: br label %exit
;
entry:
br label %loop.header
loop.header:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
%lv = load i32, i32* %ptr
%sc = icmp eq i32 %lv, 100
br i1 %sc, label %noclobber, label %clobber
noclobber:
%c.1 = icmp ult i32 %iv, 123
br i1 %c.1, label %loop.latch, label %exit.1
clobber:
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
%c = icmp ult i32 %iv, %N
br i1 %c, label %loop.latch, label %exit.2
loop.latch:
%iv.next = add i32 %iv, 1
br label %loop.header
exit.1:
ret i32 10
exit.2:
ret i32 10
}
define i32 @no_partial_unswitch_shortcut_mustprogress_no_exit_on_path(i32* %ptr, i32 %N) mustprogress {
; CHECK-LABEL: @no_partial_unswitch_shortcut_mustprogress_no_exit_on_path
; CHECK-LABEL: entry:
; CHECK-NEXT: br label %loop.header
;
entry:
br label %loop.header
loop.header:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
%lv = load i32, i32* %ptr
%sc = icmp eq i32 %lv, 100
br i1 %sc, label %noclobber, label %clobber
noclobber:
br label %loop.latch
clobber:
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
%c = icmp ult i32 %iv, %N
br i1 %c, label %loop.latch, label %exit
loop.latch:
%iv.next = add i32 %iv, 1
br label %loop.header
exit:
ret i32 10
}
define i32 @no_partial_unswitch_shortcut_mustprogress_exit_value_used(i32* %ptr, i32 %N) mustprogress {
; CHECK-LABEL: @no_partial_unswitch_shortcut_mustprogress_exit_value_use
; CHECK-LABEL: entry:
; CHECK-NEXT: br label %loop.header
;
entry:
br label %loop.header
loop.header:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
%red = phi i32 [ 0, %entry ], [ %red.next, %loop.latch ]
%lv = load i32, i32* %ptr
%sc = icmp eq i32 %lv, 100
br i1 %sc, label %noclobber, label %clobber
noclobber:
%red.add = add i32 %red, %lv
br label %loop.latch
clobber:
%red.mul = mul i32 %red, %lv
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
br label %loop.latch
loop.latch:
%red.next = phi i32 [ %red.add, %noclobber ], [ %red.mul, %clobber ]
%c = icmp ult i32 %iv, %N
%iv.next = add i32 %iv, 1
br i1 %c, label %loop.header, label %exit
exit:
ret i32 %red.next
}
define i32 @partial_unswitch_shortcut_multiple_exiting_blocks(i32* %ptr, i32 %N, i1 %ec.1) mustprogress {
; CHECK-LABEL: @partial_unswitch_shortcut_multiple_exiting_blocks
; CHECK-LABEL: entry:
; CHECK-NEXT: [[LV:%[0-9]+]] = load i32, i32* %ptr, align 4
; CHECK-NEXT: [[C:%[0-9]+]] = icmp eq i32 [[LV]], 100
; CHECK-NEXT: br i1 [[C]], label %[[CRIT_TO_EXIT:.+]], label %[[CRIT_TO_HEADER:[a-z._]+]]
;
; CHECK: [[CRIT_TO_HEADER]]:
; CHECK-NEXT: br label %loop.header
;
; CHECK: [[CRIT_TO_EXIT]]:
; CHECK-NEXT: br label %exit
;
entry:
br label %loop.header
loop.header:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
%lv = load i32, i32* %ptr
%sc = icmp eq i32 %lv, 100
br i1 %sc, label %noclobber, label %clobber
noclobber:
br i1 %ec.1, label %loop.latch, label %exit
clobber:
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
br label %loop.latch
loop.latch:
%c = icmp ult i32 %iv, %N
%iv.next = add i32 %iv, 1
br i1 %c, label %loop.header, label %exit
exit:
ret i32 10
}
define i32 @no_partial_unswitch_shortcut_multiple_exit_blocks(i32* %ptr, i32 %N, i1 %ec.1) mustprogress {
; CHECK-LABEL: @no_partial_unswitch_shortcut_multiple_exit_blocks
; CHECK-LABEL: entry:
; CHECK-NEXT: br label %loop.header
;
entry:
br label %loop.header
loop.header:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
%lv = load i32, i32* %ptr
%sc = icmp eq i32 %lv, 100
br i1 %sc, label %noclobber, label %clobber
noclobber:
br i1 %ec.1, label %loop.latch, label %exit.2
clobber:
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
br label %loop.latch
loop.latch:
%c = icmp ult i32 %iv, %N
%iv.next = add i32 %iv, 1
br i1 %c, label %loop.header, label %exit.1
exit.1:
ret i32 10
exit.2:
ret i32 20
}
define i32 @no_partial_unswitch_shortcut_mustprogress_store(i32* %ptr, i32* noalias %dst, i32 %N) mustprogress {
; CHECK-LABEL: @no_partial_unswitch_shortcut_mustprogress_store
; CHECK-LABEL: entry:
; CHECK-NEXT: br label %loop.header
;
entry:
br label %loop.header
loop.header:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
%lv = load i32, i32* %ptr
%sc = icmp eq i32 %lv, 100
br i1 %sc, label %noclobber, label %clobber
noclobber:
store i32 0, i32* %dst
br label %loop.latch
clobber:
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
br label %loop.latch
loop.latch:
%c = icmp ult i32 %iv, %N
%iv.next = add i32 %iv, 1
br i1 %c, label %loop.header, label %exit
exit:
ret i32 10
}
define i32 @no_partial_unswitch_shortcut_mustprogress_store2(i32* %ptr, i32* noalias %dst, i32 %N) mustprogress {
; CHECK-LABEL: @no_partial_unswitch_shortcut_mustprogress_store
; CHECK-LABEL: entry:
; CHECK-NEXT: br label %loop.header
;
entry:
br label %loop.header
loop.header:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
%lv = load i32, i32* %ptr
%sc = icmp eq i32 %lv, 100
br i1 %sc, label %noclobber, label %clobber
noclobber:
br label %loop.latch
clobber:
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
br label %loop.latch
loop.latch:
store i32 0, i32* %dst
%c = icmp ult i32 %iv, %N
%iv.next = add i32 %iv, 1
br i1 %c, label %loop.header, label %exit
exit:
ret i32 10
}
define i32 @no_partial_unswitch_shortcut_mustprogress_store3(i32* %ptr, i32* noalias %dst, i32 %N) mustprogress {
; CHECK-LABEL: @no_partial_unswitch_shortcut_mustprogress_store
; CHECK-LABEL: entry:
; CHECK-NEXT: br label %loop.header
;
entry:
br label %loop.header
loop.header:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
store i32 0, i32* %dst
%lv = load i32, i32* %ptr
%sc = icmp eq i32 %lv, 100
br i1 %sc, label %noclobber, label %clobber
noclobber:
br label %loop.latch
clobber:
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
call void @clobber()
br label %loop.latch
loop.latch:
%c = icmp ult i32 %iv, %N
%iv.next = add i32 %iv, 1
br i1 %c, label %loop.header, label %exit
exit:
ret i32 10
}