446 changes: 375 additions & 71 deletions llvm/include/llvm/Support/GenericDomTreeConstruction.h

Large diffs are not rendered by default.

32 changes: 14 additions & 18 deletions llvm/lib/Transforms/Scalar/ADCE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,27 +253,23 @@ void AggressiveDeadCodeElimination::initialize() {
}
}

// Mark blocks live if there is no path from the block to the
// return of the function or a successor for which this is true.
// This protects IDFCalculator which cannot handle such blocks.
for (auto &BBInfoPair : BlockInfo) {
auto &BBInfo = BBInfoPair.second;
if (BBInfo.terminatorIsLive())
continue;
auto *BB = BBInfo.BB;
if (!PDT.getNode(BB)) {
DEBUG(dbgs() << "Not post-dominated by return: " << BB->getName()
// Mark blocks live if there is no path from the block to a
// return of the function.
// We do this by seeing which of the postdomtree root children exit the
// program, and for all others, mark the subtree live.
for (auto &PDTChild : children<DomTreeNode *>(PDT.getRootNode())) {
auto *BB = PDTChild->getBlock();
auto &Info = BlockInfo[BB];
// Real function return
if (isa<ReturnInst>(Info.Terminator)) {
DEBUG(dbgs() << "post-dom root child is a return: " << BB->getName()
<< '\n';);
markLive(BBInfo.Terminator);
continue;
}
for (auto *Succ : successors(BB))
if (!PDT.getNode(Succ)) {
DEBUG(dbgs() << "Successor not post-dominated by return: "
<< BB->getName() << '\n';);
markLive(BBInfo.Terminator);
break;
}

// This child is something else, like an infinite loop.
for (auto DFNode : depth_first(PDTChild))
markLive(BlockInfo[DFNode->getBlock()].Terminator);
}

// Treat the entry block as always live
Expand Down
30 changes: 30 additions & 0 deletions llvm/test/Analysis/PostDominators/infinite-loop.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
; RUN: opt < %s -postdomtree -analyze | FileCheck %s
; RUN: opt < %s -passes='print<postdomtree>' 2>&1 | FileCheck %s

@a = external global i32, align 4

define void @fn1() {
entry:
store i32 5, i32* @a, align 4
%call = call i32 (...) @foo()
%tobool = icmp ne i32 %call, 0
br i1 %tobool, label %if.then, label %if.end

if.then: ; preds = %entry
br label %loop

loop: ; preds = %loop, %if.then
br label %loop

if.end: ; preds = %entry
store i32 6, i32* @a, align 4
ret void
}

declare i32 @foo(...)

; CHECK: Inorder PostDominator Tree:
; CHECK-NEXT: [1] <<exit node>>
; CHECK: [2] %loop
; CHECK-NEXT: [3] %if.then
; CHECK: Roots: %if.end %loop
34 changes: 34 additions & 0 deletions llvm/test/Analysis/PostDominators/infinite-loop2.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
; RUN: opt < %s -postdomtree -analyze | FileCheck %s
; RUN: opt < %s -passes='print<postdomtree>' 2>&1 | FileCheck %s

@a = external global i32, align 4

define void @fn1() {
entry:
store i32 5, i32* @a, align 4
%call = call i32 (...) @foo()
%tobool = icmp ne i32 %call, 0
br i1 %tobool, label %if.then, label %if.end

if.then: ; preds = %entry
br label %loop

loop: ; preds = %loop, %if.then
%0 = load i32, i32* @a, align 4
call void @bar(i32 %0)
br label %loop

if.end: ; preds = %entry
store i32 6, i32* @a, align 4
ret void
}

declare i32 @foo(...)
declare void @bar(i32)


; CHECK: Inorder PostDominator Tree:
; CHECK-NEXT: [1] <<exit node>>
; CHECK: [2] %loop
; CHECK-NEXT: [3] %if.then
; CHECK: Roots: %if.end %loop
34 changes: 34 additions & 0 deletions llvm/test/Analysis/PostDominators/infinite-loop3.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
; RUN: opt < %s -postdomtree -analyze | FileCheck %s
; RUN: opt < %s -passes='print<postdomtree>' 2>&1 | FileCheck %s

@a = external global i32, align 4

define void @fn1() {
entry:
store i32 5, i32* @a, align 4
%call = call i32 (...) @foo()
%tobool = icmp ne i32 %call, 0
br i1 %tobool, label %if.then, label %if.end

if.then: ; preds = %entry, %loop
br label %loop

loop: ; preds = %loop, %if.then
%0 = load i32, i32* @a, align 4
call void @bar(i32 %0)
br i1 true, label %loop, label %if.then

if.end: ; preds = %entry
store i32 6, i32* @a, align 4
ret void
}

declare i32 @foo(...)
declare void @bar(i32)


; CHECK: Inorder PostDominator Tree:
; CHECK-NEXT: [1] <<exit node>>
; CHECK: [2] %loop
; CHECK-NEXT: [3] %if.then
; CHECK: Roots: %if.end %loop
18 changes: 18 additions & 0 deletions llvm/test/Analysis/PostDominators/pr24415.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
; RUN: opt < %s -postdomtree -analyze | FileCheck %s
; RUN: opt < %s -passes='print<postdomtree>' 2>&1 | FileCheck %s

; Function Attrs: nounwind ssp uwtable
define void @foo() {
br label %1

; <label>:1 ; preds = %0, %1
br label %1
; No predecessors!
ret void
}

; CHECK: Inorder PostDominator Tree:
; CHECK-NEXT: [1] <<exit node>>
; CHECK-NEXT: [2] %2
; CHECK-NEXT: [2] %1
; CHECK-NEXT: [3] %0
8 changes: 7 additions & 1 deletion llvm/test/Analysis/PostDominators/pr6047_a.ll
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,10 @@ bb35.loopexit3:
bb35:
ret void
}
; CHECK: [3] %entry

;CHECK:Inorder PostDominator Tree:
;CHECK-NEXT: [1] <<exit node>>
;CHECK-NEXT: [2] %bb35
;CHECK-NEXT: [3] %bb35.loopexit3
;CHECK-NEXT: [2] %entry
;CHECK-NEXT: [2] %bb3.i
8 changes: 7 additions & 1 deletion llvm/test/Analysis/PostDominators/pr6047_b.ll
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,10 @@ bb35.loopexit3:
bb35:
ret void
}
; CHECK: [4] %entry
; CHECK: Inorder PostDominator Tree:
; CHECK-NEXT: [1] <<exit node>>
; CHECK-NEXT: [2] %bb35
; CHECK-NEXT: [3] %bb35.loopexit3
; CHECK-NEXT: [2] %a
; CHECK-NEXT: [2] %entry
; CHECK-NEXT: [2] %bb3.i
52 changes: 51 additions & 1 deletion llvm/test/Analysis/PostDominators/pr6047_c.ll
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,54 @@ bb35.loopexit3:
bb35:
ret void
}
; CHECK: [3] %entry
; CHECK: Inorder PostDominator Tree:
; CHECK-NEXT: [1] <<exit node>>
; CHECK-NEXT: [2] %bb35
; CHECK-NEXT: [3] %bb
; CHECK-NEXT: [3] %bb.i
; CHECK-NEXT: [3] %_float32_unpack.exit
; CHECK-NEXT: [3] %bb.i5
; CHECK-NEXT: [3] %_float32_unpack.exit8
; CHECK-NEXT: [3] %bb32.preheader
; CHECK-NEXT: [3] %bb3
; CHECK-NEXT: [3] %bb3.split.us
; CHECK-NEXT: [3] %bb.i4.us
; CHECK-NEXT: [3] %bb7.i.us
; CHECK-NEXT: [3] %bb.i4.us.backedge
; CHECK-NEXT: [3] %bb1.i.us
; CHECK-NEXT: [3] %bb6.i.us
; CHECK-NEXT: [3] %bb4.i.us
; CHECK-NEXT: [3] %bb8.i.us
; CHECK-NEXT: [3] %bb3.i.loopexit.us
; CHECK-NEXT: [3] %bb.nph21
; CHECK-NEXT: [3] %bb4
; CHECK-NEXT: [3] %bb5
; CHECK-NEXT: [3] %bb14.preheader
; CHECK-NEXT: [3] %bb.nph18
; CHECK-NEXT: [3] %bb8.us.preheader
; CHECK-NEXT: [3] %bb8.preheader
; CHECK-NEXT: [3] %bb8.us
; CHECK-NEXT: [3] %bb8
; CHECK-NEXT: [3] %bb15.loopexit
; CHECK-NEXT: [3] %bb15.loopexit2
; CHECK-NEXT: [3] %bb15
; CHECK-NEXT: [3] %bb16
; CHECK-NEXT: [3] %bb17.loopexit.split
; CHECK-NEXT: [3] %bb.nph14
; CHECK-NEXT: [3] %bb19
; CHECK-NEXT: [3] %bb20
; CHECK-NEXT: [3] %bb29.preheader
; CHECK-NEXT: [3] %bb.nph
; CHECK-NEXT: [3] %bb23.us.preheader
; CHECK-NEXT: [3] %bb23.preheader
; CHECK-NEXT: [3] %bb23.us
; CHECK-NEXT: [3] %bb23
; CHECK-NEXT: [3] %bb30.loopexit
; CHECK-NEXT: [3] %bb30.loopexit1
; CHECK-NEXT: [3] %bb30
; CHECK-NEXT: [3] %bb31
; CHECK-NEXT: [3] %bb35.loopexit
; CHECK-NEXT: [3] %bb35.loopexit3
; CHECK-NEXT: [2] %entry
; CHECK-NEXT: [2] %bb3.i
; CHECK-NEXT: Roots: %bb35 %bb3.i
10 changes: 9 additions & 1 deletion llvm/test/Analysis/PostDominators/pr6047_d.ll
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,12 @@ bb35.loopexit3:
bb35:
ret void
}
; CHECK: [4] %entry
; CHECK: Inorder PostDominator Tree:
; CHECK-NEXT: [1] <<exit node>>
; CHECK-NEXT: [2] %bb35
; CHECK-NEXT: [3] %bb35.loopexit3
; CHECK-NEXT: [2] %c
; CHECK-NEXT: [3] %a
; CHECK-NEXT: [3] %entry
; CHECK-NEXT: [3] %b
; CHECK-NEXT: [2] %bb3.i
4 changes: 1 addition & 3 deletions llvm/test/Analysis/RegionInfo/infinite_loop.ll
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,4 @@ define void @normal_condition() nounwind {
}
; CHECK-NOT: =>
; CHECK: [0] 0 => <Function Return>
; CHECK: [1] 1 => 4
; STAT: 2 region - The # of regions
; STAT: 1 region - The # of simple regions
; STAT: 1 region - The # of regions
11 changes: 4 additions & 7 deletions llvm/test/Analysis/RegionInfo/infinite_loop_2.ll
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,9 @@ define void @normal_condition() nounwind {
}
; CHECK-NOT: =>
; CHECK: [0] 0 => <Function Return>
; CHECK: [1] 1 => 3
; STAT: 2 region - The # of regions
; STAT: 1 region - The # of simple regions
; CHECK-NOT: [1]
; STAT: 1 region - The # of regions

