Skip to content

Commit

Permalink
Merge branch 'master' into readeach_type_stability
Browse files Browse the repository at this point in the history
  • Loading branch information
inkydragon authored Dec 19, 2024
2 parents f75aaa8 + d3c26b7 commit a3ceb68
Show file tree
Hide file tree
Showing 233 changed files with 3,608 additions and 3,515 deletions.
8 changes: 4 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,8 @@ Be sure to change the UUID value back before making the pull request.

The process of [creating a patch release](https://docs.julialang.org/en/v1/devdocs/build/distributing/#Point-releasing-101) is roughly as follows:

1. Create a new branch (e.g. `backports-release-1.6`) against the relevant minor release
branch (e.g. `release-1.6`). Usually a corresponding pull request is created as well.
1. Create a new branch (e.g. `backports-release-1.10`) against the relevant minor release
branch (e.g. `release-1.10`). Usually a corresponding pull request is created as well.

2. Add commits, nominally from `master` (hence "backports"), to that branch.
See below for more information on this process.
Expand All @@ -291,8 +291,8 @@ The process of [creating a patch release](https://docs.julialang.org/en/v1/devdo
the pull request associated with the backports branch. Fix any issues.

4. Once all test and benchmark reports look good, merge the backports branch into
the corresponding release branch (e.g. merge `backports-release-1.6` into
`release-1.6`).
the corresponding release branch (e.g. merge `backports-release-1.10` into
`release-1.10`).

5. Open a pull request that bumps the version of the relevant minor release to the
next patch version, e.g. as in [this pull request](https://github.com/JuliaLang/julia/pull/37718).
Expand Down
15 changes: 15 additions & 0 deletions Compiler/extras/CompilerDevTools/Manifest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# This file is machine-generated - editing it directly is not advised

julia_version = "1.12.0-DEV"
manifest_format = "2.0"
project_hash = "84f495a1bf065c95f732a48af36dd0cd2cefb9d5"

[[deps.Compiler]]
path = "../.."
uuid = "807dbc54-b67e-4c79-8afb-eafe4df6f2e1"
version = "0.0.2"

[[deps.CompilerDevTools]]
path = "."
uuid = "92b2d91f-d2bd-4c05-9214-4609ac33433f"
version = "0.0.0"
5 changes: 5 additions & 0 deletions Compiler/extras/CompilerDevTools/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name = "CompilerDevTools"
uuid = "92b2d91f-d2bd-4c05-9214-4609ac33433f"

[deps]
Compiler = "807dbc54-b67e-4c79-8afb-eafe4df6f2e1"
48 changes: 48 additions & 0 deletions Compiler/extras/CompilerDevTools/src/CompilerDevTools.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
module CompilerDevTools

using Compiler
using Core.IR

struct SplitCacheOwner; end
struct SplitCacheInterp <: Compiler.AbstractInterpreter
world::UInt
inf_params::Compiler.InferenceParams
opt_params::Compiler.OptimizationParams
inf_cache::Vector{Compiler.InferenceResult}
function SplitCacheInterp(;
world::UInt = Base.get_world_counter(),
inf_params::Compiler.InferenceParams = Compiler.InferenceParams(),
opt_params::Compiler.OptimizationParams = Compiler.OptimizationParams(),
inf_cache::Vector{Compiler.InferenceResult} = Compiler.InferenceResult[])
new(world, inf_params, opt_params, inf_cache)
end
end

Compiler.InferenceParams(interp::SplitCacheInterp) = interp.inf_params
Compiler.OptimizationParams(interp::SplitCacheInterp) = interp.opt_params
Compiler.get_inference_world(interp::SplitCacheInterp) = interp.world
Compiler.get_inference_cache(interp::SplitCacheInterp) = interp.inf_cache
Compiler.cache_owner(::SplitCacheInterp) = SplitCacheOwner()

import Core.OptimizedGenerics.CompilerPlugins: typeinf, typeinf_edge
@eval @noinline typeinf(::SplitCacheOwner, mi::MethodInstance, source_mode::UInt8) =
Base.invoke_in_world(which(typeinf, Tuple{SplitCacheOwner, MethodInstance, UInt8}).primary_world, Compiler.typeinf_ext, SplitCacheInterp(; world=Base.tls_world_age()), mi, source_mode)

@eval @noinline function typeinf_edge(::SplitCacheOwner, mi::MethodInstance, parent_frame::Compiler.InferenceState, world::UInt, source_mode::UInt8)
# TODO: This isn't quite right, we're just sketching things for now
interp = SplitCacheInterp(; world)
Compiler.typeinf_edge(interp, mi.def, mi.specTypes, Core.svec(), parent_frame, false, false)
end

function with_new_compiler(f, args...)
mi = @ccall jl_method_lookup(Any[f, args...]::Ptr{Any}, (1+length(args))::Csize_t, Base.tls_world_age()::Csize_t)::Ref{Core.MethodInstance}
world = Base.tls_world_age()
new_compiler_ci = Core.OptimizedGenerics.CompilerPlugins.typeinf(
SplitCacheOwner(), mi, Compiler.SOURCE_MODE_ABI
)
invoke(f, new_compiler_ci, args...)
end

export with_new_compiler

end
70 changes: 42 additions & 28 deletions Compiler/src/Compiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,36 +41,36 @@ ccall(:jl_set_module_uuid, Cvoid, (Any, NTuple{2, UInt64}), Compiler,

using Core.Intrinsics, Core.IR

import Core: print, println, show, write, unsafe_write,
_apply_iterate, svec, apply_type, Builtin, IntrinsicFunction,
MethodInstance, CodeInstance, MethodTable, MethodMatch, PartialOpaque,
TypeofVararg, Core, SimpleVector, donotdelete, compilerbarrier,
memoryref_isassigned, memoryrefnew, memoryrefoffset, memoryrefget,
memoryrefset!, typename
using Core: Builtin, CodeInstance, IntrinsicFunction, MethodInstance, MethodMatch,
MethodTable, PartialOpaque, SimpleVector, TypeofVararg,
_apply_iterate, apply_type, compilerbarrier, donotdelete, memoryref_isassigned,
memoryrefget, memoryrefnew, memoryrefoffset, memoryrefset!, print, println, show, svec,
typename, unsafe_write, write

using Base
using Base: Ordering, vect, EffectsOverride, BitVector, @_gc_preserve_begin, @_gc_preserve_end, RefValue,
@nospecializeinfer, @_foldable_meta, fieldindex, is_function_def, indexed_iterate, isexpr, methods,
get_world_counter, JLOptions, _methods_by_ftype, unwrap_unionall, cconvert, unsafe_convert,
issingletontype, isType, rewrap_unionall, has_free_typevars, isvarargtype, hasgenerator,
IteratorSize, SizeUnknown, _array_for, Bottom, generating_output, diff_names,
ismutationfree, NUM_EFFECTS_OVERRIDES, _NAMEDTUPLE_NAME, datatype_fieldtypes,
argument_datatype, isfieldatomic, unwrapva, iskindtype, _bits_findnext, copy_exprargs,
Generator, Filter, ismutabletypename, isvatuple, datatype_fieldcount,
isconcretedispatch, isdispatchelem, datatype_layoutsize,
datatype_arrayelem, unionlen, isidentityfree, _uniontypes, uniontypes, OneTo, Callable,
DataTypeFieldDesc, datatype_nfields, datatype_pointerfree, midpoint, is_valid_intrinsic_elptr,
allocatedinline, isbitsunion, widen_diagonal, unconstrain_vararg_length,
rename_unionall, may_invoke_generator, is_meta_expr_head, is_meta_expr, quoted,
specialize_method, hasintersect, is_nospecializeinfer, is_nospecialized,
get_nospecializeinfer_sig, tls_world_age, uniontype_layout, kwerr,
moduleroot, is_file_tracked, decode_effects_override, lookup_binding_partition,
is_some_imported, binding_kind, is_some_guard, is_some_const_binding, partition_restriction,
BINDING_KIND_GLOBAL, structdiff
using Base: @_foldable_meta, @_gc_preserve_begin, @_gc_preserve_end, @nospecializeinfer,
BINDING_KIND_GLOBAL, Base, BitVector, Bottom, Callable, DataTypeFieldDesc,
EffectsOverride, Filter, Generator, IteratorSize, JLOptions, NUM_EFFECTS_OVERRIDES,
OneTo, Ordering, RefValue, SizeUnknown, _NAMEDTUPLE_NAME,
_array_for, _bits_findnext, _methods_by_ftype, _uniontypes, all, allocatedinline, any,
argument_datatype, binding_kind, cconvert, copy_exprargs, datatype_arrayelem,
datatype_fieldcount, datatype_fieldtypes, datatype_layoutsize, datatype_nfields,
datatype_pointerfree, decode_effects_override, diff_names, fieldindex,
generating_output, get_nospecializeinfer_sig, get_world_counter, has_free_typevars,
hasgenerator, hasintersect, indexed_iterate, isType, is_file_tracked, is_function_def,
is_meta_expr, is_meta_expr_head, is_nospecialized, is_nospecializeinfer,
is_some_const_binding, is_some_guard, is_some_imported, is_valid_intrinsic_elptr,
isbitsunion, isconcretedispatch, isdispatchelem, isexpr, isfieldatomic, isidentityfree,
iskindtype, ismutabletypename, ismutationfree, issingletontype, isvarargtype, isvatuple,
kwerr, lookup_binding_partition, may_invoke_generator, methods, midpoint, moduleroot,
partition_restriction, quoted, rename_unionall, rewrap_unionall, specialize_method,
structdiff, tls_world_age, unconstrain_vararg_length, unionlen, uniontype_layout,
uniontypes, unsafe_convert, unwrap_unionall, unwrapva, vect, widen_diagonal
using Base.Order
import Base: getindex, setindex!, length, iterate, push!, isempty, first, convert, ==,
copy, popfirst!, in, haskey, resize!, copy!, append!, last, get!, size,
get, iterate, findall, min_world, max_world, _topmod, isready

import Base: ==, _topmod, append!, convert, copy, copy!, findall, first, get, get!,
getindex, haskey, in, isempty, isready, iterate, iterate, last, length, max_world,
min_world, popfirst!, push!, resize!, setindex!, size

const getproperty = Core.getfield
const setproperty! = Core.setfield!
Expand Down Expand Up @@ -181,12 +181,26 @@ include("bootstrap.jl")
include("reflection_interface.jl")
include("opaque_closure.jl")

macro __SOURCE_FILE__()
__source__.file === nothing && return nothing
return QuoteNode(__source__.file::Symbol)
end

module IRShow end
function load_irshow!()
if isdefined(Base, :end_base_include)
# This code path is exclusively for Revise, which may want to re-run this
# after bootstrap.
include(IRShow, Base.joinpath(Base.dirname(Base.String(@__SOURCE_FILE__)), "ssair/show.jl"))
else
include(IRShow, "ssair/show.jl")
end
end
if !isdefined(Base, :end_base_include)
# During bootstrap, skip including this file and defer it to base/show.jl to include later
else
# When this module is loaded as the standard library, include this file as usual
include(IRShow, "ssair/show.jl")
load_irshow!()
end

end # baremodule Compiler
Expand Down
119 changes: 82 additions & 37 deletions Compiler/src/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -856,8 +856,7 @@ end

struct InvokeCall
types # ::Type
lookupsig # ::Type
InvokeCall(@nospecialize(types), @nospecialize(lookupsig)) = new(types, lookupsig)
InvokeCall(@nospecialize(types)) = new(types)
end

struct ConstCallResult
Expand Down Expand Up @@ -2218,34 +2217,77 @@ function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::Stmt
ft′ = argtype_by_index(argtypes, 2)
ft = widenconst(ft′)
ft === Bottom && return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo()))
(types, isexact, isconcrete, istype) = instanceof_tfunc(argtype_by_index(argtypes, 3), false)
isexact || return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
unwrapped = unwrap_unionall(types)
types === Bottom && return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo()))
if !(unwrapped isa DataType && unwrapped.name === Tuple.name)
return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo()))
end
argtype = argtypes_to_type(argtype_tail(argtypes, 4))
nargtype = typeintersect(types, argtype)
nargtype === Bottom && return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo()))
nargtype isa DataType || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # other cases are not implemented below
isdispatchelem(ft) || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below
ft = ft::DataType
lookupsig = rewrap_unionall(Tuple{ft, unwrapped.parameters...}, types)::Type
nargtype = Tuple{ft, nargtype.parameters...}
argtype = Tuple{ft, argtype.parameters...}
matched, valid_worlds = findsup(lookupsig, method_table(interp))
matched === nothing && return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
update_valid_age!(sv, valid_worlds)
method = matched.method
types = argtype_by_index(argtypes, 3)
if types isa Const && types.val isa Union{Method, CodeInstance}
method_or_ci = types.val
if isa(method_or_ci, CodeInstance)
our_world = sv.world.this
argtype = argtypes_to_type(pushfirst!(argtype_tail(argtypes, 4), ft))
specsig = method_or_ci.def.specTypes
defdef = method_or_ci.def.def
exct = method_or_ci.exctype
if !hasintersect(argtype, specsig)
return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo()))
elseif !(argtype <: specsig) || (isa(defdef, Method) && !(argtype <: defdef.sig))
exct = Union{exct, TypeError}
end
callee_valid_range = WorldRange(method_or_ci.min_world, method_or_ci.max_world)
if !(our_world in callee_valid_range)
if our_world < first(callee_valid_range)
update_valid_age!(sv, WorldRange(first(sv.world.valid_worlds), first(callee_valid_range)-1))
else
update_valid_age!(sv, WorldRange(last(callee_valid_range)+1, last(sv.world.valid_worlds)))
end
return Future(CallMeta(Bottom, ErrorException, EFFECTS_THROWS, NoCallInfo()))
end
# TODO: When we add curing, we may want to assume this is nothrow
if (method_or_ci.owner === Nothing && method_ir_ci.def.def isa Method)
exct = Union{exct, ErrorException}
end
update_valid_age!(sv, callee_valid_range)
return Future(CallMeta(method_or_ci.rettype, exct, Effects(decode_effects(method_or_ci.ipo_purity_bits), nothrow=(exct===Bottom)),
InvokeCICallInfo(method_or_ci)))
else
method = method_or_ci::Method
types = method # argument value
lookupsig = method.sig # edge kind
argtype = argtypes_to_type(pushfirst!(argtype_tail(argtypes, 4), ft))
nargtype = typeintersect(lookupsig, argtype)
nargtype === Bottom && return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo()))
nargtype isa DataType || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # other cases are not implemented below
# Fall through to generic invoke handling
end
else
hasintersect(widenconst(types), Union{Method, CodeInstance}) && return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
(types, isexact, isconcrete, istype) = instanceof_tfunc(argtype_by_index(argtypes, 3), false)
isexact || return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
unwrapped = unwrap_unionall(types)
types === Bottom && return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo()))
if !(unwrapped isa DataType && unwrapped.name === Tuple.name)
return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo()))
end
argtype = argtypes_to_type(argtype_tail(argtypes, 4))
nargtype = typeintersect(types, argtype)
nargtype === Bottom && return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo()))
nargtype isa DataType || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # other cases are not implemented below
isdispatchelem(ft) || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below
ft = ft::DataType
lookupsig = rewrap_unionall(Tuple{ft, unwrapped.parameters...}, types)::Type
nargtype = Tuple{ft, nargtype.parameters...}
argtype = Tuple{ft, argtype.parameters...}
matched, valid_worlds = findsup(lookupsig, method_table(interp))
matched === nothing && return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
update_valid_age!(sv, valid_worlds)
method = matched.method
end
tienv = ccall(:jl_type_intersection_with_env, Any, (Any, Any), nargtype, method.sig)::SimpleVector
ti = tienv[1]
env = tienv[2]::SimpleVector
mresult = abstract_call_method(interp, method, ti, env, false, si, sv)::Future
match = MethodMatch(ti, env, method, argtype <: method.sig)
ft′_box = Core.Box(ft′)
lookupsig_box = Core.Box(lookupsig)
invokecall = InvokeCall(types, lookupsig)
invokecall = InvokeCall(types)
return Future{CallMeta}(mresult, interp, sv) do result, interp, sv
(; rt, exct, effects, edge, volatile_inf_result) = result
local ft′ = ft′_box.contents
Expand Down Expand Up @@ -2614,7 +2656,7 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
if sv isa InferenceState && f === typeassert
# perform very limited back-propagation of invariants after this type assertion
if rt !== Bottom && isa(fargs, Vector{Any})
farg2 = fargs[2]
farg2 = ssa_def_slot(fargs[2], sv)
if farg2 isa SlotNumber
refinements = SlotRefinement(farg2, rt)
end
Expand Down Expand Up @@ -2852,20 +2894,21 @@ end

