diff --git a/llvm/lib/Transforms/Scalar/StructurizeCFG.cpp b/llvm/lib/Transforms/Scalar/StructurizeCFG.cpp --- a/llvm/lib/Transforms/Scalar/StructurizeCFG.cpp +++ b/llvm/lib/Transforms/Scalar/StructurizeCFG.cpp @@ -91,6 +91,8 @@ using PredMap = DenseMap; using BB2BBMap = DenseMap; +using BranchDebugLocMap = DenseMap; + // A traits type that is intended to be used in graph algorithms. The graph // traits starts at an entry node, and traverses the RegionNodes that are in // the Nodes set. @@ -262,6 +264,8 @@ PredMap LoopPreds; BranchVector LoopConds; + BranchDebugLocMap TermDL; + RegionNode *PrevNode; void orderNodes(); @@ -276,6 +280,8 @@ void insertConditions(bool Loops); + void setTerminatorDebugLoc(); + void simplifyConditions(); void delPhiValues(BasicBlock *From, BasicBlock *To); @@ -540,6 +546,12 @@ // Find the last back edges analyzeLoops(RN); } + + // Reset the collected term debug locations + TermDL.clear(); + + for (BasicBlock &BB : *Func) + TermDL[&BB] = BB.getTerminator()->getDebugLoc(); } /// Insert the missing branch conditions @@ -588,6 +600,11 @@ } } +void StructurizeCFG::setTerminatorDebugLoc() { + for (std::pair E : TermDL) + E.first->getTerminator()->setDebugLoc(E.second); +} + /// Simplify any inverted conditions that were built by buildConditions. void StructurizeCFG::simplifyConditions() { SmallVector InstToErase; @@ -760,6 +777,7 @@ Order.back()->getEntry(); BasicBlock *Flow = BasicBlock::Create(Context, FlowBlockName, Func, Insert); + TermDL[Flow] = TermDL[Dominator]; DT->addNewBlock(Flow, Dominator); ParentRegion->getRegionInfo()->setRegionFor(Flow, ParentRegion); return Flow; @@ -856,6 +874,7 @@ // let it point to entry and next block Conditions.push_back(BranchInst::Create(Entry, Next, BoolUndef, Flow)); + addPhiValues(Flow, Entry); DT->changeImmediateDominator(Entry, Flow); @@ -889,21 +908,6 @@ handleLoops(false, LoopEnd); } - // If the start of the loop is the entry block, we can't branch to it so - // insert a new dummy entry block. - Function *LoopFunc = LoopStart->getParent(); - if (LoopStart == &LoopFunc->getEntryBlock()) { - LoopStart->setName("entry.orig"); - - BasicBlock *NewEntry = - BasicBlock::Create(LoopStart->getContext(), - "entry", - LoopFunc, - LoopStart); - BranchInst::Create(LoopStart, NewEntry); - DT->setNewRoot(NewEntry); - } - // Create an extra loop end node LoopEnd = needPrefix(false); BasicBlock *Next = needPostfix(LoopEnd, ExitUseAllowed); @@ -1089,6 +1093,7 @@ createFlow(); insertConditions(false); insertConditions(true); + setTerminatorDebugLoc(); simplifyConditions(); setPhiValues(); simplifyAffectedPhis(); @@ -1104,6 +1109,7 @@ Loops.clear(); LoopPreds.clear(); LoopConds.clear(); + TermDL.clear(); return true; } diff --git a/llvm/test/Transforms/StructurizeCFG/structurizecfg-debug-loc.ll b/llvm/test/Transforms/StructurizeCFG/structurizecfg-debug-loc.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/StructurizeCFG/structurizecfg-debug-loc.ll @@ -0,0 +1,209 @@ +; RUN: opt -S -o - -structurizecfg %s | FileCheck %s + +define void @if_then_else(i32 addrspace(1)* %out, i1 %arg) !dbg !7 { +; CHECK: @if_then_else( +; CHECK: entry: +; CHECK: br i1 {{.*}}, label %if.else, label %Flow, !dbg [[ITE_ENTRY_DL:![0-9]+]] +; CHECK: Flow: +; CHECK: br i1 {{.*}}, label %if.then, label %exit, !dbg [[ITE_ENTRY_DL]] +; CHECK: if.then: +; CHECK: br label %exit, !dbg [[ITE_IFTHEN_DL:![0-9]+]] +; CHECK: if.else: +; CHECK: br label %Flow, !dbg [[ITE_IFELSE_DL:![0-9]+]] +; CHECK: exit: +; +entry: + br i1 %arg, label %if.then, label %if.else, !dbg !8 + +if.then: + store i32 0, i32 addrspace(1)* %out, !dbg !9 + br label %exit, !dbg !10 + +if.else: + store i32 1, i32 addrspace(1)* %out, !dbg !11 + br label %exit, !dbg !12 + +exit: + ret void, !dbg !13 +} + +define void @while_loop(i32 addrspace(1)* %out) !dbg !14 { +; CHECK: @while_loop( +; CHECK: entry: +; CHECK: br label %while.header, !dbg [[WHILE_ENTRY_DL:![0-9]+]] +; CHECK: while.header: +; CHECK: br i1 {{.*}}, label %while.body, label %Flow, !dbg [[WHILE_HEADER_DL:![0-9]+]] +; CHECK: while.body: +; CHECK: br label %Flow, !dbg [[WHILE_BODY_DL:![0-9]+]] +; CHECK: Flow: + +; TODO: this one below should be a null location (to avoid jumping back to the condition) ? + +; CHECK: br i1 {{.*}}, label %exit, label %while.header, !dbg [[WHILE_HEADER_DL]] +; CHECK: exit: +; +entry: + br label %while.header, !dbg !15 + +while.header: + %cond = call i1 @loop_condition(), !dbg !16 + br i1 %cond, label %while.body, label %exit, !dbg !17 + +while.body: + store i32 1, i32 addrspace(1)* %out, !dbg !18 + br label %while.header, !dbg !19 + +exit: + ret void, !dbg !20 +} + +define void @while_multiple_exits(i32 addrspace(1)* %out) !dbg !21 { +; CHECK: @while_multiple_exits( +; CHECK: entry: +; CHECK: br label %while.header, !dbg [[WHILEME_ENTRY_DL:![0-9]+]] +; CHECK: while.header: +; CHECK: br i1 {{.*}}, label %while.exiting, label %Flow, !dbg [[WHILEME_HEADER_DL:![0-9]+]] +; CHECK: while.exiting: +; CHECK: br label %Flow, !dbg [[WHILEME_EXITING_DL:![0-9]+]] +; CHECK: Flow: + +; TODO: should this one be a line 0 location ? In the original code if exiting from the while.exiting branch one doesn't go back to the header +; but otherwise, when jumping back to the header the new location may appear to late + +; CHECK: br i1 {{.*}}, label %exit, label %while.header, !dbg [[WHILEME_HEADER_DL]] +; CHECK: exit: +; +entry: + br label %while.header, !dbg !22 + +while.header: + %cond0 = call i1 @loop_condition(), !dbg !23 + br i1 %cond0, label %while.exiting, label %exit, !dbg !24 + +while.exiting: + %cond1 = call i1 @loop_condition(), !dbg !25 + br i1 %cond1, label %while.header, label %exit, !dbg !26 + +exit: + ret void, !dbg !27 +} + +define void @nested_if_then_else(i32 addrspace(1)* %out, i1 %a, i1 %b) !dbg !28 { +; CHECK: @nested_if_then_else( +; CHECK: entry: +; CHECK: br i1 {{.*}}, label %if.else, label %Flow4, !dbg [[NESTED_ENTRY_DL:![0-9]+]] +; CHECK: Flow4: +; CHECK: br i1 {{.*}}, label %if.then, label %exit, !dbg [[NESTED_ENTRY_DL]] +; CHECK: if.then: +; CHECK: br i1 {{.*}}, label %if.then.else, label %Flow2, !dbg [[NESTED_IFTHEN_DL:![0-9]+]] +; CHECK: Flow2: +; CHECK: br i1 {{.*}}, label %if.then.then, label %Flow3, !dbg [[NESTED_IFTHEN_DL]] +; CHECK: if.then.then: +; CHECK: br label %Flow3, !dbg [[NESTED_IFTHENTHEN_DL:![0-9]+]] +; CHECK: if.then.else: +; CHECK: br label %Flow2, !dbg [[NESTED_IFTHENELSE_DL:![0-9]+]] +; CHECK: if.else: +; CHECK: br i1 {{.*}}, label %if.else.else, label %Flow, !dbg [[NESTED_IFELSE_DL:![0-9]+]] +; CHECK: Flow: +; CHECK: br i1 {{.*}}, label %if.else.then, label %Flow1, !dbg [[NESTED_IFELSE_DL]] +; CHECK: if.else.then: +; CHECK: br label %Flow1, !dbg [[NESTED_IFELSETHEN_DL:![0-9]+]] +; CHECK: if.else.else: +; CHECK: br label %Flow, !dbg [[NESTED_IFELSEELSE_DL:![0-9]+]] +; CHECK: Flow1: +; CHECK: br label %Flow4, !dbg [[NESTED_IFELSE_DL]] +; CHECK: Flow3: +; CHECK: br label %exit, !dbg [[NESTED_IFTHEN_DL]] +; CHECK: exit: +; +entry: + br i1 %a, label %if.then, label %if.else, !dbg !29 + +if.then: + br i1 %b, label %if.then.then, label %if.then.else, !dbg !30 + +if.then.then: + store i32 0, i32 addrspace(1)* %out, !dbg !31 + br label %exit, !dbg !32 + +if.then.else: + store i32 1, i32 addrspace(1)* %out, !dbg !33 + br label %exit, !dbg !34 + +if.else: + br i1 %b, label %if.else.then, label %if.else.else, !dbg !35 + +if.else.then: + store i32 2, i32 addrspace(1)* %out, !dbg !36 + br label %exit, !dbg !37 + +if.else.else: + store i32 3, i32 addrspace(1)* %out, !dbg !38 + br label %exit, !dbg !39 + +exit: + ret void, !dbg !40 +} + +declare i1 @loop_condition() + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!4, !5} + +; CHECK: [[ITE_ENTRY_DL]] = !DILocation(line: 2 +; CHECK: [[ITE_IFTHEN_DL]] = !DILocation(line: 4 +; CHECK: [[ITE_IFELSE_DL]] = !DILocation(line: 6 +; CHECK: [[WHILE_ENTRY_DL]] = !DILocation(line: 2 +; CHECK: [[WHILE_HEADER_DL]] = !DILocation(line: 4 +; CHECK: [[WHILE_BODY_DL]] = !DILocation(line: 6 +; CHECK: [[WHILEME_ENTRY_DL]] = !DILocation(line: 2 +; CHECK: [[WHILEME_HEADER_DL]] = !DILocation(line: 4 +; CHECK: [[WHILEME_EXITING_DL]] = !DILocation(line: 6 +; CHECK: [[NESTED_ENTRY_DL]] = !DILocation(line: 2 +; CHECK: [[NESTED_IFTHEN_DL]] = !DILocation(line: 3 +; CHECK: [[NESTED_IFTHENTHEN_DL]] = !DILocation(line: 5 +; CHECK: [[NESTED_IFTHENELSE_DL]] = !DILocation(line: 7 +; CHECK: [[NESTED_IFELSE_DL]] = !DILocation(line: 8 +; CHECK: [[NESTED_IFELSETHEN_DL]] = !DILocation(line: 10 +; CHECK: [[NESTED_IFELSEELSE_DL]] = !DILocation(line: 12 + +!0 = !{} +!1 = !DIFile(filename: "dummy.ll", directory: "/some/random/directory") +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !0) +!4 = !{i32 2, !"Dwarf Version", i32 5} +!5 = !{i32 2, !"Debug Info Version", i32 3} +!6 = !DISubroutineType(types: !0) +!7 = distinct !DISubprogram(name: "dummy", scope: !1, file: !1, line: 1, type: !6, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !2, retainedNodes: !0) +!8 = !DILocation(line: 2, scope: !7) +!9 = !DILocation(line: 3, scope: !7) +!10 = !DILocation(line: 4, scope: !7) +!11 = !DILocation(line: 5, scope: !7) +!12 = !DILocation(line: 6, scope: !7) +!13 = !DILocation(line: 7, scope: !7) +!14 = distinct !DISubprogram(name: "dummy", scope: !1, file: !1, line: 1, type: !6, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !2, retainedNodes: !0) +!15 = !DILocation(line: 2, scope: !14) +!16 = !DILocation(line: 3, scope: !14) +!17 = !DILocation(line: 4, scope: !14) +!18 = !DILocation(line: 5, scope: !14) +!19 = !DILocation(line: 6, scope: !14) +!20 = !DILocation(line: 7, scope: !14) +!21 = distinct !DISubprogram(name: "dummy", scope: !1, file: !1, line: 1, type: !6, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !2, retainedNodes: !0) +!22 = !DILocation(line: 2, scope: !21) +!23 = !DILocation(line: 3, scope: !21) +!24 = !DILocation(line: 4, scope: !21) +!25 = !DILocation(line: 5, scope: !21) +!26 = !DILocation(line: 6, scope: !21) +!27 = !DILocation(line: 7, scope: !21) +!28 = distinct !DISubprogram(name: "dummy", scope: !1, file: !1, line: 1, type: !6, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !2, retainedNodes: !0) +!29 = !DILocation(line: 2, scope: !28) +!30 = !DILocation(line: 3, scope: !28) +!31 = !DILocation(line: 4, scope: !28) +!32 = !DILocation(line: 5, scope: !28) +!33 = !DILocation(line: 6, scope: !28) +!34 = !DILocation(line: 7, scope: !28) +!35 = !DILocation(line: 8, scope: !28) +!36 = !DILocation(line: 9, scope: !28) +!37 = !DILocation(line: 10, scope: !28) +!38 = !DILocation(line: 11, scope: !28) +!39 = !DILocation(line: 12, scope: !28) +!40 = !DILocation(line: 13, scope: !28)