Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/Cthulhu.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
31 changes: 20 additions & 11 deletions src/CthulhuCompiler.jl
Original file line number Diff line number Diff line change
@@ -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}

Expand All @@ -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
16 changes: 16 additions & 0 deletions src/compiler/interpreter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
55 changes: 52 additions & 3 deletions src/compiler/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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),
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
23 changes: 15 additions & 8 deletions test/test_AbstractInterpreter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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")))
Expand All @@ -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
Expand All @@ -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)
Expand Down
3 changes: 1 addition & 2 deletions test/test_Cthulhu.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading