Skip to content

Commit

Permalink
AbstractInterpreter: allow overloading merge_effects! (#46559)
Browse files Browse the repository at this point in the history
This allows external `AbstractInterpreter`s to observe effects computed
for each statement (as like `add_remark!`) and show more fine-grained
effects information, e.g. in Cthulhu's code view.
  • Loading branch information
aviatesk authored Aug 31, 2022
1 parent dc27852 commit 5fe93ee
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 28 deletions.
40 changes: 20 additions & 20 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1914,7 +1914,7 @@ function abstract_eval_value_expr(interp::AbstractInterpreter, e::Expr, vtypes::
elseif head === :boundscheck
return Bool
elseif head === :the_exception
merge_effects!(sv, Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE))
merge_effects!(interp, sv, Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE))
return Any
end
return Any
Expand All @@ -1928,7 +1928,7 @@ function abstract_eval_special_value(interp::AbstractInterpreter, @nospecialize(
elseif isa(e, SlotNumber) || isa(e, Argument)
return vtypes[slot_id(e)].typ
elseif isa(e, GlobalRef)
return abstract_eval_global(e.mod, e.name, sv)
return abstract_eval_global(interp, e.mod, e.name, sv)
end

return Const(e)
Expand Down Expand Up @@ -1976,7 +1976,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
t = Bottom
else
callinfo = abstract_call(interp, ArgInfo(ea, argtypes), sv)
merge_effects!(sv, callinfo.effects)
merge_effects!(interp, sv, callinfo.effects)
sv.stmt_info[sv.currpc] = callinfo.info
t = callinfo.rt
end
Expand Down Expand Up @@ -2037,7 +2037,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
consistent = ALWAYS_FALSE
nothrow = false
end
merge_effects!(sv, Effects(EFFECTS_TOTAL; consistent, nothrow))
merge_effects!(interp, sv, Effects(EFFECTS_TOTAL; consistent, nothrow))
elseif ehead === :splatnew
t, isexact = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv))
nothrow = false # TODO: More precision
Expand All @@ -2055,9 +2055,9 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
end
end
consistent = !ismutabletype(t) ? ALWAYS_TRUE : CONSISTENT_IF_NOTRETURNED
merge_effects!(sv, Effects(EFFECTS_TOTAL; consistent, nothrow))
merge_effects!(interp, sv, Effects(EFFECTS_TOTAL; consistent, nothrow))
elseif ehead === :new_opaque_closure
merge_effects!(sv, Effects()) # TODO
merge_effects!(interp, sv, Effects()) # TODO
t = Union{}
if length(e.args) >= 4
ea = e.args
Expand Down Expand Up @@ -2101,17 +2101,17 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
override.inaccessiblememonly ? ALWAYS_TRUE : effects.inaccessiblememonly,
effects.nonoverlayed)
end
merge_effects!(sv, effects)
merge_effects!(interp, sv, effects)
elseif ehead === :cfunction
merge_effects!(sv, EFFECTS_UNKNOWN)
merge_effects!(interp, sv, EFFECTS_UNKNOWN)
t = e.args[1]
isa(t, Type) || (t = Any)
abstract_eval_cfunction(interp, e, vtypes, sv)
elseif ehead === :method
merge_effects!(sv, EFFECTS_UNKNOWN)
merge_effects!(interp, sv, EFFECTS_UNKNOWN)
t = (length(e.args) == 1) ? Any : Nothing
elseif ehead === :copyast
merge_effects!(sv, EFFECTS_UNKNOWN)
merge_effects!(interp, sv, EFFECTS_UNKNOWN)
t = abstract_eval_value(interp, e.args[1], vtypes, sv)
if t isa Const && t.val isa Expr
# `copyast` makes copies of Exprs
Expand Down Expand Up @@ -2149,7 +2149,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
elseif false
@label always_throw
t = Bottom
merge_effects!(sv, EFFECTS_THROWS)
merge_effects!(interp, sv, EFFECTS_THROWS)
else
t = abstract_eval_value_expr(interp, e, vtypes, sv)
end
Expand Down Expand Up @@ -2178,7 +2178,7 @@ function abstract_eval_global(M::Module, s::Symbol)
return ty
end

function abstract_eval_global(M::Module, s::Symbol, frame::InferenceState)
function abstract_eval_global(interp::AbstractInterpreter, M::Module, s::Symbol, frame::InferenceState)
rt = abstract_eval_global(M, s)
consistent = inaccessiblememonly = ALWAYS_FALSE
nothrow = false
Expand All @@ -2193,15 +2193,15 @@ function abstract_eval_global(M::Module, s::Symbol, frame::InferenceState)
elseif isdefined(M,s)
nothrow = true
end
merge_effects!(frame, Effects(EFFECTS_TOTAL; consistent, nothrow, inaccessiblememonly))
merge_effects!(interp, frame, Effects(EFFECTS_TOTAL; consistent, nothrow, inaccessiblememonly))
return rt
end

function handle_global_assignment!(interp::AbstractInterpreter, frame::InferenceState, lhs::GlobalRef, @nospecialize(newty))
effect_free = ALWAYS_FALSE
nothrow = global_assignment_nothrow(lhs.mod, lhs.name, newty)
inaccessiblememonly = ALWAYS_FALSE
merge_effects!(frame, Effects(EFFECTS_TOTAL; effect_free, nothrow, inaccessiblememonly))
merge_effects!(interp, frame, Effects(EFFECTS_TOTAL; effect_free, nothrow, inaccessiblememonly))
return nothing
end

