diff --git a/src/Cthulhu.jl b/src/Cthulhu.jl index 2a9a9f18..93281183 100644 --- a/src/Cthulhu.jl +++ b/src/Cthulhu.jl @@ -295,7 +295,7 @@ end # src/ui.jl provides the user facing interface to which _descend responds ## function _descend(term::AbstractTerminal, interp::CthulhuInterpreter, mi::MethodInstance; - override::Union{Nothing,InferenceResult}=nothing, debuginfo::Union{Symbol,DebugInfo}=DInfo.compact, # default is compact debuginfo + override::Union{Nothing,InferenceResult,SemiConcreteCallInfo}=nothing, debuginfo::Union{Symbol,DebugInfo}=DInfo.compact, # default is compact debuginfo optimize::Bool=true, interruptexc::Bool=true, iswarn::Bool=false, hide_type_stable::Union{Nothing,Bool}=nothing, verbose::Union{Nothing,Bool}=nothing, remarks::Bool=false, with_effects::Bool=false, inline_cost::Bool=false, type_annotations::Bool=true) @@ -327,7 +327,14 @@ function _descend(term::AbstractTerminal, interp::CthulhuInterpreter, mi::Method callsites = Callsite[] else if override !== nothing - if optimize + if isa(override, SemiConcreteCallInfo) + src = Compiler.copy(override.ir) + rt = get_rt(override) + infos = src.stmts.info + slottypes = src.argtypes + effects = get_effects(override) + (;codeinf) = lookup(interp, mi, optimize) + elseif optimize opt = override.src rt = override.result if isa(opt, Compiler.OptimizationState) @@ -367,7 +374,7 @@ function _descend(term::AbstractTerminal, interp::CthulhuInterpreter, mi::Method (; src, rt, infos, slottypes, codeinf, effects) = lookup(interp, mi, optimize) end src = preprocess_ci!(src, mi, optimize, CONFIG) - if optimize # optimization might have deleted some statements + if optimize || isa(src, IRCode) # optimization might have deleted some statements infos = src.stmts.info else @assert length(src.code) == length(infos) @@ -472,8 +479,14 @@ function _descend(term::AbstractTerminal, interp::CthulhuInterpreter, mi::Method continue end + doverride = nothing + if isa(info, ConstPropCallInfo) + doverride = info.result + elseif isa(info, SemiConcreteCallInfo) + doverride = info + end _descend(term, interp, next_mi; - override = isa(info, ConstPropCallInfo) ? info.result : nothing, debuginfo, + override = doverride, debuginfo, optimize, interruptexc, iswarn, hide_type_stable, remarks, with_effects, inline_cost, type_annotations) @@ -656,7 +669,7 @@ with the option to `descend` into intermediate calls. `kwargs` are passed to [`d """ ascend -if ccall(:jl_generating_output, Cint, ()) == 1 +if false && ccall(:jl_generating_output, Cint, ()) == 1 input = Pipe() Base.link_pipe!(input, reader_supports_async=true, writer_supports_async=true) term = REPL.Terminals.TTYTerminal("dumb", input.out, IOBuffer(), IOBuffer()) diff --git a/src/callsite.jl b/src/callsite.jl index 5c83c31b..3ec39f1f 100644 --- a/src/callsite.jl +++ b/src/callsite.jl @@ -136,6 +136,15 @@ get_mi(ceci::ConstEvalCallInfo) = get_mi(ceci.mi) get_rt(ceci::ConstEvalCallInfo) = get_rt(ceci.mi) get_effects(ceci::ConstEvalCallInfo) = get_effects(ceci.mi) +struct SemiConcreteCallInfo <: CallInfo + mi::CallInfo + argtypes::ArgTypes + ir::IRCode +end +get_mi(scci::SemiConcreteCallInfo) = get_mi(scci.mi) +get_rt(scci::SemiConcreteCallInfo) = get_rt(scci.mi) +get_effects(scci::SemiConcreteCallInfo) = get_effects(scci.mi) + # CUDA callsite struct CuCallInfo <: CallInfo cumi::MICallInfo @@ -303,6 +312,13 @@ function show_callinfo(limiter, ci::ConstEvalCallInfo) __show_limited(limiter, name, tt, get_rt(ci)) end +function show_callinfo(limiter, ci::SemiConcreteCallInfo) + # XXX: The first argument could be const-overriden too + name = get_mi(ci).def.name + tt = ci.argtypes[2:end] + __show_limited(limiter, name, tt, get_rt(ci)) +end + function show_callinfo(limiter, (; vmi)::ReturnTypeCallInfo) if isa(vmi, FailedCallInfo) ft = Base.tuple_type_head(vmi.sig) @@ -373,6 +389,9 @@ function Base.show(io::IO, c::Callsite) elseif isa(info, ConstEvalCallInfo) print(limiter, " = < consteval > ") show_callinfo(limiter, info) + elseif isa(info, SemiConcreteCallInfo) + print(limiter, " = < semi-consteval > ") + show_callinfo(limiter, info) elseif isa(info, OCCallInfo) print(limiter, " = < opaque closure call > ") show_callinfo(limiter, info.ci) diff --git a/src/interpreter.jl b/src/interpreter.jl index caa8e9ff..0966bd1f 100644 --- a/src/interpreter.jl +++ b/src/interpreter.jl @@ -96,7 +96,7 @@ function Compiler.finish(state::InferenceState, interp::CthulhuInterpreter) end function Compiler.transform_result_for_cache(interp::CthulhuInterpreter, linfo::MethodInstance, - valid_worlds::WorldRange, @nospecialize(inferred_result), ipo_effects::Effects = Effects()) + valid_worlds::WorldRange, @nospecialize(inferred_result), ipo_effects::Effects = Effects()) return maybe_create_optsource(inferred_result, ipo_effects) end @@ -127,6 +127,11 @@ function Compiler.inlining_policy(interp::CthulhuInterpreter) end end # @static if isdefined(Compiler, :is_stmt_inline) +function Compiler.codeinst_to_ir(interp::CthulhuInterpreter, code::CodeInstance) + isa(code.inferred, Nothing) && return nothing + return Compiler.copy((code.inferred::OptimizedSource).ir) +end + function Compiler.finish!(interp::CthulhuInterpreter, caller::InferenceResult) effects = EFFECTS_ENABLED ? caller.ipo_effects : nothing caller.src = maybe_create_optsource(caller.src, effects) diff --git a/src/reflection.jl b/src/reflection.jl index ecdf0a62..61b0d998 100644 --- a/src/reflection.jl +++ b/src/reflection.jl @@ -145,6 +145,11 @@ function process_info(interp, @nospecialize(info), argtypes::ArgTypes, @nospecia effects = get_effects(interp.unopt, linfo) mici = MICallInfo(linfo, rt, effects) ConstEvalCallInfo(mici, argtypes) + elseif (@static isdefined(Compiler, :SemiConcreteResult) && true) && isa(result, Compiler.SemiConcreteResult) + linfo = result.mi + effects = result.effects + mici = MICallInfo(linfo, rt, effects) + SemiConcreteCallInfo(mici, argtypes, result.ir) else @assert isa(result, Compiler.InferenceResult) linfo = result.linfo