Index: llvm/test/CodeGen/X86/dbg-line-fast-isel.ll =================================================================== --- llvm/test/CodeGen/X86/dbg-line-fast-isel.ll (revision 0) +++ llvm/test/CodeGen/X86/dbg-line-fast-isel.ll (revision 0) @@ -0,0 +1,92 @@ +; RUN: llc -disable-fp-elim -O0 %s -o - | FileCheck %s + +; ModuleID = 'dbg-line-fast-isel.c' +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" +target triple = "x86_64-unknown-linux-gnu" + +; int callme(int); +; +; int isel_line_test(int arg) +; { +; callme(100); +; if (arg > 5000) +; callme(200); +; callme(300); +; return 0; +; } +; +; int isel_line_test2() +; { +; callme(400); +; return 0; +; } + +define i32 @isel_line_test(i32 %arg) nounwind uwtable { +; The start of each non-entry block (or sub-block) should get a .loc directive. +; CHECK: isel_line_test: +; CHECK: # BB#1: +; CHECK-NEXT: .loc 1 7 5 +; CHECK: LBB0_2: +; CHECK-NEXT: .loc 1 8 3 +; CHECK: callq callme +; CHECK-NEXT: .loc 1 9 3 + +entry: + %arg.addr = alloca i32, align 4 + store i32 %arg, i32* %arg.addr, align 4 + call void @llvm.dbg.declare(metadata !{i32* %arg.addr}, metadata !13), !dbg !14 + %call = call i32 @callme(i32 100), !dbg !15 + %0 = load i32* %arg.addr, align 4, !dbg !17 + %cmp = icmp sgt i32 %0, 5000, !dbg !17 + br i1 %cmp, label %if.then, label %if.end, !dbg !17 + +if.then: ; preds = %entry + %call1 = call i32 @callme(i32 200), !dbg !18 + br label %if.end, !dbg !18 + +if.end: ; preds = %if.then, %entry + %call2 = call i32 @callme(i32 300), !dbg !19 + ret i32 0, !dbg !20 +} + +declare void @llvm.dbg.declare(metadata, metadata) nounwind readnone + +declare i32 @callme(i32) + +define i32 @isel_line_test2() nounwind uwtable { +; The stack adjustment should be part of the prologue. +; CHECK: isel_line_test2: +; CHECK: subq {{.*}}, %rsp +; CHECK: .loc 1 14 3 prologue_end + +entry: + %call = call i32 @callme(i32 400), !dbg !21 + ret i32 0, !dbg !23 +} + +!llvm.dbg.cu = !{!0} + +!0 = metadata !{i32 786449, i32 0, i32 12, metadata !"dbg-line-fast-isel.c", metadata !"/home/probinson/projects/upstream/ISel-dbg-line", metadata !"clang version 3.2 (trunk 164364)", i1 true, i1 false, metadata !"", i32 0, metadata !1, metadata !1, metadata !3, metadata !1} ; [ DW_TAG_compile_unit ] [/home/probinson/projects/upstream/ISel-dbg-line/dbg-line-fast-isel.c] [DW_LANG_C99] +!1 = metadata !{metadata !2} +!2 = metadata !{i32 0} +!3 = metadata !{metadata !4} +!4 = metadata !{metadata !5, metadata !10} +!5 = metadata !{i32 786478, i32 0, metadata !6, metadata !"isel_line_test", metadata !"isel_line_test", metadata !"", metadata !6, i32 3, metadata !7, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @isel_line_test, null, null, metadata !1, i32 4} ; [ DW_TAG_subprogram ] [line 3] [def] [scope 4] [isel_line_test] +!6 = metadata !{i32 786473, metadata !"dbg-line-fast-isel.c", metadata !"/home/probinson/projects/upstream/ISel-dbg-line", null} ; [ DW_TAG_file_type ] +!7 = metadata !{i32 786453, i32 0, metadata !"", i32 0, i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !8, i32 0, i32 0} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ] +!8 = metadata !{metadata !9, metadata !9} +!9 = metadata !{i32 786468, null, metadata !"int", null, i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed] +!10 = metadata !{i32 786478, i32 0, metadata !6, metadata !"isel_line_test2", metadata !"isel_line_test2", metadata !"", metadata !6, i32 12, metadata !11, i1 false, i1 true, i32 0, i32 0, null, i32 0, i1 false, i32 ()* @isel_line_test2, null, null, metadata !1, i32 13} ; [ DW_TAG_subprogram ] [line 12] [def] [scope 13] [isel_line_test2] +!11 = metadata !{i32 786453, i32 0, metadata !"", i32 0, i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !12, i32 0, i32 0} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ] +!12 = metadata !{metadata !9} +!13 = metadata !{i32 786689, metadata !5, metadata !"arg", metadata !6, i32 16777219, metadata !9, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [arg] [line 3] +!14 = metadata !{i32 3, i32 24, metadata !5, null} +!15 = metadata !{i32 5, i32 3, metadata !16, null} +!16 = metadata !{i32 786443, metadata !5, i32 4, i32 1, metadata !6, i32 0} ; [ DW_TAG_lexical_block ] [/home/probinson/projects/upstream/ISel-dbg-line/dbg-line-fast-isel.c] +!17 = metadata !{i32 6, i32 3, metadata !16, null} +!18 = metadata !{i32 7, i32 5, metadata !16, null} +!19 = metadata !{i32 8, i32 3, metadata !16, null} +!20 = metadata !{i32 9, i32 3, metadata !16, null} +!21 = metadata !{i32 14, i32 3, metadata !22, null} +!22 = metadata !{i32 786443, metadata !10, i32 13, i32 1, metadata !6, i32 1} ; [ DW_TAG_lexical_block ] [/home/probinson/projects/upstream/ISel-dbg-line/dbg-line-fast-isel.c] +!23 = metadata !{i32 15, i32 3, metadata !22, null} Index: llvm/include/llvm/CodeGen/FastISel.h =================================================================== --- llvm/include/llvm/CodeGen/FastISel.h (revision 164407) +++ llvm/include/llvm/CodeGen/FastISel.h (working copy) @@ -71,6 +71,9 @@ /// it makes sense (for example, on function calls) MachineInstr *EmitStartPt; + /// Whether this block is the function's entry block. + bool IsEntryBlock; + public: /// getLastLocalValue - Return the position of the last instruction /// emitted for materializing constants for use in the current block. @@ -86,8 +89,14 @@ /// startNewBlock - Set the current block to which generated machine /// instructions will be appended, and clear the local CSE map. /// - void startNewBlock(); + void startNewBlock(bool IsEntry); + /// wrapUpBlock - Client is done using FastISel on this block. + void wrapUpBlock() { + updateLocalValueDebugInfo(true /* WrapUpBlock */); + recomputeInsertPt(); + } + /// getCurDebugLoc() - Return current debug location information. DebugLoc getCurDebugLoc() const { return DL; } @@ -393,6 +402,12 @@ /// spilling cached variables across heavy instructions like calls. void flushLocalValueMap(); + /// updateLocalValueDebugInfo - May add debug info from the first "real" + /// instruction to local-value instructions, if appropriate. + /// WrapUpBlock tells whether this call is at the end of FastISel processing + /// for this block. + void updateLocalValueDebugInfo(bool WrapUpBlock); + /// hasTrivialKill - Test whether the given value has exactly one use. bool hasTrivialKill(const Value *V) const; Index: llvm/lib/CodeGen/SelectionDAG/FastISel.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/FastISel.cpp (revision 164407) +++ llvm/lib/CodeGen/SelectionDAG/FastISel.cpp (working copy) @@ -72,8 +72,9 @@ /// startNewBlock - Set the current block to which generated machine /// instructions will be appended, and clear the local CSE map. /// -void FastISel::startNewBlock() { +void FastISel::startNewBlock(bool IsEntry) { LocalValueMap.clear(); + IsEntryBlock = IsEntry; EmitStartPt = 0; @@ -88,11 +89,50 @@ } void FastISel::flushLocalValueMap() { + updateLocalValueDebugInfo(false /* !WrapUpBlock */); LocalValueMap.clear(); LastLocalValue = EmitStartPt; recomputeInsertPt(); } +void FastISel::updateLocalValueDebugInfo(bool WrapUpBlock) { + // If this is the wrap-up stage of block processing, and any local-value + // instructions are _not_ at the very beginning of the block, then we should + // _not_ update their debug info. We assume the top-of-block instructions + // have debug info, and any local-value instructions implicitly use that. + // Also, don't update when wrapping up the entry block, because the very + // start of the entry block will get correct debug info elsewhere. + // + // If this is not wrap-up-block processing, then we are flushing the local + // value map due to a call (or other "heavy") instruction, and in effect + // we are defining a sub-block where the local-value instructions are by + // definition at the top of the sub-block. + if (WrapUpBlock && (EmitStartPt || IsEntryBlock)) + return; + + // If there are no instructions to update, don't update anything. + if (LastLocalValue == EmitStartPt) + return; + + // Propagate debug info from the first non-local-value instruction (if + // there is one) to the local-value instructions (if they don't already + // have any). Attaching the info to the first local-value instruction is + // sufficient. + MachineBasicBlock::iterator FirstRealInstr(LastLocalValue); + ++FirstRealInstr; + if (FirstRealInstr == FuncInfo.MBB->end()) + return; + + MachineBasicBlock::iterator FirstLocalValue; + if (EmitStartPt) { + FirstLocalValue = EmitStartPt; + ++FirstLocalValue; + } else + FirstLocalValue = FuncInfo.MBB->begin(); + if (FirstLocalValue->getDebugLoc().isUnknown()) + FirstLocalValue->setDebugLoc(FirstRealInstr->getDebugLoc()); +} + bool FastISel::hasTrivialKill(const Value *V) const { // Don't consider constants or arguments to have trivial kills. const Instruction *I = dyn_cast(V); Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp (revision 164407) +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp (working copy) @@ -1029,7 +1029,7 @@ // Before doing SelectionDAG ISel, see if FastISel has been requested. if (FastIS) { - FastIS->startNewBlock(); + FastIS->startNewBlock(LLVMBB == &Fn.getEntryBlock()); // Emit code for any incoming arguments. This must happen before // beginning FastISel on the entry block. @@ -1144,7 +1144,7 @@ break; } - FastIS->recomputeInsertPt(); + FastIS->wrapUpBlock(); } if (Begin != BI)