Expand Down Expand Up @@ -2290,12 +2290,12 @@ function widenreturn_noconditional(@nospecialize(rt))
return widenconst(rt)
end

function handle_control_backedge!(frame::InferenceState, from::Int, to::Int)
function handle_control_backedge!(interp::AbstractInterpreter, frame::InferenceState, from::Int, to::Int)
if from > to
if is_effect_overridden(frame, :terminates_locally)
# this backedge is known to terminate
else
merge_effects!(frame, Effects(EFFECTS_TOTAL; terminates=false))
merge_effects!(interp, frame, Effects(EFFECTS_TOTAL; terminates=false))
end
end
return nothing
Expand Down Expand Up @@ -2331,7 +2331,7 @@ end
elseif isa(lhs, GlobalRef)
handle_global_assignment!(interp, frame, lhs, t)
elseif !isa(lhs, SSAValue)
merge_effects!(frame, EFFECTS_UNKNOWN)
merge_effects!(interp, frame, EFFECTS_UNKNOWN)
end
return BasicStmtChange(changes, t)
elseif hd === :method
Expand Down Expand Up @@ -2405,7 +2405,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
@assert length(succs) == 1
nextbb = succs[1]
ssavaluetypes[currpc] = Any
handle_control_backedge!(frame, currpc, stmt.label)
handle_control_backedge!(interp, frame, currpc, stmt.label)
@goto branch
elseif isa(stmt, GotoIfNot)
condx = stmt.cond
Expand Down Expand Up @@ -2443,7 +2443,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
falsebb = succs[1] == truebb ? succs[2] : succs[1]
if condval === false
nextbb = falsebb
handle_control_backedge!(frame, currpc, stmt.dest)
handle_control_backedge!(interp, frame, currpc, stmt.dest)
@goto branch
else
# We continue with the true branch, but process the false
Expand All @@ -2464,7 +2464,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
changed = update_bbstate!(frame, falsebb, currstate)
end
if changed
handle_control_backedge!(frame, currpc, stmt.dest)
handle_control_backedge!(interp, frame, currpc, stmt.dest)
push!(W, falsebb)
end
@goto fallthrough
Expand Down
6 changes: 3 additions & 3 deletions base/compiler/inferencestate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,11 @@ end

Effects(state::InferenceState) = state.ipo_effects

function merge_effects!(caller::InferenceState, effects::Effects)
function merge_effects!(::AbstractInterpreter, caller::InferenceState, effects::Effects)
caller.ipo_effects = merge_effects(caller.ipo_effects, effects)
end
merge_effects!(caller::InferenceState, callee::InferenceState) =
merge_effects!(caller, Effects(callee))
merge_effects!(interp::AbstractInterpreter, caller::InferenceState, callee::InferenceState) =
merge_effects!(interp, caller, Effects(callee))

is_effect_overridden(sv::InferenceState, effect::Symbol) = is_effect_overridden(sv.linfo, effect)
function is_effect_overridden(linfo::MethodInstance, effect::Symbol)
Expand Down
10 changes: 5 additions & 5 deletions base/compiler/typeinfer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -793,18 +793,18 @@ function union_caller_cycle!(a::InferenceState, b::InferenceState)
return
end

function merge_call_chain!(parent::InferenceState, ancestor::InferenceState, child::InferenceState)
function merge_call_chain!(interp::AbstractInterpreter, parent::InferenceState, ancestor::InferenceState, child::InferenceState)
# add backedge of parent <- child
# then add all backedges of parent <- parent.parent
# and merge all of the callers into ancestor.callers_in_cycle
# and ensure that walking the parent list will get the same result (DAG) from everywhere
# Also taint the termination effect, because we can no longer guarantee the absence
# of recursion.
merge_effects!(parent, Effects(EFFECTS_TOTAL; terminates=false))
merge_effects!(interp, parent, Effects(EFFECTS_TOTAL; terminates=false))
while true
add_cycle_backedge!(child, parent, parent.currpc)
union_caller_cycle!(ancestor, child)
merge_effects!(child, Effects(EFFECTS_TOTAL; terminates=false))
merge_effects!(interp, child, Effects(EFFECTS_TOTAL; terminates=false))
child = parent
child === ancestor && break
parent = child.parent::InferenceState
Expand Down Expand Up @@ -840,7 +840,7 @@ function resolve_call_cycle!(interp::AbstractInterpreter, linfo::MethodInstance,
poison_callstack(parent, frame)
return true
end
merge_call_chain!(parent, frame, frame)
merge_call_chain!(interp, parent, frame, frame)
return frame
end
for caller in frame.callers_in_cycle
Expand All @@ -849,7 +849,7 @@ function resolve_call_cycle!(interp::AbstractInterpreter, linfo::MethodInstance,
poison_callstack(parent, frame)
return true
end
merge_call_chain!(parent, frame, caller)
merge_call_chain!(interp, parent, frame, caller)
return caller
end
end
Expand Down

2 comments on commit 5fe93ee

@aviatesk
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nanosoldier runbenchmarks("string", vs="@5c5af1fffd1bd0a9124415689a4664ab934e79f1")

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your benchmark job has completed - no performance regressions were detected. A full report can be found here.

Please sign in to comment.