1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -print-predicateinfo < %s 2>&1 | FileCheck %s
3
4declare void @foo(i1)
5declare void @bar(i32)
6declare void @llvm.assume(i1)
7
8define void @testor(i32 %x, i32 %y) {
9; CHECK-LABEL: @testor(
10; CHECK-NEXT:    [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
11; CHECK-NEXT:    [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
12; CHECK-NEXT:    [[Z:%.*]] = or i1 [[XZ]], [[YZ]]
13; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
14; CHECK:         [[Y_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
15; CHECK:         [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]])
16; CHECK:         [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]])
17; CHECK:         [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
18; CHECK-NEXT:    br i1 [[Z]], label [[ONEOF:%.*]], label [[NEITHER:%.*]]
19; CHECK:       oneof:
20; CHECK-NEXT:    call void @foo(i1 [[XZ]])
21; CHECK-NEXT:    call void @foo(i1 [[YZ]])
22; CHECK-NEXT:    call void @bar(i32 [[X]])
23; CHECK-NEXT:    call void @bar(i32 [[Y]])
24; CHECK-NEXT:    ret void
25; CHECK:       neither:
26; CHECK-NEXT:    call void @foo(i1 [[XZ_0]])
27; CHECK-NEXT:    call void @foo(i1 [[YZ_0]])
28; CHECK-NEXT:    call void @bar(i32 [[X_0]])
29; CHECK-NEXT:    call void @bar(i32 [[Y_0]])
30; CHECK-NEXT:    call void @foo(i1 [[Z_0]])
31; CHECK-NEXT:    ret void
32;
33  %xz = icmp eq i32 %x, 0
34  %yz = icmp eq i32 %y, 0
35  %z = or i1 %xz, %yz
36  br i1 %z, label %oneof, label %neither
37oneof:
38;; Should not insert on the true edge for or
39  call void @foo(i1 %xz)
40  call void @foo(i1 %yz)
41  call void @bar(i32 %x)
42  call void @bar(i32 %y)
43  ret void
44neither:
45  call void @foo(i1 %xz)
46  call void @foo(i1 %yz)
47  call void @bar(i32 %x)
48  call void @bar(i32 %y)
49  call void @foo(i1 %z)
50  ret void
51}
52define void @testand(i32 %x, i32 %y) {
53; CHECK-LABEL: @testand(
54; CHECK-NEXT:    [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
55; CHECK-NEXT:    [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
56; CHECK-NEXT:    [[Z:%.*]] = and i1 [[XZ]], [[YZ]]
57; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
58; CHECK:         [[Y_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
59; CHECK:         [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]])
60; CHECK:         [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]])
61; CHECK:         [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
62; CHECK-NEXT:    br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
63; CHECK:       both:
64; CHECK-NEXT:    call void @foo(i1 [[XZ_0]])
65; CHECK-NEXT:    call void @foo(i1 [[YZ_0]])
66; CHECK-NEXT:    call void @bar(i32 [[X_0]])
67; CHECK-NEXT:    call void @bar(i32 [[Y_0]])
68; CHECK-NEXT:    ret void
69; CHECK:       nope:
70; CHECK-NEXT:    call void @foo(i1 [[XZ]])
71; CHECK-NEXT:    call void @foo(i1 [[YZ]])
72; CHECK-NEXT:    call void @bar(i32 [[X]])
73; CHECK-NEXT:    call void @bar(i32 [[Y]])
74; CHECK-NEXT:    call void @foo(i1 [[Z_0]])
75; CHECK-NEXT:    ret void
76;
77  %xz = icmp eq i32 %x, 0
78  %yz = icmp eq i32 %y, 0
79  %z = and i1 %xz, %yz
80  br i1 %z, label %both, label %nope
81both:
82  call void @foo(i1 %xz)
83  call void @foo(i1 %yz)
84  call void @bar(i32 %x)
85  call void @bar(i32 %y)
86  ret void
87nope:
88;; Should not insert on the false edge for and
89  call void @foo(i1 %xz)
90  call void @foo(i1 %yz)
91  call void @bar(i32 %x)
92  call void @bar(i32 %y)
93  call void @foo(i1 %z)
94  ret void
95}
96define void @testandsame(i32 %x, i32 %y) {
97; CHECK-LABEL: @testandsame(
98; CHECK-NEXT:    [[XGT:%.*]] = icmp sgt i32 [[X:%.*]], 0
99; CHECK-NEXT:    [[XLT:%.*]] = icmp slt i32 [[X]], 100
100; CHECK-NEXT:    [[Z:%.*]] = and i1 [[XGT]], [[XLT]]
101; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
102; CHECK:         [[X_0_1:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X_0]])
103; CHECK:         [[XGT_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XGT]])
104; CHECK:         [[XLT_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XLT]])
105; CHECK:         [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
106; CHECK-NEXT:    br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
107; CHECK:       both:
108; CHECK-NEXT:    call void @foo(i1 [[XGT_0]])
109; CHECK-NEXT:    call void @foo(i1 [[XLT_0]])
110; CHECK-NEXT:    call void @bar(i32 [[X_0_1]])
111; CHECK-NEXT:    ret void
112; CHECK:       nope:
113; CHECK-NEXT:    call void @foo(i1 [[XGT]])
114; CHECK-NEXT:    call void @foo(i1 [[XLT]])
115; CHECK-NEXT:    call void @foo(i1 [[Z_0]])
116; CHECK-NEXT:    ret void
117;
118  %xgt = icmp sgt i32 %x, 0
119  %xlt = icmp slt i32 %x, 100
120  %z = and i1 %xgt, %xlt
121  br i1 %z, label %both, label %nope
122both:
123  call void @foo(i1 %xgt)
124  call void @foo(i1 %xlt)
125  call void @bar(i32 %x)
126  ret void
127nope:
128  call void @foo(i1 %xgt)
129  call void @foo(i1 %xlt)
130  call void @foo(i1 %z)
131  ret void
132}
133
134define void @testandassume(i32 %x, i32 %y) {
135; CHECK-LABEL: @testandassume(
136; CHECK-NEXT:    [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
137; CHECK-NEXT:    [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
138; CHECK-NEXT:    [[Z:%.*]] = and i1 [[XZ]], [[YZ]]
139; CHECK:         [[TMP1:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
140; CHECK:         [[TMP2:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
141; CHECK:         [[TMP3:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]])
142; CHECK:         [[TMP4:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]])
143; CHECK:         [[TMP5:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
144; CHECK-NEXT:    call void @llvm.assume(i1 [[TMP5]])
145; CHECK:         [[DOT0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[TMP1]])
146; CHECK:         [[DOT01:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[TMP2]])
147; CHECK:         [[DOT02:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP3]])
148; CHECK:         [[DOT03:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP4]])
149; CHECK:         [[DOT04:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP5]])
150; CHECK-NEXT:    br i1 [[TMP5]], label [[BOTH:%.*]], label [[NOPE:%.*]]
151; CHECK:       both:
152; CHECK-NEXT:    call void @foo(i1 [[DOT02]])
153; CHECK-NEXT:    call void @foo(i1 [[DOT03]])
154; CHECK-NEXT:    call void @bar(i32 [[DOT0]])
155; CHECK-NEXT:    call void @bar(i32 [[DOT01]])
156; CHECK-NEXT:    ret void
157; CHECK:       nope:
158; CHECK-NEXT:    call void @foo(i1 [[DOT04]])
159; CHECK-NEXT:    ret void
160;
161  %xz = icmp eq i32 %x, 0
162  %yz = icmp eq i32 %y, 0
163  %z = and i1 %xz, %yz
164  call void @llvm.assume(i1 %z)
165  br i1 %z, label %both, label %nope
166both:
167  call void @foo(i1 %xz)
168  call void @foo(i1 %yz)
169  call void @bar(i32 %x)
170  call void @bar(i32 %y)
171  ret void
172nope:
173  call void @foo(i1 %z)
174  ret void
175}
176
177;; Unlike and/or for branches, assume is *always* true, so we only match and for it
178define void @testorassume(i32 %x, i32 %y) {
179;
180; CHECK-LABEL: @testorassume(
181; CHECK-NEXT:    [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
182; CHECK-NEXT:    [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
183; CHECK-NEXT:    [[Z:%.*]] = or i1 [[XZ]], [[YZ]]
184; CHECK-NEXT:    call void @llvm.assume(i1 [[Z]])
185; CHECK:         [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
186; CHECK-NEXT:    br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
187; CHECK:       both:
188; CHECK-NEXT:    call void @foo(i1 [[XZ]])
189; CHECK-NEXT:    call void @foo(i1 [[YZ]])
190; CHECK-NEXT:    call void @bar(i32 [[X]])
191; CHECK-NEXT:    call void @bar(i32 [[Y]])
192; CHECK-NEXT:    ret void
193; CHECK:       nope:
194; CHECK-NEXT:    call void @foo(i1 [[Z_0]])
195; CHECK-NEXT:    ret void
196;
197  %xz = icmp eq i32 %x, 0
198  %yz = icmp eq i32 %y, 0
199  %z = or i1 %xz, %yz
200  call void @llvm.assume(i1 %z)
201  br i1 %z, label %both, label %nope
202both:
203  call void @foo(i1 %xz)
204  call void @foo(i1 %yz)
205  call void @bar(i32 %x)
206  call void @bar(i32 %y)
207  ret void
208nope:
209  call void @foo(i1 %z)
210  ret void
211}
212