xref: /llvm-project/llvm/test/Transforms/InstCombine/phi-equal-incoming-pointers.ll (revision f7685af4a5bd188e6d548967d818d8569f10a70d)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -passes=instcombine,verify -S < %s | FileCheck %s --check-prefixes=ALL,INSTCOMBINE
3
4; Make sure GVN won't undo the transformation:
5; RUN: opt -passes=instcombine,gvn -S < %s | FileCheck %s --check-prefixes=ALL,INSTCOMBINEGVN
6
7declare ptr @get_ptr.i8()
8declare ptr @get_ptr.i32()
9declare void @foo.i8(ptr)
10declare void @foo.i32(ptr)
11
12define i32 @test_gep_and_bitcast(i1 %cond, i1 %cond2) {
13; ALL-LABEL: @test_gep_and_bitcast(
14; ALL-NEXT:  entry:
15; ALL-NEXT:    [[OBJ:%.*]] = call ptr @get_ptr.i8()
16; ALL-NEXT:    br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
17; ALL:       bb1:
18; ALL-NEXT:    br label [[EXIT:%.*]]
19; ALL:       bb2:
20; ALL-NEXT:    br label [[EXIT]]
21; ALL:       exit:
22; ALL-NEXT:    [[PTR_TYPED:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16
23; ALL-NEXT:    [[RES_PHI:%.*]] = load i32, ptr [[PTR_TYPED]], align 4
24; ALL-NEXT:    store i32 1, ptr [[PTR_TYPED]], align 4
25; ALL-NEXT:    [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1
26; ALL-NEXT:    ret i32 [[RES]]
27;
28entry:
29  %obj = call ptr @get_ptr.i8()
30  br i1 %cond, label %bb1, label %bb2
31
32bb1:
33  %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16
34  %res1 = load i32, ptr %ptr1
35  br label %exit
36
37bb2:
38  %ptr2 = getelementptr inbounds i8, ptr %obj, i64 16
39  %res2 = load i32, ptr %ptr2
40  br label %exit
41
42exit:
43  %ptr.typed = phi ptr [ %ptr1, %bb1 ], [ %ptr2, %bb2 ]
44  %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ]
45  store i32 1, ptr %ptr.typed
46  %res.load = load i32, ptr %ptr.typed
47  %res = select i1 %cond2, i32 %res.phi, i32 %res.load
48  ret i32 %res
49}
50
51define i32 @test_gep_and_bitcast_arg(ptr %obj, i1 %cond, i1 %cond2) {
52; ALL-LABEL: @test_gep_and_bitcast_arg(
53; ALL-NEXT:  entry:
54; ALL-NEXT:    br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
55; ALL:       bb1:
56; ALL-NEXT:    br label [[EXIT:%.*]]
57; ALL:       bb2:
58; ALL-NEXT:    br label [[EXIT]]
59; ALL:       exit:
60; ALL-NEXT:    [[PTR_TYPED:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ:%.*]], i64 16
61; ALL-NEXT:    [[RES_PHI:%.*]] = load i32, ptr [[PTR_TYPED]], align 4
62; ALL-NEXT:    store i32 1, ptr [[PTR_TYPED]], align 4
63; ALL-NEXT:    [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1
64; ALL-NEXT:    ret i32 [[RES]]
65;
66entry:
67  br i1 %cond, label %bb1, label %bb2
68
69bb1:
70  %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16
71  %res1 = load i32, ptr %ptr1
72  br label %exit
73
74bb2:
75  %ptr2 = getelementptr inbounds i8, ptr %obj, i64 16
76  %res2 = load i32, ptr %ptr2
77  br label %exit
78
79exit:
80  %ptr.typed = phi ptr [ %ptr1, %bb1 ], [ %ptr2, %bb2 ]
81  %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ]
82  store i32 1, ptr %ptr.typed
83  %res.load = load i32, ptr %ptr.typed
84  %res = select i1 %cond2, i32 %res.phi, i32 %res.load
85  ret i32 %res
86}
87
88define i32 @test_gep_and_bitcast_phi(i1 %cond, i1 %cond2, i1 %cond3) {
89; ALL-LABEL: @test_gep_and_bitcast_phi(
90; ALL-NEXT:  entry:
91; ALL-NEXT:    br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
92; ALL:       bb1:
93; ALL-NEXT:    [[OBJ1:%.*]] = call ptr @get_ptr.i8()
94; ALL-NEXT:    br label [[MERGE:%.*]]
95; ALL:       bb2:
96; ALL-NEXT:    [[OBJ2_TYPED:%.*]] = call ptr @get_ptr.i32()
97; ALL-NEXT:    br label [[MERGE]]
98; ALL:       merge:
99; ALL-NEXT:    [[OBJ:%.*]] = phi ptr [ [[OBJ1]], [[BB1]] ], [ [[OBJ2_TYPED]], [[BB2]] ]
100; ALL-NEXT:    [[ANOTHER_PHI:%.*]] = phi ptr [ [[OBJ1]], [[BB1]] ], [ null, [[BB2]] ]
101; ALL-NEXT:    call void @foo.i8(ptr [[ANOTHER_PHI]])
102; ALL-NEXT:    br i1 [[COND2:%.*]], label [[BB3:%.*]], label [[BB4:%.*]]
103; ALL:       bb3:
104; ALL-NEXT:    br label [[EXIT:%.*]]
105; ALL:       bb4:
106; ALL-NEXT:    br label [[EXIT]]
107; ALL:       exit:
108; ALL-NEXT:    [[PTR_TYPED:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16
109; ALL-NEXT:    [[RES_PHI:%.*]] = load i32, ptr [[PTR_TYPED]], align 4
110; ALL-NEXT:    store i32 1, ptr [[PTR_TYPED]], align 4
111; ALL-NEXT:    [[RES:%.*]] = select i1 [[COND3:%.*]], i32 [[RES_PHI]], i32 1
112; ALL-NEXT:    ret i32 [[RES]]
113;
114entry:
115  br i1 %cond, label %bb1, label %bb2
116
117bb1:
118  %obj1 = call ptr @get_ptr.i8()
119  br label %merge
120
121bb2:
122  %obj2.typed = call ptr @get_ptr.i32()
123  br label %merge
124
125merge:
126  %obj = phi ptr [ %obj1, %bb1 ], [ %obj2.typed, %bb2 ]
127  %another_phi = phi ptr [ %obj1, %bb1 ], [ null, %bb2 ]
128  call void @foo.i8(ptr %another_phi)
129  br i1 %cond2, label %bb3, label %bb4
130
131bb3:
132  %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16
133  %res1 = load i32, ptr %ptr1
134  br label %exit
135
136bb4:
137  %ptr2 = getelementptr inbounds i8, ptr %obj, i64 16
138  %res2 = load i32, ptr %ptr2
139  br label %exit
140
141exit:
142  %ptr.typed = phi ptr [ %ptr1, %bb3 ], [ %ptr2, %bb4 ]
143  %res.phi = phi i32 [ %res1, %bb3 ], [ %res2, %bb4 ]
144  store i32 1, ptr %ptr.typed
145  %res.load = load i32, ptr %ptr.typed
146  %res = select i1 %cond3, i32 %res.phi, i32 %res.load
147  ret i32 %res
148}
149
150define i32 @test_gep_i32ptr(i1 %cond, i1 %cond2) {
151; ALL-LABEL: @test_gep_i32ptr(
152; ALL-NEXT:  entry:
153; ALL-NEXT:    [[OBJ:%.*]] = call ptr @get_ptr.i32()
154; ALL-NEXT:    br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
155; ALL:       bb1:
156; ALL-NEXT:    br label [[EXIT:%.*]]
157; ALL:       bb2:
158; ALL-NEXT:    br label [[EXIT]]
159; ALL:       exit:
160; ALL-NEXT:    [[PTR_TYPED:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 64
161; ALL-NEXT:    [[RES_PHI:%.*]] = load i32, ptr [[PTR_TYPED]], align 4
162; ALL-NEXT:    store i32 1, ptr [[PTR_TYPED]], align 4
163; ALL-NEXT:    [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1
164; ALL-NEXT:    ret i32 [[RES]]
165;
166entry:
167  %obj = call ptr @get_ptr.i32()
168  br i1 %cond, label %bb1, label %bb2
169
170bb1:
171  %ptr1.typed = getelementptr inbounds i32, ptr %obj, i64 16
172  %res1 = load i32, ptr %ptr1.typed
173  br label %exit
174
175bb2:
176  %ptr2.typed = getelementptr inbounds i32, ptr %obj, i64 16
177  %res2 = load i32, ptr %ptr2.typed
178  br label %exit
179
180exit:
181  %ptr.typed = phi ptr [ %ptr1.typed, %bb1 ], [ %ptr2.typed, %bb2 ]
182  %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ]
183  store i32 1, ptr %ptr.typed
184  %res.load = load i32, ptr %ptr.typed
185  %res = select i1 %cond2, i32 %res.phi, i32 %res.load
186  ret i32 %res
187}
188
189define i32 @test_gep_and_bitcast_gep_base_ptr(i1 %cond, i1 %cond2) {
190; ALL-LABEL: @test_gep_and_bitcast_gep_base_ptr(
191; ALL-NEXT:  entry:
192; ALL-NEXT:    [[OBJ0:%.*]] = call ptr @get_ptr.i8()
193; ALL-NEXT:    br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
194; ALL:       bb1:
195; ALL-NEXT:    br label [[EXIT:%.*]]
196; ALL:       bb2:
197; ALL-NEXT:    br label [[EXIT]]
198; ALL:       exit:
199; ALL-NEXT:    [[PTR_TYPED:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ0]], i64 32
200; ALL-NEXT:    [[RES_PHI:%.*]] = load i32, ptr [[PTR_TYPED]], align 4
201; ALL-NEXT:    store i32 1, ptr [[PTR_TYPED]], align 4
202; ALL-NEXT:    [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1
203; ALL-NEXT:    ret i32 [[RES]]
204;
205entry:
206  %obj0 = call ptr @get_ptr.i8()
207  %obj = getelementptr inbounds i8, ptr %obj0, i64 16
208  br i1 %cond, label %bb1, label %bb2
209
210bb1:
211  %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16
212  %res1 = load i32, ptr %ptr1
213  br label %exit
214
215bb2:
216  %ptr2 = getelementptr inbounds i8, ptr %obj, i64 16
217  %res2 = load i32, ptr %ptr2
218  br label %exit
219
220exit:
221  %ptr.typed = phi ptr [ %ptr1, %bb1 ], [ %ptr2, %bb2 ]
222  %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ]
223  store i32 1, ptr %ptr.typed
224  %res.load = load i32, ptr %ptr.typed
225  %res = select i1 %cond2, i32 %res.phi, i32 %res.load
226  ret i32 %res
227}
228
229define i32 @test_gep_and_bitcast_same_bb(i1 %cond, i1 %cond2) {
230; ALL-LABEL: @test_gep_and_bitcast_same_bb(
231; ALL-NEXT:  entry:
232; ALL-NEXT:    [[OBJ:%.*]] = call ptr @get_ptr.i8()
233; ALL-NEXT:    br i1 [[COND:%.*]], label [[EXIT:%.*]], label [[BB2:%.*]]
234; ALL:       bb2:
235; ALL-NEXT:    br label [[EXIT]]
236; ALL:       exit:
237; ALL-NEXT:    [[PTR_TYPED:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16
238; ALL-NEXT:    [[RES_PHI:%.*]] = load i32, ptr [[PTR_TYPED]], align 4
239; ALL-NEXT:    store i32 1, ptr [[PTR_TYPED]], align 4
240; ALL-NEXT:    [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1
241; ALL-NEXT:    ret i32 [[RES]]
242;
243entry:
244  %obj = call ptr @get_ptr.i8()
245  %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16
246  %res1 = load i32, ptr %ptr1
247  br i1 %cond, label %exit, label %bb2
248
249bb2:
250  %ptr2 = getelementptr inbounds i8, ptr %obj, i64 16
251  %res2 = load i32, ptr %ptr2
252  br label %exit
253
254exit:
255  %ptr.typed = phi ptr [ %ptr1, %entry ], [ %ptr2, %bb2 ]
256  %res.phi = phi i32 [ %res1, %entry ], [ %res2, %bb2 ]
257  store i32 1, ptr %ptr.typed
258  %res.load = load i32, ptr %ptr.typed
259  %res = select i1 %cond2, i32 %res.phi, i32 %res.load
260  ret i32 %res
261}
262
263define i32 @test_gep_and_bitcast_same_bb_and_extra_use(i1 %cond, i1 %cond2) {
264; INSTCOMBINE-LABEL: @test_gep_and_bitcast_same_bb_and_extra_use(
265; INSTCOMBINE-NEXT:  entry:
266; INSTCOMBINE-NEXT:    [[OBJ:%.*]] = call ptr @get_ptr.i8()
267; INSTCOMBINE-NEXT:    [[PTR1:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16
268; INSTCOMBINE-NEXT:    call void @foo.i32(ptr nonnull [[PTR1]])
269; INSTCOMBINE-NEXT:    br i1 [[COND:%.*]], label [[EXIT:%.*]], label [[BB2:%.*]]
270; INSTCOMBINE:       bb2:
271; INSTCOMBINE-NEXT:    [[PTR2:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16
272; INSTCOMBINE-NEXT:    br label [[EXIT]]
273; INSTCOMBINE:       exit:
274; INSTCOMBINE-NEXT:    [[PTR_TYPED:%.*]] = phi ptr [ [[PTR1]], [[ENTRY:%.*]] ], [ [[PTR2]], [[BB2]] ]
275; INSTCOMBINE-NEXT:    [[RES_PHI:%.*]] = load i32, ptr [[PTR_TYPED]], align 4
276; INSTCOMBINE-NEXT:    store i32 1, ptr [[PTR_TYPED]], align 4
277; INSTCOMBINE-NEXT:    [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1
278; INSTCOMBINE-NEXT:    ret i32 [[RES]]
279;
280; INSTCOMBINEGVN-LABEL: @test_gep_and_bitcast_same_bb_and_extra_use(
281; INSTCOMBINEGVN-NEXT:  entry:
282; INSTCOMBINEGVN-NEXT:    [[OBJ:%.*]] = call ptr @get_ptr.i8()
283; INSTCOMBINEGVN-NEXT:    [[PTR1:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16
284; INSTCOMBINEGVN-NEXT:    call void @foo.i32(ptr nonnull [[PTR1]])
285; INSTCOMBINEGVN-NEXT:    br i1 [[COND:%.*]], label [[EXIT:%.*]], label [[BB2:%.*]]
286; INSTCOMBINEGVN:       bb2:
287; INSTCOMBINEGVN-NEXT:    br label [[EXIT]]
288; INSTCOMBINEGVN:       exit:
289; INSTCOMBINEGVN-NEXT:    [[RES_PHI:%.*]] = load i32, ptr [[PTR1]], align 4
290; INSTCOMBINEGVN-NEXT:    store i32 1, ptr [[PTR1]], align 4
291; INSTCOMBINEGVN-NEXT:    [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1
292; INSTCOMBINEGVN-NEXT:    ret i32 [[RES]]
293;
294entry:
295  %obj = call ptr @get_ptr.i8()
296  %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16
297  call void @foo.i32(ptr %ptr1)
298  %res1 = load i32, ptr %ptr1
299  br i1 %cond, label %exit, label %bb2
300
301bb2:
302  %ptr2 = getelementptr inbounds i8, ptr %obj, i64 16
303  %res2 = load i32, ptr %ptr2
304  br label %exit
305
306exit:
307  %ptr.typed = phi ptr [ %ptr1, %entry ], [ %ptr2, %bb2 ]
308  %res.phi = phi i32 [ %res1, %entry ], [ %res2, %bb2 ]
309  store i32 1, ptr %ptr.typed
310  %res.load = load i32, ptr %ptr.typed
311  %res = select i1 %cond2, i32 %res.phi, i32 %res.load
312  ret i32 %res
313}
314
315define i8 @test_gep(i1 %cond, i1 %cond2) {
316; ALL-LABEL: @test_gep(
317; ALL-NEXT:  entry:
318; ALL-NEXT:    [[OBJ:%.*]] = call ptr @get_ptr.i8()
319; ALL-NEXT:    br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
320; ALL:       bb1:
321; ALL-NEXT:    br label [[EXIT:%.*]]
322; ALL:       bb2:
323; ALL-NEXT:    br label [[EXIT]]
324; ALL:       exit:
325; ALL-NEXT:    [[PTR_TYPED:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16
326; ALL-NEXT:    [[RES_PHI:%.*]] = load i8, ptr [[PTR_TYPED]], align 1
327; ALL-NEXT:    store i8 1, ptr [[PTR_TYPED]], align 1
328; ALL-NEXT:    [[RES:%.*]] = select i1 [[COND2:%.*]], i8 [[RES_PHI]], i8 1
329; ALL-NEXT:    ret i8 [[RES]]
330;
331entry:
332  %obj = call ptr @get_ptr.i8()
333  br i1 %cond, label %bb1, label %bb2
334
335bb1:
336  %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16
337  %res1 = load i8, ptr %ptr1
338  br label %exit
339
340bb2:
341  %ptr2 = getelementptr inbounds i8, ptr %obj, i64 16
342  %res2 = load i8, ptr %ptr2
343  br label %exit
344
345exit:
346  %ptr.typed = phi ptr [ %ptr1, %bb1 ], [ %ptr2, %bb2 ]
347  %res.phi = phi i8 [ %res1, %bb1 ], [ %res2, %bb2 ]
348  store i8 1, ptr %ptr.typed
349  %res.load = load i8, ptr %ptr.typed
350  %res = select i1 %cond2, i8 %res.phi, i8 %res.load
351  ret i8 %res
352}
353
354define i32 @test_extra_uses(i1 %cond, i1 %cond2) {
355; ALL-LABEL: @test_extra_uses(
356; ALL-NEXT:  entry:
357; ALL-NEXT:    [[OBJ:%.*]] = call ptr @get_ptr.i8()
358; ALL-NEXT:    br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
359; ALL:       bb1:
360; ALL-NEXT:    [[PTR1:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16
361; ALL-NEXT:    [[RES1:%.*]] = load i32, ptr [[PTR1]], align 4
362; ALL-NEXT:    call void @foo.i32(ptr nonnull [[PTR1]])
363; ALL-NEXT:    br label [[EXIT:%.*]]
364; ALL:       bb2:
365; ALL-NEXT:    [[PTR2:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16
366; ALL-NEXT:    [[RES2:%.*]] = load i32, ptr [[PTR2]], align 4
367; ALL-NEXT:    call void @foo.i32(ptr nonnull [[PTR2]])
368; ALL-NEXT:    br label [[EXIT]]
369; ALL:       exit:
370; ALL-NEXT:    [[PTR_TYPED:%.*]] = phi ptr [ [[PTR1]], [[BB1]] ], [ [[PTR2]], [[BB2]] ]
371; ALL-NEXT:    [[RES_PHI:%.*]] = phi i32 [ [[RES1]], [[BB1]] ], [ [[RES2]], [[BB2]] ]
372; ALL-NEXT:    store i32 1, ptr [[PTR_TYPED]], align 4
373; ALL-NEXT:    [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1
374; ALL-NEXT:    ret i32 [[RES]]
375;
376entry:
377  %obj = call ptr @get_ptr.i8()
378  br i1 %cond, label %bb1, label %bb2
379
380bb1:
381  %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16
382  %res1 = load i32, ptr %ptr1
383  call void @foo.i32(ptr %ptr1)
384  br label %exit
385
386bb2:
387  %ptr2 = getelementptr inbounds i8, ptr %obj, i64 16
388  %res2 = load i32, ptr %ptr2
389  call void @foo.i32(ptr %ptr2)
390  br label %exit
391
392exit:
393  %ptr.typed = phi ptr [ %ptr1, %bb1 ], [ %ptr2, %bb2 ]
394  %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ]
395  store i32 1, ptr %ptr.typed
396  %res.load = load i32, ptr %ptr.typed
397  %res = select i1 %cond2, i32 %res.phi, i32 %res.load
398  ret i32 %res
399}
400
401define i32 @test_extra_uses_non_inbounds(i1 %cond, i1 %cond2) {
402; ALL-LABEL: @test_extra_uses_non_inbounds(
403; ALL-NEXT:  entry:
404; ALL-NEXT:    [[OBJ:%.*]] = call ptr @get_ptr.i8()
405; ALL-NEXT:    br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
406; ALL:       bb1:
407; ALL-NEXT:    [[PTR1:%.*]] = getelementptr i8, ptr [[OBJ]], i64 16
408; ALL-NEXT:    [[RES1:%.*]] = load i32, ptr [[PTR1]], align 4
409; ALL-NEXT:    call void @foo.i32(ptr nonnull [[PTR1]])
410; ALL-NEXT:    br label [[EXIT:%.*]]
411; ALL:       bb2:
412; ALL-NEXT:    [[PTR2:%.*]] = getelementptr i8, ptr [[OBJ]], i64 16
413; ALL-NEXT:    [[RES2:%.*]] = load i32, ptr [[PTR2]], align 4
414; ALL-NEXT:    call void @foo.i32(ptr nonnull [[PTR2]])
415; ALL-NEXT:    br label [[EXIT]]
416; ALL:       exit:
417; ALL-NEXT:    [[PTR_TYPED:%.*]] = phi ptr [ [[PTR1]], [[BB1]] ], [ [[PTR2]], [[BB2]] ]
418; ALL-NEXT:    [[RES_PHI:%.*]] = phi i32 [ [[RES1]], [[BB1]] ], [ [[RES2]], [[BB2]] ]
419; ALL-NEXT:    store i32 1, ptr [[PTR_TYPED]], align 4
420; ALL-NEXT:    [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1
421; ALL-NEXT:    ret i32 [[RES]]
422;
423entry:
424  %obj = call ptr @get_ptr.i8()
425  br i1 %cond, label %bb1, label %bb2
426
427bb1:
428  %ptr1 = getelementptr i8, ptr %obj, i64 16
429  %res1 = load i32, ptr %ptr1
430  call void @foo.i32(ptr %ptr1)
431  br label %exit
432
433bb2:
434  %ptr2 = getelementptr i8, ptr %obj, i64 16
435  %res2 = load i32, ptr %ptr2
436  call void @foo.i32(ptr %ptr2)
437  br label %exit
438
439exit:
440  %ptr.typed = phi ptr [ %ptr1, %bb1 ], [ %ptr2, %bb2 ]
441  %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ]
442  store i32 1, ptr %ptr.typed
443  %res.load = load i32, ptr %ptr.typed
444  %res = select i1 %cond2, i32 %res.phi, i32 %res.load
445  ret i32 %res
446}
447
448define i32 @test_extra_uses_multiple_geps(i1 %cond, i1 %cond2) {
449; ALL-LABEL: @test_extra_uses_multiple_geps(
450; ALL-NEXT:  entry:
451; ALL-NEXT:    [[OBJ:%.*]] = call ptr @get_ptr.i8()
452; ALL-NEXT:    br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
453; ALL:       bb1:
454; ALL-NEXT:    [[PTR1:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16
455; ALL-NEXT:    [[RES1:%.*]] = load i32, ptr [[PTR1]], align 4
456; ALL-NEXT:    call void @foo.i32(ptr nonnull [[PTR1]])
457; ALL-NEXT:    br label [[EXIT:%.*]]
458; ALL:       bb2:
459; ALL-NEXT:    [[PTR2_1:%.*]] = getelementptr i8, ptr [[OBJ]], i64 16
460; ALL-NEXT:    [[RES2:%.*]] = load i32, ptr [[PTR2_1]], align 4
461; ALL-NEXT:    call void @foo.i32(ptr nonnull [[PTR2_1]])
462; ALL-NEXT:    br label [[EXIT]]
463; ALL:       exit:
464; ALL-NEXT:    [[PTR_TYPED:%.*]] = phi ptr [ [[PTR1]], [[BB1]] ], [ [[PTR2_1]], [[BB2]] ]
465; ALL-NEXT:    [[RES_PHI:%.*]] = phi i32 [ [[RES1]], [[BB1]] ], [ [[RES2]], [[BB2]] ]
466; ALL-NEXT:    store i32 1, ptr [[PTR_TYPED]], align 4
467; ALL-NEXT:    [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1
468; ALL-NEXT:    ret i32 [[RES]]
469;
470entry:
471  %obj = call ptr @get_ptr.i8()
472  br i1 %cond, label %bb1, label %bb2
473
474bb1:
475  %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16
476  %res1 = load i32, ptr %ptr1
477  call void @foo.i32(ptr %ptr1)
478  br label %exit
479
480bb2:
481  %ptr2.0 = getelementptr i8, ptr %obj, i64 8
482  %ptr2.1 = getelementptr inbounds i8, ptr %ptr2.0, i64 8
483  %res2 = load i32, ptr %ptr2.1
484  call void @foo.i32(ptr %ptr2.1)
485  br label %exit
486
487exit:
488  %ptr.typed = phi ptr [ %ptr1, %bb1 ], [ %ptr2.1, %bb2 ]
489  %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ]
490  store i32 1, ptr %ptr.typed
491  %res.load = load i32, ptr %ptr.typed
492  %res = select i1 %cond2, i32 %res.phi, i32 %res.load
493  ret i32 %res
494}
495
496define i8 @test_gep_extra_uses(i1 %cond, i1 %cond2) {
497; ALL-LABEL: @test_gep_extra_uses(
498; ALL-NEXT:  entry:
499; ALL-NEXT:    [[OBJ:%.*]] = call ptr @get_ptr.i8()
500; ALL-NEXT:    br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
501; ALL:       bb1:
502; ALL-NEXT:    [[PTR1:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16
503; ALL-NEXT:    [[RES1:%.*]] = load i8, ptr [[PTR1]], align 1
504; ALL-NEXT:    call void @foo.i8(ptr nonnull [[PTR1]])
505; ALL-NEXT:    br label [[EXIT:%.*]]
506; ALL:       bb2:
507; ALL-NEXT:    [[PTR2:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16
508; ALL-NEXT:    [[RES2:%.*]] = load i8, ptr [[PTR2]], align 1
509; ALL-NEXT:    call void @foo.i8(ptr nonnull [[PTR2]])
510; ALL-NEXT:    br label [[EXIT]]
511; ALL:       exit:
512; ALL-NEXT:    [[PTR_TYPED:%.*]] = phi ptr [ [[PTR1]], [[BB1]] ], [ [[PTR2]], [[BB2]] ]
513; ALL-NEXT:    [[RES_PHI:%.*]] = phi i8 [ [[RES1]], [[BB1]] ], [ [[RES2]], [[BB2]] ]
514; ALL-NEXT:    store i8 1, ptr [[PTR_TYPED]], align 1
515; ALL-NEXT:    [[RES:%.*]] = select i1 [[COND2:%.*]], i8 [[RES_PHI]], i8 1
516; ALL-NEXT:    ret i8 [[RES]]
517;
518entry:
519  %obj = call ptr @get_ptr.i8()
520  br i1 %cond, label %bb1, label %bb2
521
522bb1:
523  %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16
524  %res1 = load i8, ptr %ptr1
525  call void @foo.i8(ptr %ptr1)
526  br label %exit
527
528bb2:
529  %ptr2 = getelementptr inbounds i8, ptr %obj, i64 16
530  %res2 = load i8, ptr %ptr2
531  call void @foo.i8(ptr %ptr2)
532  br label %exit
533
534exit:
535  %ptr.typed = phi ptr [ %ptr1, %bb1 ], [ %ptr2, %bb2 ]
536  %res.phi = phi i8 [ %res1, %bb1 ], [ %res2, %bb2 ]
537  store i8 1, ptr %ptr.typed
538  %res.load = load i8, ptr %ptr.typed
539  %res = select i1 %cond2, i8 %res.phi, i8 %res.load
540  ret i8 %res
541}
542
543; `swifterror` addresses are restricted to load and stores and call arguments.
544declare void @takeAddress(ptr swifterror)
545
546define ptr @test_dont_optimize_swifterror(i1 %cond, i1 %cond2, ptr %ptr) {
547; INSTCOMBINE-LABEL: @test_dont_optimize_swifterror(
548; INSTCOMBINE-NEXT:  entry:
549; INSTCOMBINE-NEXT:    [[OBJ:%.*]] = alloca swifterror ptr, align 8
550; INSTCOMBINE-NEXT:    [[OBJ2:%.*]] = alloca swifterror ptr, align 8
551; INSTCOMBINE-NEXT:    call void @takeAddress(ptr nonnull swifterror [[OBJ]])
552; INSTCOMBINE-NEXT:    call void @takeAddress(ptr nonnull swifterror [[OBJ2]])
553; INSTCOMBINE-NEXT:    store ptr [[PTR:%.*]], ptr [[OBJ]], align 8
554; INSTCOMBINE-NEXT:    br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
555; INSTCOMBINE:       bb1:
556; INSTCOMBINE-NEXT:    [[RES1:%.*]] = load ptr, ptr [[OBJ]], align 8
557; INSTCOMBINE-NEXT:    br label [[EXIT:%.*]]
558; INSTCOMBINE:       bb2:
559; INSTCOMBINE-NEXT:    [[RES2:%.*]] = load ptr, ptr [[OBJ2]], align 8
560; INSTCOMBINE-NEXT:    br label [[EXIT]]
561; INSTCOMBINE:       exit:
562; INSTCOMBINE-NEXT:    [[RES_PHI:%.*]] = phi ptr [ [[RES1]], [[BB1]] ], [ [[RES2]], [[BB2]] ]
563; INSTCOMBINE-NEXT:    store ptr null, ptr [[OBJ]], align 8
564; INSTCOMBINE-NEXT:    [[RES:%.*]] = select i1 [[COND2:%.*]], ptr [[RES_PHI]], ptr null
565; INSTCOMBINE-NEXT:    ret ptr [[RES]]
566;
567; INSTCOMBINEGVN-LABEL: @test_dont_optimize_swifterror(
568; INSTCOMBINEGVN-NEXT:  entry:
569; INSTCOMBINEGVN-NEXT:    [[OBJ:%.*]] = alloca swifterror ptr, align 8
570; INSTCOMBINEGVN-NEXT:    [[OBJ2:%.*]] = alloca swifterror ptr, align 8
571; INSTCOMBINEGVN-NEXT:    call void @takeAddress(ptr nonnull swifterror [[OBJ]])
572; INSTCOMBINEGVN-NEXT:    call void @takeAddress(ptr nonnull swifterror [[OBJ2]])
573; INSTCOMBINEGVN-NEXT:    store ptr [[PTR:%.*]], ptr [[OBJ]], align 8
574; INSTCOMBINEGVN-NEXT:    br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
575; INSTCOMBINEGVN:       bb1:
576; INSTCOMBINEGVN-NEXT:    br label [[EXIT:%.*]]
577; INSTCOMBINEGVN:       bb2:
578; INSTCOMBINEGVN-NEXT:    [[RES2:%.*]] = load ptr, ptr [[OBJ2]], align 8
579; INSTCOMBINEGVN-NEXT:    br label [[EXIT]]
580; INSTCOMBINEGVN:       exit:
581; INSTCOMBINEGVN-NEXT:    [[RES_PHI:%.*]] = phi ptr [ [[PTR]], [[BB1]] ], [ [[RES2]], [[BB2]] ]
582; INSTCOMBINEGVN-NEXT:    store ptr null, ptr [[OBJ]], align 8
583; INSTCOMBINEGVN-NEXT:    [[RES:%.*]] = select i1 [[COND2:%.*]], ptr [[RES_PHI]], ptr null
584; INSTCOMBINEGVN-NEXT:    ret ptr [[RES]]
585;
586entry:
587  %obj = alloca swifterror ptr, align 8
588  %obj2 = alloca swifterror ptr, align 8
589  call void @takeAddress(ptr swifterror %obj)
590  call void @takeAddress(ptr swifterror %obj2)
591  store ptr %ptr, ptr %obj, align 8
592  br i1 %cond, label %bb1, label %bb2
593
594bb1:                                              ; preds = %entry
595  %res1 = load ptr, ptr %obj, align 8
596  br label %exit
597
598bb2:                                              ; preds = %entry
599  %res2 = load ptr, ptr %obj2, align 8
600  br label %exit
601
602exit:                                             ; preds = %bb2, %bb1
603  %res.phi = phi ptr [ %res1, %bb1 ], [ %res2, %bb2 ]
604  store ptr null, ptr %obj, align 8
605  %res = select i1 %cond2, ptr %res.phi, ptr null
606  ret ptr %res
607}
608