From b2f4366ee8f82c710409415d23be2f921c9616b1 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 31 Oct 2024 23:56:04 +0000 Subject: [PATCH] Make Compiler a stdlib This is a further extension to #56128 to make the compiler into a proper stdlib, useable outside of `Base` as `using Compiler` in the same way that `JuliaSyntax` works already. There's a few remaining questions around how loading works, but mechanically, this PR is complete. For those remaining questions, I'll probably put up a separate PR that would migrate JuliaSyntax to it and then simply adopt that here once we've figured out the correct semantics. --- base/Base.jl | 1 + base/Base_compiler.jl | 11 ++- base/boot.jl | 1 - base/compiler/bootstrap.jl | 52 ------------ base/coreir.jl | 54 +++++++++++++ base/{compiler/parsing.jl => flparse.jl} | 0 base/show.jl | 2 +- src/toplevel.c | 15 ++++ stdlib/Compiler/Project.toml | 3 + .../Compiler/src/Compiler.jl | 79 ++++++++++-------- .../Compiler/src}/abstractinterpretation.jl | 8 +- .../Compiler/src}/abstractlattice.jl | 0 stdlib/Compiler/src/bootstrap.jl | 57 +++++++++++++ .../Compiler/src}/cicache.jl | 0 .../Compiler/src}/effects.jl | 0 .../Compiler/src}/inferenceresult.jl | 0 .../Compiler/src}/inferencestate.jl | 0 .../Compiler/src}/methodtable.jl | 0 .../Compiler/src}/optimize.jl | 16 ++-- .../compiler => stdlib/Compiler/src}/sort.jl | 0 .../ssair/EscapeAnalysis/EscapeAnalysis.jl | 13 +-- .../src}/ssair/EscapeAnalysis/disjoint_set.jl | 0 .../Compiler/src}/ssair/basicblock.jl | 0 .../Compiler/src}/ssair/domtree.jl | 0 .../Compiler/src}/ssair/heap.jl | 0 .../Compiler/src}/ssair/inlining.jl | 0 .../Compiler/src}/ssair/ir.jl | 2 - .../Compiler/src}/ssair/irinterp.jl | 0 .../Compiler/src}/ssair/legacy.jl | 0 .../Compiler/src}/ssair/passes.jl | 0 .../Compiler/src}/ssair/show.jl | 0 .../Compiler/src}/ssair/slot2ssa.jl | 0 .../Compiler/src}/ssair/tarjan.jl | 0 .../Compiler/src}/ssair/verify.jl | 0 .../Compiler/src}/stmtinfo.jl | 0 .../Compiler/src}/tfuncs.jl | 4 +- .../Compiler/src}/typeinfer.jl | 2 +- .../Compiler/src}/typelattice.jl | 80 ++++--------------- .../Compiler/src}/typelimits.jl | 2 +- .../compiler => stdlib/Compiler/src}/types.jl | 0 .../Compiler/src}/typeutils.jl | 0 .../Compiler/src}/utilities.jl | 0 .../Compiler/src}/validation.jl | 0 stdlib/Makefile | 2 +- test/compiler/inference.jl | 2 +- 45 files changed, 225 insertions(+), 181 deletions(-) delete mode 100644 base/compiler/bootstrap.jl create mode 100644 base/coreir.jl rename base/{compiler/parsing.jl => flparse.jl} (100%) create mode 100644 stdlib/Compiler/Project.toml rename base/compiler/compiler.jl => stdlib/Compiler/src/Compiler.jl (72%) rename {base/compiler => stdlib/Compiler/src}/abstractinterpretation.jl (99%) rename {base/compiler => stdlib/Compiler/src}/abstractlattice.jl (100%) create mode 100644 stdlib/Compiler/src/bootstrap.jl rename {base/compiler => stdlib/Compiler/src}/cicache.jl (100%) rename {base/compiler => stdlib/Compiler/src}/effects.jl (100%) rename {base/compiler => stdlib/Compiler/src}/inferenceresult.jl (100%) rename {base/compiler => stdlib/Compiler/src}/inferencestate.jl (100%) rename {base/compiler => stdlib/Compiler/src}/methodtable.jl (100%) rename {base/compiler => stdlib/Compiler/src}/optimize.jl (99%) rename {base/compiler => stdlib/Compiler/src}/sort.jl (100%) rename {base/compiler => stdlib/Compiler/src}/ssair/EscapeAnalysis/EscapeAnalysis.jl (99%) rename {base/compiler => stdlib/Compiler/src}/ssair/EscapeAnalysis/disjoint_set.jl (100%) rename {base/compiler => stdlib/Compiler/src}/ssair/basicblock.jl (100%) rename {base/compiler => stdlib/Compiler/src}/ssair/domtree.jl (100%) rename {base/compiler => stdlib/Compiler/src}/ssair/heap.jl (100%) rename {base/compiler => stdlib/Compiler/src}/ssair/inlining.jl (100%) rename {base/compiler => stdlib/Compiler/src}/ssair/ir.jl (99%) rename {base/compiler => stdlib/Compiler/src}/ssair/irinterp.jl (100%) rename {base/compiler => stdlib/Compiler/src}/ssair/legacy.jl (100%) rename {base/compiler => stdlib/Compiler/src}/ssair/passes.jl (100%) rename {base/compiler => stdlib/Compiler/src}/ssair/show.jl (100%) rename {base/compiler => stdlib/Compiler/src}/ssair/slot2ssa.jl (100%) rename {base/compiler => stdlib/Compiler/src}/ssair/tarjan.jl (100%) rename {base/compiler => stdlib/Compiler/src}/ssair/verify.jl (100%) rename {base/compiler => stdlib/Compiler/src}/stmtinfo.jl (100%) rename {base/compiler => stdlib/Compiler/src}/tfuncs.jl (99%) rename {base/compiler => stdlib/Compiler/src}/typeinfer.jl (99%) rename {base/compiler => stdlib/Compiler/src}/typelattice.jl (92%) rename {base/compiler => stdlib/Compiler/src}/typelimits.jl (99%) rename {base/compiler => stdlib/Compiler/src}/types.jl (100%) rename {base/compiler => stdlib/Compiler/src}/typeutils.jl (100%) rename {base/compiler => stdlib/Compiler/src}/utilities.jl (100%) rename {base/compiler => stdlib/Compiler/src}/validation.jl (100%) diff --git a/base/Base.jl b/base/Base.jl index 50bf74fc12e95d..4b8c0984bd538b 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -380,6 +380,7 @@ a_method_to_overwrite_in_test() = inferencebarrier(1) # Compatibility with when Compiler was in Core @eval Core const Compiler = Main.Base.Compiler +@eval Compiler const fl_parse = Core.Main.Base.fl_parse # External libraries vendored into Base Core.println("JuliaSyntax/src/JuliaSyntax.jl") diff --git a/base/Base_compiler.jl b/base/Base_compiler.jl index 3578b8f070db31..19f3a39bcd8b98 100644 --- a/base/Base_compiler.jl +++ b/base/Base_compiler.jl @@ -252,15 +252,14 @@ include("namedtuple.jl") include("ordering.jl") using .Order -include("compiler/compiler.jl") +include("coreir.jl") + +include("../stdlib/Compiler/src/Compiler.jl") const _return_type = Compiler.return_type # Enable compiler -Core.eval(Compiler, quote -include("compiler/bootstrap.jl") -ccall(:jl_set_typeinf_func, Cvoid, (Any,), typeinf_ext_toplevel) +Compiler.bootstrap!() -include("compiler/parsing.jl") +include("flparse.jl") Core._setparser!(fl_parse) -end) diff --git a/base/boot.jl b/base/boot.jl index 5d40191ecab211..612efc0b50c8a4 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -512,7 +512,6 @@ eval(Core, quote UpsilonNode(@nospecialize(val)) = $(Expr(:new, :UpsilonNode, :val)) UpsilonNode() = $(Expr(:new, :UpsilonNode)) Const(@nospecialize(v)) = $(Expr(:new, :Const, :v)) - # NOTE the main constructor is defined within `Core.Compiler` _PartialStruct(@nospecialize(typ), fields::Array{Any, 1}) = $(Expr(:new, :PartialStruct, :typ, :fields)) PartialOpaque(@nospecialize(typ), @nospecialize(env), parent::MethodInstance, source) = $(Expr(:new, :PartialOpaque, :typ, :env, :parent, :source)) InterConditional(slot::Int, @nospecialize(thentype), @nospecialize(elsetype)) = $(Expr(:new, :InterConditional, :slot, :thentype, :elsetype)) diff --git a/base/compiler/bootstrap.jl b/base/compiler/bootstrap.jl deleted file mode 100644 index 3162bccbdb4b96..00000000000000 --- a/base/compiler/bootstrap.jl +++ /dev/null @@ -1,52 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -# make sure that typeinf is executed before turning on typeinf_ext -# this ensures that typeinf_ext doesn't recurse before it can add the item to the workq -# especially try to make sure any recursive and leaf functions have concrete signatures, -# since we won't be able to specialize & infer them at runtime - -let time() = ccall(:jl_clock_now, Float64, ()) - println("Compiling the compiler. This may take several minutes ...") - interp = NativeInterpreter() - - # analyze_escapes_tt = Tuple{typeof(analyze_escapes), IRCode, Int, TODO} - optimize_tt = Tuple{typeof(optimize), NativeInterpreter, OptimizationState{NativeInterpreter}, InferenceResult} - fs = Any[ - # we first create caches for the optimizer, because they contain many loop constructions - # and they're better to not run in interpreter even during bootstrapping - #=analyze_escapes_tt,=# optimize_tt, - # then we create caches for inference entries - typeinf_ext, typeinf, typeinf_edge, - ] - # tfuncs can't be inferred from the inference entries above, so here we infer them manually - for x in T_FFUNC_VAL - push!(fs, x[3]) - end - for i = 1:length(T_IFUNC) - if isassigned(T_IFUNC, i) - x = T_IFUNC[i] - push!(fs, x[3]) - else - println(stderr, "WARNING: tfunc missing for ", reinterpret(IntrinsicFunction, Int32(i))) - end - end - starttime = time() - for f in fs - if isa(f, DataType) && f.name === typename(Tuple) - tt = f - else - tt = Tuple{typeof(f), Vararg{Any}} - end - for m in _methods_by_ftype(tt, 10, get_world_counter())::Vector - # remove any TypeVars from the intersection - m = m::MethodMatch - typ = Any[m.spec_types.parameters...] - for i = 1:length(typ) - typ[i] = unwraptv(typ[i]) - end - typeinf_type(interp, m.method, Tuple{typ...}, m.sparams) - end - end - endtime = time() - println("Base.Compiler ──── ", sub_float(endtime,starttime), " seconds") -end diff --git a/base/coreir.jl b/base/coreir.jl new file mode 100644 index 00000000000000..a21eeceffe4c59 --- /dev/null +++ b/base/coreir.jl @@ -0,0 +1,54 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +Core.PhiNode() = Core.PhiNode(Int32[], Any[]) + +""" + struct Const + val + end + +The type representing a constant value. +""" +Core.Const + +""" + struct PartialStruct + typ + fields::Vector{Any} # elements are other type lattice members + end + +This extended lattice element is introduced when we have information about an object's +fields beyond what can be obtained from the object type. E.g. it represents a tuple where +some elements are known to be constants or a struct whose `Any`-typed field is initialized +with `Int` values. + +- `typ` indicates the type of the object +- `fields` holds the lattice elements corresponding to each field of the object + +If `typ` is a struct, `fields` represents the fields of the struct that are guaranteed to be +initialized. For instance, if the length of `fields` of `PartialStruct` representing a +struct with 4 fields is 3, the 4th field may not be initialized. If the length is 4, all +fields are guaranteed to be initialized. + +If `typ` is a tuple, the last element of `fields` may be `Vararg`. In this case, it is +guaranteed that the number of elements in the tuple is at least `length(fields)-1`, but the +exact number of elements is unknown. +""" +Core.PartialStruct + +""" + struct InterConditional + slot::Int + thentype + elsetype + end + +Similar to `Conditional`, but conveys inter-procedural constraints imposed on call arguments. +This is separate from `Conditional` to catch logic errors: the lattice element name is `InterConditional` +while processing a call, then `Conditional` everywhere else. Thus `InterConditional` does not appear in +`CompilerTypes`—these type's usages are disjoint—though we define the lattice for `InterConditional`. +""" +Core.InterConditional + +InterConditional(var::SlotNumber, @nospecialize(thentype), @nospecialize(elsetype)) = + InterConditional(slot_id(var), thentype, elsetype) diff --git a/base/compiler/parsing.jl b/base/flparse.jl similarity index 100% rename from base/compiler/parsing.jl rename to base/flparse.jl diff --git a/base/show.jl b/base/show.jl index 26efd0a93f716c..953557a2679b55 100644 --- a/base/show.jl +++ b/base/show.jl @@ -2856,7 +2856,7 @@ module IRShow Effects, ALWAYS_TRUE, ALWAYS_FALSE, DebugInfoStream, getdebugidx, VarState, InvalidIRError, argextype, widenconst, singleton_type, sptypes_from_meth_instance, EMPTY_SPTYPES - include("compiler/ssair/show.jl") + include("../stdlib/Compiler/src/ssair/show.jl") const __debuginfo = Dict{Symbol, Any}( # :full => src -> statementidx_lineinfo_printer(src), # and add variable slot information diff --git a/src/toplevel.c b/src/toplevel.c index 45143f99a178c6..b0163683cf87ce 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -1289,6 +1289,21 @@ JL_DLLEXPORT jl_value_t *jl_prepend_cwd(jl_value_t *str) return jl_cstr_to_string(path); } +JL_DLLEXPORT jl_value_t *jl_prepend_string(jl_value_t *prefix, jl_value_t *str) +{ + char path[1024]; + const char *pstr = (const char*)jl_string_data(prefix); + size_t sz = strlen(pstr); + const char *fstr = (const char*)jl_string_data(str); + if (strlen(fstr) + sz >= sizeof(path)) { + jl_errorf("use a bigger buffer for jl_fullpath"); + } + strcpy(path, pstr); + strcpy(path + sz, fstr); + return jl_cstr_to_string(path); +} + + #ifdef __cplusplus } #endif diff --git a/stdlib/Compiler/Project.toml b/stdlib/Compiler/Project.toml new file mode 100644 index 00000000000000..b933d08db5205a --- /dev/null +++ b/stdlib/Compiler/Project.toml @@ -0,0 +1,3 @@ +name = "Compiler" +uuid = "807dbc54-b67e-4c79-8afb-eafe4df6f2e1" +version = "0.0.1" diff --git a/base/compiler/compiler.jl b/stdlib/Compiler/src/Compiler.jl similarity index 72% rename from base/compiler/compiler.jl rename to stdlib/Compiler/src/Compiler.jl index f4b7b73f1bf768..d36412fb68d6f9 100644 --- a/base/compiler/compiler.jl +++ b/stdlib/Compiler/src/Compiler.jl @@ -12,8 +12,8 @@ import Core: print, println, show, write, unsafe_write, memoryref_isassigned, memoryrefnew, memoryrefoffset, memoryrefget, memoryrefset!, typename -using ..Base -using ..Base: Ordering, vect, EffectsOverride, BitVector, @_gc_preserve_begin, @_gc_preserve_end, RefValue, +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, @@ -29,8 +29,8 @@ using ..Base: Ordering, vect, EffectsOverride, BitVector, @_gc_preserve_begin, @ specialize_method, hasintersect, is_nospecializeinfer, is_nospecialized, get_nospecializeinfer_sig, tls_world_age, uniontype_layout, kwerr, moduleroot, is_file_tracked, decode_effects_override -using ..Base.Order -import ..Base: getindex, setindex!, length, iterate, push!, isempty, first, convert, ==, +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 @@ -46,8 +46,21 @@ ccall(:jl_set_istopmod, Cvoid, (Any, Bool), Compiler, false) eval(x) = Core.eval(Compiler, x) eval(m, x) = Core.eval(m, x) -include(x) = Base.include(Compiler, x) -include(mod, x) = Base.include(mod, x) +function include(x::String) + if !isdefined(Base, :end_base_include) + # During bootstrap, all includes are relative to `base/` + x = ccall(:jl_prepend_string, Ref{String}, (Any, Any), "../stdlib/Compiler/src/", x) + end + Base.include(Compiler, x) +end + +function include(mod::Module, x::String) + if !isdefined(Base, :end_base_include) + x = ccall(:jl_prepend_string, Ref{String}, (Any, Any), "../stdlib/Compiler/src/", x) + end + Base.include(mod, x) +end + macro _boundscheck() Expr(:boundscheck) end @@ -59,7 +72,7 @@ abstract type AbstractInterpreter end function return_type end # promotion.jl expects this to exist is_return_type(Core.@nospecialize(f)) = f === return_type -include("compiler/sort.jl") +include("sort.jl") # We don't include some.jl, but this definition is still useful. something(x::Nothing, y...) = something(y...) @@ -94,30 +107,32 @@ else end end -include("compiler/cicache.jl") -include("compiler/methodtable.jl") -include("compiler/effects.jl") -include("compiler/types.jl") -include("compiler/utilities.jl") -include("compiler/validation.jl") - -include("compiler/ssair/basicblock.jl") -include("compiler/ssair/domtree.jl") -include("compiler/ssair/ir.jl") -include("compiler/ssair/tarjan.jl") - -include("compiler/abstractlattice.jl") -include("compiler/stmtinfo.jl") -include("compiler/inferenceresult.jl") -include("compiler/inferencestate.jl") - -include("compiler/typeutils.jl") -include("compiler/typelimits.jl") -include("compiler/typelattice.jl") -include("compiler/tfuncs.jl") - -include("compiler/abstractinterpretation.jl") -include("compiler/typeinfer.jl") -include("compiler/optimize.jl") +include("cicache.jl") +include("methodtable.jl") +include("effects.jl") +include("types.jl") +include("utilities.jl") +include("validation.jl") + +include("ssair/basicblock.jl") +include("ssair/domtree.jl") +include("ssair/ir.jl") +include("ssair/tarjan.jl") + +include("abstractlattice.jl") +include("stmtinfo.jl") +include("inferenceresult.jl") +include("inferencestate.jl") + +include("typeutils.jl") +include("typelimits.jl") +include("typelattice.jl") +include("tfuncs.jl") + +include("abstractinterpretation.jl") +include("typeinfer.jl") +include("optimize.jl") + +include("bootstrap.jl") end diff --git a/base/compiler/abstractinterpretation.jl b/stdlib/Compiler/src/abstractinterpretation.jl similarity index 99% rename from base/compiler/abstractinterpretation.jl rename to stdlib/Compiler/src/abstractinterpretation.jl index 16a03bb7bd72b2..f18a1aa8acfbec 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/stdlib/Compiler/src/abstractinterpretation.jl @@ -2119,7 +2119,7 @@ function form_partially_defined_struct(@nospecialize(obj), @nospecialize(name)) else fldidx > nminfld || return nothing end - return PartialStruct(objt0, Any[obj isa PartialStruct && i≤length(obj.fields) ? + return PartialStruct(fallback_lattice, objt0, Any[obj isa PartialStruct && i≤length(obj.fields) ? obj.fields[i] : fieldtype(objt0,i) for i = 1:fldidx]) end @@ -2955,7 +2955,7 @@ function abstract_eval_new(interp::AbstractInterpreter, e::Expr, vtypes::Union{V # - any refinement information is available (`anyrefine`), or when # - `nargs` is greater than `n_initialized` derived from the struct type # information alone - rt = PartialStruct(rt, ats) + rt = PartialStruct(𝕃ᵢ, rt, ats) end else rt = refine_partial_type(rt) @@ -2990,7 +2990,7 @@ function abstract_eval_splatnew(interp::AbstractInterpreter, e::Expr, vtypes::Un all(i::Int -> ⊑(𝕃ᵢ, (at.fields::Vector{Any})[i], fieldtype(t, i)), 1:n) end)) nothrow = isexact - rt = PartialStruct(rt, at.fields::Vector{Any}) + rt = PartialStruct(𝕃ᵢ, rt, at.fields::Vector{Any}) end else rt = refine_partial_type(rt) @@ -3527,7 +3527,7 @@ end end fields[i] = a end - anyrefine && return PartialStruct(rt.typ, fields) + anyrefine && return PartialStruct(𝕃ᵢ, rt.typ, fields) end if isa(rt, PartialOpaque) return rt # XXX: this case was missed in #39512 diff --git a/base/compiler/abstractlattice.jl b/stdlib/Compiler/src/abstractlattice.jl similarity index 100% rename from base/compiler/abstractlattice.jl rename to stdlib/Compiler/src/abstractlattice.jl diff --git a/stdlib/Compiler/src/bootstrap.jl b/stdlib/Compiler/src/bootstrap.jl new file mode 100644 index 00000000000000..985516ae8127b0 --- /dev/null +++ b/stdlib/Compiler/src/bootstrap.jl @@ -0,0 +1,57 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +# make sure that typeinf is executed before turning on typeinf_ext +# this ensures that typeinf_ext doesn't recurse before it can add the item to the workq +# especially try to make sure any recursive and leaf functions have concrete signatures, +# since we won't be able to specialize & infer them at runtime + +activate!() = ccall(:jl_set_typeinf_func, Cvoid, (Any,), typeinf_ext_toplevel) + +function bootstrap!() + let time() = ccall(:jl_clock_now, Float64, ()) + println("Compiling the compiler. This may take several minutes ...") + interp = NativeInterpreter() + + # analyze_escapes_tt = Tuple{typeof(analyze_escapes), IRCode, Int, TODO} + optimize_tt = Tuple{typeof(optimize), NativeInterpreter, OptimizationState{NativeInterpreter}, InferenceResult} + fs = Any[ + # we first create caches for the optimizer, because they contain many loop constructions + # and they're better to not run in interpreter even during bootstrapping + #=analyze_escapes_tt,=# optimize_tt, + # then we create caches for inference entries + typeinf_ext, typeinf, typeinf_edge, + ] + # tfuncs can't be inferred from the inference entries above, so here we infer them manually + for x in T_FFUNC_VAL + push!(fs, x[3]) + end + for i = 1:length(T_IFUNC) + if isassigned(T_IFUNC, i) + x = T_IFUNC[i] + push!(fs, x[3]) + else + println(stderr, "WARNING: tfunc missing for ", reinterpret(IntrinsicFunction, Int32(i))) + end + end + starttime = time() + for f in fs + if isa(f, DataType) && f.name === typename(Tuple) + tt = f + else + tt = Tuple{typeof(f), Vararg{Any}} + end + for m in _methods_by_ftype(tt, 10, get_world_counter())::Vector + # remove any TypeVars from the intersection + m = m::MethodMatch + typ = Any[m.spec_types.parameters...] + for i = 1:length(typ) + typ[i] = unwraptv(typ[i]) + end + typeinf_type(interp, m.method, Tuple{typ...}, m.sparams) + end + end + endtime = time() + println("Base.Compiler ──── ", sub_float(endtime,starttime), " seconds") + end + activate!() +end diff --git a/base/compiler/cicache.jl b/stdlib/Compiler/src/cicache.jl similarity index 100% rename from base/compiler/cicache.jl rename to stdlib/Compiler/src/cicache.jl diff --git a/base/compiler/effects.jl b/stdlib/Compiler/src/effects.jl similarity index 100% rename from base/compiler/effects.jl rename to stdlib/Compiler/src/effects.jl diff --git a/base/compiler/inferenceresult.jl b/stdlib/Compiler/src/inferenceresult.jl similarity index 100% rename from base/compiler/inferenceresult.jl rename to stdlib/Compiler/src/inferenceresult.jl diff --git a/base/compiler/inferencestate.jl b/stdlib/Compiler/src/inferencestate.jl similarity index 100% rename from base/compiler/inferencestate.jl rename to stdlib/Compiler/src/inferencestate.jl diff --git a/base/compiler/methodtable.jl b/stdlib/Compiler/src/methodtable.jl similarity index 100% rename from base/compiler/methodtable.jl rename to stdlib/Compiler/src/methodtable.jl diff --git a/base/compiler/optimize.jl b/stdlib/Compiler/src/optimize.jl similarity index 99% rename from base/compiler/optimize.jl rename to stdlib/Compiler/src/optimize.jl index aeb3e6849773b8..84dff88a0a20fc 100644 --- a/base/compiler/optimize.jl +++ b/stdlib/Compiler/src/optimize.jl @@ -212,14 +212,14 @@ end function argextype end # imported by EscapeAnalysis function try_compute_field end # imported by EscapeAnalysis -include("compiler/ssair/heap.jl") -include("compiler/ssair/slot2ssa.jl") -include("compiler/ssair/inlining.jl") -include("compiler/ssair/verify.jl") -include("compiler/ssair/legacy.jl") -include("compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl") -include("compiler/ssair/passes.jl") -include("compiler/ssair/irinterp.jl") +include("ssair/heap.jl") +include("ssair/slot2ssa.jl") +include("ssair/inlining.jl") +include("ssair/verify.jl") +include("ssair/legacy.jl") +include("ssair/EscapeAnalysis/EscapeAnalysis.jl") +include("ssair/passes.jl") +include("ssair/irinterp.jl") function ir_to_codeinf!(opt::OptimizationState) (; linfo, src) = opt diff --git a/base/compiler/sort.jl b/stdlib/Compiler/src/sort.jl similarity index 100% rename from base/compiler/sort.jl rename to stdlib/Compiler/src/sort.jl diff --git a/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl b/stdlib/Compiler/src/ssair/EscapeAnalysis/EscapeAnalysis.jl similarity index 99% rename from base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl rename to stdlib/Compiler/src/ssair/EscapeAnalysis/EscapeAnalysis.jl index 370699f9f57350..07e53d75043962 100644 --- a/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl +++ b/stdlib/Compiler/src/ssair/EscapeAnalysis/EscapeAnalysis.jl @@ -30,13 +30,16 @@ using ..Compiler: # Core.Compiler specific definitions is_meta_expr_head, is_mutation_free_argtype, isexpr, println, setfield!_nothrow, singleton_type, try_compute_field, try_compute_fieldidx, widenconst, ⊑, Compiler -include(x) = _TOP_MOD.include(@__MODULE__, x) -if _TOP_MOD === Compiler - include("compiler/ssair/EscapeAnalysis/disjoint_set.jl") -else - include("disjoint_set.jl") +function include(x) + if !isdefined(_TOP_MOD.Base, :end_base_include) + # During bootstrap, all includes are relative to `base/` + x = ccall(:jl_prepend_string, Ref{String}, (Any, Any), "ssair/EscapeAnalysis/", x) + end + _TOP_MOD.include(@__MODULE__, x) end +include("disjoint_set.jl") + const AInfo = IdSet{Any} """ diff --git a/base/compiler/ssair/EscapeAnalysis/disjoint_set.jl b/stdlib/Compiler/src/ssair/EscapeAnalysis/disjoint_set.jl similarity index 100% rename from base/compiler/ssair/EscapeAnalysis/disjoint_set.jl rename to stdlib/Compiler/src/ssair/EscapeAnalysis/disjoint_set.jl diff --git a/base/compiler/ssair/basicblock.jl b/stdlib/Compiler/src/ssair/basicblock.jl similarity index 100% rename from base/compiler/ssair/basicblock.jl rename to stdlib/Compiler/src/ssair/basicblock.jl diff --git a/base/compiler/ssair/domtree.jl b/stdlib/Compiler/src/ssair/domtree.jl similarity index 100% rename from base/compiler/ssair/domtree.jl rename to stdlib/Compiler/src/ssair/domtree.jl diff --git a/base/compiler/ssair/heap.jl b/stdlib/Compiler/src/ssair/heap.jl similarity index 100% rename from base/compiler/ssair/heap.jl rename to stdlib/Compiler/src/ssair/heap.jl diff --git a/base/compiler/ssair/inlining.jl b/stdlib/Compiler/src/ssair/inlining.jl similarity index 100% rename from base/compiler/ssair/inlining.jl rename to stdlib/Compiler/src/ssair/inlining.jl diff --git a/base/compiler/ssair/ir.jl b/stdlib/Compiler/src/ssair/ir.jl similarity index 99% rename from base/compiler/ssair/ir.jl rename to stdlib/Compiler/src/ssair/ir.jl index 1efa10f2437ad8..9a76c7370c68d6 100644 --- a/base/compiler/ssair/ir.jl +++ b/stdlib/Compiler/src/ssair/ir.jl @@ -1,7 +1,5 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -Core.PhiNode() = Core.PhiNode(Int32[], Any[]) - isterminator(@nospecialize(stmt)) = isa(stmt, GotoNode) || isa(stmt, GotoIfNot) || isa(stmt, ReturnNode) || isa(stmt, EnterNode) || isexpr(stmt, :leave) diff --git a/base/compiler/ssair/irinterp.jl b/stdlib/Compiler/src/ssair/irinterp.jl similarity index 100% rename from base/compiler/ssair/irinterp.jl rename to stdlib/Compiler/src/ssair/irinterp.jl diff --git a/base/compiler/ssair/legacy.jl b/stdlib/Compiler/src/ssair/legacy.jl similarity index 100% rename from base/compiler/ssair/legacy.jl rename to stdlib/Compiler/src/ssair/legacy.jl diff --git a/base/compiler/ssair/passes.jl b/stdlib/Compiler/src/ssair/passes.jl similarity index 100% rename from base/compiler/ssair/passes.jl rename to stdlib/Compiler/src/ssair/passes.jl diff --git a/base/compiler/ssair/show.jl b/stdlib/Compiler/src/ssair/show.jl similarity index 100% rename from base/compiler/ssair/show.jl rename to stdlib/Compiler/src/ssair/show.jl diff --git a/base/compiler/ssair/slot2ssa.jl b/stdlib/Compiler/src/ssair/slot2ssa.jl similarity index 100% rename from base/compiler/ssair/slot2ssa.jl rename to stdlib/Compiler/src/ssair/slot2ssa.jl diff --git a/base/compiler/ssair/tarjan.jl b/stdlib/Compiler/src/ssair/tarjan.jl similarity index 100% rename from base/compiler/ssair/tarjan.jl rename to stdlib/Compiler/src/ssair/tarjan.jl diff --git a/base/compiler/ssair/verify.jl b/stdlib/Compiler/src/ssair/verify.jl similarity index 100% rename from base/compiler/ssair/verify.jl rename to stdlib/Compiler/src/ssair/verify.jl diff --git a/base/compiler/stmtinfo.jl b/stdlib/Compiler/src/stmtinfo.jl similarity index 100% rename from base/compiler/stmtinfo.jl rename to stdlib/Compiler/src/stmtinfo.jl diff --git a/base/compiler/tfuncs.jl b/stdlib/Compiler/src/tfuncs.jl similarity index 99% rename from base/compiler/tfuncs.jl rename to stdlib/Compiler/src/tfuncs.jl index aaa1354fd5e540..d82b7289cbde8f 100644 --- a/base/compiler/tfuncs.jl +++ b/stdlib/Compiler/src/tfuncs.jl @@ -1436,7 +1436,7 @@ end if TF2 === Bottom RT = Bottom elseif isconcretetype(RT) && has_nontrivial_extended_info(𝕃ᵢ, TF2) # isconcrete condition required to form a PartialStruct - RT = PartialStruct(RT, Any[TF, TF2]) + RT = PartialStruct(fallback_lattice, RT, Any[TF, TF2]) end info = ModifyOpInfo(callinfo.info) return CallMeta(RT, Any, Effects(), info) @@ -1996,7 +1996,7 @@ function tuple_tfunc(𝕃::AbstractLattice, argtypes::Vector{Any}) typ = Tuple{params...} # replace a singleton type with its equivalent Const object issingletontype(typ) && return Const(typ.instance) - return anyinfo ? PartialStruct(typ, argtypes) : typ + return anyinfo ? PartialStruct(𝕃, typ, argtypes) : typ end @nospecs function memoryrefget_tfunc(𝕃::AbstractLattice, mem, order, boundscheck) diff --git a/base/compiler/typeinfer.jl b/stdlib/Compiler/src/typeinfer.jl similarity index 99% rename from base/compiler/typeinfer.jl rename to stdlib/Compiler/src/typeinfer.jl index 2d46976819e2d6..05d218de956a6d 100644 --- a/base/compiler/typeinfer.jl +++ b/stdlib/Compiler/src/typeinfer.jl @@ -861,7 +861,7 @@ function cached_return_type(code::CodeInstance) # the second subtyping/egal conditions are necessary to distinguish usual cases # from rare cases when `Const` wrapped those extended lattice type objects if isa(rettype_const, Vector{Any}) && !(Vector{Any} <: rettype) - return PartialStruct(rettype, rettype_const) + return PartialStruct(fallback_lattice, rettype, rettype_const) elseif isa(rettype_const, PartialOpaque) && rettype <: Core.OpaqueClosure return rettype_const elseif isa(rettype_const, InterConditional) && rettype !== InterConditional diff --git a/base/compiler/typelattice.jl b/stdlib/Compiler/src/typelattice.jl similarity index 92% rename from base/compiler/typelattice.jl rename to stdlib/Compiler/src/typelattice.jl index 86fa8af21615fe..2832edc9219ffd 100644 --- a/base/compiler/typelattice.jl +++ b/stdlib/Compiler/src/typelattice.jl @@ -6,48 +6,7 @@ # N.B.: Const/PartialStruct/InterConditional are defined in Core, to allow them to be used # inside the global code cache. - -import Core: Const, PartialStruct - -""" - struct Const - val - end - -The type representing a constant value. -""" -:(Const) - -""" - struct PartialStruct - typ - fields::Vector{Any} # elements are other type lattice members - end - -This extended lattice element is introduced when we have information about an object's -fields beyond what can be obtained from the object type. E.g. it represents a tuple where -some elements are known to be constants or a struct whose `Any`-typed field is initialized -with `Int` values. - -- `typ` indicates the type of the object -- `fields` holds the lattice elements corresponding to each field of the object - -If `typ` is a struct, `fields` represents the fields of the struct that are guaranteed to be -initialized. For instance, if the length of `fields` of `PartialStruct` representing a -struct with 4 fields is 3, the 4th field may not be initialized. If the length is 4, all -fields are guaranteed to be initialized. - -If `typ` is a tuple, the last element of `fields` may be `Vararg`. In this case, it is -guaranteed that the number of elements in the tuple is at least `length(fields)-1`, but the -exact number of elements is unknown. -""" -:(PartialStruct) -function PartialStruct(@nospecialize(typ), fields::Vector{Any}) - for i = 1:length(fields) - assert_nested_slotwrapper(fields[i]) - end - return Core._PartialStruct(typ, fields) -end +import Core: Const, InterConditional, PartialStruct """ cnd::Conditional @@ -87,23 +46,6 @@ end Conditional(var::SlotNumber, @nospecialize(thentype), @nospecialize(elsetype); isdefined::Bool=false) = Conditional(slot_id(var), thentype, elsetype; isdefined) -import Core: InterConditional -""" - struct InterConditional - slot::Int - thentype - elsetype - end - -Similar to `Conditional`, but conveys inter-procedural constraints imposed on call arguments. -This is separate from `Conditional` to catch logic errors: the lattice element name is `InterConditional` -while processing a call, then `Conditional` everywhere else. Thus `InterConditional` does not appear in -`CompilerTypes`—these type's usages are disjoint—though we define the lattice for `InterConditional`. -""" -:(InterConditional) -InterConditional(var::SlotNumber, @nospecialize(thentype), @nospecialize(elsetype)) = - InterConditional(slot_id(var), thentype, elsetype) - const AnyConditional = Union{Conditional,InterConditional} Conditional(cnd::InterConditional) = Conditional(cnd.slot, cnd.thentype, cnd.elsetype) InterConditional(cnd::Conditional) = InterConditional(cnd.slot, cnd.thentype, cnd.elsetype) @@ -388,8 +330,8 @@ end end end return Conditional(slot, - thenfields === nothing ? Bottom : PartialStruct(vartyp.typ, thenfields), - elsefields === nothing ? Bottom : PartialStruct(vartyp.typ, elsefields)) + thenfields === nothing ? Bottom : PartialStruct(fallback_lattice, vartyp.typ, thenfields), + elsefields === nothing ? Bottom : PartialStruct(fallback_lattice, vartyp.typ, elsefields)) else vartyp_widened = widenconst(vartyp) thenfields = thentype === Bottom ? nothing : Any[] @@ -405,8 +347,8 @@ end end end return Conditional(slot, - thenfields === nothing ? Bottom : PartialStruct(vartyp_widened, thenfields), - elsefields === nothing ? Bottom : PartialStruct(vartyp_widened, elsefields)) + thenfields === nothing ? Bottom : PartialStruct(fallback_lattice, vartyp_widened, thenfields), + elsefields === nothing ? Bottom : PartialStruct(fallback_lattice, vartyp_widened, elsefields)) end end @@ -734,7 +676,7 @@ widenconst(::AnyConditional) = Bool widenconst(a::AnyMustAlias) = widenconst(widenmustalias(a)) widenconst(c::Const) = (v = c.val; isa(v, Type) ? Type{v} : typeof(v)) widenconst(::PartialTypeVar) = TypeVar -widenconst(t::PartialStruct) = t.typ +widenconst(t::Core.PartialStruct) = t.typ widenconst(t::PartialOpaque) = t.typ @nospecializeinfer widenconst(@nospecialize t::Type) = t widenconst(::TypeVar) = error("unhandled TypeVar") @@ -799,3 +741,13 @@ function stoverwrite1!(state::VarTable, change::StateUpdate) state[changeid] = newtype return state end + +# The ::AbstractLattice argument is unused and simply serves to disambiguate +# different instances of the compiler that may share the `Core.PartialStruct` +# type. +function Core.PartialStruct(::AbstractLattice, @nospecialize(typ), fields::Vector{Any}) + for i = 1:length(fields) + assert_nested_slotwrapper(fields[i]) + end + return Core._PartialStruct(typ, fields) +end diff --git a/base/compiler/typelimits.jl b/stdlib/Compiler/src/typelimits.jl similarity index 99% rename from base/compiler/typelimits.jl rename to stdlib/Compiler/src/typelimits.jl index 3d0e5f3d0877d2..e420db030715b8 100644 --- a/base/compiler/typelimits.jl +++ b/stdlib/Compiler/src/typelimits.jl @@ -641,7 +641,7 @@ end ⋤(𝕃, tyi, ft) # just a type-level information, but more precise than the declared type end end - anyrefine && return PartialStruct(aty, fields) + anyrefine && return PartialStruct(𝕃, aty, fields) end return nothing end diff --git a/base/compiler/types.jl b/stdlib/Compiler/src/types.jl similarity index 100% rename from base/compiler/types.jl rename to stdlib/Compiler/src/types.jl diff --git a/base/compiler/typeutils.jl b/stdlib/Compiler/src/typeutils.jl similarity index 100% rename from base/compiler/typeutils.jl rename to stdlib/Compiler/src/typeutils.jl diff --git a/base/compiler/utilities.jl b/stdlib/Compiler/src/utilities.jl similarity index 100% rename from base/compiler/utilities.jl rename to stdlib/Compiler/src/utilities.jl diff --git a/base/compiler/validation.jl b/stdlib/Compiler/src/validation.jl similarity index 100% rename from base/compiler/validation.jl rename to stdlib/Compiler/src/validation.jl diff --git a/stdlib/Makefile b/stdlib/Makefile index ebc40c9db2b12a..4ee448c0dbba61 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -43,7 +43,7 @@ $(foreach jll,$(JLLS),$(eval $(call download-artifacts-toml,$(jll)))) STDLIBS = Artifacts Base64 CRC32c Dates FileWatching \ Future InteractiveUtils Libdl LibGit2 LinearAlgebra Logging \ Markdown Mmap Printf Profile Random REPL Serialization \ - SharedArrays Sockets Test TOML Unicode UUIDs \ + SharedArrays Sockets Test TOML Unicode UUIDs Compiler \ $(JLL_NAMES) STDLIBS_EXT = Pkg Statistics LazyArtifacts LibCURL DelimitedFiles Downloads ArgTools \ diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index 9fafc9bdca6adf..33660ecac5965c 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -1535,7 +1535,7 @@ let nfields_tfunc(@nospecialize xs...) = @test sizeof_nothrow(String) @test !sizeof_nothrow(Type{String}) @test sizeof_tfunc(Type{Union{Int64, Int32}}) == Const(Core.sizeof(Union{Int64, Int32})) - let PT = Core.PartialStruct(Tuple{Int64,UInt64}, Any[Const(10), UInt64]) + let PT = Core.PartialStruct(Cpre.Compiler.fallback_lattice, Tuple{Int64,UInt64}, Any[Const(10), UInt64]) @test sizeof_tfunc(PT) === Const(16) @test nfields_tfunc(PT) === Const(2) @test sizeof_nothrow(PT)