Skip to content

Commit

Permalink
Refactor abstract_eval to separate out statements and values (#36350)
Browse files Browse the repository at this point in the history
In preparation for adding the ability for statements to return
additional info, while values will only ever have a type.
  • Loading branch information
Keno authored Jun 23, 2020
1 parent be72a57 commit fd6eee7
Showing 1 changed file with 43 additions and 24 deletions.
67 changes: 43 additions & 24 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -970,7 +970,7 @@ function sp_type_rewrap(@nospecialize(T), linfo::MethodInstance, isreturn::Bool)
end

function abstract_eval_cfunction(interp::AbstractInterpreter, e::Expr, vtypes::VarTable, sv::InferenceState)
f = abstract_eval(interp, e.args[2], vtypes, sv)
f = abstract_eval_value(interp, e.args[2], vtypes, sv)
# rt = sp_type_rewrap(e.args[3], sv.linfo, true)
at = Any[ sp_type_rewrap(argt, sv.linfo, false) for argt in e.args[4]::SimpleVector ]
pushfirst!(at, f)
Expand All @@ -981,7 +981,21 @@ function abstract_eval_cfunction(interp::AbstractInterpreter, e::Expr, vtypes::V
nothing
end

function abstract_eval(interp::AbstractInterpreter, @nospecialize(e), vtypes::VarTable, sv::InferenceState)
function abstract_eval_value_expr(interp::AbstractInterpreter, e::Expr, vtypes::VarTable, sv::InferenceState)
if e.head === :static_parameter
n = e.args[1]
t = Any
if 1 <= n <= length(sv.sptypes)
t = sv.sptypes[n]
end
elseif e.head === :boundscheck
return Bool
else
return Any
end
end

function abstract_eval_special_value(interp::AbstractInterpreter, @nospecialize(e), vtypes::VarTable, sv::InferenceState)
if isa(e, QuoteNode)
return AbstractEvalConstant((e::QuoteNode).value)
elseif isa(e, SSAValue)
Expand All @@ -992,31 +1006,44 @@ function abstract_eval(interp::AbstractInterpreter, @nospecialize(e), vtypes::Va
return abstract_eval_global(e.mod, e.name)
end

return AbstractEvalConstant(e)
end

function abstract_eval_value(interp::AbstractInterpreter, @nospecialize(e), vtypes::VarTable, sv::InferenceState)
if isa(e, Expr)
return abstract_eval_value_expr(interp, e, vtypes, sv)
else
return abstract_eval_special_value(interp, e, vtypes, sv)
end
end

function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), vtypes::VarTable, sv::InferenceState)
if !isa(e, Expr)
return AbstractEvalConstant(e)
return abstract_eval_special_value(interp, e, vtypes, sv)
end

e = e::Expr
if e.head === :call
ea = e.args
n = length(ea)
argtypes = Vector{Any}(undef, n)
@inbounds for i = 1:n
ai = abstract_eval(interp, ea[i], vtypes, sv)
ai = abstract_eval_value(interp, ea[i], vtypes, sv)
if ai === Bottom
return Bottom
end
argtypes[i] = ai
end
t = abstract_call(interp, ea, argtypes, vtypes, sv)
elseif e.head === :new
t = instanceof_tfunc(abstract_eval(interp, e.args[1], vtypes, sv))[1]
t = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv))[1]
if isconcretetype(t) && !t.mutable
args = Vector{Any}(undef, length(e.args)-1)
ats = Vector{Any}(undef, length(e.args)-1)
anyconst = false
allconst = true
for i = 2:length(e.args)
at = abstract_eval(interp, e.args[i], vtypes, sv)
at = abstract_eval_value(interp, e.args[i], vtypes, sv)
if !anyconst
anyconst = has_nontrivial_const_info(at)
end
Expand Down Expand Up @@ -1046,9 +1073,9 @@ function abstract_eval(interp::AbstractInterpreter, @nospecialize(e), vtypes::Va
end
end
elseif e.head === :splatnew
t = instanceof_tfunc(abstract_eval(interp, e.args[1], vtypes, sv))[1]
t = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv))[1]
if length(e.args) == 2 && isconcretetype(t) && !t.mutable
at = abstract_eval(interp, e.args[2], vtypes, sv)
at = abstract_eval_value(interp, e.args[2], vtypes, sv)
n = fieldcount(t)
if isa(at, Const) && isa(at.val, Tuple) && n == length(at.val) &&
_all(i->at.val[i] isa fieldtype(t, i), 1:n)
Expand All @@ -1059,35 +1086,27 @@ function abstract_eval(interp::AbstractInterpreter, @nospecialize(e), vtypes::Va
end
end
elseif e.head === :foreigncall
abstract_eval(interp, e.args[1], vtypes, sv)
abstract_eval_value(interp, e.args[1], vtypes, sv)
t = sp_type_rewrap(e.args[2], sv.linfo, true)
for i = 3:length(e.args)
if abstract_eval(interp, e.args[i], vtypes, sv) === Bottom
if abstract_eval_value(interp, e.args[i], vtypes, sv) === Bottom
t = Bottom
end
end
elseif e.head === :cfunction
t = e.args[1]
isa(t, Type) || (t = Any)
abstract_eval_cfunction(interp, e, vtypes, sv)
elseif e.head === :static_parameter
n = e.args[1]
t = Any
if 1 <= n <= length(sv.sptypes)
t = sv.sptypes[n]
end
elseif e.head === :method
t = (length(e.args) == 1) ? Any : Nothing
elseif e.head === :copyast
t = abstract_eval(interp, e.args[1], vtypes, sv)
t = abstract_eval_value(interp, e.args[1], vtypes, sv)
if t isa Const && t.val isa Expr
# `copyast` makes copies of Exprs
t = Expr
end
elseif e.head === :invoke
error("type inference data-flow error: tried to double infer a function")
elseif e.head === :boundscheck
return Bool
elseif e.head === :isdefined
sym = e.args[1]
t = Bool
Expand Down Expand Up @@ -1116,7 +1135,7 @@ function abstract_eval(interp::AbstractInterpreter, @nospecialize(e), vtypes::Va
end
end
else
t = Any
return abstract_eval_value_expr(interp, e, vtypes, sv)
end
@assert !isa(t, TypeVar)
if isa(t, DataType) && isdefined(t, :instance)
Expand Down Expand Up @@ -1175,7 +1194,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
elseif isa(stmt, GotoNode)
pc´ = (stmt::GotoNode).label
elseif isa(stmt, GotoIfNot)
condt = abstract_eval(interp, stmt.cond, s[pc], frame)
condt = abstract_eval_value(interp, stmt.cond, s[pc], frame)
if condt === Bottom
break
end
Expand Down Expand Up @@ -1209,7 +1228,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
end
elseif isa(stmt, ReturnNode)
pc´ = n + 1
rt = widenconditional(abstract_eval(interp, stmt.val, s[pc], frame))
rt = widenconditional(abstract_eval_value(interp, stmt.val, s[pc], frame))
if !isa(rt, Const) && !isa(rt, Type) && !isa(rt, PartialStruct)
# only propagate information we know we can store
# and is valid inter-procedurally
Expand Down Expand Up @@ -1254,7 +1273,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
end
else
if hd === :(=)
t = abstract_eval(interp, stmt.args[2], changes, frame)
t = abstract_eval_statement(interp, stmt.args[2], changes, frame)
t === Bottom && break
frame.src.ssavaluetypes[pc] = t
lhs = stmt.args[1]
Expand All @@ -1269,7 +1288,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
elseif hd === :inbounds || hd === :meta || hd === :loopinfo || hd == :code_coverage_effect
# these do not generate code
else
t = abstract_eval(interp, stmt, changes, frame)
t = abstract_eval_statement(interp, stmt, changes, frame)
t === Bottom && break
if !isempty(frame.ssavalue_uses[pc])
record_ssa_assign(pc, t, frame)
Expand Down

0 comments on commit fd6eee7

Please sign in to comment.