; BBIT: 0, 1, 2, 5, 11, 6, 12, 3, 4,
; BBIT: 1, 2, 5, 11, 6, 12,
; BBIT: 0, 1, 2, 5, 11, 6, 12, 3, 4,

; RNIT: 0, 1 => 3, 3, 4,
; RNIT: 1, 2, 5, 11, 6, 12,
; RNIT: 0, 1, 2, 5, 11, 6, 12, 3, 4,
14 changes: 4 additions & 10 deletions llvm/test/Analysis/RegionInfo/infinite_loop_3.ll
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,10 @@ define void @normal_condition() nounwind {
ret void
}
; CHECK-NOT: =>
; CHECK: [0] 0 => <Function Return>
; CHECK-NEXT: [1] 1 => 3
; CHECK-NEXT: [1] 7 => 1
; STAT: 3 region - The # of regions
; STAT: 2 region - The # of simple regions
; CHECK:[0] 0 => <Function Return>
; CHECK-NOT: [1]
; STAT: 1 region - The # of regions

; BBIT: 0, 7, 1, 2, 5, 11, 6, 12, 3, 4, 8, 9, 13, 10, 14,
; BBIT: 7, 8, 9, 13, 10, 14,
; BBIT: 1, 2, 5, 11, 6, 12,

; RNIT: 0, 7 => 1, 1 => 3, 3, 4,
; RNIT: 7, 8, 9, 13, 10, 14,
; RNIT: 1, 2, 5, 11, 6, 12,
; RNIT: 0, 7, 1, 2, 5, 11, 6, 12, 3, 4, 8, 9, 13, 10, 14,
14 changes: 8 additions & 6 deletions llvm/test/Analysis/RegionInfo/infinite_loop_4.ll
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@ define void @normal_condition() nounwind {
}
; CHECK-NOT: =>
; CHECK: [0] 0 => <Function Return>
; CHECK-NEXT: [1] 7 => 3
; STAT: 2 region - The # of regions
; CHECK-NEXT: [1] 2 => 10
; CHECK_NEXT: [2] 5 => 6
; STAT: 3 region - The # of regions
; STAT: 1 region - The # of simple regions

