diff --git a/lib/Transforms/Utils/InlineFunction.cpp b/lib/Transforms/Utils/InlineFunction.cpp index f14afdb78cb..73861866956 100644 --- a/lib/Transforms/Utils/InlineFunction.cpp +++ b/lib/Transforms/Utils/InlineFunction.cpp @@ -823,20 +823,42 @@ static bool hasLifetimeMarkers(AllocaInst *AI) { return false; } -/// updateInlinedAtInfo - Helper function used by fixupLineNumbers to -/// recursively update InlinedAtEntry of a DebugLoc. -static DebugLoc updateInlinedAtInfo(const DebugLoc &DL, - const DebugLoc &InlinedAtDL, - LLVMContext &Ctx) { - if (MDNode *IA = DL.getInlinedAt(Ctx)) { - DebugLoc NewInlinedAtDL - = updateInlinedAtInfo(DebugLoc::getFromDILocation(IA), InlinedAtDL, Ctx); - return DebugLoc::get(DL.getLine(), DL.getCol(), DL.getScope(Ctx), - NewInlinedAtDL.getAsMDNode(Ctx)); +/// Rebuild the entire inlined-at chain for this instruction so that the top of +/// the chain now is inlined-at the new call site. +static DebugLoc +updateInlinedAtInfo(DebugLoc DL, MDLocation *InlinedAtNode, + LLVMContext &Ctx, + DenseMap &IANodes) { + SmallVector InlinedAtLocations; + MDLocation *Last = InlinedAtNode; + DebugLoc CurInlinedAt = DL; + + // Gather all the inlined-at nodes + while (MDLocation *IA = + cast_or_null(CurInlinedAt.getInlinedAt(Ctx))) { + // Skip any we've already built nodes for + if (MDLocation *Found = IANodes[IA]) { + Last = Found; + break; + } + + InlinedAtLocations.push_back(IA); + CurInlinedAt = DebugLoc::getFromDILocation(IA); } - return DebugLoc::get(DL.getLine(), DL.getCol(), DL.getScope(Ctx), - InlinedAtDL.getAsMDNode(Ctx)); + // Starting from the top, rebuild the nodes to point to the new inlined-at + // location (then rebuilding the rest of the chain behind it) and update the + // map of already-constructed inlined-at nodes. + for (auto I = InlinedAtLocations.rbegin(), E = InlinedAtLocations.rend(); + I != E; ++I) { + const MDLocation *MD = *I; + Last = IANodes[MD] = MDLocation::getDistinct( + Ctx, MD->getLine(), MD->getColumn(), MD->getScope(), Last); + } + + // And finally create the normal location for this instruction, referring to + // the new inlined-at chain. + return DebugLoc::get(DL.getLine(), DL.getCol(), DL.getScope(Ctx), Last); } /// fixupLineNumbers - Update inlined instructions' line numbers to @@ -847,6 +869,20 @@ static void fixupLineNumbers(Function *Fn, Function::iterator FI, if (TheCallDL.isUnknown()) return; + auto &Ctx = Fn->getContext(); + auto *InlinedAtNode = cast(TheCallDL.getAsMDNode(Ctx)); + + // Create a unique call site, not to be confused with any other call from the + // same location. + InlinedAtNode = MDLocation::getDistinct( + Ctx, InlinedAtNode->getLine(), InlinedAtNode->getColumn(), + InlinedAtNode->getScope(), InlinedAtNode->getInlinedAt()); + + // Cache the inlined-at nodes as they're built so they are reused, without + // this every instruction's inlined-at chain would become distinct from each + // other. + DenseMap IANodes; + for (; FI != Fn->end(); ++FI) { for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) { @@ -864,7 +900,7 @@ static void fixupLineNumbers(Function *Fn, Function::iterator FI, BI->setDebugLoc(TheCallDL); } else { - BI->setDebugLoc(updateInlinedAtInfo(DL, TheCallDL, BI->getContext())); + BI->setDebugLoc(updateInlinedAtInfo(DL, InlinedAtNode, BI->getContext(), IANodes)); if (DbgValueInst *DVI = dyn_cast(BI)) { LLVMContext &Ctx = BI->getContext(); MDNode *InlinedAt = BI->getDebugLoc().getInlinedAt(Ctx); diff --git a/test/DebugInfo/inline-debug-info-multiret.ll b/test/DebugInfo/inline-debug-info-multiret.ll index 0115ecd3a8d..71f29ec36bc 100644 --- a/test/DebugInfo/inline-debug-info-multiret.ll +++ b/test/DebugInfo/inline-debug-info-multiret.ll @@ -10,7 +10,7 @@ ; CHECK: br label %invoke.cont, !dbg ![[MD]] ; The branch instruction has the source location of line 9 and its inlined location ; has the source location of line 14. -; CHECK: ![[INL:[0-9]+]] = !MDLocation(line: 14, scope: {{.*}}) +; CHECK: ![[INL:[0-9]+]] = distinct !MDLocation(line: 14, scope: {{.*}}) ; CHECK: ![[MD]] = !MDLocation(line: 9, scope: {{.*}}, inlinedAt: ![[INL]]) ; ModuleID = 'test.cpp' diff --git a/test/DebugInfo/inline-debug-info.ll b/test/DebugInfo/inline-debug-info.ll index 5d2f652034d..9b9439b5e81 100644 --- a/test/DebugInfo/inline-debug-info.ll +++ b/test/DebugInfo/inline-debug-info.ll @@ -28,11 +28,11 @@ ; CHECK: _Z4testi.exit: ; Make sure the branch instruction created during inlining has a debug location, ; so the range of the inlined function is correct. -; CHECK: br label %invoke.cont, !dbg ![[MD:[0-9]+]] +; CHECK: br label %invoke.cont, !dbg [[MD:![0-9]+]] ; The branch instruction has the source location of line 9 and its inlined location ; has the source location of line 14. -; CHECK: ![[INL:[0-9]+]] = !MDLocation(line: 14, scope: {{.*}}) -; CHECK: ![[MD]] = !MDLocation(line: 9, scope: {{.*}}, inlinedAt: ![[INL]]) +; CHECK: [[INL:![0-9]*]] = distinct !MDLocation(line: 14, scope: {{.*}}) +; CHECK: [[MD]] = !MDLocation(line: 9, scope: {{.*}}, inlinedAt: [[INL]]) ; ModuleID = 'test.cpp' target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" diff --git a/test/DebugInfo/inline-no-debug-info.ll b/test/DebugInfo/inline-no-debug-info.ll index 68fd8e7a01b..6b58bcc201d 100644 --- a/test/DebugInfo/inline-no-debug-info.ll +++ b/test/DebugInfo/inline-no-debug-info.ll @@ -21,10 +21,11 @@ ; Debug location of the code in caller() and of the inlined code that did not ; have any debug location before. -; CHECK-DAG: [[A]] = !MDLocation(line: 4, scope: !{{[01-9]+}}) +; CHECK-DAG: [[A]] = !MDLocation(line: 4, scope: !{{[0-9]+}}) ; Debug location of the inlined code. -; CHECK-DAG: [[B]] = !MDLocation(line: 2, scope: !{{[01-9]+}}, inlinedAt: [[A]]) +; CHECK-DAG: [[B]] = !MDLocation(line: 2, scope: !{{[0-9]+}}, inlinedAt: [[A_INL:![0-9]*]]) +; CHECK-DAG: [[A_INL]] = distinct !MDLocation(line: 4, scope: !{{[0-9]+}}) target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/test/Transforms/Inline/debug-info-duplicate-calls.ll b/test/Transforms/Inline/debug-info-duplicate-calls.ll new file mode 100644 index 00000000000..2363693bd5c --- /dev/null +++ b/test/Transforms/Inline/debug-info-duplicate-calls.ll @@ -0,0 +1,121 @@ +; RUN: opt < %s -always-inline -S | FileCheck %s + +; Original input generated from clang -emit-llvm -S -c -mllvm -disable-llvm-optzns +; +; #define CALLS1 f2(); f2(); +; #define CALLS2 f4(); f4(); +; void f1(); +; inline __attribute__((always_inline)) void f2() { +; f1(); +; } +; inline __attribute__((always_inline)) void f3() { +; CALLS1 +; } +; inline __attribute__((always_inline)) void f4() { +; f3(); +; } +; void f() { +; CALLS2 +; } + +; There should be unique locations for all 4 of these instructions, correctly +; describing the inlining that has occurred, even in the face of duplicate call +; site locations. + +; The nomenclature used for the tags here is [cs] where +; 'cs' is an abbreviation for 'call site' and the number indicates which call +; site from within the named function this is. (so, given the above inlining, we +; should have 4 calls to 'f1', two from the first call to f4 and two from the +; second call to f4) + +; CHECK: call void @_Z2f1v(), !dbg [[fcs1_f4_f3cs1_f2:![0-9]+]] +; CHECK: call void @_Z2f1v(), !dbg [[fcs1_f4_f3cs2_f2:![0-9]+]] +; CHECK: call void @_Z2f1v(), !dbg [[fcs2_f4_f3cs1_f2:![0-9]+]] +; CHECK: call void @_Z2f1v(), !dbg [[fcs2_f4_f3cs2_f2:![0-9]+]] + +; CHECK-DAG: [[F:![0-9]+]] = {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [f] +; CHECK-DAG: [[F2:![0-9]+]] = {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [f2] +; CHECK-DAG: [[F3:![0-9]+]] = {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [f3] +; CHECK-DAG: [[F4:![0-9]+]] = {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [f4] + +; CHECK: [[fcs1_f4_f3cs1_f2]] = {{.*}}, scope: [[F2]], inlinedAt: [[fcs1_f4_f3cs1:![0-9]+]]) +; CHECK: [[fcs1_f4_f3cs1]] = {{.*}}, scope: [[F3]], inlinedAt: [[fcs1_f4:![0-9]+]]) +; CHECK: [[fcs1_f4]] = {{.*}}, scope: [[F4]], inlinedAt: [[fcs1:![0-9]+]]) +; CHECK: [[fcs1]] = {{.*}}, scope: [[F]]) +; CHECK: [[fcs1_f4_f3cs2_f2]] = {{.*}}, scope: [[F2]], inlinedAt: [[fcs1_f4_f3cs2:![0-9]+]]) +; CHECK: [[fcs1_f4_f3cs2]] = {{.*}}, scope: [[F3]], inlinedAt: [[fcs1_f4]]) + +; CHECK: [[fcs2_f4_f3cs1_f2]] = {{.*}}, scope: [[F2]], inlinedAt: [[fcs2_f4_f3cs1:![0-9]+]]) +; CHECK: [[fcs2_f4_f3cs1]] = {{.*}}, scope: [[F3]], inlinedAt: [[fcs2_f4:![0-9]+]]) +; CHECK: [[fcs2_f4]] = {{.*}}, scope: [[F4]], inlinedAt: [[fcs2:![0-9]+]]) +; CHECK: [[fcs2]] = {{.*}}, scope: [[F]]) +; CHECK: [[fcs2_f4_f3cs2_f2]] = {{.*}}, scope: [[F2]], inlinedAt: [[fcs2_f4_f3cs2:![0-9]+]]) +; CHECK: [[fcs2_f4_f3cs2]] = {{.*}}, scope: [[F3]], inlinedAt: [[fcs2_f4]]) + +$_Z2f4v = comdat any + +$_Z2f3v = comdat any + +$_Z2f2v = comdat any + +; Function Attrs: uwtable +define void @_Z1fv() #0 { +entry: + call void @_Z2f4v(), !dbg !13 + call void @_Z2f4v(), !dbg !13 + ret void, !dbg !14 +} + +; Function Attrs: alwaysinline inlinehint uwtable +define linkonce_odr void @_Z2f4v() #1 comdat { +entry: + call void @_Z2f3v(), !dbg !15 + ret void, !dbg !16 +} + +; Function Attrs: alwaysinline inlinehint uwtable +define linkonce_odr void @_Z2f3v() #1 comdat { +entry: + call void @_Z2f2v(), !dbg !17 + call void @_Z2f2v(), !dbg !17 + ret void, !dbg !18 +} + +; Function Attrs: alwaysinline inlinehint uwtable +define linkonce_odr void @_Z2f2v() #1 comdat { +entry: + call void @_Z2f1v(), !dbg !19 + ret void, !dbg !20 +} + +declare void @_Z2f1v() #2 + +attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { alwaysinline inlinehint uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!10, !11} +!llvm.ident = !{!12} + +!0 = !{!"0x11\004\00clang version 3.7.0 (trunk 226474) (llvm/trunk 226478)\000\00\000\00\002", !1, !2, !2, !3, !2, !2} ; [ DW_TAG_compile_unit ] [/tmp/dbginfo/debug-info-duplicate-calls.cpp] [DW_LANG_C_plus_plus] +!1 = !{!"debug-info-duplicate-calls.cpp", !"/tmp/dbginfo"} +!2 = !{} +!3 = !{!4, !7, !8, !9} +!4 = !{!"0x2e\00f\00f\00\0013\000\001\000\000\00256\000\0013", !1, !5, !6, null, void ()* @_Z1fv, null, null, !2} ; [ DW_TAG_subprogram ] [line 13] [def] [f] +!5 = !{!"0x29", !1} ; [ DW_TAG_file_type ] [/tmp/dbginfo/debug-info-duplicate-calls.cpp] +!6 = !{!"0x15\00\000\000\000\000\000\000", null, null, null, !2, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ] +!7 = !{!"0x2e\00f4\00f4\00\0010\000\001\000\000\00256\000\0010", !1, !5, !6, null, void ()* @_Z2f4v, null, null, !2} ; [ DW_TAG_subprogram ] [line 10] [def] [f4] +!8 = !{!"0x2e\00f3\00f3\00\007\000\001\000\000\00256\000\007", !1, !5, !6, null, void ()* @_Z2f3v, null, null, !2} ; [ DW_TAG_subprogram ] [line 7] [def] [f3] +!9 = !{!"0x2e\00f2\00f2\00\004\000\001\000\000\00256\000\004", !1, !5, !6, null, void ()* @_Z2f2v, null, null, !2} ; [ DW_TAG_subprogram ] [line 4] [def] [f2] +!10 = !{i32 2, !"Dwarf Version", i32 4} +!11 = !{i32 2, !"Debug Info Version", i32 2} +!12 = !{!"clang version 3.7.0 (trunk 226474) (llvm/trunk 226478)"} +!13 = !MDLocation(line: 14, column: 3, scope: !4) +!14 = !MDLocation(line: 15, column: 1, scope: !4) +!15 = !MDLocation(line: 11, column: 3, scope: !7) +!16 = !MDLocation(line: 12, column: 1, scope: !7) +!17 = !MDLocation(line: 8, column: 3, scope: !8) +!18 = !MDLocation(line: 9, column: 1, scope: !8) +!19 = !MDLocation(line: 5, column: 3, scope: !9) +!20 = !MDLocation(line: 6, column: 1, scope: !9) diff --git a/test/Transforms/Inline/debug-invoke.ll b/test/Transforms/Inline/debug-invoke.ll index 4815e689b8a..74ba9dc7084 100644 --- a/test/Transforms/Inline/debug-invoke.ll +++ b/test/Transforms/Inline/debug-invoke.ll @@ -6,7 +6,7 @@ ; CHECK-NEXT: to label {{.*}} unwind label {{.*}}, !dbg [[INL_LOC:!.*]] ; CHECK: [[EMPTY:.*]] = !{} ; CHECK: [[INL_LOC]] = !MDLocation(line: 1, scope: [[EMPTY]], inlinedAt: [[INL_AT:.*]]) -; CHECK: [[INL_AT]] = !MDLocation(line: 2, scope: [[EMPTY]]) +; CHECK: [[INL_AT]] = distinct !MDLocation(line: 2, scope: [[EMPTY]]) declare void @test() declare i32 @__gxx_personality_v0(...) diff --git a/test/Transforms/Inline/inline_dbg_declare.ll b/test/Transforms/Inline/inline_dbg_declare.ll index 563cde31416..0bba3fc9195 100644 --- a/test/Transforms/Inline/inline_dbg_declare.ll +++ b/test/Transforms/Inline/inline_dbg_declare.ll @@ -92,5 +92,6 @@ attributes #1 = { nounwind readnone } !22 = !MDLocation(line: 8, column: 14, scope: !9) !23 = !MDLocation(line: 9, column: 1, scope: !9) -; CHECK: [[m23]] = !{!"0x101\00x\0016777217\000", !4, !5, !8, !22} ; [ DW_TAG_arg_variable ] [x] [line 1] -; CHECK: [[m24]] = !MDLocation(line: 1, column: 17, scope: !4, inlinedAt: !22) +; CHECK: [[m23]] = !{!"0x101\00x\0016777217\000", !4, !5, !8, [[CALL_SITE:![0-9]*]]} ; [ DW_TAG_arg_variable ] [x] [line 1] +; CHECK: [[CALL_SITE]] = distinct !MDLocation(line: 8, column: 14, scope: !9) +; CHECK: [[m24]] = !MDLocation(line: 1, column: 17, scope: !4, inlinedAt: [[CALL_SITE]])