Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -52,6 +52,7 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/CFG.h" +#include "llvm/IR/DIBuilder.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/GetElementPtrTypeIterator.h" @@ -2057,8 +2058,6 @@ return false; LLVM_FALLTHROUGH; } - case Intrinsic::dbg_declare: - case Intrinsic::dbg_value: case Intrinsic::invariant_start: case Intrinsic::invariant_end: case Intrinsic::lifetime_start: @@ -2094,6 +2093,16 @@ // to null and free calls, delete the calls and replace the comparisons with // true or false as appropriate. SmallVector Users; + + // If we are removing a local variable, insert dbg.value calls before each + // store. + DbgDeclareInst *DDI = nullptr; + std::unique_ptr DIB; + if (isa(MI)) { + DDI = FindAllocaDbgDeclare(&MI); + DIB.reset(new DIBuilder(*MI.getModule(), /*AllowUnresolved=*/false)); + } + if (isAllocSiteRemovable(&MI, Users, &TLI)) { for (unsigned i = 0, e = Users.size(); i != e; ++i) { // Lowering all @llvm.objectsize calls first because they may @@ -2126,6 +2135,8 @@ } else if (isa(I) || isa(I) || isa(I)) { replaceInstUsesWith(*I, UndefValue::get(I->getType())); + } else if (DDI && isa(I)) { + ConvertDebugDeclareToDebugValue(DDI, cast(I), *DIB); } eraseInstFromFunction(*I); } @@ -2137,6 +2148,10 @@ InvokeInst::Create(F, II->getNormalDest(), II->getUnwindDest(), None, "", II->getParent()); } + + if (DDI) + eraseInstFromFunction(*DDI); + return eraseInstFromFunction(MI); } return nullptr; @@ -3189,12 +3204,9 @@ AC.registerAssumption(cast(I)); })); - // Lower dbg.declare intrinsics otherwise their value may be clobbered - // by instcombiner. - bool MadeIRChange = LowerDbgDeclare(F); - // Iterate while there is work to do. int Iteration = 0; + bool MadeIRChange = false; for (;;) { ++Iteration; DEBUG(dbgs() << "\n\nINSTCOMBINE ITERATION #" << Iteration << " on " Index: llvm/test/DebugInfo/X86/formal_parameter.ll =================================================================== --- llvm/test/DebugInfo/X86/formal_parameter.ll +++ llvm/test/DebugInfo/X86/formal_parameter.ll @@ -13,7 +13,6 @@ ; } ; ; RUN: opt %s -O2 -S -o %t -; RUN: cat %t | FileCheck --check-prefix=LOWERING %s ; RUN: llc -filetype=obj %t -o - | llvm-dwarfdump -debug-dump=info - | FileCheck %s ; Test that we only emit only one DW_AT_formal_parameter "map" for this function. ; rdar://problem/14874886 @@ -30,12 +29,6 @@ store i32 %map, i32* %map.addr, align 4, !tbaa !15 call void @llvm.dbg.declare(metadata i32* %map.addr, metadata !10, metadata !DIExpression()), !dbg !14 %call = call i32 (i32*, ...) bitcast (i32 (...)* @lookup to i32 (i32*, ...)*)(i32* %map.addr) #3, !dbg !19 - ; Ensure that all dbg intrinsics have the same scope after - ; LowerDbgDeclare is finished with them. - ; - ; LOWERING: call void @llvm.dbg.value{{.*}}, !dbg ![[LOC:.*]] - ; LOWERING: call void @llvm.dbg.value{{.*}}, !dbg ![[LOC]] - ; LOWERING: call void @llvm.dbg.value{{.*}}, !dbg ![[LOC]] %0 = load i32, i32* %map.addr, align 4, !dbg !20, !tbaa !15 %call1 = call i32 (i32, ...) bitcast (i32 (...)* @verify to i32 (i32, ...)*)(i32 %0) #3, !dbg !20 ret void, !dbg !22 Index: llvm/test/DebugInfo/X86/instcombine-instrinsics.ll =================================================================== --- llvm/test/DebugInfo/X86/instcombine-instrinsics.ll +++ /dev/null @@ -1,78 +0,0 @@ -; RUN: opt %s -O2 -S -o - | FileCheck %s -; Verify that we emit the same intrinsic at most once. -; rdar://problem/13056109 -; -; CHECK: call void @llvm.dbg.value(metadata %struct.i14** %p -; CHECK-NOT: call void @llvm.dbg.value(metadata %struct.i14** %p -; CHECK-NEXT: call i32 @foo -; CHECK: ret -; -; -; typedef struct { -; long i; -; } i14; -; -; int foo(i14**); -; -; void init() { -; i14* p = 0; -; foo(&p); -; p->i |= 4; -; foo(&p); -; } -; -; ModuleID = 'instcombine_intrinsics.c' -target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-apple-macosx10.9.0" - -%struct.i14 = type { i64 } - -; Function Attrs: nounwind ssp uwtable -define void @init() #0 !dbg !4 { - %p = alloca %struct.i14*, align 8 - call void @llvm.dbg.declare(metadata %struct.i14** %p, metadata !11, metadata !DIExpression()), !dbg !18 - store %struct.i14* null, %struct.i14** %p, align 8, !dbg !18 - %1 = call i32 @foo(%struct.i14** %p), !dbg !19 - %2 = load %struct.i14*, %struct.i14** %p, align 8, !dbg !20 - %3 = getelementptr inbounds %struct.i14, %struct.i14* %2, i32 0, i32 0, !dbg !20 - %4 = load i64, i64* %3, align 8, !dbg !20 - %5 = or i64 %4, 4, !dbg !20 - store i64 %5, i64* %3, align 8, !dbg !20 - %6 = call i32 @foo(%struct.i14** %p), !dbg !21 - ret void, !dbg !22 -} - -; Function Attrs: nounwind readnone -declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 - -declare i32 @foo(%struct.i14**) - -attributes #0 = { nounwind ssp uwtable } -attributes #1 = { nounwind readnone } - -!llvm.dbg.cu = !{!0} -!llvm.module.flags = !{!8, !9} -!llvm.ident = !{!10} - -!0 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.5.0 ", isOptimized: false, emissionKind: FullDebug, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2) -!1 = !DIFile(filename: "instcombine_intrinsics.c", directory: "") -!2 = !{} -!4 = distinct !DISubprogram(name: "init", line: 7, isLocal: false, isDefinition: true, virtualIndex: 6, isOptimized: false, unit: !0, scopeLine: 7, file: !1, scope: !5, type: !6, variables: !2) -!5 = !DIFile(filename: "instcombine_intrinsics.c", directory: "") -!6 = !DISubroutineType(types: !7) -!7 = !{null} -!8 = !{i32 2, !"Dwarf Version", i32 2} -!9 = !{i32 1, !"Debug Info Version", i32 3} -!10 = !{!"clang version 3.5.0 "} -!11 = !DILocalVariable(name: "p", line: 8, scope: !4, file: !5, type: !12) -!12 = !DIDerivedType(tag: DW_TAG_pointer_type, size: 64, align: 64, baseType: !13) -!13 = !DIDerivedType(tag: DW_TAG_typedef, name: "i14", line: 3, file: !1, baseType: !14) -!14 = !DICompositeType(tag: DW_TAG_structure_type, line: 1, size: 64, align: 64, file: !1, elements: !15) -!15 = !{!16} -!16 = !DIDerivedType(tag: DW_TAG_member, name: "i", line: 2, size: 64, align: 64, file: !1, scope: !14, baseType: !17) -!17 = !DIBasicType(tag: DW_TAG_base_type, name: "long int", size: 64, align: 64, encoding: DW_ATE_signed) -!18 = !DILocation(line: 8, scope: !4) -!19 = !DILocation(line: 9, scope: !4) -!20 = !DILocation(line: 10, scope: !4) -!21 = !DILocation(line: 11, scope: !4) -!22 = !DILocation(line: 12, scope: !4) Index: llvm/test/Transforms/InstCombine/debuginfo-skip.ll =================================================================== --- llvm/test/Transforms/InstCombine/debuginfo-skip.ll +++ llvm/test/Transforms/InstCombine/debuginfo-skip.ll @@ -1,12 +1,4 @@ -; RUN: opt < %s -instcombine -debug -S -o %t 2>&1 | FileCheck %s -; RUN: cat %t | FileCheck %s --check-prefix=CHECK-IR -; REQUIRES: asserts - -; Debug output from InstCombine should not have any @llvm.dbg.* instructions visited -; CHECK-NOT: call void @llvm.dbg. - -; The resulting IR should still have them -; CHECK-IR: call void @llvm.dbg. +; RUN: opt < %s -instcombine -S | FileCheck %s define i32 @foo(i32 %j) #0 !dbg !7 { entry: @@ -18,6 +10,14 @@ ret i32 %0, !dbg !15 } +; Instcombine can remove the alloca and forward the load to store, but it +; should convert the declare to dbg value. +; CHECK-LABEL: define i32 @foo(i32 %j) +; CHECK-NOT: alloca +; CHECK: call void @llvm.dbg.value(metadata i32 %j, {{.*}}) +; CHECK: call void @llvm.dbg.value(metadata i32 10, {{.*}}) +; CHECK: ret i32 %j + declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 declare void @llvm.dbg.value(metadata, metadata, metadata) #1 Index: llvm/test/Transforms/InstCombine/debuginfo.ll =================================================================== --- llvm/test/Transforms/InstCombine/debuginfo.ll +++ llvm/test/Transforms/InstCombine/debuginfo.ll @@ -1,48 +1,92 @@ ; RUN: opt < %s -instcombine -S | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64--linux" + +%struct.TwoRegs = type { i64, i64 } + declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone declare i64 @llvm.objectsize.i64.p0i8(i8*, i1) nounwind readnone -declare i8* @foo(i8*, i32, i64, i64) nounwind +declare i8* @passthru_callee(i8*, i32, i64, i64) -define hidden i8* @foobar(i8* %__dest, i32 %__val, i64 %__len) nounwind inlinehint ssp !dbg !1 { +define i8* @passthru(i8* %a, i32 %b, i64 %c) !dbg !1 { entry: - %__dest.addr = alloca i8*, align 8 - %__val.addr = alloca i32, align 4 - %__len.addr = alloca i64, align 8 - store i8* %__dest, i8** %__dest.addr, align 8 -; CHECK-NOT: call void @llvm.dbg.declare -; CHECK: call void @llvm.dbg.value - call void @llvm.dbg.declare(metadata i8** %__dest.addr, metadata !0, metadata !DIExpression()), !dbg !16 - store i32 %__val, i32* %__val.addr, align 4 - call void @llvm.dbg.declare(metadata i32* %__val.addr, metadata !7, metadata !DIExpression()), !dbg !18 - store i64 %__len, i64* %__len.addr, align 8 - call void @llvm.dbg.declare(metadata i64* %__len.addr, metadata !9, metadata !DIExpression()), !dbg !20 - %tmp = load i8*, i8** %__dest.addr, align 8, !dbg !21 - %tmp1 = load i32, i32* %__val.addr, align 4, !dbg !21 - %tmp2 = load i64, i64* %__len.addr, align 8, !dbg !21 - %tmp3 = load i8*, i8** %__dest.addr, align 8, !dbg !21 + %a.addr = alloca i8*, align 8 + %b.addr = alloca i32, align 4 + %c.addr = alloca i64, align 8 + store i8* %a, i8** %a.addr, align 8 + call void @llvm.dbg.declare(metadata i8** %a.addr, metadata !0, metadata !DIExpression()), !dbg !16 + store i32 %b, i32* %b.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !7, metadata !DIExpression()), !dbg !18 + store i64 %c, i64* %c.addr, align 8 + call void @llvm.dbg.declare(metadata i64* %c.addr, metadata !9, metadata !DIExpression()), !dbg !20 + %tmp = load i8*, i8** %a.addr, align 8, !dbg !21 + %tmp1 = load i32, i32* %b.addr, align 4, !dbg !21 + %tmp2 = load i64, i64* %c.addr, align 8, !dbg !21 + %tmp3 = load i8*, i8** %a.addr, align 8, !dbg !21 %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %tmp3, i1 false), !dbg !21 - %call = call i8* @foo(i8* %tmp, i32 %tmp1, i64 %tmp2, i64 %0), !dbg !21 + %call = call i8* @passthru_callee(i8* %tmp, i32 %tmp1, i64 %tmp2, i64 %0), !dbg !21 ret i8* %call, !dbg !21 } +; CHECK-LABEL: define i8* @passthru(i8* %a, i32 %b, i64 %c) +; CHECK-NOT: alloca +; CHECK-NOT: store +; CHECK-NOT: call void @llvm.dbg.declare +; CHECK: call void @llvm.dbg.value(metadata i8* %a, {{.*}}) +; CHECK-NOT: store +; CHECK: call void @llvm.dbg.value(metadata i32 %b, {{.*}}) +; CHECK-NOT: store +; CHECK: call void @llvm.dbg.value(metadata i64 %c, {{.*}}) +; CHECK-NOT: store +; CHECK: call i8* @passthru_callee(i8* %a, i32 %b, i64 %c, i64 %{{.*}}) + +declare void @tworegs_callee(i64, i64) + +define void @tworegs(i64 %o.coerce0, i64 %o.coerce1) !dbg !31 { +entry: + %o = alloca %struct.TwoRegs, align 8 + %0 = bitcast %struct.TwoRegs* %o to { i64, i64 }* + %1 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %0, i32 0, i32 0 + store i64 %o.coerce0, i64* %1, align 8 + %2 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %0, i32 0, i32 1 + store i64 %o.coerce1, i64* %2, align 8 + call void @llvm.dbg.declare(metadata %struct.TwoRegs* %o, metadata !35, metadata !DIExpression()), !dbg !32 + %3 = bitcast %struct.TwoRegs* %o to { i64, i64 }*, !dbg !33 + %4 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %3, i32 0, i32 0, !dbg !33 + %5 = load i64, i64* %4, align 8, !dbg !33 + %6 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %3, i32 0, i32 1, !dbg !33 + %7 = load i64, i64* %6, align 8, !dbg !33 + call void @tworegs_callee(i64 %5, i64 %7), !dbg !33 + ret void, !dbg !33 +} + +; CHECK-LABEL: define void @tworegs(i64 %o.coerce0, i64 %o.coerce1) +; CHECK-NOT: alloca +; CHECK-NOT: store +; CHECK-NOT: call void @llvm.dbg.declare +; CHECK: call void @llvm.dbg.value(metadata i64 %o.coerce0, {{.*}}) +; CHECK-NOT: store +; CHECK: call void @llvm.dbg.value(metadata i64 %o.coerce1, {{.*}}) +; CHECK-NOT: store +; CHECK: call void @tworegs_callee(i64 %o.coerce0, i64 %o.coerce1) + + !llvm.dbg.cu = !{!3} !llvm.module.flags = !{!30} -!0 = !DILocalVariable(name: "__dest", line: 78, arg: 1, scope: !1, file: !2, type: !6) -!1 = distinct !DISubprogram(name: "foobar", line: 79, isLocal: true, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !3, scopeLine: 79, file: !27, scope: !2, type: !4, variables: !25) +!0 = !DILocalVariable(name: "a", line: 78, arg: 1, scope: !1, file: !2, type: !6) +!1 = distinct !DISubprogram(name: "passthru", line: 79, isLocal: true, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !3, scopeLine: 79, file: !27, scope: !2, type: !4, variables: !25) !2 = !DIFile(filename: "string.h", directory: "Game") !3 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.0 (trunk 127710)", isOptimized: true, emissionKind: FullDebug, file: !28, enums: !29, retainedTypes: !29) !4 = !DISubroutineType(types: !5) !5 = !{!6} !6 = !DIDerivedType(tag: DW_TAG_pointer_type, size: 64, align: 64, scope: !3, baseType: null) -!7 = !DILocalVariable(name: "__val", line: 78, arg: 2, scope: !1, file: !2, type: !8) +!7 = !DILocalVariable(name: "b", line: 78, arg: 2, scope: !1, file: !2, type: !8) !8 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed) -!9 = !DILocalVariable(name: "__len", line: 78, arg: 3, scope: !1, file: !2, type: !10) -!10 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_t", line: 80, file: !27, scope: !3, baseType: !11) -!11 = !DIDerivedType(tag: DW_TAG_typedef, name: "__darwin_size_t", line: 90, file: !27, scope: !3, baseType: !12) +!9 = !DILocalVariable(name: "c", line: 78, arg: 3, scope: !1, file: !2, type: !12) !12 = !DIBasicType(tag: DW_TAG_base_type, name: "long unsigned int", size: 64, align: 64, encoding: DW_ATE_unsigned) !16 = !DILocation(line: 78, column: 28, scope: !1) !18 = !DILocation(line: 78, column: 40, scope: !1) @@ -51,8 +95,19 @@ !22 = distinct !DILexicalBlock(line: 80, column: 3, file: !27, scope: !23) !23 = distinct !DILexicalBlock(line: 79, column: 1, file: !27, scope: !1) !25 = !{!0, !7, !9} -!26 = !DIFile(filename: "bits.c", directory: "Game") !27 = !DIFile(filename: "string.h", directory: "Game") !28 = !DIFile(filename: "bits.c", directory: "Game") !29 = !{} !30 = !{i32 1, !"Debug Info Version", i32 3} + +!31 = distinct !DISubprogram(name: "tworegs", scope: !28, file: !28, line: 4, type: !4, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: true, unit: !3, variables: !34) +!32 = !DILocation(line: 4, column: 23, scope: !31) +!33 = !DILocation(line: 5, column: 3, scope: !31) +!34 = !{!35} +!35 = !DILocalVariable(name: "o", arg: 1, scope: !31, file: !28, line: 4, type: !36) +!36 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "TwoRegs", file: !28, line: 1, size: 128, elements: !37) +!37 = !{!38, !39} +!38 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !36, file: !28, line: 1, baseType: !12, size: 64) +!39 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !36, file: !28, line: 1, baseType: !12, size: 64) +!40 = !DISubroutineType(types: !41) +!41 = !{!36} Index: llvm/test/Transforms/Util/simplify-dbg-declare-load.ll =================================================================== --- llvm/test/Transforms/Util/simplify-dbg-declare-load.ll +++ llvm/test/Transforms/Util/simplify-dbg-declare-load.ll @@ -19,13 +19,16 @@ unreachable idxend: ; preds = %top -; CHECK-NOT: call void @llvm.dbg.value(metadata %foo* %cp, %0 = load volatile %foo, %foo* %cp, align 8 -; CHECK: call void @llvm.dbg.value(metadata %foo %0, store volatile %foo %0, %foo* undef, align 8 ret void } +; Keep the declare if we keep the alloca. +; CHECK-LABEL: define void @julia_fastshortest_6256() +; CHECK: %cp = alloca %foo, align 8 +; CHECK: call void @llvm.dbg.declare(metadata %foo* %cp, + attributes #0 = { nounwind readnone } attributes #1 = { sspreq }