Skip to content

Commit

Permalink
inference: implement a basic DCE pass
Browse files Browse the repository at this point in the history
sufficient for removing dead code left over in typical boundscheck blocks
  • Loading branch information
vtjnash committed Aug 8, 2017
1 parent 702a437 commit d001ebb
Showing 1 changed file with 71 additions and 19 deletions.
90 changes: 71 additions & 19 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2736,6 +2736,18 @@ function label_counter(body::Vector{Any})
end
genlabel(sv) = LabelNode(sv.label_counter += 1)

function get_label_map(body::Vector{Any}, sv::InferenceState)
labelmap = zeros(Int, sv.label_counter)
for i = 1:length(body)
el = body[i]
if isa(el, LabelNode)
labelmap[el.label] = i
end
end
return labelmap
end


function find_ssavalue_uses(body::Vector{Any}, nvals::Int)
uses = IntSet[ IntSet() for i = 1:nvals ]
for line in 1:length(body)
Expand Down Expand Up @@ -3346,6 +3358,7 @@ function optimize(me::InferenceState)
gotoifnot_elim_pass!(me)
inlining_pass!(me, me.src.propagate_inbounds)
gotoifnot_elim_pass!(me)
basic_dce_pass!(me)
void_use_elim_pass!(me)
alloc_elim_pass!(me)
getfield_elim_pass!(me)
Expand Down Expand Up @@ -5482,6 +5495,7 @@ function getfield_elim_pass!(sv::InferenceState)
body = sv.src.code
nssavalues = length(sv.src.ssavaluetypes)
sv.ssavalue_defs = find_ssavalue_defs(body, nssavalues)
sv.ssavalue_uses = find_ssavalue_uses(body, nssavalues)
for i = 1:length(body)
body[i] = _getfield_elim_pass!(body[i], sv)
end
Expand All @@ -5500,7 +5514,11 @@ function _getfield_elim_pass!(e::Expr, sv::InferenceState)
j = e.args[3]
single_use = true
while isa(e1, SSAValue)
single_use = false
if single_use
if length(sv.ssavalue_uses[e1.id + 1]) > 1
single_use = false
end
end
def = sv.ssavalue_defs[e1.id + 1]
stmt = sv.src.code[def]::Expr
e1 = stmt.args[2]
Expand Down Expand Up @@ -5587,7 +5605,6 @@ function gotoifnot_elim_pass!(sv::InferenceState)
expr = body[i]
i += 1
isa(expr, Expr) || continue
expr = expr::Expr
expr.head === :gotoifnot || continue
cond = expr.args[1]
condt = exprtype(cond, sv.src, sv.mod)
Expand All @@ -5607,6 +5624,45 @@ function gotoifnot_elim_pass!(sv::InferenceState)
end
end

# basic dead-code-elimination of unreachable statements
function basic_dce_pass!(sv::InferenceState)
body = sv.src.code
labelmap = get_label_map(body, sv)
reachable = IntSet()
W = IntSet()
push!(W, 1)
while !isempty(W)
pc = pop!(W)
pc in reachable && continue
push!(reachable, pc)
expr = body[pc]
pc += 1
if isa(expr, GotoNode)
pc = labelmap[expr.label]
elseif isa(expr, Expr)
label = 0
if expr.head === :gotoifnot
label = labelmap[expr.args[2]::Int]
label === 0 || push!(W, label) # inference must have computed that this condition is always true
elseif expr.head === :enter
push!(W, labelmap[expr.args[1]::Int])
elseif expr.head === :return
continue
end
end
pc <= length(body) && push!(W, pc)
end
for i in 1:length(body)
expr = body[i]
if !(i in reachable ||
(isa(expr, Expr) && is_meta_expr(expr)) ||
isa(expr, LineNumberNode))
body[i] = nothing
end
end
end


# eliminate allocation of unnecessary objects
# that are only used as arguments to safe getfield calls
function alloc_elim_pass!(sv::InferenceState)
Expand Down Expand Up @@ -5815,37 +5871,33 @@ end
# fix label numbers to always equal the statement index of the label
function reindex_labels!(sv::InferenceState)
body = sv.src.code
mapping = zeros(Int, sv.label_counter)
for i = 1:length(body)
el = body[i]
if isa(el,LabelNode)
mapping[el.label] = i
body[i] = LabelNode(i)
end
end
mapping = get_label_map(body, sv)
for i = 1:length(body)
el = body[i]
# For goto and enter, the statement and the target has to be
# both reachable or both not. For gotoifnot, the dead code
# elimination in type_annotate! can delete the target
# of a reachable (but never taken) node. In which case we can
# just replace the node with the branch condition.
if isa(el,GotoNode)
if isa(el, LabelNode)
labelnum = mapping[el.label]
@assert labelnum !== 0
body[i] = LabelNode(labelnum)
elseif isa(el, GotoNode)
labelnum = mapping[el.label]
@assert labelnum !== 0
body[i] = GotoNode(labelnum)
elseif isa(el,Expr)
el = el::Expr
elseif isa(el, Expr)
if el.head === :gotoifnot
labelnum = mapping[el.args[2]]
if labelnum !== 0
el.args[2] = mapping[el.args[2]]
else
# Might have side effects
labelnum = mapping[el.args[2]::Int]
if labelnum === 0
# Might still have side effects
body[i] = el.args[1]
else
el.args[2] = labelnum
end
elseif el.head === :enter
labelnum = mapping[el.args[1]]
labelnum = mapping[el.args[1]::Int]
@assert labelnum !== 0
el.args[1] = labelnum
end
Expand Down

0 comments on commit d001ebb

Please sign in to comment.