Skip to content
106 changes: 99 additions & 7 deletions base/compiler/ssair/domtree.jl
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ struct SNCAData
label::PreNumber
end

copy(d::SNCAData) = SNCAData(d.semi, d.label)

"Represents a Basic Block, in the DomTree"
struct DomTreeNode
# How deep we are in the DomTree
Expand All @@ -183,6 +185,8 @@ end

DomTreeNode() = DomTreeNode(1, Vector{BBNumber}())

copy(n::DomTreeNode) = DomTreeNode(n.level, copy(n.children))

"Data structure that encodes which basic block dominates which."
struct DomTree
# These can be reused when updating domtree dynamically
Expand All @@ -196,9 +200,12 @@ struct DomTree
nodes::Vector{DomTreeNode}
end

function DomTree()
return DomTree(DFSTree(0), SNCAData[], BBNumber[], DomTreeNode[])
end
DomTree() = DomTree(DFSTree(0), SNCAData[], BBNumber[], DomTreeNode[])

copy(d::DomTree) = DomTree(copy(d.dfs_tree),
copy(d.snca_state),
copy(d.idoms_bb),
copy(d.nodes))

function construct_domtree(blocks::Vector{BasicBlock})
return update_domtree!(blocks, DomTree(), true, 0)
Expand All @@ -207,7 +214,7 @@ end
function update_domtree!(blocks::Vector{BasicBlock}, domtree::DomTree,
recompute_dfs::Bool, max_pre::PreNumber)
if recompute_dfs
DFS!(domtree.dfs_tree, blocks)
DFS!(domtree.dfs_tree, cfg.blocks)
end

if max_pre == 0
Expand Down Expand Up @@ -482,9 +489,9 @@ end
Rename basic block numbers in a dominator tree, removing the block if it is
renamed to -1.
"""
function rename_nodes!(domtree::DomTree, rename_bb::Vector{BBNumber})
function rename_blocks!(domtree::DomTree, rename_bb::Vector{BBNumber})
# Rename DFS tree
rename_nodes!(domtree.dfs_tree, rename_bb)
rename_blocks!(domtree.dfs_tree, rename_bb)

# `snca_state` is indexed by preorder number, so should be unchanged

Expand Down Expand Up @@ -512,7 +519,7 @@ end
Rename basic block numbers in a DFS tree, removing the block if it is renamed
to -1.
"""
function rename_nodes!(D::DFSTree, rename_bb::Vector{BBNumber})
function rename_blocks!(D::DFSTree, rename_bb::Vector{BBNumber})
n_blocks = length(D.to_pre)
n_reachable_blocks = length(D.from_pre)

Expand Down Expand Up @@ -540,6 +547,91 @@ function rename_nodes!(D::DFSTree, rename_bb::Vector{BBNumber})
return D
end

"""
Combine two blocks `from` and `to`. It is assumed that there is an edge from
`from` to `to`, and that the sole successor of `from` is `to` and the sole
predecessor of `to` is `from`. This does not remove the `to` node, which is
then considered to have no edges.
"""
function combine_blocks!(domtree::DomTree, from::BBNumber, to::BBNumber)
orig_pre_of_to = domtree.dfs_tree.to_pre[to]

# Combine nodes in DFS tree
combine_blocks!(domtree.dfs_tree, from, to)

# Update `snca_state`
deleteat!(domtree.snca_state, orig_pre_of_to)
for pre in 1:length(domtree.snca_state)
# If semidominator was `to`, set it to `from` instead
if domtree.snca_state[pre].semi == orig_pre_of_to
label = domtree.snca_state[pre].label
domtree.snca_state[pre] = SNCAData(orig_pre_of_to - 1, label)
end
# Labels will be reset anyway, so no need to update them
end

# Update `idoms_bb`
for bb in 1:length(domtree.idoms_bb)
# If immediate dominator was `to`, set it to `from` instead
if domtree.idoms_bb[bb] == to
domtree.idoms_bb[bb] = from
end
end

# Update `nodes`
copy!(domtree.nodes[from].children, domtree.nodes[to].children)
domtree.nodes[to] = DomTreeNode()
# Recursively decrement level of the affected children
worklist = domtree.nodes[from].children
while !isempty(worklist)
node = pop!(worklist)
domtree.nodes[node] = DomTreeNode(domtree.nodes[node].level-1,
domtree.nodes[node].children)
foreach(child -> push!(worklist, child),
domtree.nodes[node].children)
end

return domtree
end

function combine_blocks!(D::DFSTree, from::BBNumber, to::BBNumber)
# Reassignment of preorder and postorder numbers depend on these
# conditions, which should hold if `from` has only one successor `to` and
# `to` has only one predecessor `from`.
@assert D.to_pre[from] + 1 == D.to_pre[to]
@assert D.to_post[from] == D.to_post[to] + 1