; BBIT: 0, 7, 1, 2, 5, 11, 6, 10, 8, 9, 13, 14, 12, 3, 4,
; BBIT: 7, 1, 2, 5, 11, 6, 10, 8, 9, 13, 14, 12,

; RNIT: 0, 7 => 3, 3, 4,
; RNIT: 7, 1, 2, 5, 11, 6, 10, 8, 9, 13, 14, 12,
; BBIT: 2, 5, 11, 6, 12,
; BBIT: 5, 11, 12,
; RNIT: 0, 7, 1, 2 => 10, 10, 8, 9, 13, 14, 3, 4,
; RNIT: 2, 5 => 6, 6,
; RNIT: 5, 11, 12,
2 changes: 0 additions & 2 deletions llvm/test/Analysis/RegionInfo/infinite_loop_5_a.ll
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,4 @@ define void @normal_condition() nounwind {

; CHECK: Region tree:
; CHECK-NEXT: [0] 0 => <Function Return>
; CHECK-NEXT: [1] 7 => 3
; CHECK-NEXT: End region tree

1 change: 0 additions & 1 deletion llvm/test/Analysis/RegionInfo/infinite_loop_5_b.ll
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,4 @@ define void @normal_condition() nounwind {

; CHECK: Region tree:
; CHECK-NEXT: [0] 0 => <Function Return>
; CHECK-NEXT: [1] 7 => 3
; CHECK-NEXT: End region tree
16 changes: 2 additions & 14 deletions llvm/test/CodeGen/AMDGPU/branch-relaxation.ll
Original file line number Diff line number Diff line change
Expand Up @@ -428,24 +428,13 @@ endif:
}

; si_mask_branch
; s_cbranch_execz
; s_branch

; GCN-LABEL: {{^}}analyze_mask_branch:
; GCN: v_cmp_lt_f32_e32 vcc
; GCN-NEXT: s_and_saveexec_b64 [[MASK:s\[[0-9]+:[0-9]+\]]], vcc
; GCN-NEXT: ; mask branch [[RET:BB[0-9]+_[0-9]+]]
; GCN-NEXT: s_cbranch_execz [[BRANCH_SKIP:BB[0-9]+_[0-9]+]]
; GCN-NEXT: s_branch [[LOOP_BODY:BB[0-9]+_[0-9]+]]

; GCN-NEXT: [[BRANCH_SKIP]]: ; %entry
; GCN-NEXT: s_getpc_b64 vcc
; GCN-NEXT: s_add_u32 vcc_lo, vcc_lo, [[RET]]-([[BRANCH_SKIP]]+4)
; GCN-NEXT: s_addc_u32 vcc_hi, vcc_hi, 0
; GCN-NEXT: s_setpc_b64 vcc

; GCN-NEXT: [[LOOP_BODY]]: ; %loop_body
; GCN: s_mov_b64 vcc, -1{{$}}
; GCN-NEXT: [[LOOP_BODY:BB[0-9]+_[0-9]+]]: ; %loop_body
; GCN: ;;#ASMSTART
; GCN: v_nop_e64
; GCN: v_nop_e64
Expand All @@ -454,7 +443,6 @@ endif:
; GCN: v_nop_e64
; GCN: v_nop_e64
; GCN: ;;#ASMEND
; GCN-NEXT: s_cbranch_vccz [[RET]]

; GCN-NEXT: [[LONGBB:BB[0-9]+_[0-9]+]]: ; %loop_body
; GCN-NEXT: ; in Loop: Header=[[LOOP_BODY]] Depth=1
Expand All @@ -463,7 +451,7 @@ endif:
; GCN-NEXT: s_subb_u32 vcc_hi, vcc_hi, 0
; GCN-NEXT: s_setpc_b64 vcc

; GCN-NEXT: [[RET]]: ; %Flow
; GCN-NEXT: [[RET]]: ; %ret
; GCN-NEXT: s_or_b64 exec, exec, [[MASK]]
; GCN: buffer_store_dword
; GCN-NEXT: s_endpgm
Expand Down
17 changes: 3 additions & 14 deletions llvm/test/CodeGen/ARM/struct-byval-frame-index.ll
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,11 @@
; generated.
; PR16393

; We expect the spill to be generated in %if.end230 and the reloads in
; %if.end249 and %for.body285.
; We expect 4-byte spill and reload to be generated.

; CHECK: set_stored_macroblock_parameters
; CHECK: @ %if.end230
; CHECK-NOT:@ %if.
; CHECK-NOT:@ %for.
; CHECK: str r{{.*}}, [sp, [[SLOT:#[0-9]+]]] @ 4-byte Spill
; CHECK: @ %if.end249
; CHECK-NOT:@ %if.
; CHECK-NOT:@ %for.
; CHECK: ldr r{{.*}}, [sp, [[SLOT]]] @ 4-byte Reload
; CHECK: @ %for.body285
; CHECK-NOT:@ %if.
; CHECK-NOT:@ %for.
; CHECK: ldr r{{.*}}, [sp, [[SLOT]]] @ 4-byte Reload
; CHECK: str r{{.*}}, [sp, {{#[0-9]+}}] @ 4-byte Spill
; CHECK: ldr r{{.*}}, [lr, {{#[0-9]+}}] @ 4-byte Reload

target triple = "armv7l-unknown-linux-gnueabihf"

Expand Down
7 changes: 4 additions & 3 deletions llvm/test/CodeGen/Thumb2/v8_IT_5.ll
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
; RUN: llc < %s -mtriple=thumbv8 -arm-atomic-cfg-tidy=0 | FileCheck %s
; RUN: llc < %s -mtriple=thumbv7 -arm-atomic-cfg-tidy=0 -arm-restrict-it | FileCheck %s
; CHECK: it ne
; CHECK: it ne
; CHECK-NEXT: cmpne
; CHECK-NEXT: bne [[JUMPTARGET:.LBB[0-9]+_[0-9]+]]
; CHECK: cbz
Expand All @@ -9,9 +9,10 @@
; CHECK-NEXT: b
; CHECK: [[JUMPTARGET]]:{{.*}}%if.else173
; CHECK-NEXT: mov.w
; CHECK-NEXT: pop
; CHECK-NEXT: %if.else145
; CHECK-NEXT: bx lr
; CHECK: %if.else145
; CHECK-NEXT: mov.w
; CHECK: pop.w

%struct.hc = type { i32, i32, i32, i32 }

Expand Down
9 changes: 6 additions & 3 deletions llvm/test/Transforms/StructurizeCFG/branch-on-argument.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
; CHECK-LABEL: @invert_branch_on_arg_inf_loop(
; CHECK: entry:
; CHECK: %arg.inv = xor i1 %arg, true
; CHECK: phi i1 [ false, %Flow1 ], [ %arg.inv, %entry ]
define void @invert_branch_on_arg_inf_loop(i32 addrspace(1)* %out, i1 %arg) {
entry:
br i1 %arg, label %for.end, label %for.body
br i1 %arg, label %for.end, label %sesestart
sesestart:
br label %for.body

for.body: ; preds = %entry, %for.body
store i32 999, i32 addrspace(1)* %out, align 4
br label %for.body
br i1 %arg, label %for.body, label %seseend
seseend:
ret void

for.end: ; preds = %Flow
ret void
Expand Down
7 changes: 7 additions & 0 deletions llvm/test/Transforms/StructurizeCFG/no-branch-to-entry.ll
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
; XFAIL: *

; This test used to generate a region that caused it to delete the entry block,
; but it does not anymore after the changes to handling of infinite loops in the
; PostDominatorTree.
; TODO: This should be either replaced with another IR or deleted completely.

; RUN: opt -S -o - -structurizecfg -verify-dom-info < %s | FileCheck %s

; CHECK-LABEL: @no_branch_to_entry_undef(
Expand Down
159 changes: 92 additions & 67 deletions llvm/unittests/IR/DominatorTreeTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,8 @@ TEST(DominatorTree, NonUniqueEdges) {
}

// Verify that the PDT is correctly updated in case an edge removal results
// in a new unreachable CFG node.
// in a new unreachable CFG node. Also make sure that the updated PDT is the
// same as a freshly recalculated one.
//
// For the following input code and initial PDT:
//
Expand All @@ -348,27 +349,18 @@ TEST(DominatorTree, NonUniqueEdges) {
// CFG' PDT-updated
//
// A Exit
// | |
// B D
// | / | \
// B C B D
// | \ |
// v \ B
// / D \
// C \ A
// | v
// v \ A
// / D
// C \
// | \
// unreachable Exit
//
// WARNING: PDT-updated is inconsistent with PDT-recalculated, which is
// constructed from CFG' when recalculating the PDT from scratch.
//
// PDT-recalculated
// Both the blocks that end with ret and with unreachable become trivial
// PostDomTree roots, as they have no successors.
//
// Exit
// / | \
// C B D
// |
// A
//
// TODO: document the wanted behavior after resolving this inconsistency.
TEST(DominatorTree, DeletingEdgesIntroducesUnreachables) {
StringRef ModuleString =
"define void @f() {\n"
Expand All @@ -395,26 +387,33 @@ TEST(DominatorTree, DeletingEdgesIntroducesUnreachables) {
BasicBlock *C = &*FI++;
BasicBlock *D = &*FI++;

assert(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
ASSERT_TRUE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
EXPECT_TRUE(DT->verify());
EXPECT_TRUE(PDT->verify());

C->getTerminator()->eraseFromParent();
new UnreachableInst(C->getContext(), C);

DT->deleteEdge(C, B);
PDT->deleteEdge(C, B);

EXPECT_TRUE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
EXPECT_EQ(PDT->getNode(C), nullptr);

PDT->recalculate(F);
EXPECT_TRUE(DT->verify());
EXPECT_TRUE(PDT->verify());

EXPECT_FALSE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
EXPECT_NE(PDT->getNode(C), nullptr);

DominatorTree NDT(F);
EXPECT_EQ(DT->compare(NDT), 0);

PostDomTree NPDT(F);
EXPECT_EQ(PDT->compare(NPDT), 0);
});
}

// Verify that the PDT is correctly updated in case an edge removal results
// in an infinite loop.
// in an infinite loop. Also make sure that the updated PDT is the
// same as a freshly recalculated one.
//
// Test case:
//
Expand All @@ -434,27 +433,26 @@ TEST(DominatorTree, DeletingEdgesIntroducesUnreachables) {
// After deleting the edge C->B, C is part of an infinite reverse-unreachable
// loop:
//
// CFG' PDT'
// CFG' PDT'
//
// A Exit
// | |
// B D
// | / | \
// B C B D
// | \ |
// v \ B
// / D \
// C \ A
// v \ A
// / D
// C \
// / \ v
// ^ v Exit
// \_/
//
// In PDT, D post-dominates B. We verify that this post-dominance
// relation is preserved _after_ deleting the edge C->B from CFG.
//
// As C now becomes reverse-unreachable, it is not anymore part of the
// PDT. We also verify this property.
// As C now becomes reverse-unreachable, it forms a new non-trivial root and
// gets connected to the virtual exit.
// D does not postdominate B anymore, because there are two forward paths from
// B to the virtual exit:
// - B -> C -> VirtualExit
// - B -> D -> VirtualExit.
//
// TODO: Can we change the PDT definition such that C remains part of the
// CFG?
TEST(DominatorTree, DeletingEdgesIntroducesInfiniteLoop) {
StringRef ModuleString =
"define void @f() {\n"
Expand Down Expand Up @@ -483,20 +481,25 @@ TEST(DominatorTree, DeletingEdgesIntroducesInfiniteLoop) {
BasicBlock *C = &*FI++;
BasicBlock *D = &*FI++;

assert(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
ASSERT_TRUE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
EXPECT_TRUE(DT->verify());
EXPECT_TRUE(PDT->verify());

auto SwitchC = cast<SwitchInst>(C->getTerminator());
SwitchC->removeCase(SwitchC->case_begin());
DT->deleteEdge(C, B);
EXPECT_TRUE(DT->verify());
PDT->deleteEdge(C, B);
EXPECT_TRUE(PDT->verify());

EXPECT_TRUE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
EXPECT_EQ(PDT->getNode(C), nullptr);
EXPECT_FALSE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
EXPECT_NE(PDT->getNode(C), nullptr);

PDT->recalculate(F);
DominatorTree NDT(F);
EXPECT_EQ(DT->compare(NDT), 0);

EXPECT_TRUE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
EXPECT_EQ(PDT->getNode(C), nullptr);
PostDomTree NPDT(F);
EXPECT_EQ(PDT->compare(NPDT), 0);
});
}

Expand All @@ -509,9 +512,9 @@ TEST(DominatorTree, DeletingEdgesIntroducesInfiniteLoop) {
//
// A Exit
// | / | \
// B-- C B D
// | \ |
// v \ A
// B-- C2 B D
// | \ / |
// v \ C A
// / D
// C--C2 \
// / \ \ v
Expand All @@ -521,27 +524,22 @@ TEST(DominatorTree, DeletingEdgesIntroducesInfiniteLoop) {
// After deleting the edge C->E, C is part of an infinite reverse-unreachable
// loop:
//
// CFG' PDT'
// CFG' PDT'
//
// A Exit
// | |
// B D
// | / | \
// B C B D
// | \ |
// v \ B
// / D \
// C \ A
// v \ A
// / D
// C \
// / \ v
// ^ v Exit
// \_/
//
// In PDT, D does not post-dominate B. After the edge C->E is removed, a new
// post-dominance relation is introduced.
//
// As C now becomes reverse-unreachable, it is not anymore part of the
// PDT. We also verify this property.
// In PDT, D does not post-dominate B. After the edge C -> C2 is removed,
// C becomes a new nontrivial PDT root.
//
// TODO: Can we change the PDT definition such that C remains part of the
// CFG, at best without loosing the dominance relation D postdom B.
TEST(DominatorTree, DeletingEdgesIntroducesInfiniteLoop2) {
StringRef ModuleString =
"define void @f() {\n"
Expand Down Expand Up @@ -573,24 +571,30 @@ TEST(DominatorTree, DeletingEdgesIntroducesInfiniteLoop2) {
BasicBlock *C2 = &*FI++;
BasicBlock *D = &*FI++;

EXPECT_TRUE(DT->verify());
EXPECT_TRUE(PDT->verify());

auto SwitchC = cast<SwitchInst>(C->getTerminator());
SwitchC->removeCase(SwitchC->case_begin());
DT->deleteEdge(C, C2);
PDT->deleteEdge(C, C2);
C2->eraseFromParent();
C2->removeFromParent();

EXPECT_EQ(DT->getNode(C2), nullptr);
PDT->eraseNode(C2);
delete C2;

EXPECT_TRUE(DT->verify());
EXPECT_TRUE(PDT->verify());

EXPECT_TRUE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
EXPECT_EQ(PDT->getNode(C), nullptr);
EXPECT_EQ(PDT->getNode(C2), nullptr);
EXPECT_FALSE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
EXPECT_NE(PDT->getNode(C), nullptr);

PDT->recalculate(F);
DominatorTree NDT(F);
EXPECT_EQ(DT->compare(NDT), 0);

EXPECT_TRUE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
EXPECT_EQ(PDT->getNode(C), nullptr);
EXPECT_EQ(PDT->getNode(C2), nullptr);
PostDomTree NPDT(F);
EXPECT_EQ(PDT->compare(NPDT), 0);
});
}

Expand Down Expand Up @@ -686,6 +690,27 @@ TEST(DominatorTree, InsertUnreachable) {
}
}

TEST(DominatorTree, InsertFromUnreachable) {
CFGHolder Holder;
std::vector<CFGBuilder::Arc> Arcs = {{"1", "2"}, {"2", "3"}, {"3", "4"}};

std::vector<CFGBuilder::Update> Updates = {{Insert, {"3", "5"}}};
CFGBuilder B(Holder.F, Arcs, Updates);
PostDomTree PDT(*Holder.F);
EXPECT_TRUE(PDT.verify());

Optional<CFGBuilder::Update> LastUpdate = B.applyUpdate();
EXPECT_TRUE(LastUpdate);

EXPECT_EQ(LastUpdate->Action, Insert);
BasicBlock *From = B.getOrAddBlock(LastUpdate->Edge.From);
BasicBlock *To = B.getOrAddBlock(LastUpdate->Edge.To);
PDT.insertEdge(From, To);
EXPECT_TRUE(PDT.verify());
EXPECT_TRUE(PDT.getRoots().size() == 2);
EXPECT_NE(PDT.getNode(B.getOrAddBlock("5")), nullptr);
}

TEST(DominatorTree, InsertMixed) {
CFGHolder Holder;
std::vector<CFGBuilder::Arc> Arcs = {
Expand Down