1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s
3
4define i8 @simple(i1) {
5; CHECK-LABEL: @simple(
6; CHECK-NEXT:  entry:
7; CHECK-NEXT:    [[S:%.*]] = select i1 [[TMP0:%.*]], i8 0, i8 1
8; CHECK-NEXT:    br i1 [[TMP0]], label [[THEN:%.*]], label [[ELSE:%.*]]
9; CHECK:       then:
10; CHECK-NEXT:    ret i8 0
11; CHECK:       else:
12; CHECK-NEXT:    ret i8 1
13;
14entry:
15  %s = select i1 %0, i8 0, i8 1
16  br i1 %0, label %then, label %else
17
18then:
19  %a = phi i8 [ %s, %entry ]
20  ret i8 %a
21
22else:
23  %b = phi i8 [ %s, %entry ]
24  ret i8 %b
25}
26
27define void @loop(i32) {
28; CHECK-LABEL: @loop(
29; CHECK-NEXT:  entry:
30; CHECK-NEXT:    br label [[LOOP:%.*]]
31; CHECK:       loop:
32; CHECK-NEXT:    [[IDX:%.*]] = phi i32 [ [[TMP0:%.*]], [[ENTRY:%.*]] ], [ [[TMP2:%.*]], [[LOOP]] ]
33; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[IDX]], 0
34; CHECK-NEXT:    [[TMP2]] = add i32 [[IDX]], -1
35; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[TMP1]], i32 0, i32 [[TMP2]]
36; CHECK-NEXT:    br i1 [[TMP1]], label [[OUT:%.*]], label [[LOOP]]
37; CHECK:       out:
38; CHECK-NEXT:    ret void
39;
40entry:
41  br label %loop
42
43loop:
44  %idx = phi i32 [ %0, %entry ], [ %sel, %loop ]
45  %1 = icmp eq i32 %idx, 0
46  %2 = add i32 %idx, -1
47  %sel = select i1 %1, i32 0, i32 %2
48  br i1 %1, label %out, label %loop
49
50out:
51  ret void
52}
53
54define i8 @not_correlated(i1, i1) {
55; CHECK-LABEL: @not_correlated(
56; CHECK-NEXT:  entry:
57; CHECK-NEXT:    [[S:%.*]] = select i1 [[TMP0:%.*]], i8 0, i8 1
58; CHECK-NEXT:    br i1 [[TMP1:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
59; CHECK:       then:
60; CHECK-NEXT:    ret i8 [[S]]
61; CHECK:       else:
62; CHECK-NEXT:    ret i8 [[S]]
63;
64entry:
65  %s = select i1 %0, i8 0, i8 1
66  br i1 %1, label %then, label %else
67
68then:
69  %a = phi i8 [ %s, %entry ]
70  ret i8 %a
71
72else:
73  %b = phi i8 [ %s, %entry ]
74  ret i8 %b
75}
76
77@c = global i32 0, align 4
78@b = global i32 0, align 4
79
80define i32 @PR23752() {
81; CHECK-LABEL: @PR23752(
82; CHECK-NEXT:  entry:
83; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
84; CHECK:       for.body:
85; CHECK-NEXT:    [[SEL:%.*]] = select i1 icmp sgt (i32* @b, i32* @c), i32 0, i32 1
86; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[SEL]], 1
87; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[IF_END:%.*]]
88; CHECK:       if.end:
89; CHECK-NEXT:    ret i32 1
90;
91entry:
92  br label %for.body
93
94for.body:
95  %phi = phi i32 [ 0, %entry ], [ %sel, %for.body ]
96  %sel = select i1 icmp sgt (i32* @b, i32* @c), i32 %phi, i32 1
97  %cmp = icmp ne i32 %sel, 1
98  br i1 %cmp, label %for.body, label %if.end
99
100
101if.end:
102  ret i32 %sel
103}
104
105define i1 @test1(i32* %p, i1 %unknown) {
106; CHECK-LABEL: @test1(
107; CHECK-NEXT:    [[PVAL:%.*]] = load i32, i32* [[P:%.*]], align 4
108; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[PVAL]], 255
109; CHECK-NEXT:    br i1 [[CMP1]], label [[NEXT:%.*]], label [[EXIT:%.*]]
110; CHECK:       next:
111; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[UNKNOWN:%.*]], i32 [[PVAL]], i32 5
112; CHECK-NEXT:    ret i1 false
113; CHECK:       exit:
114; CHECK-NEXT:    ret i1 true
115;
116  %pval = load i32, i32* %p
117  %cmp1 = icmp slt i32 %pval, 255
118  br i1 %cmp1, label %next, label %exit
119
120next:
121  %min = select i1 %unknown, i32 %pval, i32 5
122  %res = icmp eq i32 %min, 255
123  ret i1 %res
124
125exit:
126  ret i1 true
127}
128
129; Check that we take a conservative meet
130define i1 @test2(i32* %p, i32 %qval, i1 %unknown) {
131; CHECK-LABEL: @test2(
132; CHECK-NEXT:    [[PVAL:%.*]] = load i32, i32* [[P:%.*]], align 4
133; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[PVAL]], 255
134; CHECK-NEXT:    br i1 [[CMP1]], label [[NEXT:%.*]], label [[EXIT:%.*]]
135; CHECK:       next:
136; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[UNKNOWN:%.*]], i32 [[PVAL]], i32 [[QVAL:%.*]]
137; CHECK-NEXT:    [[RES:%.*]] = icmp eq i32 [[MIN]], 255
138; CHECK-NEXT:    ret i1 [[RES]]
139; CHECK:       exit:
140; CHECK-NEXT:    ret i1 true
141;
142  %pval = load i32, i32* %p
143  %cmp1 = icmp slt i32 %pval, 255
144  br i1 %cmp1, label %next, label %exit
145
146next:
147  %min = select i1 %unknown, i32 %pval, i32 %qval
148  %res = icmp eq i32 %min, 255
149  ret i1 %res
150
151exit:
152  ret i1 true
153}
154
155; Same as @test2, but for the opposite select input
156define i1 @test3(i32* %p, i32 %qval, i1 %unknown) {
157; CHECK-LABEL: @test3(
158; CHECK-NEXT:    [[PVAL:%.*]] = load i32, i32* [[P:%.*]], align 4
159; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[PVAL]], 255
160; CHECK-NEXT:    br i1 [[CMP1]], label [[NEXT:%.*]], label [[EXIT:%.*]]
161; CHECK:       next:
162; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[UNKNOWN:%.*]], i32 [[QVAL:%.*]], i32 [[PVAL]]
163; CHECK-NEXT:    [[RES:%.*]] = icmp eq i32 [[MIN]], 255
164; CHECK-NEXT:    ret i1 [[RES]]
165; CHECK:       exit:
166; CHECK-NEXT:    ret i1 true
167;
168  %pval = load i32, i32* %p
169  %cmp1 = icmp slt i32 %pval, 255
170  br i1 %cmp1, label %next, label %exit
171
172next:
173  %min = select i1 %unknown, i32 %qval, i32 %pval
174  %res = icmp eq i32 %min, 255
175  ret i1 %res
176
177exit:
178  ret i1 true
179}
180
181; Conflicting constants (i.e. isOverdefined result)
182; NOTE: Using doubles in this version is a bit of a hack.  This
183; is to get around the fact that all integers (including constants
184; and non-constants) are actually represented as constant-ranges.
185define i1 @test4(i32* %p, i32 %qval, i1 %unknown) {
186; CHECK-LABEL: @test4(
187; CHECK-NEXT:    [[PVAL:%.*]] = load i32, i32* [[P:%.*]], align 4
188; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[PVAL]], 255
189; CHECK-NEXT:    br i1 [[CMP1]], label [[NEXT:%.*]], label [[EXIT:%.*]]
190; CHECK:       next:
191; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[UNKNOWN:%.*]], double 1.000000e+00, double 0.000000e+00
192; CHECK-NEXT:    [[RES:%.*]] = fcmp oeq double [[MIN]], 3.000000e+02
193; CHECK-NEXT:    ret i1 [[RES]]
194; CHECK:       exit:
195; CHECK-NEXT:    ret i1 true
196;
197  %pval = load i32, i32* %p
198  %cmp1 = icmp slt i32 %pval, 255
199  br i1 %cmp1, label %next, label %exit
200
201next:
202  %min = select i1 %unknown, double 1.0, double 0.0
203  %res = fcmp oeq double %min, 300.0
204  ret i1 %res
205
206exit:
207  ret i1 true
208}
209
210;; Using the condition to clamp the result
211;;
212
213define i1 @test5(i32* %p, i1 %unknown) {
214; CHECK-LABEL: @test5(
215; CHECK-NEXT:    [[PVAL:%.*]] = load i32, i32* [[P:%.*]], align 4
216; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[PVAL]], 255
217; CHECK-NEXT:    br i1 [[CMP1]], label [[NEXT:%.*]], label [[EXIT:%.*]]
218; CHECK:       next:
219; CHECK-NEXT:    [[COND:%.*]] = icmp sgt i32 [[PVAL]], 0
220; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[COND]], i32 [[PVAL]], i32 5
221; CHECK-NEXT:    ret i1 false
222; CHECK:       exit:
223; CHECK-NEXT:    ret i1 true
224;
225  %pval = load i32, i32* %p
226  %cmp1 = icmp slt i32 %pval, 255
227  br i1 %cmp1, label %next, label %exit
228
229next:
230  %cond = icmp sgt i32 %pval, 0
231  %min = select i1 %cond, i32 %pval, i32 5
232  %res = icmp eq i32 %min, -1
233  ret i1 %res
234
235exit:
236  ret i1 true
237}
238
239define i1 @test6(i32* %p, i1 %unknown) {
240; CHECK-LABEL: @test6(
241; CHECK-NEXT:    [[PVAL:%.*]] = load i32, i32* [[P:%.*]], align 4
242; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[PVAL]], 255
243; CHECK-NEXT:    br i1 [[CMP1]], label [[NEXT:%.*]], label [[EXIT:%.*]]
244; CHECK:       next:
245; CHECK-NEXT:    [[COND:%.*]] = icmp ne i32 [[PVAL]], 254
246; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i32 [[PVAL]], i32 1
247; CHECK-NEXT:    ret i1 true
248; CHECK:       exit:
249; CHECK-NEXT:    ret i1 true
250;
251  %pval = load i32, i32* %p
252  %cmp1 = icmp ult i32 %pval, 255
253  br i1 %cmp1, label %next, label %exit
254
255next:
256  %cond = icmp ne i32 %pval, 254
257  %sel = select i1 %cond, i32 %pval, i32 1
258  %res = icmp slt i32 %sel, 254
259  ret i1 %res
260
261exit:
262  ret i1 true
263}
264