Skip to content

Commit

Permalink
Handle foreigncall in irinterp, fix abstract_invoke inf loop
Browse files Browse the repository at this point in the history
  • Loading branch information
Ian Atol committed Jul 22, 2022
1 parent 291cad3 commit bed999e
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 12 deletions.
43 changes: 43 additions & 0 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -218,11 +218,19 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
if seen != napplicable
# there may be unanalyzed effects within unseen dispatch candidate,
# but we can still ignore nonoverlayed effect here since we already accounted for it
<<<<<<< HEAD
all_effects = tristate_merge(all_effects, EFFECTS_UNKNOWN)
elseif isa(matches, MethodMatches) ? (!matches.fullmatch || any_ambig(matches)) :
(!all(matches.fullmatches) || any_ambig(matches))
# Account for the fact that we may encounter a MethodError with a non-covered or ambiguous signature.
all_effects = Effects(all_effects; nothrow=ALWAYS_FALSE)
=======
all_effects = EFFECTS_UNKNOWN
elseif isa(matches, MethodMatches) ? (!matches.fullmatch || any_ambig(matches)) :
(!_all(b->b, matches.fullmatches) || any_ambig(matches))
# Account for the fact that we may encounter a MethodError with a non-covered or ambiguous signature.
all_effects = Effects(all_effects, nothrow=TRISTATE_UNKNOWN)
>>>>>>> 983f70db2c (Handle foreigncall in irinterp, fix abstract_invoke inf loop)
end

rettype = from_interprocedural!(rettype, sv, arginfo, conditionals)
Expand All @@ -244,7 +252,11 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
delete!(sv.pclimitations, caller)
end
end
<<<<<<< HEAD
return CallMeta(rettype, all_effects, info)
=======
return CallMeta(rettype, info, all_effects)
>>>>>>> 983f70db2c (Handle foreigncall in irinterp, fix abstract_invoke inf loop)
end

