Files
Alexis Engelke 284ef1b4ac [Support][NFCI] Store DomTree children as linked list (#176409)
Reduce the size of a DomTreeNodeBase from 80 to 56 bytes by not storing
the children in a SmallVector. Instead, store children as forward-linked
list. This also avoids extra allocations for nodes with many children.
Additionally, DomTreeNodeBase is now trivially destructible.

A lot of code depends on the order of nodes in the dominator tree, so
make sure that the order is the same when inserting nodes. (Not having
to do this would save 8 bytes per node.)

NewGVN uses the order of nodes in the dominator tree in a way that is
not entirely clear to me (https://reviews.llvm.org/D28129). I kept the
semantics as, but now this is the only external user of
addChild/removeChild, which actually should be private.

https://llvm-compile-time-tracker.com/compare.php?from=263802c56b4db3fc9b6ed9fd313499cb03ca44da&to=43e0c0c5b663b3a4067252fc0addbaccefd0014d&stat=instructions:u
2026-01-17 21:09:49 +01:00

112 lines
5.2 KiB
LLVM

; RUN: opt < %s -disable-output -passes='jump-threading,print<domtree>' 2>&1 | FileCheck %s
; REQUIRES: asserts
; The idea behind this test case is to verify that the dominator tree is
; updated in a deterministic way. Optimizations, at least EarlyCSE, are
; iterating the vectors that hold child nodes in the DominatorTree. Thus, the
; end result might differ depending on the order in which nodes are inserted
; in the dominator tree. Unfortunately this test case is quite large, but it
; happened to trigger a non-determinism quite often when being executed
; multipe times (it was possible to see varying results when running the test
; less that 10 times in a row).
; The actual problem was tracked down to llvm::MergeBasicBlockIntoOnlyPred, so
; the important property of the test is probably that it triggers a call to
; that function, and that the PredsOfPredBB set that is used to populate
; Updates for the DomTreeUpdater is populated with more than one entry.
; CHECK: Inorder Dominator Tree: DFSNumbers invalid: 0 slow queries.
; CHECK-NEXT: [1] %entry {4294967295,4294967295} [0]
; CHECK-NEXT: [2] %for.cond1 {4294967295,4294967295} [1]
; CHECK-NEXT: [3] %if.then {4294967295,4294967295} [2]
; CHECK-NEXT: [4] %for.cond5.preheader {4294967295,4294967295} [3]
; CHECK-NEXT: [5] %for.body7 {4294967295,4294967295} [4]
; CHECK-NEXT: [6] %for.inc {4294967295,4294967295} [5]
; CHECK-NEXT: [5] %cleanup {4294967295,4294967295} [4]
; CHECK-NEXT: [6] %cleanup16 {4294967295,4294967295} [5]
; CHECK-NEXT: [7] %unreachable {4294967295,4294967295} [6]
; CHECK-NEXT: [7] %for.end21 {4294967295,4294967295} [6]
; CHECK-NEXT: [5] %return {4294967295,4294967295} [4]
; CHECK-NEXT: [3] %cleanup16.thread {4294967295,4294967295} [2]
; CHECK-NEXT: [3] %for.inc19 {4294967295,4294967295} [2]
; CHECK-NEXT: [2] %infinite.loop {4294967295,4294967295} [1]
; CHECK-NEXT: Roots: %entry
@a = dso_local local_unnamed_addr global i16 0, align 1
; Function Attrs: nounwind
define dso_local i16 @g(i16 %a0, i16 %a1, i16 %a2, i16 %a3) local_unnamed_addr {
entry:
%tobool.not = icmp eq i16 %a0, 0
br i1 %tobool.not, label %for.cond1, label %infinite.loop
infinite.loop: ; preds = %infinite.loop, %entry
br label %infinite.loop
for.cond1: ; preds = %for.inc19, %entry
%retval.0 = phi i16 [ %retval.3, %for.inc19 ], [ undef, %entry ]
%i.0 = phi i16 [ %i.3, %for.inc19 ], [ undef, %entry ]
%tobool2.not = icmp eq i16 %a1, 0
br i1 %tobool2.not, label %if.end15, label %if.then
if.then: ; preds = %for.cond1
%tobool3.not = icmp eq i16 %a2, 0
br i1 %tobool3.not, label %if.end15, label %for.cond5.preheader
for.cond5.preheader: ; preds = %if.then
%tobool8.not = icmp eq i16 %a3, 0
%tobool6.not31 = icmp eq i16 %i.0, 0
br i1 %tobool6.not31, label %for.end10, label %for.body7
for.body7: ; preds = %for.inc, %for.cond5.preheader
%i.132 = phi i16 [ %inc, %for.inc ], [ %i.0, %for.cond5.preheader ]
br i1 %tobool8.not, label %for.inc, label %cleanup
for.inc: ; preds = %for.body7
%inc = add i16 %i.132, 1
%tobool6.not = icmp eq i16 %inc, 0
br i1 %tobool6.not, label %for.end10, label %for.body7
for.end10: ; preds = %for.inc, %for.cond5.preheader
%i.1.lcssa = phi i16 [ %i.0, %for.cond5.preheader ], [ 0, %for.inc ]
%.26 = select i1 %tobool8.not, i32 0, i32 4
br label %cleanup
cleanup: ; preds = %for.end10, %for.body7
%i.128 = phi i16 [ %i.1.lcssa, %for.end10 ], [ %i.0, %for.body7 ]
%retval.1 = phi i16 [ %retval.0, %for.end10 ], [ 1, %for.body7 ]
%cond = phi i1 [ %tobool8.not, %for.end10 ], [ false, %for.body7 ]
%cleanup.dest.slot.0 = phi i32 [ %.26, %for.end10 ], [ 1, %for.body7 ]
br i1 %cond, label %if.end15, label %cleanup16
if.end15: ; preds = %cleanup, %if.then, %for.cond1
%retval.2 = phi i16 [ %retval.1, %cleanup ], [ %retval.0, %if.then ], [ %retval.0, %for.cond1 ]
%i.2 = phi i16 [ %i.128, %cleanup ], [ %i.0, %if.then ], [ %i.0, %for.cond1 ]
store i16 0, ptr @a, align 1
br label %cleanup16
cleanup16: ; preds = %if.end15, %cleanup
%retval.3 = phi i16 [ %retval.2, %if.end15 ], [ %retval.1, %cleanup ]
%i.3 = phi i16 [ %i.2, %if.end15 ], [ %i.128, %cleanup ]
%cleanup.dest.slot.1 = phi i32 [ 0, %if.end15 ], [ %cleanup.dest.slot.0, %cleanup ]
switch i32 %cleanup.dest.slot.1, label %unreachable [
i32 0, label %for.inc19
i32 1, label %return
i32 4, label %for.end21
]
for.inc19: ; preds = %cleanup16
br label %for.cond1
for.end21: ; preds = %cleanup16
br label %return
return: ; preds = %for.end21, %cleanup16
%retval.4 = phi i16 [ 17, %for.end21 ], [ %retval.3, %cleanup16 ]
ret i16 %retval.4
unreachable: ; preds = %cleanup16
unreachable
}