1; RUN: opt -instcombine -S < %s | FileCheck %s
2
3target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
4target triple = "x86_64-unknown-linux-gnu"
5
6; If all the operands to a phi node are of the same operation, instcombine
7; will try to pull them through the phi node, combining them into a single
8; operation. Check that when it does this the combined operation has a merged
9; debug location.
10
11; Test folding of a binary operation.  Generated from source:
12
13; extern int foo(void);
14; extern int bar(void);
15;
16; int binop(int a, int b) {
17;   if(a)
18;     b -= foo();
19;   else
20;     b -= bar();
21;   return b;
22; }
23
24; CHECK: define i32 @binop
25; CHECK-LABEL: if.end:
26; CHECK: %[[PHI:.*]] = phi i32 [ %call, %if.then ], [ %call1, %if.else ]
27; CHECK: sub nsw i32 %b, %[[PHI]], !dbg [[binopMergedLoc:![0-9]+]]
28; CHECK: ret i32
29
30define i32 @binop(i32 %a, i32 %b) !dbg !6 {
31entry:
32  %tobool = icmp ne i32 %a, 0, !dbg !8
33  br i1 %tobool, label %if.then, label %if.else, !dbg !8
34
35if.then:                                          ; preds = %entry
36  %call = call i32 @foo(), !dbg !9
37  %sub = sub nsw i32 %b, %call, !dbg !10
38  br label %if.end, !dbg !11
39
40if.else:                                          ; preds = %entry
41  %call1 = call i32 @bar(), !dbg !12
42  %sub2 = sub nsw i32 %b, %call1, !dbg !13
43  br label %if.end
44
45if.end:                                           ; preds = %if.else, %if.then
46  %b.addr.0 = phi i32 [ %sub, %if.then ], [ %sub2, %if.else ]
47  ret i32 %b.addr.0, !dbg !14
48}
49
50; Test folding of a compare.  Generated from source (with editing to
51; common the zext):
52
53; extern int foo(void);
54; extern int bar(void);
55;
56; int cmp(int a, int b) {
57;   int r;
58;   if(a)
59;     r = foo() < b;
60;   else
61;     r = bar() < b;
62;   return r;
63; }
64
65; CHECK: define i32 @cmp
66; CHECK-LABEL: if.end:
67; CHECK: %[[PHI:.*]] = phi i32 [ %call, %if.then ], [ %call1, %if.else ]
68; CHECK: icmp slt i32 %[[PHI]], %b, !dbg [[cmpMergedLoc:![0-9]+]]
69; CHECK: ret i32
70
71define i32 @cmp(i32 %a, i32 %b) !dbg !15 {
72entry:
73  %tobool = icmp ne i32 %a, 0, !dbg !16
74  br i1 %tobool, label %if.then, label %if.else, !dbg !16
75
76if.then:                                          ; preds = %entry
77  %call = call i32 @foo(), !dbg !17
78  %cmp = icmp slt i32 %call, %b, !dbg !18
79  br label %if.end, !dbg !19
80
81if.else:                                          ; preds = %entry
82  %call1 = call i32 @bar(), !dbg !20
83  %cmp2 = icmp slt i32 %call1, %b, !dbg !21
84  br label %if.end
85
86if.end:                                           ; preds = %if.else, %if.then
87  %r.0 = phi i1 [ %cmp, %if.then ], [ %cmp2, %if.else ]
88  %conv = zext i1 %r.0 to i32
89  ret i32 %conv, !dbg !22
90}
91
92; Test folding of getelementptr.  Generated from source:
93
94; extern long long foo2(void);
95; extern long long bar2(void);
96;
97; int *gep(int a, int *b) {
98;   int *r;
99;   if(a)
100;     r = &b[foo2()];
101;   else
102;     r = &b[bar2()];
103;   return p;
104; }
105
106; CHECK: define i32* @gep
107; CHECK-LABEL: if.end:
108; CHECK: %[[PHI:.*]] = phi i64 [ %call, %if.then ], [ %call1, %if.else ]
109; CHECK: getelementptr inbounds i32, i32* %b, i64 %[[PHI]], !dbg [[gepMergedLoc:![0-9]+]]
110; CHECK: ret i32*
111
112define i32* @gep(i32 %a, i32* %b) !dbg !23 {
113entry:
114  %tobool = icmp ne i32 %a, 0, !dbg !24
115  br i1 %tobool, label %if.then, label %if.else, !dbg !24
116
117if.then:                                          ; preds = %entry
118  %call = call i64 @foo2(), !dbg !25
119  %arrayidx = getelementptr inbounds i32, i32* %b, i64 %call, !dbg !26
120  br label %if.end, !dbg !27
121
122if.else:                                          ; preds = %entry
123  %call1 = call i64 @bar2(), !dbg !28
124  %arrayidx2 = getelementptr inbounds i32, i32* %b, i64 %call1, !dbg !29
125  br label %if.end
126
127if.end:                                           ; preds = %if.else, %if.then
128  %r.0 = phi i32* [ %arrayidx, %if.then ], [ %arrayidx2, %if.else ]
129  ret i32* %r.0, !dbg !30
130}
131
132; Test folding of load.  Generated from source:
133
134; extern int *foo3(void);
135; extern int *bar3(void);
136;
137; int load(int a) {
138;   int r;
139;   if(a)
140;     r = *foo3();
141;   else
142;     r = *bar3();
143;   return r;
144; }
145
146; CHECK: define i32 @load
147; CHECK-LABEL: if.end:
148; CHECK: %[[PHI:.*]] = phi i32* [ %call, %if.then ], [ %call1, %if.else ]
149; CHECK: load i32, i32* %[[PHI]],{{.*}} !dbg [[loadMergedLoc:![0-9]+]]
150; CHECK: ret i32
151
152define i32 @load(i32 %a) !dbg !31 {
153entry:
154  %tobool = icmp ne i32 %a, 0, !dbg !32
155  br i1 %tobool, label %if.then, label %if.else, !dbg !32
156
157if.then:                                          ; preds = %entry
158  %call = call i32* @foo3(), !dbg !33
159  %0 = load i32, i32* %call, align 4, !dbg !34
160  br label %if.end, !dbg !35
161
162if.else:                                          ; preds = %entry
163  %call1 = call i32* @bar3(), !dbg !36
164  %1 = load i32, i32* %call1, align 4, !dbg !37
165  br label %if.end
166
167if.end:                                           ; preds = %if.else, %if.then
168  %r.0 = phi i32 [ %0, %if.then ], [ %1, %if.else ]
169  ret i32 %r.0, !dbg !38
170}
171
172; Test folding of a cast.  Generated from source:
173
174; extern int foo(void);
175; extern int bar(void);
176;
177; long long cast(int a) {
178;   long long r;
179;   if(a)
180;     r = foo();
181;   else
182;     r = bar();
183;   return r;
184; }
185
186; CHECK: define i64 @cast
187; CHECK-LABEL: if.end:
188; CHECK: %[[PHI:.*]] = phi i32 [ %call, %if.then ], [ %call1, %if.else ]
189; CHECK: sext i32 %[[PHI]] to i64, !dbg [[castMergedLoc:![0-9]+]]
190; CHECK: ret i64
191
192define i64 @cast(i32 %a) !dbg !39 {
193entry:
194  %tobool = icmp ne i32 %a, 0, !dbg !40
195  br i1 %tobool, label %if.then, label %if.else, !dbg !40
196
197if.then:                                          ; preds = %entry
198  %call = call i32 @foo(), !dbg !41
199  %conv = sext i32 %call to i64, !dbg !41
200  br label %if.end, !dbg !42
201
202if.else:                                          ; preds = %entry
203  %call1 = call i32 @bar(), !dbg !43
204  %conv2 = sext i32 %call1 to i64, !dbg !43
205  br label %if.end
206
207if.end:                                           ; preds = %if.else, %if.then
208  %r.0 = phi i64 [ %conv, %if.then ], [ %conv2, %if.else ]
209  ret i64 %r.0, !dbg !44
210}
211
212; Test folding of a binary op with a RHS constant.  Generated from source:
213
214; extern int foo(void);
215; extern int bar(void);
216;
217; int binop_const(int a) {
218;   int r;
219;   if(a)
220;     r = foo() - 5;
221;   else
222;     r = bar() - 5;
223;   return r;
224; }
225
226; CHECK: define i32 @binop_const
227; CHECK-LABEL: if.end:
228; CHECK: %[[PHI:.*]] = phi i32 [ %call, %if.then ], [ %call1, %if.else ]
229; CHECK: add nsw i32 %[[PHI]], -5, !dbg [[binopConstMergedLoc:![0-9]+]]
230; CHECK: ret i32
231
232define i32 @binop_const(i32 %a) !dbg !45 {
233entry:
234  %tobool = icmp ne i32 %a, 0, !dbg !46
235  br i1 %tobool, label %if.then, label %if.else, !dbg !46
236
237if.then:                                          ; preds = %entry
238  %call = call i32 @foo(), !dbg !47
239  %sub = sub nsw i32 %call, 5, !dbg !48
240  br label %if.end, !dbg !49
241
242if.else:                                          ; preds = %entry
243  %call1 = call i32 @bar(), !dbg !50
244  %sub2 = sub nsw i32 %call1, 5, !dbg !51
245  br label %if.end
246
247if.end:                                           ; preds = %if.else, %if.then
248  %r.0 = phi i32 [ %sub, %if.then ], [ %sub2, %if.else ]
249  ret i32 %r.0, !dbg !52
250}
251
252; Test folding of a compare with RHS constant.  Generated from source (with
253; editing to common the zext):
254
255; extern int foo(void);
256; extern int bar(void);
257;
258; int cmp_const(int a) {
259;   int r;
260;   if(a)
261;     r = foo() < 10;
262;   else
263;     r = bar() < 10;
264;   return r;
265; }
266
267; CHECK: define i32 @cmp_const
268; CHECK-LABEL: if.end:
269; CHECK: %[[PHI:.*]] = phi i32 [ %call, %if.then ], [ %call1, %if.else ]
270; CHECK: icmp slt i32 %[[PHI]], 10, !dbg [[cmpConstMergedLoc:![0-9]+]]
271; CHECK: ret i32
272
273define i32 @cmp_const(i32 %a) !dbg !53 {
274entry:
275  %tobool = icmp ne i32 %a, 0, !dbg !54
276  br i1 %tobool, label %if.then, label %if.else, !dbg !54
277
278if.then:                                          ; preds = %entry
279  %call = call i32 @foo(), !dbg !55
280  %cmp = icmp slt i32 %call, 10, !dbg !56
281  br label %if.end, !dbg !57
282
283if.else:                                          ; preds = %entry
284  %call1 = call i32 @bar(), !dbg !58
285  %cmp2 = icmp slt i32 %call1, 10, !dbg !59
286  br label %if.end
287
288if.end:                                           ; preds = %if.else, %if.then
289  %r.0 = phi i1 [ %cmp, %if.then ], [ %cmp2, %if.else ]
290  %conv = zext i1 %r.0 to i32
291  ret i32 %conv, !dbg !60
292}
293
294declare i32 @foo()
295declare i32 @bar()
296declare i64 @foo2()
297declare i64 @bar2()
298declare i32* @foo3()
299declare i32* @bar3()
300
301; CHECK: [[binopMergedLoc]] = !DILocation(line: 0
302; CHECK: [[cmpMergedLoc]] = !DILocation(line: 0
303; CHECK: [[gepMergedLoc]] = !DILocation(line: 0
304; CHECK: [[loadMergedLoc]] = !DILocation(line: 0
305; CHECK: [[castMergedLoc]] = !DILocation(line: 0
306; CHECK: [[binopConstMergedLoc]] = !DILocation(line: 0
307; CHECK: [[cmpConstMergedLoc]] = !DILocation(line: 0
308
309!llvm.dbg.cu = !{!0}
310!llvm.module.flags = !{!3, !4}
311
312!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "", isOptimized: false, runtimeVersion: 0, emissionKind: LineTablesOnly, enums: !2)
313!1 = !DIFile(filename: "test.c", directory: "")
314!2 = !{}
315!3 = !{i32 2, !"Dwarf Version", i32 4}
316!4 = !{i32 2, !"Debug Info Version", i32 3}
317!6 = distinct !DISubprogram(name: "binop", scope: !1, file: !1, line: 8, type: !7, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
318!7 = !DISubroutineType(types: !2)
319!8 = !DILocation(line: 9, column: 6, scope: !6)
320!9 = !DILocation(line: 10, column: 10, scope: !6)
321!10 = !DILocation(line: 10, column: 7, scope: !6)
322!11 = !DILocation(line: 10, column: 5, scope: !6)
323!12 = !DILocation(line: 12, column: 10, scope: !6)
324!13 = !DILocation(line: 12, column: 7, scope: !6)
325!14 = !DILocation(line: 13, column: 3, scope: !6)
326!15 = distinct !DISubprogram(name: "cmp", scope: !1, file: !1, line: 16, type: !7, isLocal: false, isDefinition: true, scopeLine: 16, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
327!16 = !DILocation(line: 18, column: 6, scope: !15)
328!17 = !DILocation(line: 19, column: 9, scope: !15)
329!18 = !DILocation(line: 19, column: 15, scope: !15)
330!19 = !DILocation(line: 19, column: 5, scope: !15)
331!20 = !DILocation(line: 21, column: 9, scope: !15)
332!21 = !DILocation(line: 21, column: 15, scope: !15)
333!22 = !DILocation(line: 22, column: 3, scope: !15)
334!23 = distinct !DISubprogram(name: "gep", scope: !1, file: !1, line: 25, type: !7, isLocal: false, isDefinition: true, scopeLine: 25, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
335!24 = !DILocation(line: 27, column: 6, scope: !23)
336!25 = !DILocation(line: 28, column: 12, scope: !23)
337!26 = !DILocation(line: 28, column: 10, scope: !23)
338!27 = !DILocation(line: 28, column: 5, scope: !23)
339!28 = !DILocation(line: 30, column: 12, scope: !23)
340!29 = !DILocation(line: 30, column: 10, scope: !23)
341!30 = !DILocation(line: 31, column: 3, scope: !23)
342!31 = distinct !DISubprogram(name: "load", scope: !1, file: !1, line: 34, type: !7, isLocal: false, isDefinition: true, scopeLine: 34, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
343!32 = !DILocation(line: 36, column: 6, scope: !31)
344!33 = !DILocation(line: 37, column: 10, scope: !31)
345!34 = !DILocation(line: 37, column: 9, scope: !31)
346!35 = !DILocation(line: 37, column: 5, scope: !31)
347!36 = !DILocation(line: 39, column: 10, scope: !31)
348!37 = !DILocation(line: 39, column: 9, scope: !31)
349!38 = !DILocation(line: 40, column: 3, scope: !31)
350!39 = distinct !DISubprogram(name: "cast", scope: !1, file: !1, line: 43, type: !7, isLocal: false, isDefinition: true, scopeLine: 43, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
351!40 = !DILocation(line: 45, column: 6, scope: !39)
352!41 = !DILocation(line: 46, column: 9, scope: !39)
353!42 = !DILocation(line: 46, column: 5, scope: !39)
354!43 = !DILocation(line: 48, column: 9, scope: !39)
355!44 = !DILocation(line: 49, column: 3, scope: !39)
356!45 = distinct !DISubprogram(name: "binop_const", scope: !1, file: !1, line: 52, type: !7, isLocal: false, isDefinition: true, scopeLine: 52, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
357!46 = !DILocation(line: 54, column: 6, scope: !45)
358!47 = !DILocation(line: 55, column: 9, scope: !45)
359!48 = !DILocation(line: 55, column: 15, scope: !45)
360!49 = !DILocation(line: 55, column: 5, scope: !45)
361!50 = !DILocation(line: 57, column: 9, scope: !45)
362!51 = !DILocation(line: 57, column: 15, scope: !45)
363!52 = !DILocation(line: 58, column: 3, scope: !45)
364!53 = distinct !DISubprogram(name: "cmp_const", scope: !1, file: !1, line: 61, type: !7, isLocal: false, isDefinition: true, scopeLine: 61, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
365!54 = !DILocation(line: 63, column: 6, scope: !53)
366!55 = !DILocation(line: 64, column: 9, scope: !53)
367!56 = !DILocation(line: 64, column: 15, scope: !53)
368!57 = !DILocation(line: 64, column: 5, scope: !53)
369!58 = !DILocation(line: 66, column: 9, scope: !53)
370!59 = !DILocation(line: 66, column: 15, scope: !53)
371!60 = !DILocation(line: 67, column: 3, scope: !53)
372