Skip to content

Commit

Permalink
[NewOptimizer] Do proper liveness analysis before idf
Browse files Browse the repository at this point in the history
  • Loading branch information
Keno committed Mar 16, 2018
1 parent 464f29f commit d3fc586
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 13 deletions.
2 changes: 1 addition & 1 deletion base/compiler/bootstrap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# especially try to make sure any recursive and leaf functions have concrete signatures,
# since we won't be able to specialize & infer them at runtime

let fs = Any[typeinf_ext, typeinf, typeinf_edge, pure_eval_call, optimize],
let fs = Any[typeinf_ext, typeinf, typeinf_edge, pure_eval_call, optimize, run_passes],
world = ccall(:jl_get_world_counter, UInt, ())
for x in T_FFUNC_VAL
push!(fs, x[3])
Expand Down
6 changes: 3 additions & 3 deletions base/compiler/ssair/passes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -330,9 +330,9 @@ function getfield_elim_pass!(ir::IRCode, domtree)
ftyp = fieldtype(typ, fidx)
if !isempty(du.uses)
push!(du.defs, idx)
ldu = lift_defuse(ir.cfg, du)
ldu = compute_live_ins(ir.cfg, du)
phiblocks = []
if !isempty(ldu.uses)
if !isempty(ldu.live_in_bbs)
phiblocks = idf(ir.cfg, ldu, domtree)
end
phinodes = IdDict{Int, SSAValue}()
Expand All @@ -341,7 +341,7 @@ function getfield_elim_pass!(ir::IRCode, domtree)
phinodes[b] = insert_node!(ir, first(ir.cfg.blocks[b].stmts), ftyp, n)
end
# Now go through all uses and rewrite them
allblocks = sort(vcat(phiblocks, ldu.defs))
allblocks = sort(vcat(phiblocks, ldu.def_bbs))
for stmt in du.uses
ir[SSAValue(stmt)] = compute_value_for_use(ir, domtree, allblocks, du, phinodes, fidx, stmt)
end
Expand Down
60 changes: 52 additions & 8 deletions base/compiler/ssair/slot2ssa.jl
Original file line number Diff line number Diff line change
Expand Up @@ -219,10 +219,15 @@ function typ_for_val(@nospecialize(val), ci::CodeInfo)
return Const(val)
end

struct BlockLiveness
def_bbs::Vector{Int}
live_in_bbs::Vector{Int}
end

# Run iterated dominance frontier
function idf(cfg::CFG, defuse, domtree::DomTree)
function idf(cfg::CFG, liveness::BlockLiveness, domtree::DomTree)
# This should be a priority queue, but TODO - sorted array for now
defs = defuse.defs
defs = liveness.def_bbs
pq = Tuple{Int, Int}[(defs[i], domtree.nodes[defs[i]].level) for i in 1:length(defs)]
sort!(pq, by=x->x[2])
phiblocks = Int[]
Expand All @@ -239,14 +244,15 @@ function idf(cfg::CFG, defuse, domtree::DomTree)
succ_level > level && continue
succ in processed && continue
push!(processed, succ)
# <- TODO: Use liveness here
if !(succ in liveness.live_in_bbs)
continue
end
push!(phiblocks, succ)
if !(succ in defs)
push!(pq, (succ, succ_level))
sort!(pq, by=x->x[2])
end
end

for child in domtree.nodes[active].children
child in visited && continue
push!(visited, child)
Expand Down Expand Up @@ -419,10 +425,48 @@ function domsort_ssa!(ir, domtree)
new_ir
end