struct FailedMethodMatch
Expand Down Expand Up @@ -824,7 +836,11 @@ function concrete_eval_call(interp::AbstractInterpreter,
Core._call_in_world_total(world, f, args...)
catch
# The evaulation threw. By :consistent-cy, we're guaranteed this would have happened at runtime
<<<<<<< HEAD
return ConstCallResults(Union{}, ConcreteResult(result.edge::MethodInstance, result.effects), result.effects)
=======
return ConstCallResults(Union{}, ConcreteResult(result.edge, result.edge_effects), result.edge_effects)
>>>>>>> 983f70db2c (Handle foreigncall in irinterp, fix abstract_invoke inf loop)
end
if is_inlineable_constant(value) || call_result_unused(sv)
# If the constant is not inlineable, still do the const-prop, since the
Expand Down Expand Up @@ -2194,6 +2210,33 @@ function abstract_eval_phi(interp::AbstractInterpreter, phi::PhiNode, vtypes::Un
return rt
end

function abstract_eval_foreigncall(interp::AbstractInterpreter, fcall::Expr, vtypes::Union{VarTable, Nothing}, sv::Union{InferenceState, IRCode}, mi::Union{MethodInstance, Nothing}=nothing)
args = fcall.args
abstract_eval_value(interp, args[1], vtypes, sv)
mi′ = mi === nothing ? sv.linfo : mi
t = sp_type_rewrap(args[2], mi′, true)
for i = 3:length(args)
if abstract_eval_value(interp, args[i], vtypes, sv) === Bottom
t = Bottom
end
end
cconv = args[5]
if isa(cconv, QuoteNode) && isa(cconv.value, Tuple{Symbol, UInt8})
effects = cconv.value[2]::UInt8
effects = decode_effects_override(effects)
effects = Effects(
effects.consistent ? ALWAYS_TRUE : TRISTATE_UNKNOWN,
effects.effect_free ? ALWAYS_TRUE : TRISTATE_UNKNOWN,
effects.nothrow ? ALWAYS_TRUE : TRISTATE_UNKNOWN,
effects.terminates_globally ? ALWAYS_TRUE : TRISTATE_UNKNOWN,
#=nonoverlayed=#true
)
else
effects = EFFECTS_UNKNOWN
end
return RTEffects(t, effects)
end

function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), vtypes::VarTable, sv::InferenceState)
if !isa(e, Expr)
if isa(e, PhiNode)
Expand Down
2 changes: 1 addition & 1 deletion base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1360,7 +1360,7 @@ function handle_semi_concrete_result!(result::SemiConcreteResult, cases::Vector{
return true
end

function const_result_item(result::ConstResult, state::InliningState)
function concrete_result_item(result::ConstResult, state::InliningState)
if !isdefined(result, :result) || !is_inlineable_constant(result.result)
case = compileable_specialization(state.et, result.mi, result.effects)
@assert case !== nothing "concrete evaluation should never happen for uncompileable callsite"
Expand Down
38 changes: 28 additions & 10 deletions base/compiler/ssair/irinterp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,8 @@ function getindex(tpdum::TwoPhaseDefUseMap, idx::Int)
end

function concrete_eval_invoke(interp::AbstractInterpreter, ir::IRCode, mi_cache,
sv::InferenceState, inst::Expr)
mi′ = inst.args[1]::MethodInstance
code = get(mi_cache, mi′, nothing)
sv::InferenceState, inst::Expr, mi::MethodInstance)
code = get(mi_cache, mi, nothing)
code === nothing && return nothing
argtypes = collect_argtypes(interp, inst.args[2:end], nothing, ir)
effects = decode_effects(code.ipo_purity_bits)
Expand All @@ -132,7 +131,7 @@ function concrete_eval_invoke(interp::AbstractInterpreter, ir::IRCode, mi_cache,
else
ir′ = codeinst_to_ir(interp, code)
if ir′ !== nothing
return ir_abstract_constant_propagation(interp, mi_cache, sv, mi, ir′, argtypes)
return ir_abstract_constant_propagation(interp, mi_cache, sv, mi, ir′, argtypes)
end
end
return nothing
Expand All @@ -142,7 +141,7 @@ function reprocess_instruction!(interp::AbstractInterpreter, ir::IRCode, mi::Met
mi_cache, sv::InferenceState,
tpdum::TwoPhaseDefUseMap, idx::Int, bb::Union{Int, Nothing},
@nospecialize(inst), @nospecialize(typ),
phi_revisit)
phi_revisit, mi::MethodInstance)
function update_phi!(from, to)
if length(ir.cfg.blocks[to].preds) == 0
return
Expand Down Expand Up @@ -197,12 +196,21 @@ function reprocess_instruction!(interp::AbstractInterpreter, ir::IRCode, mi::Met
ir.stmts[idx][:type] = rt
return true
end
elseif inst.head === :foreigncall
(;rt, effects) = abstract_eval_foreigncall(interp, inst, nothing, ir, mi)
if !(typ rt)
ir.stmts[idx][:type] = rt
return true
end
elseif inst.head === :invoke
rr = concrete_eval_invoke(interp, ir, mi_cache, sv, inst)
if rr !== nothing
if !(typ rr)
ir.stmts[idx][:type] = rr
return true
mi′ = inst.args[1]::MethodInstance
if mi′ !== mi # prevent infinite loop
rr = concrete_eval_invoke(interp, ir, mi_cache, sv, inst, mi′)
if rr !== nothing
if !(typ rr)
ir.stmts[idx][:type] = rr
return true
end
end
end
elseif inst.head === :foreigncall
Expand Down Expand Up @@ -307,8 +315,13 @@ function _ir_abstract_constant_propagation(interp::AbstractInterpreter, mi_cache
any_refined = true
delete!(ssa_refined, idx)
end
<<<<<<< HEAD
if any_refined && reprocess_instruction!(interp, ir, mi, mi_cache,
frame, tpdum, idx, bb, inst, typ, ssa_refined)
=======
if any_refined && reprocess_instruction!(interp, ir, mi_cache,
frame, tpdum, idx, bb, inst, typ, ssa_refined, mi)
>>>>>>> 983f70db2c (Handle foreigncall in irinterp, fix abstract_invoke inf loop)
push!(ssa_refined, idx)
end
if idx == lstmt && process_terminator!(ip, bb, idx)
Expand Down Expand Up @@ -376,8 +389,13 @@ function _ir_abstract_constant_propagation(interp::AbstractInterpreter, mi_cache
idx = popfirst!(stmt_ip)
inst = ir.stmts[idx][:inst]
typ = ir.stmts[idx][:type]
<<<<<<< HEAD
if reprocess_instruction!(interp, ir, mi, mi_cache, frame,
tpdum, idx, nothing, inst, typ, ssa_refined)
=======
if reprocess_instruction!(interp, ir, mi_cache, frame,
tpdum, idx, nothing, inst, typ, ssa_refined, mi)
>>>>>>> 983f70db2c (Handle foreigncall in irinterp, fix abstract_invoke inf loop)
append!(stmt_ip, tpdum[idx])
end
end
Expand Down
5 changes: 5 additions & 0 deletions base/compiler/stmtinfo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ struct SemiConcreteResult
ir::IRCode
effects::Effects
end
<<<<<<< HEAD
=======

const ConstResult = Union{ConstPropResult,ConcreteResult, SemiConcreteResult}
>>>>>>> 983f70db2c (Handle foreigncall in irinterp, fix abstract_invoke inf loop)

const ConstResult = Union{ConstPropResult,ConcreteResult, SemiConcreteResult}
"""
Expand Down
2 changes: 1 addition & 1 deletion test/compiler/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4153,4 +4153,4 @@ end
return y
end
call_pure_annotated_loop(x) = Val{pure_annotated_loop(x, 1)}()
@test Core.Compiler.return_type(call_pure_annotated_loop, Tuple{Int}) == Val{1}
@test Core.Compiler.return_type(call_pure_annotated_loop, Tuple{Int}) == Val{1}

0 comments on commit bed999e

Please sign in to comment.