function abstract_eval_cfunction(interp::AbstractInterpreter, e::Expr, sstate::StatementState, sv::AbsIntState)
f = abstract_eval_value(interp, e.args[2], sstate, sv)
# rt = sp_type_rewrap(e.args[3], sv.linfo, true)
# rt = sp_type_rewrap(e.args[3], sv.linfo, true) # verify that the result type make sense?
# rt === Bottom && return RTEffects(Union{}, Any, EFFECTS_UNKNOWN)
atv = e.args[4]::SimpleVector
at = Vector{Any}(undef, length(atv) + 1)
at[1] = f
for i = 1:length(atv)
at[i + 1] = sp_type_rewrap(at[i], frame_instance(sv), false)
at[i + 1] === Bottom && return
atᵢ = at[i + 1] = sp_type_rewrap(atv[i], frame_instance(sv), false)
atᵢ === Bottom && return RTEffects(Union{}, Any, EFFECTS_UNKNOWN)
end
# this may be the wrong world for the call,
# but some of the result is likely to be valid anyways
# and that may help generate better codegen
abstract_call(interp, ArgInfo(nothing, at), StmtInfo(false, false), sv)::Future
rt = e.args[1]
isa(rt, Type) || (rt = Any)
isconcretetype(rt) || (rt = Any)
return RTEffects(rt, Any, EFFECTS_UNKNOWN)
end