# Set preorder number of `to` to 0,
# decrement preorder numbers greater than original preorder number of `to`.
# Set postorder number of `to` to 0,
# decrement postorder numbers greater than original preorder number of `to`.

orig_pre_of_to = D.to_pre[to]
orig_post_of_to = D.to_post[to]

D.to_pre[to] = 0
D.to_post[to] = 0
for bb in 1:length(D.to_pre)
if D.to_pre[bb] > orig_pre_of_to
D.to_pre[bb] -= 1
end
if D.to_post[bb] > orig_post_of_to
D.to_post[bb] -= 1
end
end
deleteat!(D.from_pre, orig_pre_of_to)
deleteat!(D.from_post, orig_post_of_to)

deleteat!(D.to_parent_pre, orig_pre_of_to)
for pre in 1:length(D.to_parent_pre)
if D.to_parent_pre[pre] > orig_pre_of_to
D.to_parent_pre[pre] -= 1
end
end

return D
end

"""
Checks if bb1 dominates bb2.
bb1 and bb2 are indexes into the CFG blocks.
Expand Down
4 changes: 1 addition & 3 deletions base/compiler/ssair/driver.jl
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,8 @@ end

function slot2reg(ir::IRCode, ci::CodeInfo, nargs::Int, sv::OptimizationState)
# need `ci` for the slot metadata, IR for the code
@timeit "domtree 1" domtree = construct_domtree(ir.cfg.blocks)
defuse_insts = scan_slot_def_use(nargs, ci, ir.stmts.inst)
@timeit "construct_ssa" ir = construct_ssa!(ci, ir, domtree, defuse_insts, nargs, sv.sptypes, sv.slottypes) # consumes `ir`
@timeit "construct_ssa" ir = construct_ssa!(ci, ir, defuse_insts, nargs, sv.sptypes, sv.slottypes) # consumes `ir`
return ir
end

Expand All @@ -123,7 +122,6 @@ function run_passes(ci::CodeInfo, nargs::Int, sv::OptimizationState)
ir = convert_to_ircode(ci, copy_exprargs(ci.code), preserve_coverage, nargs, sv)
ir = slot2reg(ir, ci, nargs, sv)
#@Base.show ("after_construct", ir)
# TODO: Domsorting can produce an updated domtree - no need to recompute here
@timeit "compact 1" ir = compact!(ir)
@timeit "Inlining" ir = ssa_inlining_pass!(ir, ir.linetable, sv.inlining, ci.propagate_inbounds)
#@timeit "verify 2" verify_ir(ir)
Expand Down
10 changes: 8 additions & 2 deletions base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ function finish_cfg_inline!(state::CFGInliningState)
end
end

# NOTE: The domtree is not kept up-to-date with changes this makes
function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector{Any},
linetable::Vector{LineInfoNode}, item::InliningTodo,
boundscheck::Symbol, todo_bbs::Vector{Tuple{Int, Int}})
Expand Down Expand Up @@ -415,6 +416,7 @@ end

const fatal_type_bound_error = ErrorException("fatal error in type inference (type bound)")

# NOTE: The domtree is not kept up-to-date with changes this makes
function ir_inline_unionsplit!(compact::IncrementalCompact, idx::Int,
argexprs::Vector{Any}, linetable::Vector{LineInfoNode},
item::UnionSplit, boundscheck::Symbol, todo_bbs::Vector{Tuple{Int, Int}})
Expand Down Expand Up @@ -497,7 +499,9 @@ function ir_inline_unionsplit!(compact::IncrementalCompact, idx::Int,
end

function batch_inline!(todo::Vector{Pair{Int, Any}}, ir::IRCode, linetable::Vector{LineInfoNode}, propagate_inbounds::Bool)
# Compute the new CFG first (modulo statement ranges, which will be computed below)
# Compute the new CFG first (modulo statement ranges, which will be
# computed below, and the domtree, which will be updated below before we
# iterate through the statements)
state = CFGInliningState(ir)
for (idx, item) in todo
if isa(item, UnionSplit)
Expand All @@ -519,6 +523,9 @@ function batch_inline!(todo::Vector{Pair{Int, Any}}, ir::IRCode, linetable::Vect

let compact = IncrementalCompact(ir, false)
compact.result_bbs = state.new_cfg_blocks
# Recompute the domtree now that the CFG has been modified
compact.result_domtree = construct_domtree(compact.result_bbs)

# This needs to be a minimum and is more of a size hint
nn = 0
for (_, item) in todo
Expand Down Expand Up @@ -567,7 +574,6 @@ function batch_inline!(todo::Vector{Pair{Int, Any}}, ir::IRCode, linetable::Vect
compact[idx] = PhiNode(Int32[edge == length(state.bb_rename) ? length(state.new_cfg_blocks) : state.bb_rename[edge+1]-1 for edge in stmt.edges], stmt.values)
end
end

ir = finish(compact)
end
return ir
Expand Down
Loading