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