From 7e8290e4792fe510091e371b087521ad7f5ea9f8 Mon Sep 17 00:00:00 2001 From: Yichao Yu Date: Sat, 23 Apr 2016 12:25:01 -0400 Subject: [PATCH] More aggressive allocation elimination. * Mutable allocations that aren't mutated or escaped * Allocations that aren't used (Fix #12415) * Allocations of fields that aren't used or escaped --- base/inference.jl | 75 +++++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 25 deletions(-) diff --git a/base/inference.jl b/base/inference.jl index a321aba433f85..1a5b06721e81a 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -3149,7 +3149,7 @@ function _getfield_elim_pass!(e::Expr, sv) e1 = e.args[2] j = e.args[3] if isa(e1,Expr) - alloc = is_immutable_allocation(e1, sv) + alloc = is_allocation(e1, sv) if !is(alloc, false) flen, fnames = alloc if isa(j,QuoteNode) @@ -3184,16 +3184,16 @@ end _getfield_elim_pass!(e::ANY, sv) = e -# check if e is a successful allocation of an immutable struct +# check if e is a successful allocation of an struct # if it is, returns (n,f) such that it is always valid to call # getfield(..., 1 <= x <= n) or getfield(..., x in f) on the result -function is_immutable_allocation(e :: ANY, sv::InferenceState) +function is_allocation(e :: ANY, sv::InferenceState) isa(e, Expr) || return false if is_known_call(e, tuple, sv) return (length(e.args)-1,()) elseif e.head === :new typ = widenconst(exprtype(e, sv)) - if isleaftype(typ) && !typ.mutable + if isleaftype(typ) @assert(isa(typ,DataType)) nf = length(e.args)-1 names = fieldnames(typ) @@ -3210,7 +3210,7 @@ function is_immutable_allocation(e :: ANY, sv::InferenceState) false end -# eliminate allocation of unnecessary immutables +# eliminate allocation of unnecessary objects # that are only used as arguments to safe getfield calls function alloc_elim_pass!(linfo::LambdaInfo, sv::InferenceState) body = linfo.code @@ -3221,41 +3221,66 @@ function alloc_elim_pass!(linfo::LambdaInfo, sv::InferenceState) i = 1 while i < length(body) e = body[i] - if !(isa(e,Expr) && is(e.head,:(=)) && (isa(e.args[1], GenSym) || - (isa(e.args[1],Slot) && haskey(vs, e.args[1].id)))) + if !isa(e, Expr) i += 1 continue end - var = e.args[1] - rhs = e.args[2] - alloc = is_immutable_allocation(rhs, sv) + e = e::Expr + if is(e.head,:(=)) && (isa(e.args[1], GenSym) || + (isa(e.args[1],Slot) && haskey(vs, e.args[1].id))) + var = e.args[1] + rhs = e.args[2] + else + var = nothing + rhs = e + end + alloc = is_allocation(rhs, sv) if !is(alloc,false) nv, field_names = alloc tup = rhs.args - if occurs_outside_getfield(bexpr, var, sv, nv, field_names) + # This makes sure the value doesn't escape so we can elide + # allocation of mutable types too + if (!is(var, nothing) && + occurs_outside_getfield(bexpr, var, sv, nv, field_names)) i += 1 continue end deleteat!(body, i) # remove tuple allocation # convert tuple allocation to a series of local var assignments - vals = cell(nv) n_ins = 0 - for j=1:nv - tupelt = tup[j+1] - if isa(tupelt,Number) || isa(tupelt,AbstractString) || isa(tupelt,QuoteNode) - vals[j] = tupelt - else - elty = exprtype(tupelt,sv) - tmpv = newvar!(sv, elty) - tmp = Expr(:(=), tmpv, tupelt) - insert!(body, i+n_ins, tmp) - vals[j] = tmpv - n_ins += 1 + if is(var, nothing) + for j=1:nv + tupelt = tup[j+1] + if !(isa(tupelt,Number) || isa(tupelt,AbstractString) || + isa(tupelt,QuoteNode) || isa(tupelt, GenSym)) + insert!(body, i+n_ins, tupelt) + n_ins += 1 + end + end + else + vals = cell(nv) + for j=1:nv + tupelt = tup[j+1] + if (isa(tupelt,Number) || isa(tupelt,AbstractString) || + isa(tupelt,QuoteNode) || isa(tupelt, GenSym)) + vals[j] = tupelt + else + elty = exprtype(tupelt,sv) + tmpv = newvar!(sv, elty) + tmp = Expr(:(=), tmpv, tupelt) + insert!(body, i+n_ins, tmp) + vals[j] = tmpv + n_ins += 1 + end end + replace_getfield!(linfo, bexpr, var, vals, field_names, + sv, i + n_ins) end - i += n_ins - replace_getfield!(linfo, bexpr, var, vals, field_names, sv, i) + # Do not increment counter and do the optimization recursively + # on the allocation of fields too. + # This line can probably be added back for linear IR + # i += n_ins else i += 1 end