Skip to content

Commit

Permalink
fix missing inlining-cost for loops (JuliaLang#23169)
Browse files Browse the repository at this point in the history
loops were previously being incorrectly counted as free,
leading to potentially excessive inlining of multiple loops

also restores 69a18b9 in the improved
cost model
  • Loading branch information
vtjnash authored Sep 15, 2017
1 parent da6b948 commit 06da784
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 24 deletions.
12 changes: 6 additions & 6 deletions base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -441,16 +441,16 @@ See also [`zeros`](@ref), [`similar`](@ref).
"""
function ones end

for (fname, felt) in ((:zeros,:zero), (:ones,:one))
for (fname, felt) in ((:zeros, :zero), (:ones, :one))
@eval begin
# allow signature of similar
$fname(a::AbstractArray, T::Type, dims::Tuple) = fill!(similar(a, T, dims), $felt(T))
$fname(a::AbstractArray, T::Type, dims...) = fill!(similar(a,T,dims...), $felt(T))
$fname(a::AbstractArray, T::Type=eltype(a)) = fill!(similar(a,T), $felt(T))
$fname(a::AbstractArray, ::Type{T}, dims::Tuple) where {T} = fill!(similar(a, T, dims), $felt(T))
$fname(a::AbstractArray, ::Type{T}, dims...) where {T} = fill!(similar(a, T, dims...), $felt(T))
$fname(a::AbstractArray, ::Type{T}=eltype(a)) where {T} = fill!(similar(a, T), $felt(T))

$fname(T::Type, dims::Tuple) = fill!(Array{T}(Dims(dims)), $felt(T))
$fname(::Type{T}, dims::NTuple{N, Any}) where {T, N} = fill!(Array{T,N}(Dims(dims)), $felt(T))
$fname(dims::Tuple) = ($fname)(Float64, dims)
$fname(T::Type, dims...) = $fname(T, dims)
$fname(::Type{T}, dims...) where {T} = $fname(T, dims)
$fname(dims...) = $fname(dims)
end
end
Expand Down
6 changes: 2 additions & 4 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1279,11 +1279,9 @@ end
# #19635
for fname in (:ones, :zeros)
@eval @deprecate ($fname)(T::Type, arr) ($fname)(T, size(arr))
@eval ($fname)(T::Type, i::Integer) = ($fname)(T, (i,))
@eval ($fname)(::Type{T}, i::Integer) where {T} = ($fname)(T, (i,)) # provides disambiguation with method in Base
@eval function ($fname)(::Type{T}, arr::Array{T}) where T
msg = string("`", $fname, "{T}(::Type{T}, arr::Array{T})` is deprecated, use ",
"`", $fname , "(T, size(arr))` instead. ",
)
msg = $("`$fname{T}(::Type{T}, arr::Array{T})` is deprecated, use `$fname(T, size(arr))` instead.")
error(msg)
end
end
Expand Down
47 changes: 33 additions & 14 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4713,17 +4713,16 @@ plus_saturate(x, y) = max(x, y, x+y)
# known return type
isknowntype(T) = (T == Union{}) || isleaftype(T)

statement_cost(::Any, src::CodeInfo, mod::Module, params::InferenceParams) = 0
statement_cost(qn::QuoteNode, src::CodeInfo, mod::Module, params::InferenceParams) =
statement_cost(qn.value, src, mod, params)
function statement_cost(ex::Expr, src::CodeInfo, mod::Module, params::InferenceParams)
function statement_cost(ex::Expr, line::Int, src::CodeInfo, mod::Module, params::InferenceParams)
head = ex.head
if is_meta_expr(ex) || head == :copyast # not sure if copyast is right
return 0
end
argcost = 0
for a in ex.args
argcost = plus_saturate(argcost, statement_cost(a, src, mod, params))
if a isa Expr
argcost = plus_saturate(argcost, statement_cost(a, line, src, mod, params))
end
end
if head == :return || head == :(=)
return argcost
Expand Down Expand Up @@ -4775,10 +4774,20 @@ function statement_cost(ex::Expr, src::CodeInfo, mod::Module, params::InferenceP
return ex.typ == Union{} ? 0 : plus_saturate(20, argcost)
elseif head == :llvmcall
return plus_saturate(10, argcost) # a wild guess at typical cost
elseif (head == :&)
return plus_saturate(length(ex.args), argcost)
end
argcost
elseif head == :enter
# try/catch is a couple function calls,
# but don't inline functions with try/catch
# since these aren't usually performance-sensitive functions,
# and llvm is more likely to miscompile them when these functions get large
return typemax(Int)
elseif head == :gotoifnot
target = ex.args[2]::Int
# loops are generally always expensive
# but assume that forward jumps are already counted for from
# summing the cost of the not-taken branch
return target < line ? plus_saturate(40, argcost) : argcost
end
return argcost
end

function inline_worthy(body::Array{Any,1}, src::CodeInfo, mod::Module,
Expand All @@ -4787,23 +4796,33 @@ function inline_worthy(body::Array{Any,1}, src::CodeInfo, mod::Module,
bodycost = 0
for line = 1:length(body)
stmt = body[line]
thiscost = statement_cost(stmt, src, mod, params)
if stmt isa Expr
thiscost = statement_cost(stmt, line, src, mod, params)::Int
elseif stmt isa GotoNode
# loops are generally always expensive
# but assume that forward jumps are already counted for from
# summing the cost of the not-taken branch
thiscost = stmt.label < line ? 40 : 0
else
continue
end
bodycost = plus_saturate(bodycost, thiscost)
bodycost == typemax(Int) && return false
end
bodycost <= cost_threshold
return bodycost <= cost_threshold
end

function inline_worthy(body::Expr, src::CodeInfo, mod::Module, params::InferenceParams,
cost_threshold::Integer=params.inline_cost_threshold)
bodycost = statement_cost(body, src, mod, params)
bodycost <= cost_threshold
bodycost = statement_cost(body, typemax(Int), src, mod, params)
return bodycost <= cost_threshold
end

function inline_worthy(@nospecialize(body), src::CodeInfo, mod::Module, params::InferenceParams,
cost_threshold::Integer=params.inline_cost_threshold)
newbody = exprtype(body, src, mod)
!isa(newbody, Expr) && return true
inline_worthy(newbody, src, mod, params, cost_threshold)
return inline_worthy(newbody, src, mod, params, cost_threshold)
end

ssavalue_increment(@nospecialize(body), incr) = body
Expand Down

0 comments on commit 06da784

Please sign in to comment.