From 22726ec7a16ac62fc0e9407d1f3461b247ba416d Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki Date: Sun, 10 Oct 2021 19:33:18 +0900 Subject: [PATCH] update to `avi/typelattice`, incoming type lattice overhaul --- src/Cthulhu.jl | 59 +++++++++++++++++++++++++++++++++++++++------- src/callsite.jl | 8 +++---- src/codeview.jl | 14 +++++++---- src/interpreter.jl | 6 ++--- src/reflection.jl | 14 +++++------ 5 files changed, 75 insertions(+), 26 deletions(-) diff --git a/src/Cthulhu.jl b/src/Cthulhu.jl index cc32704d..e8e08b8f 100644 --- a/src/Cthulhu.jl +++ b/src/Cthulhu.jl @@ -7,10 +7,12 @@ using InteractiveUtils using UUIDs using REPL: REPL, AbstractTerminal -using Core: MethodInstance +import Core: MethodInstance, OpaqueClosure const Compiler = Core.Compiler -import Core.Compiler: MethodMatch, LimitedAccuracy, ignorelimited, specialize_method +import Core.Compiler: MethodMatch, specialize_method, widenconst, + LimitedAccuracy, Const, PartialStruct, InterConditional, PartialOpaque import Base: unwrapva, isvarargtype, unwrap_unionall, rewrap_unionall + const mapany = Base.mapany # branch on https://github.com/JuliaLang/julia/pull/42125 @@ -21,6 +23,17 @@ else macro constprop(_, ex); esc(ex); end end +const IS_OVERHAULED = isdefined(Core.Compiler, :LatticeElement) +@static if IS_OVERHAULED + import Core.Compiler: ⊤, ⊥, LatticeElement, NativeType, LatticeElement, isConst, + isLimitedAccuracy, Argtypes, SSAValueTypes + ignorelimited(@nospecialize x) = isa(x, LatticeElement) ? Core.Compiler.ignorelimited(x) : x +else + import Core.Compiler: ignorelimited + const Argtypes = Vector{Any} + const SSAValueTypes = Vector{Any} +end + Base.@kwdef mutable struct CthulhuConfig enable_highlighter::Bool = false highlighter::Cmd = `pygmentize -l` @@ -212,15 +225,36 @@ end descend(interp::CthulhuInterpreter, mi::MethodInstance; kwargs...) = _descend(interp, mi; iswarn=false, interruptexc=false, kwargs...) +@static if IS_OVERHAULED +import Core.Compiler: ConditionalInfo function codeinst_rt(code::CodeInstance) rettype = code.rettype if isdefined(code, :rettype_const) rettype_const = code.rettype_const if isa(rettype_const, Vector{Any}) && !(Vector{Any} <: rettype) - return Core.PartialStruct(rettype, rettype_const) - elseif isa(rettype_const, Core.PartialOpaque) && rettype <: Core.OpaqueClosure + return PartialStruct(rettype, rettype_const) + elseif isa(rettype_const, PartialOpaque) && rettype <: OpaqueClosure return rettype_const - elseif isa(rettype_const, Core.InterConditional) && !(Core.InterConditional <: rettype) + elseif isa(rettype_const, ConditionalInfo) && !(ConditionalInfo <: rettype) + @assert rettype_const.inter + return InterConditional(rettype_const.slot_id, rettype_const.vtype, rettype_const.elsetype), mi + else + return Const(rettype_const) + end + else + return rettype + end +end +else # @static if IS_OVERHAULED +function codeinst_rt(code::CodeInstance) + rettype = code.rettype + if isdefined(code, :rettype_const) + rettype_const = code.rettype_const + if isa(rettype_const, Vector{Any}) && !(Vector{Any} <: rettype) + return PartialStruct(rettype, rettype_const) + elseif isa(rettype_const, PartialOpaque) && rettype <: OpaqueClosure + return rettype_const + elseif isa(rettype_const, InterConditional) && !(InterConditional <: rettype) return rettype_const else return Const(rettype_const) @@ -229,6 +263,7 @@ function codeinst_rt(code::CodeInstance) return rettype end end +end # @static if IS_OVERHAULED # `@constprop :aggressive` here in order to make sure the constant propagation of `allow_no_src` @constprop :aggressive function lookup(interp::CthulhuInterpreter, mi::MethodInstance, optimize::Bool; allow_no_src::Bool=false) @@ -238,7 +273,11 @@ end infos = interp.unopt[mi].stmt_info slottypes = src.slottypes if isnothing(slottypes) - slottypes = Any[ Any for i = 1:length(src.slotflags) ] + @static if IS_OVERHAULED + slottypes = LatticeElement[ ⊤ for i = 1:length(src.slotflags) ] + else + slottypes = Any[ Any for i = 1:length(src.slotflags) ] + end end else codeinst = interp.opt[mi] @@ -255,7 +294,11 @@ end # But with coverage on, the empty function body isn't empty due to :code_coverage_effect expressions. codeinf = src = nothing infos = [] - slottypes = Any[Base.unwrap_unionall(mi.specTypes).parameters...] + @static if IS_OVERHAULED + slottypes = AbstractLatticce[NativeType(t) for t in Base.unwrap_unionall(mi.specTypes).parameters] + else + slottypes = Any[Base.unwrap_unionall(mi.specTypes).parameters...] + end else Core.eval(Main, quote interp = $interp @@ -266,7 +309,7 @@ end end end # NOTE return `codeinf::CodeInfo` in any case since it can provide additional information on slot names - (; src, rt, infos, slottypes, codeinf) + return (; src, rt, infos, slottypes, codeinf) end ## diff --git a/src/callsite.jl b/src/callsite.jl index 327cd600..8657183e 100644 --- a/src/callsite.jl +++ b/src/callsite.jl @@ -7,7 +7,7 @@ struct MICallInfo <: CallInfo mi::MethodInstance rt function MICallInfo(mi::MethodInstance, @nospecialize(rt)) - if isa(rt, LimitedAccuracy) + if @static IS_OVERHAULED ? isLimitedAccuracy(rt) : isa(rt, LimitedAccuracy) return LimitedCallInfo(new(mi, ignorelimited(rt))) else return new(mi, rt) @@ -36,9 +36,9 @@ struct UncachedCallInfo <: WrappedCallInfo end struct PureCallInfo <: CallInfo - argtypes::Vector{Any} + argtypes::Argtypes rt - PureCallInfo(argtypes::Vector{Any}, @nospecialize(rt)) = + PureCallInfo(argtypes::Argtypes, @nospecialize(rt)) = new(argtypes, rt) end get_mi(::PureCallInfo) = nothing @@ -242,7 +242,7 @@ end function show_callinfo(limiter, ci::Union{MultiCallInfo, FailedCallInfo, GeneratedCallInfo}) types = (ci.sig::DataType).parameters ft, tt = types[1], types[2:end] - f = Compiler.singleton_type(ft) + f = Compiler.singleton_type((@static IS_OVERHAULED ? LatticeElement : identity)(ft)) if f !== nothing name = "→ $f" elseif ft isa Union diff --git a/src/codeview.jl b/src/codeview.jl index e885d76c..60391ffa 100644 --- a/src/codeview.jl +++ b/src/codeview.jl @@ -119,7 +119,11 @@ function cthulhu_typed(io::IO, debuginfo::Symbol, if isa(src, Core.CodeInfo) # we're working on pre-optimization state, need to ignore `LimitedAccuracy` src = copy(src) - src.ssavaluetypes = Base.mapany(ignorelimited, src.ssavaluetypes::Vector{Any}) + @static if IS_OVERHAULED + src.ssavaluetypes = SSAValueTypes([ignorelimited(t) for t in src.ssavaluetypes::SSAValueTypes]) + else + src.ssavaluetypes = Base.mapany(ignorelimited, src.ssavaluetypes::SSAValueTypes) + end src.rettype = ignorelimited(src.rettype) if src.slotnames !== nothing @@ -144,8 +148,9 @@ function cthulhu_typed(io::IO, debuginfo::Symbol, isa(mi, MethodInstance) || throw("`mi::MethodInstance` is required") code = src isa IRCode ? src.stmts.inst : src.code cst = Vector{Int}(undef, length(code)) + sptypes = Core.Compiler.sptypes_from_meth_instance(mi) params = Core.Compiler.OptimizationParams(interp) - maxcost = Core.Compiler.statement_costs!(cst, code, src, Any[mi.sparam_vals...], false, params) + maxcost = Core.Compiler.statement_costs!(cst, code, src, sptypes, false, params) nd = ndigits(maxcost) _lineprinter = lineprinter(src) function preprinter(io, linestart, idx) @@ -195,8 +200,9 @@ function show_variables(io, src, slotnames) slottypes = src.slottypes for i = 1:length(slotnames) print(io, " ", slotnames[i]) - if isa(slottypes, Vector{Any}) - InteractiveUtils.warntype_type_printer(io, slottypes[i], true) + if isa(slottypes, Argtypes) + typ = (@static IS_OVERHAULED ? Core.Compiler.unwraptype : identity)(slottypes[i]) + InteractiveUtils.warntype_type_printer(io, typ, true) end println(io) end diff --git a/src/interpreter.jl b/src/interpreter.jl index 3b827215..6222f916 100644 --- a/src/interpreter.jl +++ b/src/interpreter.jl @@ -93,8 +93,8 @@ end @static if isdefined(Compiler, :is_stmt_inline) function Compiler.inlining_policy( interp::CthulhuInterpreter, @nospecialize(src), stmt_flag::UInt8, - mi::MethodInstance, argtypes::Vector{Any}) - @assert isa(src, OptimizedSource) || isnothing(src) + mi::MethodInstance, argtypes::Argtypes) + @assert isa(src, OptimizedSource) || isnothing(src) "`inlining_policy(::CthulhuInterpreter, ...)` got unexpected source: `$(typeof(src))`" if isa(src, OptimizedSource) if Compiler.is_stmt_inline(stmt_flag) || src.isinlineable return src.ir @@ -103,7 +103,7 @@ function Compiler.inlining_policy( # the default inlining policy may try additional effor to find the source in a local cache return Base.@invoke Compiler.inlining_policy( interp::AbstractInterpreter, nothing, stmt_flag::UInt8, - mi::MethodInstance, argtypes::Vector{Any}) + mi::MethodInstance, argtypes::Argtypes) end return nothing end diff --git a/src/reflection.jl b/src/reflection.jl index e4c04ec7..c92ad40e 100644 --- a/src/reflection.jl +++ b/src/reflection.jl @@ -23,15 +23,13 @@ function transform(::Val{:CuFunction}, callsite, callexpr, CI, mi, slottypes; wo sptypes = sptypes_from_meth_instance(mi) tt = argextype(callexpr.args[4], CI, sptypes, slottypes) ft = argextype(callexpr.args[3], CI, sptypes, slottypes) - isa(tt, Const) || return callsite - return Callsite(callsite.id, CuCallInfo(callinfo(Tuple{widenconst(ft), tt.val.parameters...}, Nothing; world)), callsite.head) + (@static IS_OVERHAULED ? isConst(tt) : isa(tt, Const)) || return callsite + return Callsite(callsite.id, CuCallInfo(callinfo(Tuple{widenconst(ft), tt.val.parameters...}, Nothing, world)), callsite.head) end -const ArgTypes = Vector{Any} - function find_callsites(interp::CthulhuInterpreter, CI::Union{Core.CodeInfo, IRCode}, stmt_info::Union{Vector, Nothing}, mi::Core.MethodInstance, - slottypes::Vector{Any}, optimize::Bool=true) + slottypes::Argtypes, optimize::Bool=true) sptypes = sptypes_from_meth_instance(mi) callsites = Callsite[] @@ -48,7 +46,9 @@ function find_callsites(interp::CthulhuInterpreter, CI::Union{Core.CodeInfo, IRC if !optimize args = (ignorelhs(c)::Expr).args end - argtypes = mapany(function (@nospecialize(arg),) + argtypes = @static IS_OVERHAULED ? + LatticeElement[argextype(arg, CI, sptypes, slottypes) for arg in args] : + mapany(function (@nospecialize(arg),) t = argextype(arg, CI, sptypes, slottypes) return widenconst(ignorelimited(t)) end, args) @@ -103,7 +103,7 @@ function find_callsites(interp::CthulhuInterpreter, CI::Union{Core.CodeInfo, IRC return callsites end -function process_info(interp, @nospecialize(info), argtypes::ArgTypes, @nospecialize(rt), optimize::Bool) +function process_info(interp, @nospecialize(info), argtypes::Argtypes, @nospecialize(rt), optimize::Bool) is_cached(@nospecialize(key)) = haskey(optimize ? interp.opt : interp.unopt, key) process_recursive(@nospecialize(newinfo)) = process_info(interp, newinfo, argtypes, rt, optimize)