139 lines
4.5 KiB
LLVM
139 lines
4.5 KiB
LLVM
|
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||
|
; RUN: opt -S -loop-guard-widening -enable-new-pm=0 < %s | FileCheck %s
|
||
|
; RUN: opt -S -passes="loop(guard-widening)" < %s | FileCheck %s
|
||
|
|
||
|
declare void @llvm.experimental.guard(i1,...)
|
||
|
|
||
|
@G = external global i32
|
||
|
|
||
|
; Show that we can widen into early checks within a loop, and in the process
|
||
|
; expose optimization oppurtunities.
|
||
|
define void @widen_within_loop(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
|
||
|
; CHECK-LABEL: @widen_within_loop(
|
||
|
; CHECK-NEXT: entry:
|
||
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||
|
; CHECK: loop:
|
||
|
; CHECK-NEXT: store i32 0, i32* @G
|
||
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
|
||
|
; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_2:%.*]]
|
||
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"(i32 0) ]
|
||
|
; CHECK-NEXT: store i32 1, i32* @G
|
||
|
; CHECK-NEXT: store i32 2, i32* @G
|
||
|
; CHECK-NEXT: store i32 3, i32* @G
|
||
|
; CHECK-NEXT: br label [[LOOP]]
|
||
|
;
|
||
|
entry:
|
||
|
br label %loop
|
||
|
|
||
|
loop:
|
||
|
store i32 0, i32* @G
|
||
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ]
|
||
|
store i32 1, i32* @G
|
||
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"(i32 1) ]
|
||
|
store i32 2, i32* @G
|
||
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ]
|
||
|
store i32 3, i32* @G
|
||
|
br label %loop
|
||
|
}
|
||
|
|
||
|
define void @widen_into_preheader(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
|
||
|
; CHECK-LABEL: @widen_into_preheader(
|
||
|
; CHECK-NEXT: entry:
|
||
|
; CHECK-NEXT: store i32 0, i32* @G
|
||
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
|
||
|
; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_2:%.*]]
|
||
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"(i32 0) ]
|
||
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||
|
; CHECK: loop:
|
||
|
; CHECK-NEXT: store i32 1, i32* @G
|
||
|
; CHECK-NEXT: store i32 2, i32* @G
|
||
|
; CHECK-NEXT: store i32 3, i32* @G
|
||
|
; CHECK-NEXT: br label [[LOOP]]
|
||
|
;
|
||
|
entry:
|
||
|
store i32 0, i32* @G
|
||
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ]
|
||
|
br label %loop
|
||
|
|
||
|
loop:
|
||
|
store i32 1, i32* @G
|
||
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"(i32 1) ]
|
||
|
store i32 2, i32* @G
|
||
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ]
|
||
|
store i32 3, i32* @G
|
||
|
br label %loop
|
||
|
}
|
||
|
|
||
|
define void @dont_widen_over_common_exit(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
|
||
|
; CHECK-LABEL: @dont_widen_over_common_exit(
|
||
|
; CHECK-NEXT: entry:
|
||
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||
|
; CHECK: loop:
|
||
|
; CHECK-NEXT: store i32 0, i32* @G
|
||
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"(i32 0) ]
|
||
|
; CHECK-NEXT: store i32 1, i32* @G
|
||
|
; CHECK-NEXT: br i1 [[COND_1:%.*]], label [[BACKEDGE:%.*]], label [[EXIT:%.*]]
|
||
|
; CHECK: backedge:
|
||
|
; CHECK-NEXT: store i32 2, i32* @G
|
||
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_2:%.*]]) [ "deopt"(i32 2) ]
|
||
|
; CHECK-NEXT: store i32 3, i32* @G
|
||
|
; CHECK-NEXT: br label [[LOOP]]
|
||
|
; CHECK: exit:
|
||
|
; CHECK-NEXT: ret void
|
||
|
;
|
||
|
entry:
|
||
|
br label %loop
|
||
|
|
||
|
loop:
|
||
|
store i32 0, i32* @G
|
||
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ]
|
||
|
store i32 1, i32* @G
|
||
|
br i1 %cond_1, label %backedge, label %exit
|
||
|
|
||
|
backedge:
|
||
|
store i32 2, i32* @G
|
||
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ]
|
||
|
store i32 3, i32* @G
|
||
|
br label %loop
|
||
|
|
||
|
exit:
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
define void @widen_over_common_exit_to_ph(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
|
||
|
; CHECK-LABEL: @widen_over_common_exit_to_ph(
|
||
|
; CHECK-NEXT: entry:
|
||
|
; CHECK-NEXT: store i32 0, i32* @G
|
||
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_2:%.*]]
|
||
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"(i32 0) ]
|
||
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||
|
; CHECK: loop:
|
||
|
; CHECK-NEXT: store i32 1, i32* @G
|
||
|
; CHECK-NEXT: br i1 [[COND_1:%.*]], label [[BACKEDGE:%.*]], label [[EXIT:%.*]]
|
||
|
; CHECK: backedge:
|
||
|
; CHECK-NEXT: store i32 2, i32* @G
|
||
|
; CHECK-NEXT: store i32 3, i32* @G
|
||
|
; CHECK-NEXT: br label [[LOOP]]
|
||
|
; CHECK: exit:
|
||
|
; CHECK-NEXT: ret void
|
||
|
;
|
||
|
entry:
|
||
|
store i32 0, i32* @G
|
||
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ]
|
||
|
br label %loop
|
||
|
|
||
|
loop:
|
||
|
store i32 1, i32* @G
|
||
|
br i1 %cond_1, label %backedge, label %exit
|
||
|
|
||
|
backedge:
|
||
|
store i32 2, i32* @G
|
||
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ]
|
||
|
store i32 3, i32* @G
|
||
|
br label %loop
|
||
|
|
||
|
exit:
|
||
|
ret void
|
||
|
}
|
||
|
|