123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371 |
- ; RUN: opt -instcombine -S < %s | FileCheck %s
- target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
- target triple = "x86_64-unknown-linux-gnu"
- ; If all the operands to a phi node are of the same operation, instcombine
- ; will try to pull them through the phi node, combining them into a single
- ; operation. Check that when it does this the combined operation has a merged
- ; debug location.
- ; Test folding of a binary operation. Generated from source:
- ; extern int foo(void);
- ; extern int bar(void);
- ;
- ; int binop(int a, int b) {
- ; if(a)
- ; b -= foo();
- ; else
- ; b -= bar();
- ; return b;
- ; }
- ; CHECK: define i32 @binop
- ; CHECK-LABEL: if.end:
- ; CHECK: %[[PHI:.*]] = phi i32 [ %call, %if.then ], [ %call1, %if.else ]
- ; CHECK: sub nsw i32 %b, %[[PHI]], !dbg [[binopMergedLoc:![0-9]+]]
- ; CHECK: ret i32
- define i32 @binop(i32 %a, i32 %b) !dbg !6 {
- entry:
- %tobool = icmp ne i32 %a, 0, !dbg !8
- br i1 %tobool, label %if.then, label %if.else, !dbg !8
- if.then: ; preds = %entry
- %call = call i32 @foo(), !dbg !9
- %sub = sub nsw i32 %b, %call, !dbg !10
- br label %if.end, !dbg !11
- if.else: ; preds = %entry
- %call1 = call i32 @bar(), !dbg !12
- %sub2 = sub nsw i32 %b, %call1, !dbg !13
- br label %if.end
- if.end: ; preds = %if.else, %if.then
- %b.addr.0 = phi i32 [ %sub, %if.then ], [ %sub2, %if.else ]
- ret i32 %b.addr.0, !dbg !14
- }
- ; Test folding of a compare. Generated from source (with editing to
- ; common the zext):
- ; extern int foo(void);
- ; extern int bar(void);
- ;
- ; int cmp(int a, int b) {
- ; int r;
- ; if(a)
- ; r = foo() < b;
- ; else
- ; r = bar() < b;
- ; return r;
- ; }
- ; CHECK: define i32 @cmp
- ; CHECK-LABEL: if.end:
- ; CHECK: %[[PHI:.*]] = phi i32 [ %call, %if.then ], [ %call1, %if.else ]
- ; CHECK: icmp slt i32 %[[PHI]], %b, !dbg [[cmpMergedLoc:![0-9]+]]
- ; CHECK: ret i32
- define i32 @cmp(i32 %a, i32 %b) !dbg !15 {
- entry:
- %tobool = icmp ne i32 %a, 0, !dbg !16
- br i1 %tobool, label %if.then, label %if.else, !dbg !16
- if.then: ; preds = %entry
- %call = call i32 @foo(), !dbg !17
- %cmp = icmp slt i32 %call, %b, !dbg !18
- br label %if.end, !dbg !19
- if.else: ; preds = %entry
- %call1 = call i32 @bar(), !dbg !20
- %cmp2 = icmp slt i32 %call1, %b, !dbg !21
- br label %if.end
- if.end: ; preds = %if.else, %if.then
- %r.0 = phi i1 [ %cmp, %if.then ], [ %cmp2, %if.else ]
- %conv = zext i1 %r.0 to i32
- ret i32 %conv, !dbg !22
- }
- ; Test folding of getelementptr. Generated from source:
- ; extern long long foo2(void);
- ; extern long long bar2(void);
- ;
- ; int *gep(int a, int *b) {
- ; int *r;
- ; if(a)
- ; r = &b[foo2()];
- ; else
- ; r = &b[bar2()];
- ; return p;
- ; }
- ; CHECK: define i32* @gep
- ; CHECK-LABEL: if.end:
- ; CHECK: %[[PHI:.*]] = phi i64 [ %call, %if.then ], [ %call1, %if.else ]
- ; CHECK: getelementptr inbounds i32, i32* %b, i64 %[[PHI]], !dbg [[gepMergedLoc:![0-9]+]]
- ; CHECK: ret i32*
- define i32* @gep(i32 %a, i32* %b) !dbg !23 {
- entry:
- %tobool = icmp ne i32 %a, 0, !dbg !24
- br i1 %tobool, label %if.then, label %if.else, !dbg !24
- if.then: ; preds = %entry
- %call = call i64 @foo2(), !dbg !25
- %arrayidx = getelementptr inbounds i32, i32* %b, i64 %call, !dbg !26
- br label %if.end, !dbg !27
- if.else: ; preds = %entry
- %call1 = call i64 @bar2(), !dbg !28
- %arrayidx2 = getelementptr inbounds i32, i32* %b, i64 %call1, !dbg !29
- br label %if.end
- if.end: ; preds = %if.else, %if.then
- %r.0 = phi i32* [ %arrayidx, %if.then ], [ %arrayidx2, %if.else ]
- ret i32* %r.0, !dbg !30
- }
- ; Test folding of load. Generated from source:
- ; extern int *foo3(void);
- ; extern int *bar3(void);
- ;
- ; int load(int a) {
- ; int r;
- ; if(a)
- ; r = *foo3();
- ; else
- ; r = *bar3();
- ; return r;
- ; }
- ; CHECK: define i32 @load
- ; CHECK-LABEL: if.end:
- ; CHECK: %[[PHI:.*]] = phi i32* [ %call, %if.then ], [ %call1, %if.else ]
- ; CHECK: load i32, i32* %[[PHI]],{{.*}} !dbg [[loadMergedLoc:![0-9]+]]
- ; CHECK: ret i32
- define i32 @load(i32 %a) !dbg !31 {
- entry:
- %tobool = icmp ne i32 %a, 0, !dbg !32
- br i1 %tobool, label %if.then, label %if.else, !dbg !32
- if.then: ; preds = %entry
- %call = call i32* @foo3(), !dbg !33
- %0 = load i32, i32* %call, align 4, !dbg !34
- br label %if.end, !dbg !35
- if.else: ; preds = %entry
- %call1 = call i32* @bar3(), !dbg !36
- %1 = load i32, i32* %call1, align 4, !dbg !37
- br label %if.end
- if.end: ; preds = %if.else, %if.then
- %r.0 = phi i32 [ %0, %if.then ], [ %1, %if.else ]
- ret i32 %r.0, !dbg !38
- }
- ; Test folding of a cast. Generated from source:
- ; extern int foo(void);
- ; extern int bar(void);
- ;
- ; long long cast(int a) {
- ; long long r;
- ; if(a)
- ; r = foo();
- ; else
- ; r = bar();
- ; return r;
- ; }
- ; CHECK: define i64 @cast
- ; CHECK-LABEL: if.end:
- ; CHECK: %[[PHI:.*]] = phi i32 [ %call, %if.then ], [ %call1, %if.else ]
- ; CHECK: sext i32 %[[PHI]] to i64, !dbg [[castMergedLoc:![0-9]+]]
- ; CHECK: ret i64
- define i64 @cast(i32 %a) !dbg !39 {
- entry:
- %tobool = icmp ne i32 %a, 0, !dbg !40
- br i1 %tobool, label %if.then, label %if.else, !dbg !40
- if.then: ; preds = %entry
- %call = call i32 @foo(), !dbg !41
- %conv = sext i32 %call to i64, !dbg !41
- br label %if.end, !dbg !42
- if.else: ; preds = %entry
- %call1 = call i32 @bar(), !dbg !43
- %conv2 = sext i32 %call1 to i64, !dbg !43
- br label %if.end
- if.end: ; preds = %if.else, %if.then
- %r.0 = phi i64 [ %conv, %if.then ], [ %conv2, %if.else ]
- ret i64 %r.0, !dbg !44
- }
- ; Test folding of a binary op with a RHS constant. Generated from source:
- ; extern int foo(void);
- ; extern int bar(void);
- ;
- ; int binop_const(int a) {
- ; int r;
- ; if(a)
- ; r = foo() - 5;
- ; else
- ; r = bar() - 5;
- ; return r;
- ; }
- ; CHECK: define i32 @binop_const
- ; CHECK-LABEL: if.end:
- ; CHECK: %[[PHI:.*]] = phi i32 [ %call, %if.then ], [ %call1, %if.else ]
- ; CHECK: add nsw i32 %[[PHI]], -5, !dbg [[binopConstMergedLoc:![0-9]+]]
- ; CHECK: ret i32
- define i32 @binop_const(i32 %a) !dbg !45 {
- entry:
- %tobool = icmp ne i32 %a, 0, !dbg !46
- br i1 %tobool, label %if.then, label %if.else, !dbg !46
- if.then: ; preds = %entry
- %call = call i32 @foo(), !dbg !47
- %sub = sub nsw i32 %call, 5, !dbg !48
- br label %if.end, !dbg !49
- if.else: ; preds = %entry
- %call1 = call i32 @bar(), !dbg !50
- %sub2 = sub nsw i32 %call1, 5, !dbg !51
- br label %if.end
- if.end: ; preds = %if.else, %if.then
- %r.0 = phi i32 [ %sub, %if.then ], [ %sub2, %if.else ]
- ret i32 %r.0, !dbg !52
- }
- ; Test folding of a compare with RHS constant. Generated from source (with
- ; editing to common the zext):
- ; extern int foo(void);
- ; extern int bar(void);
- ;
- ; int cmp_const(int a) {
- ; int r;
- ; if(a)
- ; r = foo() < 10;
- ; else
- ; r = bar() < 10;
- ; return r;
- ; }
- ; CHECK: define i32 @cmp_const
- ; CHECK-LABEL: if.end:
- ; CHECK: %[[PHI:.*]] = phi i32 [ %call, %if.then ], [ %call1, %if.else ]
- ; CHECK: icmp slt i32 %[[PHI]], 10, !dbg [[cmpConstMergedLoc:![0-9]+]]
- ; CHECK: ret i32
- define i32 @cmp_const(i32 %a) !dbg !53 {
- entry:
- %tobool = icmp ne i32 %a, 0, !dbg !54
- br i1 %tobool, label %if.then, label %if.else, !dbg !54
- if.then: ; preds = %entry
- %call = call i32 @foo(), !dbg !55
- %cmp = icmp slt i32 %call, 10, !dbg !56
- br label %if.end, !dbg !57
- if.else: ; preds = %entry
- %call1 = call i32 @bar(), !dbg !58
- %cmp2 = icmp slt i32 %call1, 10, !dbg !59
- br label %if.end
- if.end: ; preds = %if.else, %if.then
- %r.0 = phi i1 [ %cmp, %if.then ], [ %cmp2, %if.else ]
- %conv = zext i1 %r.0 to i32
- ret i32 %conv, !dbg !60
- }
- declare i32 @foo()
- declare i32 @bar()
- declare i64 @foo2()
- declare i64 @bar2()
- declare i32* @foo3()
- declare i32* @bar3()
- ; CHECK: [[binopMergedLoc]] = !DILocation(line: 0
- ; CHECK: [[cmpMergedLoc]] = !DILocation(line: 0
- ; CHECK: [[gepMergedLoc]] = !DILocation(line: 0
- ; CHECK: [[loadMergedLoc]] = !DILocation(line: 0
- ; CHECK: [[castMergedLoc]] = !DILocation(line: 0
- ; CHECK: [[binopConstMergedLoc]] = !DILocation(line: 0
- ; CHECK: [[cmpConstMergedLoc]] = !DILocation(line: 0
- !llvm.dbg.cu = !{!0}
- !llvm.module.flags = !{!3, !4}
- !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "", isOptimized: false, runtimeVersion: 0, emissionKind: LineTablesOnly, enums: !2)
- !1 = !DIFile(filename: "test.c", directory: "")
- !2 = !{}
- !3 = !{i32 2, !"Dwarf Version", i32 4}
- !4 = !{i32 2, !"Debug Info Version", i32 3}
- !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)
- !7 = !DISubroutineType(types: !2)
- !8 = !DILocation(line: 9, column: 6, scope: !6)
- !9 = !DILocation(line: 10, column: 10, scope: !6)
- !10 = !DILocation(line: 10, column: 7, scope: !6)
- !11 = !DILocation(line: 10, column: 5, scope: !6)
- !12 = !DILocation(line: 12, column: 10, scope: !6)
- !13 = !DILocation(line: 12, column: 7, scope: !6)
- !14 = !DILocation(line: 13, column: 3, scope: !6)
- !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)
- !16 = !DILocation(line: 18, column: 6, scope: !15)
- !17 = !DILocation(line: 19, column: 9, scope: !15)
- !18 = !DILocation(line: 19, column: 15, scope: !15)
- !19 = !DILocation(line: 19, column: 5, scope: !15)
- !20 = !DILocation(line: 21, column: 9, scope: !15)
- !21 = !DILocation(line: 21, column: 15, scope: !15)
- !22 = !DILocation(line: 22, column: 3, scope: !15)
- !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)
- !24 = !DILocation(line: 27, column: 6, scope: !23)
- !25 = !DILocation(line: 28, column: 12, scope: !23)
- !26 = !DILocation(line: 28, column: 10, scope: !23)
- !27 = !DILocation(line: 28, column: 5, scope: !23)
- !28 = !DILocation(line: 30, column: 12, scope: !23)
- !29 = !DILocation(line: 30, column: 10, scope: !23)
- !30 = !DILocation(line: 31, column: 3, scope: !23)
- !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)
- !32 = !DILocation(line: 36, column: 6, scope: !31)
- !33 = !DILocation(line: 37, column: 10, scope: !31)
- !34 = !DILocation(line: 37, column: 9, scope: !31)
- !35 = !DILocation(line: 37, column: 5, scope: !31)
- !36 = !DILocation(line: 39, column: 10, scope: !31)
- !37 = !DILocation(line: 39, column: 9, scope: !31)
- !38 = !DILocation(line: 40, column: 3, scope: !31)
- !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)
- !40 = !DILocation(line: 45, column: 6, scope: !39)
- !41 = !DILocation(line: 46, column: 9, scope: !39)
- !42 = !DILocation(line: 46, column: 5, scope: !39)
- !43 = !DILocation(line: 48, column: 9, scope: !39)
- !44 = !DILocation(line: 49, column: 3, scope: !39)
- !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)
- !46 = !DILocation(line: 54, column: 6, scope: !45)
- !47 = !DILocation(line: 55, column: 9, scope: !45)
- !48 = !DILocation(line: 55, column: 15, scope: !45)
- !49 = !DILocation(line: 55, column: 5, scope: !45)
- !50 = !DILocation(line: 57, column: 9, scope: !45)
- !51 = !DILocation(line: 57, column: 15, scope: !45)
- !52 = !DILocation(line: 58, column: 3, scope: !45)
- !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)
- !54 = !DILocation(line: 63, column: 6, scope: !53)
- !55 = !DILocation(line: 64, column: 9, scope: !53)
- !56 = !DILocation(line: 64, column: 15, scope: !53)
- !57 = !DILocation(line: 64, column: 5, scope: !53)
- !58 = !DILocation(line: 66, column: 9, scope: !53)
- !59 = !DILocation(line: 66, column: 15, scope: !53)
- !60 = !DILocation(line: 67, column: 3, scope: !53)
|