Expand Down Expand Up @@ -3198,8 +3241,16 @@ function abstract_eval_throw_undef_if_not(interp::AbstractInterpreter, e::Expr,
end

function abstract_eval_the_exception(::AbstractInterpreter, sv::InferenceState)
(;handlers, handler_at) = sv.handler_info::HandlerInfo
return the_exception_info(handlers[handler_at[sv.currpc][2]].exct)
(;handler_info) = sv
if handler_info === nothing
return the_exception_info(Any)
end
(;handlers, handler_at) = handler_info
handler_id = handler_at[sv.currpc][2]
if handler_id === 0
return the_exception_info(Any)
end
return the_exception_info(handlers[handler_id].exct)
end
abstract_eval_the_exception(::AbstractInterpreter, ::IRInterpretationState) = the_exception_info(Any)
the_exception_info(@nospecialize t) = RTEffects(t, Union{}, Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE))
Expand Down Expand Up @@ -4009,13 +4060,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextr
end
effects === nothing || merge_override_effects!(interp, effects, frame)
if lhs !== nothing && rt !== Bottom
if isa(lhs, SlotNumber)
changes = StateUpdate(lhs, VarState(rt, false))
elseif isa(lhs, GlobalRef)
handle_global_assignment!(interp, frame, currsaw_latestworld, lhs, rt)
else
merge_effects!(interp, frame, EFFECTS_UNKNOWN)
end
changes = StateUpdate(lhs::SlotNumber, VarState(rt, false))
end
end
if !has_curr_ssaflag(frame, IR_FLAG_NOTHROW)
Expand Down
2 changes: 1 addition & 1 deletion Compiler/src/abstractlattice.jl
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ end
if isa(t, Const)
# don't consider mutable values useful constants
val = t.val
return isa(val, Symbol) || isa(val, Type) || !ismutable(val)
return isa(val, Symbol) || isa(val, Type) || isa(val, Method) || isa(val, CodeInstance) || !ismutable(val)
end
isa(t, PartialTypeVar) && return false # this isn't forwardable
return is_const_prop_profitable_arg(widenlattice(𝕃), t)
Expand Down
Loading

0 comments on commit a3ceb68

Please sign in to comment.