diff --git a/base/inference.jl b/base/inference.jl index dcf4a7c4c360d..f653b2d2ebb25 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -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) @@ -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) @@ -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 @@ -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] @@ -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) @@ -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) @@ -5815,14 +5871,7 @@ 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 @@ -5830,22 +5879,25 @@ function reindex_labels!(sv::InferenceState) # 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