Index: llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -3099,13 +3099,35 @@ ++NumSunkInst; // Also sink all related debug uses from the source basic block. Otherwise we - // get debug use before the def. - SmallVector DbgUsers; + // get debug use before the def. Attempt to salvage debug uses first, to + // maximise the range variables have location for. If we cannot salvage, then + // mark the location undef: we know it was supposed to receive a new location + // here, but that computation has been sunk. + SmallVector DbgUsers; findDbgUsers(DbgUsers, I); - for (auto *DII : DbgUsers) { + for (auto *DII : reverse(DbgUsers)) { if (DII->getParent() == SrcBlock) { - DII->moveBefore(&*InsertPos); - LLVM_DEBUG(dbgs() << "SINK: " << *DII << '\n'); + // dbg.value is in the same basic block as the sunk inst, see if we can + // salvage it. Clone a new copy of the instruction: on success we need + // both salvaged and unsalvaged copies. + SmallVector TmpUser{ + cast(DII->clone())}; + + if (!salvageDebugInfoForDbgValues(*I, TmpUser)) { + // We are unable to salvage: sink the cloned dbg.value, and mark the + // original as undef, terminating any earlier variable location. + LLVM_DEBUG(dbgs() << "SINK: " << *DII << '\n'); + TmpUser[0]->insertBefore(&*InsertPos); + Value *Undef = UndefValue::get(I->getType()); + DII->setOperand(0, MetadataAsValue::get(DII->getContext(), + ValueAsMetadata::get(Undef))); + } else { + // We successfully salvaged: place the salvaged dbg.value in the + // original location, and move the unmodified dbg.value to sink with + // the sunk inst. + TmpUser[0]->insertBefore(DII); + DII->moveBefore(&*InsertPos); + } } } return true; Index: llvm/trunk/test/Transforms/InstCombine/debuginfo-sink.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/debuginfo-sink.ll +++ llvm/trunk/test/Transforms/InstCombine/debuginfo-sink.ll @@ -0,0 +1,78 @@ +; RUN: opt %s -instcombine -S | FileCheck %s + +; Test sinking of dbg.values when instcombine sinks associated instructions. + +declare void @llvm.dbg.value(metadata, metadata, metadata) + +; This GEP is sunk, but can be folded into a DIExpression. Check that it +; gets folded. The dbg.value should be duplicated in the block its sunk +; into, to maximise liveness. +; +; CHECK-LABEL: define i32 @foo(i32* +; CHECK: call void @llvm.dbg.value(metadata i32* %a, metadata !{{[0-9]+}}, +; CHECK-SAME: metadata !DIExpression(DW_OP_plus_uconst, 4, DW_OP_stack_value)) +; CHECK-NEXT: br label %sink1 + +define i32 @foo(i32 *%a) !dbg !7 { +entry: + %gep = getelementptr i32, i32 *%a, i32 1 + call void @llvm.dbg.value(metadata i32 *%gep, metadata !16, metadata !12), !dbg !15 + br label %sink1 + +sink1: +; CHECK-LABEL: sink1: +; CHECK: call void @llvm.dbg.value(metadata i32* %gep, +; CHECK-SAME: metadata !{{[0-9]+}}, metadata !DIExpression()) +; CHECK-NEXT: load + %0 = load i32, i32* %gep, align 4, !dbg !15 + ret i32 %0, !dbg !15 +} + +; In this example the GEP cannot (yet) be salvaged. Check that not only is the +; dbg.value sunk, but an undef dbg.value is left to terminate any earlier +; value range. + +; CHECK-LABEL: define i32 @bar( +; CHECK: call void @llvm.dbg.value(metadata i32* undef, +; CHECK-NEXT: br label %sink2 + +define i32 @bar(i32 *%a, i32 %b) !dbg !70 { +entry: + %gep = getelementptr i32, i32 *%a, i32 %b + call void @llvm.dbg.value(metadata i32* %gep, metadata !73, metadata !12), !dbg !74 + br label %sink2 + +sink2: +; CHECK-LABEL: sink2: +; CHECK: call void @llvm.dbg.value(metadata i32* %gep, +; CHECK-SAME: metadata !{{[0-9]+}}, metadata !DIExpression()) +; CHECK-NEXT: load +; CHECK-NEXT: ret + %0 = load i32, i32* %gep + ret i32 %0 +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +!1 = !DIFile(filename: "a.c", directory: ".") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"PIC Level", i32 2} +!6 = !{!"clang"} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DILocalVariable(name: "j", scope: !7, file: !1, line: 2, type: !10) +!12 = !DIExpression() +!15 = !DILocation(line: 5, column: 3, scope: !7) +!16 = !DILocalVariable(name: "h", scope: !7, file: !1, line: 4, type: !10) +!70 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 2, type: !71, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2) +!71 = !DISubroutineType(types: !72) +!72 = !{!10, !10, !10} +!73 = !DILocalVariable(name: "k", scope: !70, file: !1, line: 2, type: !10) +!74 = !DILocation(line: 5, column: 3, scope: !70)