From ba560f58d31a519cf95277ba1498e2b3e12d093b Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Mon, 18 Mar 2024 00:43:04 +0000 Subject: [PATCH] compiler: Refactor `concrete_eval_invoke` This passes slightly more information into this function (the full `inst` rather than just the `stmt`) in order to allow external absint to access additional fields (the flags and the info) if necessary to make concrete evaluation decisions. It also splits out the actual concrete evaluation from the part that just maps the `inst` to a CodeInstance. --- base/compiler/ssair/irinterp.jl | 43 ++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/base/compiler/ssair/irinterp.jl b/base/compiler/ssair/irinterp.jl index 3b6cfa9019d76..8a66d0f939e63 100644 --- a/base/compiler/ssair/irinterp.jl +++ b/base/compiler/ssair/irinterp.jl @@ -5,39 +5,44 @@ function collect_limitations!(@nospecialize(typ), ::IRInterpretationState) return typ end -function concrete_eval_invoke(interp::AbstractInterpreter, - inst::Expr, mi::MethodInstance, irsv::IRInterpretationState) - world = frame_world(irsv) - mi_cache = WorldView(code_cache(interp), world) - code = get(mi_cache, mi, nothing) - code === nothing && return Pair{Any,Tuple{Bool,Bool}}(nothing, (false, false)) - argtypes = collect_argtypes(interp, inst.args[2:end], nothing, irsv) - argtypes === nothing && return Pair{Any,Tuple{Bool,Bool}}(Bottom, (false, false)) - effects = decode_effects(code.ipo_purity_bits) +function concrete_eval_invoke(interp::AbstractInterpreter, ci::CodeInstance, argtypes::Vector{Any}, parent::IRInterpretationState) + world = frame_world(parent) + effects = decode_effects(ci.ipo_purity_bits) if (is_foldable(effects) && is_all_const_arg(argtypes, #=start=#1) && (is_nonoverlayed(interp) || is_nonoverlayed(effects))) args = collect_const_args(argtypes, #=start=#1) - value = let world = get_inference_world(interp) - try - Core._call_in_world_total(world, args...) - catch - return Pair{Any,Tuple{Bool,Bool}}(Bottom, (false, is_noub(effects))) - end + value = try + Core._call_in_world_total(world, args...) + catch + return Pair{Any,Tuple{Bool,Bool}}(Bottom, (false, is_noub(effects))) end return Pair{Any,Tuple{Bool,Bool}}(Const(value), (true, true)) else - if is_constprop_edge_recursed(mi, irsv) + mi = ci.def + if is_constprop_edge_recursed(mi, parent) return Pair{Any,Tuple{Bool,Bool}}(nothing, (is_nothrow(effects), is_noub(effects))) end - newirsv = IRInterpretationState(interp, code, mi, argtypes, world) + newirsv = IRInterpretationState(interp, ci, mi, argtypes, world) if newirsv !== nothing - newirsv.parent = irsv + newirsv.parent = parent return ir_abstract_constant_propagation(interp, newirsv) end return Pair{Any,Tuple{Bool,Bool}}(nothing, (is_nothrow(effects), is_noub(effects))) end end +function abstract_eval_invoke_inst(interp::AbstractInterpreter, inst::Instruction, irsv::IRInterpretationState) + stmt = inst[:stmt] + mi = stmt.args[1]::MethodInstance + world = frame_world(irsv) + mi_cache = WorldView(code_cache(interp), world) + code = get(mi_cache, mi, nothing) + code === nothing && return Pair{Any,Tuple{Bool,Bool}}(nothing, (false, false)) + argtypes = collect_argtypes(interp, stmt.args[2:end], nothing, irsv) + argtypes === nothing && return Pair{Any,Tuple{Bool,Bool}}(Bottom, (false, false)) + return concrete_eval_invoke(interp, code, argtypes, irsv) +end + abstract_eval_ssavalue(s::SSAValue, sv::IRInterpretationState) = abstract_eval_ssavalue(s, sv.ir) function abstract_eval_phi_stmt(interp::AbstractInterpreter, phi::PhiNode, ::Int, irsv::IRInterpretationState) @@ -141,7 +146,7 @@ function reprocess_instruction!(interp::AbstractInterpreter, inst::Instruction, (; rt, effects) = abstract_eval_statement_expr(interp, stmt, nothing, irsv) add_flag!(inst, flags_for_effects(effects)) elseif head === :invoke - rt, (nothrow, noub) = concrete_eval_invoke(interp, stmt, stmt.args[1]::MethodInstance, irsv) + rt, (nothrow, noub) = abstract_eval_invoke_inst(interp, inst, irsv) if nothrow add_flag!(inst, IR_FLAG_NOTHROW) end