diff --git a/src/Cthulhu.jl b/src/Cthulhu.jl index 6fa7f319..b64bc2e0 100644 --- a/src/Cthulhu.jl +++ b/src/Cthulhu.jl @@ -11,7 +11,11 @@ const IRShow = Base.IRShow using Accessors using CodeTracking: CodeTracking using InteractiveUtils +@static if VERSION ≥ v"1.14-" +using .IRShow: is_expected_union +else using InteractiveUtils: is_expected_union +end using UUIDs using REPL: REPL, AbstractTerminal using JuliaSyntax: JuliaSyntax, children diff --git a/src/CthulhuCompiler.jl b/src/CthulhuCompiler.jl index 2a19aaec..84151447 100644 --- a/src/CthulhuCompiler.jl +++ b/src/CthulhuCompiler.jl @@ -1,19 +1,26 @@ Base.Experimental.@compiler_options compile=min optimize=1 -import .Cthulhu: AbstractProvider, get_abstract_interpreter, get_inference_world, find_method_instance, generate_code_instance, get_override, lookup, find_caller_of, get_inlining_costs, show_parameters, get_ci, get_rt, get_pc_remarks, get_pc_effects, get_pc_excts, show_callsite, show_callinfo, print_callsite_info, cthulhu_source, cthulhu_typed, cthulhu_ast, cthulhu_llvm, cthulhu_native, find_callsites, ir_to_src -using .Cthulhu: CthulhuState, CthulhuConfig, CallInfo, Callsite, cached_exception_type, get_mi +import .Cthulhu: + AbstractProvider, cthulhu_ast, cthulhu_llvm, cthulhu_native, cthulhu_source, + cthulhu_typed, find_caller_of, find_callsites, find_method_instance, + generate_code_instance, get_abstract_interpreter, get_ci, get_inference_world, + get_inlining_costs, get_override, get_pc_effects, get_pc_excts, get_pc_remarks, get_rt, + ir_to_src, lookup, print_callsite_info, show_callinfo, show_callsite, show_parameters +using .Cthulhu: + CthulhuState, CthulhuConfig, CallInfo, Callsite, + cached_exception_type, get_mi -using Base: isvarargtype, unwrapva, unwrap_unionall, mapany, get_world_counter +using Base: get_world_counter, isvarargtype, mapany, unwrap_unionall, unwrapva using JuliaSyntax: JuliaSyntax, children, is_leaf -using .CC: AbstractInterpreter, CallMeta, ApplyCallInfo, CallInfo as CCCallInfo, ConstCallInfo, - EFFECTS_TOTAL, Effects, IncrementalCompact, InferenceParams, InferenceResult, - InferenceState, IRCode, LimitedAccuracy, MethodMatchInfo, MethodResultPure, - NativeInterpreter, NoCallInfo, OptimizationParams, OptimizationState, - UnionSplitApplyCallInfo, UnionSplitInfo, WorldRange, WorldView, - argextype, argtypes_to_type, compileable_specialization, ignorelimited, singleton_type, - specialize_method, sptypes_from_meth_instance, widenconst, method_table, findsup, - cached_return_type +using .CC: AbstractInterpreter, ApplyCallInfo, CallInfo as CCCallInfo, CallMeta, + EFFECTS_TOTAL, Effects, IncrementalCompact, InferenceParams, + InferenceResult, InferenceState, IRCode, LimitedAccuracy, MethodMatchInfo, + MethodResultPure, NativeInterpreter, NoCallInfo, OptimizationParams, OptimizationState, + UnionSplitApplyCallInfo, UnionSplitInfo, + argextype, argtypes_to_type, cached_return_type, compileable_specialization, findsup, + ignorelimited, method_table, singleton_type, specialize_method, sptypes_from_meth_instance, + widenconst const ArgTypes = Vector{Any} @@ -29,6 +36,8 @@ get_effects(codeinst::CodeInstance) = CC.decode_effects(codeinst.ipo_purity_bits get_effects(codeinst::CodeInfo) = CC.decode_effects(codeinst.purity) get_effects(result::InferenceResult) = result.ipo_effects get_effects(source::InferredSource) = source.effects +@static if VERSION < v"1.14.0-DEV.60" get_effects(result::CC.ConstPropResult) = get_effects(result.result) +end get_effects(result::CC.ConcreteResult) = result.effects get_effects(result::CC.SemiConcreteResult) = result.effects diff --git a/src/compiler/interpreter.jl b/src/compiler/interpreter.jl index 42cf2f30..f2b360b0 100644 --- a/src/compiler/interpreter.jl +++ b/src/compiler/interpreter.jl @@ -231,6 +231,21 @@ CC.retrieve_ir_for_inlining(cached_result::CodeInstance, src::OptimizedSource) = CC.retrieve_ir_for_inlining(mi::MethodInstance, src::OptimizedSource, preserve_local_sources::Bool) = CC.retrieve_ir_for_inlining(mi, src.ir, preserve_local_sources) +@static if VERSION ≥ v"1.14.0-DEV.60" +function CC.ci_get_source(::CthulhuInterpreter, code::CodeInstance) + return code.inferred +end +function CC.IRInterpretationState(interp::CthulhuInterpreter, + code::CodeInstance, mi::MethodInstance, argtypes::Vector{Any}, @nospecialize(inferred)) + inferred::OptimizedSource + ir = CC.copy(inferred.ir) + src = inferred.src + spec_info = CC.SpecInfo(src) + argtypes = CC.va_process_argtypes(CC.optimizer_lattice(interp), argtypes, src.nargs, src.isva, mi) + return CC.IRInterpretationState(interp, spec_info, ir, mi, argtypes, + code.min_world, code.max_world) +end +else function CC.IRInterpretationState(interp::CthulhuInterpreter, code::CodeInstance, mi::MethodInstance, argtypes::Vector{Any}, world::UInt) inferred = code.inferred @@ -243,3 +258,4 @@ function CC.IRInterpretationState(interp::CthulhuInterpreter, return CC.IRInterpretationState(interp, spec_info, ir, mi, argtypes, world, code.min_world, code.max_world) end +end diff --git a/src/compiler/reflection.jl b/src/compiler/reflection.jl index 301b8da2..6ab5ffd6 100644 --- a/src/compiler/reflection.jl +++ b/src/compiler/reflection.jl @@ -122,7 +122,37 @@ function find_callsites(provider::AbstractProvider, result::LookupResult, ci::Co return callsites, sourcenodes end -function process_const_info(provider::AbstractProvider, ::LookupResult, @nospecialize(thisinfo), +@static if VERSION ≥ v"1.14.0-DEV.60" +function process_result( + ::AbstractProvider, ::LookupResult, argtypes::ArgTypes, + @nospecialize(rt), @nospecialize(result), @nospecialize(exct) + ) + if isnothing(result) + return nothing + elseif isa(result, CC.ConcreteResult) + edge = result.edge + effects = get_effects(result) + mici = EdgeCallInfo(edge, rt, effects, exct) + return ConcreteCallInfo(mici, argtypes) + elseif isa(result, CC.SemiConcreteResult) + effects = get_effects(result) + mici = EdgeCallInfo(result.edge, rt, effects, exct) + return SemiConcreteCallInfo(mici, result.ir) + else + @assert isa(result, CC.InferenceResult) + overridden_by_const = result.overridden_by_const + if overridden_by_const !== nothing && any(overridden_by_const) + effects = get_effects(result) + mici = EdgeCallInfo(result.ci_as_edge, rt, effects, exct) + return ConstPropCallInfo(mici, result) + else + effects = get_effects(result) + return EdgeCallInfo(result.ci_as_edge, rt, effects, exct) + end + end +end +else +function process_const_info(::AbstractProvider, ::LookupResult, @nospecialize(thisinfo), argtypes::ArgTypes, @nospecialize(rt), @nospecialize(result), @nospecialize(exct)) if isnothing(result) @@ -152,6 +182,7 @@ function process_const_info(provider::AbstractProvider, ::LookupResult, @nospeci return ConstPropCallInfo(mici, result) end end +end function process_info(provider::AbstractProvider, result::LookupResult, @nospecialize(info::CCCallInfo), argtypes::ArgTypes, @nospecialize(rt), @@ -176,10 +207,16 @@ function process_info(provider::AbstractProvider, result::LookupResult, @nospeci if edge === nothing RTCallInfo(unwrapconst(argtypes[1]), argtypes[2:end], rt, exct) else + @static if VERSION ≥ v"1.14.0-DEV.60" + @something( + process_result(provider, result, argtypes, rt, info.call_results[i], exct), + RTCallInfo(unwrapconst(argtypes[1]), argtypes[2:end], rt, exct)) + else effects = @something(effects, get_effects(edge)) EdgeCallInfo(edge, rt, effects, exct) + end end - end for edge in info.edges if edge !== nothing] + end for (i, edge) in enumerate(info.edges) if edge !== nothing] elseif isa(info, UnionSplitInfo) return mapreduce(process_recursive, vcat, info.split; init=CallInfo[])::Vector{CallInfo} elseif isa(info, UnionSplitApplyCallInfo) @@ -188,7 +225,7 @@ function process_info(provider::AbstractProvider, result::LookupResult, @nospeci # XXX: This could probably use its own info. For now, # we ignore any implicit iterate calls. return process_recursive(info.call) - elseif isa(info, ConstCallInfo) + elseif (@static VERSION < v"1.14.0-DEV.60" ? true : false) && isa(info, CC.ConstCallInfo) infos = process_recursive(info.call) @assert length(infos) == length(info.results) return CallInfo[let @@ -197,9 +234,15 @@ function process_info(provider::AbstractProvider, result::LookupResult, @nospeci elseif isa(info, CC.InvokeCallInfo) edge = info.edge if edge !== nothing + @static if VERSION ≥ v"1.14.0-DEV.60" + innerinfo = @something( + process_result(provider, result, argtypes, rt, info.result, exct), + RTCallInfo(unwrapconst(argtypes[1]), argtypes[2:end], rt, exct)) + else effects = @something(effects, get_effects(edge)) thisinfo = EdgeCallInfo(edge, rt, effects) innerinfo = process_const_info(provider, result, thisinfo, argtypes, rt, info.result, exct) + end else innerinfo = RTCallInfo(unwrapconst(argtypes[1]), argtypes[2:end], rt, exct) end @@ -208,9 +251,15 @@ function process_info(provider::AbstractProvider, result::LookupResult, @nospeci elseif isa(info, CC.OpaqueClosureCallInfo) edge = info.edge if edge !== nothing + @static if VERSION ≥ v"1.14.0-DEV.60" + innerinfo = @something( + process_result(provider, result, argtypes, rt, info.result, exct), + RTCallInfo(unwrapconst(argtypes[1]), argtypes[2:end], rt, exct)) + else effects = @something(effects, get_effects(edge)) thisinfo = EdgeCallInfo(edge, rt, effects) innerinfo = process_const_info(provider, result, thisinfo, argtypes, rt, info.result, exct) + end else innerinfo = RTCallInfo(unwrapconst(argtypes[1]), argtypes[2:end], rt, exct) end diff --git a/test/test_AbstractInterpreter.jl b/test/test_AbstractInterpreter.jl index ec928aa3..ada135c6 100644 --- a/test/test_AbstractInterpreter.jl +++ b/test/test_AbstractInterpreter.jl @@ -14,10 +14,11 @@ from the native code cache, satisfying the minimum interface requirements. When the `ephemeral_cache=true` option is specified, `NewInterpreter` will hold `CodeInstance` in an ephemeral non-integrated cache, rather than in the integrated -`Core.Compiler.InternalCodeCache`. +`Core.CC.InternalCodeCache`. Keep in mind that ephemeral cache lacks support for invalidation and doesn't persist across -sessions. However it is an usual Julia object of the type `code_cache::IdDict{MethodInstance,CodeInstance}`, -making it easier for debugging and inspecting the compiler behavior. +sessions. However it is an usual Julia object of the type +`global_cache::IdDict{MethodInstance,CodeInstance}`, +making it easier for debugging and inspecting the CC behavior. """ macro newinterp(InterpName, ephemeral_cache::Bool=false) cache_token = QuoteNode(gensym(string(InterpName, "CacheToken"))) @@ -38,17 +39,17 @@ macro newinterp(InterpName, ephemeral_cache::Bool=false) inf_params::$CC.InferenceParams opt_params::$CC.OptimizationParams inf_cache::Vector{$CC.InferenceResult} - $(ephemeral_cache && :(code_cache::$InterpCacheName)) + $(ephemeral_cache && :(global_cache::$InterpCacheName)) function $InterpName(meta = nothing; world::UInt = Base.get_world_counter(), inf_params::$CC.InferenceParams = $CC.InferenceParams(), opt_params::$CC.OptimizationParams = $CC.OptimizationParams(), inf_cache::Vector{$CC.InferenceResult} = $CC.InferenceResult[], $(ephemeral_cache ? - Expr(:kw, :(code_cache::$InterpCacheName), :($InterpCacheName())) : + Expr(:kw, :(global_cache::$InterpCacheName), :($InterpCacheName())) : Expr(:kw, :_, :nothing))) return $(ephemeral_cache ? - :(new(meta, world, inf_params, opt_params, inf_cache, code_cache)) : + :(new(meta, world, inf_params, opt_params, inf_cache, global_cache)) : :(new(meta, world, inf_params, opt_params, inf_cache))) end end @@ -57,8 +58,14 @@ macro newinterp(InterpName, ephemeral_cache::Bool=false) $CC.get_inference_world(interp::$InterpName) = interp.world $CC.get_inference_cache(interp::$InterpName) = interp.inf_cache $CC.cache_owner(::$InterpName) = $cache_token - $(ephemeral_cache && quote - $CC.code_cache(interp::$InterpName) = $CC.WorldView(interp.code_cache, $CC.WorldRange(interp.world)) + $(ephemeral_cache && @static VERSION ≥ v"1.14.0-DEV.60" ? quote + $CC.code_cache(interp::$InterpName) = $CC.OverlayCodeCache(interp.global_cache, interp.inf_cache) + $CC.get(cache::$InterpCacheName, mi::$C.MethodInstance, default) = get(cache.dict, mi, default) + $CC.getindex(cache::$InterpCacheName, mi::$C.MethodInstance) = getindex(cache.dict, mi) + $CC.haskey(cache::$InterpCacheName, mi::$C.MethodInstance) = haskey(cache.dict, mi) + $CC.setindex!(cache::$InterpCacheName, ci::$C.CodeInstance, mi::$C.MethodInstance) = setindex!(cache.dict, ci, mi) + end : quote + $CC.code_cache(interp::$InterpName) = $CC.WorldView(interp.global_cache, $CC.WorldRange(interp.world)) $CC.get(wvc::$CC.WorldView{$InterpCacheName}, mi::$C.MethodInstance, default) = get(wvc.cache.dict, mi, default) $CC.getindex(wvc::$CC.WorldView{$InterpCacheName}, mi::$C.MethodInstance) = getindex(wvc.cache.dict, mi) $CC.haskey(wvc::$CC.WorldView{$InterpCacheName}, mi::$C.MethodInstance) = haskey(wvc.cache.dict, mi) diff --git a/test/test_Cthulhu.jl b/test/test_Cthulhu.jl index b6a171f0..86a1c89e 100644 --- a/test/test_Cthulhu.jl +++ b/test/test_Cthulhu.jl @@ -259,8 +259,7 @@ Base.@assume_effects :terminates_locally function issue41694(x) end return res end -@testset "ConstResult" begin - # constant prop' on all the splits +@testset "Concrete eval result" begin callsites = find_callsites_by_ftt(() -> issue41694(12); optimize = false) callinfo = only(callsites).info @test isa(callinfo, Cthulhu.ConcreteCallInfo)