function compute_live_ins(cfg, defuse)
# We remove from `uses` any block where all uses are dominated
# by a def. This prevents insertion of dead phi nodes at the top
# of such a block if that block happens to be in a loop
ordered = Tuple{Int, Int, Bool}[(x, block_for_inst(cfg, x), true) for x in defuse.uses]
for x in defuse.defs
push!(ordered, (x, block_for_inst(cfg, x), false))
end
ordered = sort(ordered, by=x->x[1])
bb_defs = Int[]
bb_uses = Int[]
last_bb = last_def_bb = 0
for (_, bb, is_use) in ordered
if bb != last_bb && is_use
push!(bb_uses, bb)
end
last_bb = bb
if last_def_bb != bb && !is_use
push!(bb_defs, bb)
last_def_bb = bb
end
end
# To obtain live ins from bb_uses, recursively add predecessors
extra_liveins = IdSet{Int}()
worklist = Int[]
for bb in bb_uses
append!(worklist, filter(p->!(p in bb_defs), cfg.blocks[bb].preds))
end
while !isempty(worklist)
elem = pop!(worklist)
(elem in bb_uses || elem in extra_liveins) && continue
push!(extra_liveins, elem)
append!(worklist, filter(p->!(p in bb_defs), cfg.blocks[elem].preds))
end
append!(bb_uses, extra_liveins)
BlockLiveness(bb_defs, bb_uses)
end

function construct_ssa!(ci::CodeInfo, ir::IRCode, domtree::DomTree, defuse, nargs::Int)
cfg = ir.cfg
left = Int[]
defuse_blocks = lift_defuse(ir.cfg, defuse)
livenesses = map(du->compute_live_ins(cfg, du), defuse)
phi_slots = Vector{Int}[Vector{Int}() for _ = 1:length(ir.cfg.blocks)]
phi_nodes = Vector{Pair{Int,PhiNode}}[Vector{Pair{Int,PhiNode}}() for _ = 1:length(cfg.blocks)]
phi_ssas = SSAValue[]
Expand Down Expand Up @@ -451,7 +495,7 @@ function construct_ssa!(ci::CodeInfo, ir::IRCode, domtree::DomTree, defuse, narg
continue
end
# TODO: Perform liveness here to eliminate dead phi nodes
phiblocks = idf(cfg, defuse_blocks[idx], domtree)
phiblocks = idf(cfg, livenesses[idx], domtree)
for block in phiblocks
push!(phi_slots[block], idx)
node = PhiNode()
Expand Down Expand Up @@ -623,6 +667,6 @@ function construct_ssa!(ci::CodeInfo, ir::IRCode, domtree::DomTree, defuse, narg
(pt, typ, new_to_regular(renumber_ssa!(stmt, ssavalmap)), line)
end for i in 1:length(new_nodes)]
ir = IRCode(ir, code, types, ir.lines, ir.cfg, new_nodes)
ir = domsort_ssa!(ir, domtree)
#ir = domsort_ssa!(ir, domtree)
ir
end
end
9 changes: 8 additions & 1 deletion base/compiler/ssair/verify.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ function check_op(ir::IRCode, domtree::DomTree, @nospecialize(op), use_bb::Int,
else
if !dominates(domtree, def_bb, use_bb)
#@Base.show ir
#@Base.show ir.cfg
#@Base.error "Basic Block $def_bb does not dominate block $use_bb (tried to use value $(op.id))"
error()
end
Expand All @@ -29,14 +30,20 @@ function verify_ir(ir::IRCode)
# @assert isempty(ir.new_nodes)
# Verify CFG
last_end = 0
for block in ir.cfg.blocks
for (idx, block) in pairs(ir.cfg.blocks)
if first(block.stmts) != last_end + 1
#ranges = [(idx,first(bb.stmts),last(bb.stmts)) for (idx, bb) in pairs(ir.cfg.blocks)]
#@Base.show ranges
#@Base.show (first(block.stmts), last_end)
error()
end
last_end = last(block.stmts)
for p in block.preds
idx in ir.cfg.blocks[p].succs || error()
end
for s in block.succs
idx in ir.cfg.blocks[s].preds || error()
end
end
# Verify statements
domtree = construct_domtree(ir.cfg)
Expand Down

0 comments on commit d3fc586

Please sign in to comment.