diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index b32f21541a946..9595a49fa518f 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -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) @@ -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 @@ -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 @@ -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) diff --git a/base/compiler/ssair/inlining.jl b/base/compiler/ssair/inlining.jl index c9ca4c7feb3c1..ab2576c519cfb 100644 --- a/base/compiler/ssair/inlining.jl +++ b/base/compiler/ssair/inlining.jl @@ -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" diff --git a/base/compiler/ssair/irinterp.jl b/base/compiler/ssair/irinterp.jl index 70dcda7678410..753f9b6335841 100644 --- a/base/compiler/ssair/irinterp.jl +++ b/base/compiler/ssair/irinterp.jl @@ -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) @@ -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 @@ -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 @@ -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 @@ -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) @@ -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 diff --git a/base/compiler/stmtinfo.jl b/base/compiler/stmtinfo.jl index d61926fedd885..a2b3b113a3481 100644 --- a/base/compiler/stmtinfo.jl +++ b/base/compiler/stmtinfo.jl @@ -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} """ diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index 04a2abb179d32..97eab7f82b4dc 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -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} \ No newline at end of file +@test Core.Compiler.return_type(call_pure_annotated_loop, Tuple{Int}) == Val{1}