1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -loop-guard-widening -enable-new-pm=0 < %s | FileCheck %s
3; RUN: opt -S -passes="loop(guard-widening)" < %s | FileCheck %s
4
5declare void @llvm.experimental.guard(i1,...)
6
7@G = external global i32
8
9; Show that we can widen into early checks within a loop, and in the process
10; expose optimization oppurtunities.
11define void @widen_within_loop(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
12; CHECK-LABEL: @widen_within_loop(
13; CHECK-NEXT:  entry:
14; CHECK-NEXT:    br label [[LOOP:%.*]]
15; CHECK:       loop:
16; CHECK-NEXT:    store i32 0, i32* @G
17; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
18; CHECK-NEXT:    [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_2:%.*]]
19; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"(i32 0) ]
20; CHECK-NEXT:    store i32 1, i32* @G
21; CHECK-NEXT:    store i32 2, i32* @G
22; CHECK-NEXT:    store i32 3, i32* @G
23; CHECK-NEXT:    br label [[LOOP]]
24;
25entry:
26  br label %loop
27
28loop:
29  store i32 0, i32* @G
30  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ]
31  store i32 1, i32* @G
32  call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"(i32 1) ]
33  store i32 2, i32* @G
34  call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ]
35  store i32 3, i32* @G
36  br label %loop
37}
38
39define void @widen_into_preheader(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
40; CHECK-LABEL: @widen_into_preheader(
41; CHECK-NEXT:  entry:
42; CHECK-NEXT:    store i32 0, i32* @G
43; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
44; CHECK-NEXT:    [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_2:%.*]]
45; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"(i32 0) ]
46; CHECK-NEXT:    br label [[LOOP:%.*]]
47; CHECK:       loop:
48; CHECK-NEXT:    store i32 1, i32* @G
49; CHECK-NEXT:    store i32 2, i32* @G
50; CHECK-NEXT:    store i32 3, i32* @G
51; CHECK-NEXT:    br label [[LOOP]]
52;
53entry:
54  store i32 0, i32* @G
55  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ]
56  br label %loop
57
58loop:
59  store i32 1, i32* @G
60  call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"(i32 1) ]
61  store i32 2, i32* @G
62  call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ]
63  store i32 3, i32* @G
64  br label %loop
65}
66
67define void @dont_widen_over_common_exit(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
68; CHECK-LABEL: @dont_widen_over_common_exit(
69; CHECK-NEXT:  entry:
70; CHECK-NEXT:    br label [[LOOP:%.*]]
71; CHECK:       loop:
72; CHECK-NEXT:    store i32 0, i32* @G
73; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"(i32 0) ]
74; CHECK-NEXT:    store i32 1, i32* @G
75; CHECK-NEXT:    br i1 [[COND_1:%.*]], label [[BACKEDGE:%.*]], label [[EXIT:%.*]]
76; CHECK:       backedge:
77; CHECK-NEXT:    store i32 2, i32* @G
78; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_2:%.*]]) [ "deopt"(i32 2) ]
79; CHECK-NEXT:    store i32 3, i32* @G
80; CHECK-NEXT:    br label [[LOOP]]
81; CHECK:       exit:
82; CHECK-NEXT:    ret void
83;
84entry:
85  br label %loop
86
87loop:
88  store i32 0, i32* @G
89  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ]
90  store i32 1, i32* @G
91  br i1 %cond_1, label %backedge, label %exit
92
93backedge:
94  store i32 2, i32* @G
95  call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ]
96  store i32 3, i32* @G
97  br label %loop
98
99exit:
100  ret void
101}
102
103define void @widen_over_common_exit_to_ph(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
104; CHECK-LABEL: @widen_over_common_exit_to_ph(
105; CHECK-NEXT:  entry:
106; CHECK-NEXT:    store i32 0, i32* @G
107; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_2:%.*]]
108; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"(i32 0) ]
109; CHECK-NEXT:    br label [[LOOP:%.*]]
110; CHECK:       loop:
111; CHECK-NEXT:    store i32 1, i32* @G
112; CHECK-NEXT:    br i1 [[COND_1:%.*]], label [[BACKEDGE:%.*]], label [[EXIT:%.*]]
113; CHECK:       backedge:
114; CHECK-NEXT:    store i32 2, i32* @G
115; CHECK-NEXT:    store i32 3, i32* @G
116; CHECK-NEXT:    br label [[LOOP]]
117; CHECK:       exit:
118; CHECK-NEXT:    ret void
119;
120entry:
121  store i32 0, i32* @G
122  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ]
123  br label %loop
124
125loop:
126  store i32 1, i32* @G
127  br i1 %cond_1, label %backedge, label %exit
128
129backedge:
130  store i32 2, i32* @G
131  call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ]
132  store i32 3, i32* @G
133  br label %loop
134
135exit:
136  ret void
137}
138
139