1 ; RUN: opt -instcombine -S < %s | FileCheck %s
3 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
4 target triple = "x86_64-unknown-linux-gnu"
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
11 ; Test folding of a binary operation. Generated from source:
13 ; extern int foo(void);
14 ; extern int bar(void);
16 ; int binop(int a, int b) {
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]+]]
30 define i32 @binop(i32 %a, i32 %b) !dbg !6 {
32 %tobool = icmp ne i32 %a, 0, !dbg !8
33 br i1 %tobool, label %if.then, label %if.else, !dbg !8
35 if.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
40 if.else: ; preds = %entry
41 %call1 = call i32 @bar(), !dbg !12
42 %sub2 = sub nsw i32 %b, %call1, !dbg !13
45 if.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
50 ; Test folding of a compare. Generated from source (with editing to
53 ; extern int foo(void);
54 ; extern int bar(void);
56 ; int cmp(int a, int b) {
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]+]]
71 define i32 @cmp(i32 %a, i32 %b) !dbg !15 {
73 %tobool = icmp ne i32 %a, 0, !dbg !16
74 br i1 %tobool, label %if.then, label %if.else, !dbg !16
76 if.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
81 if.else: ; preds = %entry
82 %call1 = call i32 @bar(), !dbg !20
83 %cmp2 = icmp slt i32 %call1, %b, !dbg !21
86 if.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
92 ; Test folding of getelementptr. Generated from source:
94 ; extern long long foo2(void);
95 ; extern long long bar2(void);
97 ; int *gep(int a, int *b) {
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]+]]
112 define i32* @gep(i32 %a, i32* %b) !dbg !23 {
114 %tobool = icmp ne i32 %a, 0, !dbg !24
115 br i1 %tobool, label %if.then, label %if.else, !dbg !24
117 if.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
122 if.else: ; preds = %entry
123 %call1 = call i64 @bar2(), !dbg !28
124 %arrayidx2 = getelementptr inbounds i32, i32* %b, i64 %call1, !dbg !29
127 if.end: ; preds = %if.else, %if.then
128 %r.0 = phi i32* [ %arrayidx, %if.then ], [ %arrayidx2, %if.else ]
129 ret i32* %r.0, !dbg !30
132 ; Test folding of load. Generated from source:
134 ; extern int *foo3(void);
135 ; extern int *bar3(void);
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]+]]
152 define i32 @load(i32 %a) !dbg !31 {
154 %tobool = icmp ne i32 %a, 0, !dbg !32
155 br i1 %tobool, label %if.then, label %if.else, !dbg !32
157 if.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
162 if.else: ; preds = %entry
163 %call1 = call i32* @bar3(), !dbg !36
164 %1 = load i32, i32* %call1, align 4, !dbg !37
167 if.end: ; preds = %if.else, %if.then
168 %r.0 = phi i32 [ %0, %if.then ], [ %1, %if.else ]
169 ret i32 %r.0, !dbg !38
172 ; Test folding of a cast. Generated from source:
174 ; extern int foo(void);
175 ; extern int bar(void);
177 ; long long cast(int a) {
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]+]]
192 define i64 @cast(i32 %a) !dbg !39 {
194 %tobool = icmp ne i32 %a, 0, !dbg !40
195 br i1 %tobool, label %if.then, label %if.else, !dbg !40
197 if.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
202 if.else: ; preds = %entry
203 %call1 = call i32 @bar(), !dbg !43
204 %conv2 = sext i32 %call1 to i64, !dbg !43
207 if.end: ; preds = %if.else, %if.then
208 %r.0 = phi i64 [ %conv, %if.then ], [ %conv2, %if.else ]
209 ret i64 %r.0, !dbg !44
212 ; Test folding of a binary op with a RHS constant. Generated from source:
214 ; extern int foo(void);
215 ; extern int bar(void);
217 ; int binop_const(int a) {
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]+]]
232 define i32 @binop_const(i32 %a) !dbg !45 {
234 %tobool = icmp ne i32 %a, 0, !dbg !46
235 br i1 %tobool, label %if.then, label %if.else, !dbg !46
237 if.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
242 if.else: ; preds = %entry
243 %call1 = call i32 @bar(), !dbg !50
244 %sub2 = sub nsw i32 %call1, 5, !dbg !51
247 if.end: ; preds = %if.else, %if.then
248 %r.0 = phi i32 [ %sub, %if.then ], [ %sub2, %if.else ]
249 ret i32 %r.0, !dbg !52
252 ; Test folding of a compare with RHS constant. Generated from source (with
253 ; editing to common the zext):
255 ; extern int foo(void);
256 ; extern int bar(void);
258 ; int cmp_const(int a) {
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]+]]
273 define i32 @cmp_const(i32 %a) !dbg !53 {
275 %tobool = icmp ne i32 %a, 0, !dbg !54
276 br i1 %tobool, label %if.then, label %if.else, !dbg !54
278 if.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
283 if.else: ; preds = %entry
284 %call1 = call i32 @bar(), !dbg !58
285 %cmp2 = icmp slt i32 %call1, 10, !dbg !59
288 if.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
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
310 !llvm.module.flags = !{!3, !4}
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: "")
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)