diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0c5b6593f40f5..9768aa212e16e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -269,7 +269,7 @@ Be sure to change the UUID value back before making the pull request. ### Contributing to patch releases -The process of creating a patch release is roughly as follows: +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. diff --git a/Make.inc b/Make.inc index 7b6ffd7804dc4..82733dd39052b 100644 --- a/Make.inc +++ b/Make.inc @@ -705,7 +705,7 @@ JLDFLAGS += $(SANITIZE_LDFLAGS) endif # SANITIZE TAR := $(shell which gtar 2>/dev/null || which tar 2>/dev/null) -TAR_TEST := $(shell $(TAR) --help 2>&1 | egrep 'bsdtar|strip-components') +TAR_TEST := $(shell $(TAR) --help 2>&1 | grep -E 'bsdtar|strip-components') ifeq (,$(findstring components,$(TAR_TEST))) ifneq (bsdtar,$(findstring bsdtar,$(TAR_TEST))) $(error "please install either GNU tar or bsdtar") @@ -772,6 +772,8 @@ else ifeq (cygwin, $(shell $(CC) -dumpmachine | cut -d\- -f3)) $(error "cannot build julia with cygwin-target compilers. set XC_HOST to i686-w64-mingw32 or x86_64-w64-mingw32 for mingw cross-compile") else ifeq (msys, $(shell $(CC) -dumpmachine | cut -d\- -f3)) $(error "cannot build julia with msys-target compilers. please see the README.windows document for instructions on setting up mingw-w64 compilers") +else ifneq (,$(findstring MSYS,$(shell uname))) +$(error "cannot build julia from a msys shell. please launch a mingw shell instead by setting MSYSTEM=MINGW64") endif ifeq ($(BUILD_OS),Darwin) @@ -1223,6 +1225,9 @@ else NO_WHOLE_ARCHIVE := -Wl,--no-whole-archive endif +# Initialize these once, then add to them in OS-specific blocks +JLIBLDFLAGS := + ifeq ($(OS), Linux) OSLIBS += -Wl,--no-as-needed -ldl -lrt -lpthread -latomic -Wl,--export-dynamic,--as-needed,--no-whole-archive # Detect if ifunc is supported @@ -1236,14 +1241,14 @@ ifneq ($(SANITIZE),1) JLDFLAGS += -Wl,-no-undefined endif ifeq (-Bsymbolic-functions, $(shell $(LD) --help | grep -o -e "-Bsymbolic-functions")) -JLIBLDFLAGS := -Wl,-Bsymbolic-functions -else -JLIBLDFLAGS := +JLIBLDFLAGS += -Wl,-Bsymbolic-functions +endif +ifeq (--enable-new-dtags, $(shell $(LD) --help | grep -o -e "--enable-new-dtags")) +JLIBLDFLAGS += -Wl,--enable-new-dtags endif + # Linker doesn't detect automatically that Julia doesn't need executable stack JLIBLDFLAGS += -Wl,-z,noexecstack -else ifneq ($(OS), Darwin) -JLIBLDFLAGS := endif ifeq ($(OS), FreeBSD) @@ -1266,7 +1271,7 @@ OSLIBS += -framework CoreFoundation WHOLE_ARCHIVE := -Xlinker -all_load NO_WHOLE_ARCHIVE := HAVE_SSP := 1 -JLIBLDFLAGS := -Wl,-compatibility_version,$(SOMAJOR) -Wl,-current_version,$(JULIA_MAJOR_VERSION).$(JULIA_MINOR_VERSION).$(JULIA_PATCH_VERSION) +JLIBLDFLAGS += -Wl,-compatibility_version,$(SOMAJOR) -Wl,-current_version,$(JULIA_MAJOR_VERSION).$(JULIA_MINOR_VERSION).$(JULIA_PATCH_VERSION) endif ifeq ($(OS), WINNT) @@ -1368,7 +1373,6 @@ CLANGSA_FLAGS := CLANGSA_CXXFLAGS := ifeq ($(OS), Darwin) # on new XCode, the files are hidden CLANGSA_FLAGS += -isysroot $(shell xcode-select -p)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -CLANGSA_CXXFLAGS += -isystem $(shell xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1 endif ifeq ($(USEGCC),1) # try to help clang find the c++ files for CC by guessing the value for --prefix @@ -1394,13 +1398,13 @@ define symlink_target # (from, to-dir, to-name) CLEAN_TARGETS += clean-$$(abspath $(2)/$(3)) clean-$$(abspath $(2)/$(3)): ifeq ($(BUILD_OS), WINNT) - -cmd //C rmdir $$(call mingw_to_dos,$(2)/$(3),cd $(2) &&) + -cmd //C rmdir $$(call cygpath_w,$(2)/$(3)) else rm -rf $$(abspath $(2)/$(3)) endif $$(abspath $(2)/$(3)): | $$(abspath $(2)) ifeq ($$(BUILD_OS), WINNT) - @cmd //C mklink //J $$(call mingw_to_dos,$(2)/$(3),cd $(2) &&) $$(call mingw_to_dos,$(1),) + @cmd //C mklink //J $$(call cygpath_w,$(2)/$(3)) $$(call cygpath_w,$(1)) else ifneq (,$$(findstring CYGWIN,$$(BUILD_OS))) @cmd /C mklink /J $$(call cygpath_w,$(2)/$(3)) $$(call cygpath_w,$(1)) else ifdef JULIA_VAGRANT_BUILD @@ -1418,7 +1422,7 @@ WINE ?= wine # many of the following targets must be = not := because the expansion of the makefile functions (and $1) shouldn't happen until later ifeq ($(BUILD_OS), WINNT) # MSYS spawn = $(1) -cygpath_w = $(1) +cygpath_w = `cygpath -w $(1)` else ifneq (,$(findstring CYGWIN,$(BUILD_OS))) # Cygwin spawn = $(1) cygpath_w = `cygpath -w $(1)` diff --git a/Makefile b/Makefile index d96497ca94d2e..90aa758588f2a 100644 --- a/Makefile +++ b/Makefile @@ -229,8 +229,10 @@ endif endif endif +# Note that we disable MSYS2's path munging here, as otherwise +# it replaces our `:`-separated list as a `;`-separated one. define stringreplace - $(build_depsbindir)/stringreplace $$(strings -t x - $1 | grep $2 | awk '{print $$1;}') $3 255 "$(call cygpath_w,$1)" + MSYS2_ARG_CONV_EXCL='*' $(build_depsbindir)/stringreplace $$(strings -t x - $1 | grep $2 | awk '{print $$1;}') $3 255 "$(call cygpath_w,$1)" endef @@ -370,8 +372,10 @@ endif ifneq (,$(findstring $(OS),Linux FreeBSD)) ifeq ($(JULIA_BUILD_MODE),release) $(PATCHELF) --set-rpath '$$ORIGIN:$$ORIGIN/$(reverse_private_libdir_rel)' $(DESTDIR)$(private_libdir)/libjulia-internal.$(SHLIB_EXT) + $(PATCHELF) --set-rpath '$$ORIGIN:$$ORIGIN/$(reverse_private_libdir_rel)' $(DESTDIR)$(private_libdir)/libjulia-codegen.$(SHLIB_EXT) else ifeq ($(JULIA_BUILD_MODE),debug) $(PATCHELF) --set-rpath '$$ORIGIN:$$ORIGIN/$(reverse_private_libdir_rel)' $(DESTDIR)$(private_libdir)/libjulia-internal-debug.$(SHLIB_EXT) + $(PATCHELF) --set-rpath '$$ORIGIN:$$ORIGIN/$(reverse_private_libdir_rel)' $(DESTDIR)$(private_libdir)/libjulia-codegen-debug.$(SHLIB_EXT) endif endif @@ -426,6 +430,12 @@ ifneq ($(OPENBLAS_DYNAMIC_ARCH),1) endif endif endif + +ifeq ($(USE_BINARYBUILDER_OPENBLAS),0) + # https://github.com/JuliaLang/julia/issues/46579 + USE_BINARYBUILDER_OBJCONV=0 +endif + ifneq ($(prefix),$(abspath julia-$(JULIA_COMMIT))) $(error prefix must not be set for make binary-dist) endif diff --git a/NEWS.md b/NEWS.md index 421093b6e0681..183920f122477 100644 --- a/NEWS.md +++ b/NEWS.md @@ -9,6 +9,7 @@ New language features handled via `Base.split_rest`. ([#42902]) * Character literals now support the same syntax allowed in string literals; i.e. the syntax can represent invalid UTF-8 sequences as allowed by the `Char` type ([#44989]). +* Nested combinations of tuples and named tuples of symbols are now allowed as type parameters ([#46300]). Language changes ---------------- @@ -35,6 +36,8 @@ Compiler/Runtime improvements `@nospecialize`-d call sites and avoiding excessive compilation. ([#44512]) * All the previous usages of `@pure`-macro in `Base` has been replaced with the preferred `Base.@assume_effects`-based annotations. ([#44776]) +* `invoke(f, invokesig, args...)` calls to a less-specific method than would normally be chosen + for `f(args...)` are no longer spuriously invalidated when loading package precompile files. ([#46010]) Command-line option changes --------------------------- @@ -85,6 +88,7 @@ Library changes * `@time` now separates out % time spent recompiling invalidated methods ([#45015]). * `eachslice` now works over multiple dimensions; `eachslice`, `eachrow` and `eachcol` return a `Slices` object, which allows dispatching to provide more efficient methods ([#32310]). +* `@kwdef` is now exported and added to the public API ([#46273]) Standard library changes ------------------------ @@ -125,6 +129,9 @@ Standard library changes via the `REPL.activate(::Module)` function or via typing the module in the REPL and pressing the keybinding Alt-m ([#33872]). +* An "IPython mode" which mimics the behaviour of the prompts and storing the evaluated result in `Out` can be + activated with `REPL.ipython_mode!()`. See the manual for how to enable this at startup. + #### SparseArrays #### Test diff --git a/base/Base.jl b/base/Base.jl index 0905eaa811394..4e91809f978df 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -87,7 +87,7 @@ if false end """ - time_ns() + time_ns() -> UInt64 Get the time in nanoseconds. The time corresponding to 0 is undefined, and wraps every 5.8 years. """ @@ -107,9 +107,6 @@ include("options.jl") include("promotion.jl") include("tuple.jl") include("expr.jl") -Pair{A, B}(@nospecialize(a), @nospecialize(b)) where {A, B} = (@inline; Pair{A, B}(convert(A, a)::A, convert(B, b)::B)) -#Pair{Any, B}(@nospecialize(a::Any), b) where {B} = (@inline; Pair{Any, B}(a, Base.convert(B, b)::B)) -#Pair{A, Any}(a, @nospecialize(b::Any)) where {A} = (@inline; Pair{A, Any}(Base.convert(A, a)::A, b)) include("pair.jl") include("traits.jl") include("range.jl") @@ -125,6 +122,13 @@ include("pointer.jl") include("refvalue.jl") include("refpointer.jl") +# now replace the Pair constructor (relevant for NamedTuples) with one that calls our Base.convert +delete_method(which(Pair{Any,Any}, (Any, Any))) +@eval function (P::Type{Pair{A, B}})(@nospecialize(a), @nospecialize(b)) where {A, B} + @inline + return $(Expr(:new, :P, :(convert(A, a)), :(convert(B, b)))) +end + # The REPL stdlib hooks into Base using this Ref const REPL_MODULE_REF = Ref{Module}() @@ -429,6 +433,7 @@ end for m in methods(include) delete_method(m) end + # These functions are duplicated in client.jl/include(::String) for # nicer stacktraces. Modifications here have to be backported there include(mod::Module, _path::AbstractString) = _include(identity, mod, _path) diff --git a/base/Enums.jl b/base/Enums.jl index 413c880fcd3f2..aea3aeeee188e 100644 --- a/base/Enums.jl +++ b/base/Enums.jl @@ -17,7 +17,7 @@ abstract type Enum{T<:Integer} end basetype(::Type{<:Enum{T}}) where {T<:Integer} = T (::Type{T})(x::Enum{T2}) where {T<:Integer,T2<:Integer} = T(bitcast(T2, x))::T -Base.cconvert(::Type{T}, x::Enum{T2}) where {T<:Integer,T2<:Integer} = T(x) +Base.cconvert(::Type{T}, x::Enum{T2}) where {T<:Integer,T2<:Integer} = T(x)::T Base.write(io::IO, x::Enum{T}) where {T<:Integer} = write(io, T(x)) Base.read(io::IO, ::Type{T}) where {T<:Enum} = T(read(io, basetype(T))) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index c3d04dcbef39d..e0ba09f10c063 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -14,8 +14,8 @@ See also: [`AbstractVector`](@ref), [`AbstractMatrix`](@ref), [`eltype`](@ref), AbstractArray convert(::Type{T}, a::T) where {T<:AbstractArray} = a -convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a) -convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a) +convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T} +convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N} """ size(A::AbstractArray, [dim]) @@ -1972,7 +1972,7 @@ typed_hcat(T::Type, A::AbstractArray...) = _cat_t(Val(2), T, A...) hvcat_rows(rows::Tuple...) = hvcat(map(length, rows), (rows...)...) typed_hvcat_rows(T::Type, rows::Tuple...) = typed_hvcat(T, map(length, rows), (rows...)...) -function hvcat(nbc::Integer, as...) +function hvcat(nbc::Int, as...) # nbc = # of block columns n = length(as) mod(n,nbc) != 0 && @@ -1982,11 +1982,12 @@ function hvcat(nbc::Integer, as...) end """ - hvcat(rows::Tuple{Vararg{Int}}, values...) + hvcat(blocks_per_row::Union{Tuple{Vararg{Int}}, Int}, values...) Horizontal and vertical concatenation in one call. This function is called for block matrix syntax. The first argument specifies the number of arguments to concatenate in each block -row. +row. If the first argument is a single integer `n`, then all block rows are assumed to have `n` +block columns. # Examples ```jldoctest @@ -2014,10 +2015,9 @@ julia> hvcat((2,2,2), a,b,c,d,e,f) 1 2 3 4 5 6 +julia> hvcat((2,2,2), a,b,c,d,e,f) == hvcat(2, a,b,c,d,e,f) +true ``` - -If the first argument is a single integer `n`, then all block rows are assumed to have `n` -block columns. """ hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractVecOrMat...) = typed_hvcat(promote_eltype(xs...), rows, xs...) hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractVecOrMat{T}...) where {T} = typed_hvcat(T, rows, xs...) diff --git a/base/abstractdict.jl b/base/abstractdict.jl index 7f1d8b4a1c504..39de4c441a966 100644 --- a/base/abstractdict.jl +++ b/base/abstractdict.jl @@ -565,7 +565,7 @@ push!(t::AbstractDict, p::Pair, q::Pair, r::Pair...) = push!(push!(push!(t, p), convert(::Type{T}, x::T) where {T<:AbstractDict} = x function convert(::Type{T}, x::AbstractDict) where T<:AbstractDict - h = T(x) + h = T(x)::T if length(h) != length(x) error("key collision during dictionary conversion") end diff --git a/base/abstractset.jl b/base/abstractset.jl index 85d81480ab990..62784af2bd67b 100644 --- a/base/abstractset.jl +++ b/base/abstractset.jl @@ -248,7 +248,6 @@ end Construct the symmetric difference of elements in the passed in sets. When `s` is not an `AbstractSet`, the order is maintained. -Note that in this case the multiplicity of elements matters. See also [`symdiff!`](@ref), [`setdiff`](@ref), [`union`](@ref) and [`intersect`](@ref). @@ -261,11 +260,6 @@ julia> symdiff([1,2,3], [3,4,5], [4,5,6]) 6 julia> symdiff([1,2,1], [2, 1, 2]) -2-element Vector{Int64}: - 1 - 2 - -julia> symdiff(unique([1,2,1]), unique([2, 1, 2])) Int64[] ``` """ @@ -286,7 +280,9 @@ function symdiff!(s::AbstractSet, itrs...) return s end -function symdiff!(s::AbstractSet, itr) +symdiff!(s::AbstractSet, itr) = symdiff!(s::AbstractSet, Set(itr)) + +function symdiff!(s::AbstractSet, itr::AbstractSet) for x in itr x in s ? delete!(s, x) : push!(s, x) end diff --git a/base/accumulate.jl b/base/accumulate.jl index 663bd850695a8..eeb9759e125c7 100644 --- a/base/accumulate.jl +++ b/base/accumulate.jl @@ -280,7 +280,7 @@ function accumulate(op, A; dims::Union{Nothing,Integer}=nothing, kw...) elseif keys(nt) === (:init,) out = similar(A, promote_op(op, typeof(nt.init), eltype(A))) else - throw(ArgumentError("acccumulate does not support the keyword arguments $(setdiff(keys(nt), (:init,)))")) + throw(ArgumentError("accumulate does not support the keyword arguments $(setdiff(keys(nt), (:init,)))")) end accumulate!(op, out, A; dims=dims, kw...) end @@ -341,7 +341,7 @@ function accumulate!(op, B, A; dims::Union{Integer, Nothing} = nothing, kw...) elseif keys(kw) === (:init,) _accumulate!(op, B, A, dims, Some(nt.init)) else - throw(ArgumentError("acccumulate! does not support the keyword arguments $(setdiff(keys(nt), (:init,)))")) + throw(ArgumentError("accumulate! does not support the keyword arguments $(setdiff(keys(nt), (:init,)))")) end end diff --git a/base/array.jl b/base/array.jl index 85296b4d94f21..4e11a98621ec0 100644 --- a/base/array.jl +++ b/base/array.jl @@ -610,7 +610,7 @@ oneunit(x::AbstractMatrix{T}) where {T} = _one(oneunit(T), x) ## Conversions ## -convert(::Type{T}, a::AbstractArray) where {T<:Array} = a isa T ? a : T(a) +convert(::Type{T}, a::AbstractArray) where {T<:Array} = a isa T ? a : T(a)::T promote_rule(a::Type{Array{T,n}}, b::Type{Array{S,n}}) where {T,n,S} = el_same(promote_type(T,S), a, b) @@ -2325,7 +2325,7 @@ findall(testf::Function, A) = collect(first(p) for p in pairs(A) if testf(last(p # Broadcasting is much faster for small testf, and computing # integer indices from logical index using findall has a negligible cost -findall(testf::Function, A::AbstractArray) = findall(testf.(A)) +findall(testf::F, A::AbstractArray) where {F<:Function} = findall(testf.(A)) """ findall(A) diff --git a/base/arrayshow.jl b/base/arrayshow.jl index 0d480b64bb32d..e3028cd65dfe0 100644 --- a/base/arrayshow.jl +++ b/base/arrayshow.jl @@ -278,7 +278,7 @@ show_nd(io::IO, a::AbstractArray, print_matrix::Function, show_full::Bool) = _show_nd(io, inferencebarrier(a), print_matrix, show_full, map(unitrange, axes(a))) function _show_nd(io::IO, @nospecialize(a::AbstractArray), print_matrix::Function, show_full::Bool, axs::Tuple{Vararg{AbstractUnitRange}}) - limit::Bool = get(io, :limit, false) + limit = get(io, :limit, false)::Bool if isempty(a) return end @@ -361,7 +361,7 @@ print_array(io::IO, X::AbstractArray) = show_nd(io, X, print_matrix, true) # typeinfo aware # implements: show(io::IO, ::MIME"text/plain", X::AbstractArray) function show(io::IO, ::MIME"text/plain", X::AbstractArray) - if isempty(X) && (get(io, :compact, false) || X isa Vector) + if isempty(X) && (get(io, :compact, false)::Bool || X isa Vector) return show(io, X) end # 0) show summary before setting :compact @@ -374,12 +374,12 @@ function show(io::IO, ::MIME"text/plain", X::AbstractArray) if !haskey(io, :compact) && length(axes(X, 2)) > 1 io = IOContext(io, :compact => true) end - if get(io, :limit, false) && eltype(X) === Method + if get(io, :limit, false)::Bool && eltype(X) === Method # override usual show method for Vector{Method}: don't abbreviate long lists io = IOContext(io, :limit => false) end - if get(io, :limit, false) && displaysize(io)[1]-4 <= 0 + if get(io, :limit, false)::Bool && displaysize(io)[1]-4 <= 0 return print(io, " …") else println(io) @@ -516,7 +516,7 @@ function show_vector(io::IO, v, opn='[', cls=']') if !implicit io = IOContext(io, :typeinfo => eltype(v)) end - limited = get(io, :limit, false) + limited = get(io, :limit, false)::Bool if limited && length(v) > 20 axs1 = axes1(v) @@ -568,11 +568,11 @@ function typeinfo_prefix(io::IO, X) if X isa AbstractDict if eltype_X == eltype_ctx - sprint(show_type_name, typeof(X).name), false + sprint(show_type_name, typeof(X).name; context=io), false elseif !isempty(X) && typeinfo_implicit(keytype(X)) && typeinfo_implicit(valtype(X)) - sprint(show_type_name, typeof(X).name), true + sprint(show_type_name, typeof(X).name; context=io), true else - string(typeof(X)), false + sprint(print, typeof(X); context=io), false end else # Types hard-coded here are those which are created by default for a given syntax @@ -581,9 +581,9 @@ function typeinfo_prefix(io::IO, X) elseif !isempty(X) && typeinfo_implicit(eltype_X) "", true elseif print_without_params(eltype_X) - sprint(show_type_name, unwrap_unionall(eltype_X).name), false # Print "Array" rather than "Array{T,N}" + sprint(show_type_name, unwrap_unionall(eltype_X).name; context=io), false # Print "Array" rather than "Array{T,N}" else - string(eltype_X), false + sprint(print, eltype_X; context=io), false end end end diff --git a/base/baseext.jl b/base/baseext.jl index 8ebd599312453..625a82ff29234 100644 --- a/base/baseext.jl +++ b/base/baseext.jl @@ -16,7 +16,7 @@ VecElement # hook up VecElement constructor to Base.convert VecElement{T}(arg) where {T} = VecElement{T}(convert(T, arg)) convert(::Type{T}, arg::T) where {T<:VecElement} = arg -convert(::Type{T}, arg) where {T<:VecElement} = T(arg) +convert(::Type{T}, arg) where {T<:VecElement} = T(arg)::T # ## dims-type-converting Array constructors for convenience # type and dimensionality specified, accepting dims as series of Integers diff --git a/base/binaryplatforms.jl b/base/binaryplatforms.jl index 6eeaca1be84e3..cf08a961772da 100644 --- a/base/binaryplatforms.jl +++ b/base/binaryplatforms.jl @@ -259,14 +259,14 @@ end function set_compare_strategy!(p::Platform, key::String, f::Function) if !haskey(p.tags, key) - throw(ArgumentError("Cannot set comparison strategy for nonexistant tag $(key)!")) + throw(ArgumentError("Cannot set comparison strategy for nonexistent tag $(key)!")) end p.compare_strategies[key] = f end function get_compare_strategy(p::Platform, key::String, default = compare_default) if !haskey(p.tags, key) - throw(ArgumentError("Cannot get comparison strategy for nonexistant tag $(key)!")) + throw(ArgumentError("Cannot get comparison strategy for nonexistent tag $(key)!")) end return get(p.compare_strategies, key, default) end @@ -1027,7 +1027,7 @@ function platforms_match(a::AbstractPlatform, b::AbstractPlatform) # Call the comparator, passing in which objects requested this comparison (one, the other, or both) # For some comparators this doesn't matter, but for non-symmetrical comparisons, it does. - if !comparator(ak, bk, a_comp == comparator, b_comp == comparator) + if !(comparator(ak, bk, a_comp == comparator, b_comp == comparator)::Bool) return false end end diff --git a/base/bitarray.jl b/base/bitarray.jl index 095acf6a519e3..841509a90ba44 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -577,7 +577,7 @@ julia> BitArray(x+y == 3 for x = 1:2 for y = 1:3) BitArray(itr) = gen_bitarray(IteratorSize(itr), itr) BitArray{N}(itr) where N = gen_bitarrayN(BitArray{N}, IteratorSize(itr), itr) -convert(T::Type{<:BitArray}, a::AbstractArray) = a isa T ? a : T(a) +convert(::Type{T}, a::AbstractArray) where {T<:BitArray} = a isa T ? a : T(a)::T # generic constructor from an iterable without compile-time info # (we pass start(itr) explicitly to avoid a type-instability with filters) diff --git a/base/bitset.jl b/base/bitset.jl index 0abd9d4b782d2..8727b857bd36b 100644 --- a/base/bitset.jl +++ b/base/bitset.jl @@ -137,20 +137,10 @@ function union!(s::BitSet, r::AbstractUnitRange{<:Integer}) # grow s.bits as necessary if diffb >= len - _growend!(s.bits, diffb - len + 1) - # we set only some values to CHK0, those which will not be - # fully overwritten (i.e. only or'ed with `|`) - s.bits[end] = CHK0 # end == diffb + 1 - if diffa >= len - s.bits[diffa + 1] = CHK0 - end + _growend0!(s.bits, diffb - len + 1) end if diffa < 0 - _growbeg!(s.bits, -diffa) - s.bits[1] = CHK0 - if diffb < 0 - s.bits[diffb - diffa + 1] = CHK0 - end + _growbeg0!(s.bits, -diffa) s.offset = cidxa # s.offset += diffa diffb -= diffa diffa = 0 @@ -326,6 +316,13 @@ function symdiff!(s::BitSet, ns) return s end +function symdiff!(s::BitSet, ns::AbstractSet) + for x in ns + int_symdiff!(s, x) + end + return s +end + function int_symdiff!(s::BitSet, n::Integer) n0 = _check_bitset_bounds(n) val = !(n0 in s) diff --git a/base/bool.jl b/base/bool.jl index 7648df3e0250e..d7dcf76caa91b 100644 --- a/base/bool.jl +++ b/base/bool.jl @@ -112,7 +112,8 @@ nand(x...) = ~(&)(x...) Bitwise nor (not or) of `x` and `y`. Implements [three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic), -returning [`missing`](@ref) if one of the arguments is `missing`. +returning [`missing`](@ref) if one of the arguments is `missing` and the +other is not `true`. The infix operation `a ⊽ b` is a synonym for `nor(a,b)`, and `⊽` can be typed by tab-completing `\\nor` or `\\barvee` in the Julia REPL. @@ -131,6 +132,9 @@ false julia> false ⊽ false true +julia> false ⊽ missing +missing + julia> [true; true; false] .⊽ [true; false; false] 3-element BitVector: 0 diff --git a/base/boot.jl b/base/boot.jl index 24b428af1c528..cc2cec5ec6e57 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -412,7 +412,7 @@ eval(Core, quote end LineInfoNode(mod::Module, @nospecialize(method), file::Symbol, line::Int32, inlined_at::Int32) = $(Expr(:new, :LineInfoNode, :mod, :method, :file, :line, :inlined_at)) - GlobalRef(m::Module, s::Symbol) = $(Expr(:new, :GlobalRef, :m, :s)) + GlobalRef(m::Module, s::Symbol, binding::Ptr{Nothing}) = $(Expr(:new, :GlobalRef, :m, :s, :binding)) SlotNumber(n::Int) = $(Expr(:new, :SlotNumber, :n)) TypedSlot(n::Int, @nospecialize(t)) = $(Expr(:new, :TypedSlot, :n, :t)) PhiNode(edges::Array{Int32, 1}, values::Array{Any, 1}) = $(Expr(:new, :PhiNode, :edges, :values)) @@ -812,6 +812,8 @@ Unsigned(x::Union{Float16, Float32, Float64, Bool}) = UInt(x) Integer(x::Integer) = x Integer(x::Union{Float16, Float32, Float64}) = Int(x) +GlobalRef(m::Module, s::Symbol) = GlobalRef(m, s, bitcast(Ptr{Nothing}, 0)) + # Binding for the julia parser, called as # # Core._parse(text, filename, lineno, offset, options) @@ -840,8 +842,10 @@ struct Pair{A, B} # but also mark the whole function with `@inline` to ensure we will inline it whenever possible # (even if `convert(::Type{A}, a::A)` for some reason was expensive) Pair(a, b) = new{typeof(a), typeof(b)}(a, b) - Pair{A, B}(a::A, b::B) where {A, B} = new(a, b) - Pair{Any, Any}(@nospecialize(a::Any), @nospecialize(b::Any)) = new(a, b) + function Pair{A, B}(@nospecialize(a), @nospecialize(b)) where {A, B} + @inline + return new(a::A, b::B) + end end ccall(:jl_set_istopmod, Cvoid, (Any, Bool), Core, true) diff --git a/base/broadcast.jl b/base/broadcast.jl index a54016ad00917..1eb4194d27447 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -195,7 +195,7 @@ function broadcasted(::OrOr, a, bc::Broadcasted) end Base.convert(::Type{Broadcasted{NewStyle}}, bc::Broadcasted{Style,Axes,F,Args}) where {NewStyle,Style,Axes,F,Args} = - Broadcasted{NewStyle,Axes,F,Args}(bc.f, bc.args, bc.axes) + Broadcasted{NewStyle,Axes,F,Args}(bc.f, bc.args, bc.axes)::Broadcasted{NewStyle,Axes,F,Args} function Base.show(io::IO, bc::Broadcasted{Style}) where {Style} print(io, Broadcasted) diff --git a/base/c.jl b/base/c.jl index 7d168f2293c9c..cfff070973f25 100644 --- a/base/c.jl +++ b/base/c.jl @@ -129,7 +129,7 @@ A C-style string composed of the native wide character type [`Cwchar_t`](@ref)s. `Cwstring`s are NUL-terminated. For C-style strings composed of the native character type, see [`Cstring`](@ref). For more information -about string interopability with C, see the +about string interoperability with C, see the [manual](@ref man-bits-types). """ @@ -142,7 +142,7 @@ A C-style string composed of the native character type [`Cchar`](@ref)s. `Cstring`s are NUL-terminated. For C-style strings composed of the native wide character type, see [`Cwstring`](@ref). For more information -about string interopability with C, see the +about string interoperability with C, see the [manual](@ref man-bits-types). """ Cstring diff --git a/base/channels.jl b/base/channels.jl index 46a2b4b208026..aa4d913dcdadd 100644 --- a/base/channels.jl +++ b/base/channels.jl @@ -380,7 +380,7 @@ end """ fetch(c::Channel) -Waits for and returns (with removing) the first available item from the `Channel`. +Waits for and returns (without removing) the first available item from the `Channel`. Note: `fetch` is unsupported on an unbuffered (0-size) `Channel`. # Examples diff --git a/base/char.jl b/base/char.jl index c8b1c28166bbf..08d661c41de56 100644 --- a/base/char.jl +++ b/base/char.jl @@ -181,9 +181,9 @@ end end convert(::Type{AbstractChar}, x::Number) = Char(x) # default to Char -convert(::Type{T}, x::Number) where {T<:AbstractChar} = T(x) -convert(::Type{T}, x::AbstractChar) where {T<:Number} = T(x) -convert(::Type{T}, c::AbstractChar) where {T<:AbstractChar} = T(c) +convert(::Type{T}, x::Number) where {T<:AbstractChar} = T(x)::T +convert(::Type{T}, x::AbstractChar) where {T<:Number} = T(x)::T +convert(::Type{T}, c::AbstractChar) where {T<:AbstractChar} = T(c)::T convert(::Type{T}, c::T) where {T<:AbstractChar} = c rem(x::AbstractChar, ::Type{T}) where {T<:Number} = rem(codepoint(x), T) @@ -318,7 +318,7 @@ end function show(io::IO, ::MIME"text/plain", c::T) where {T<:AbstractChar} show(io, c) - get(io, :compact, false) && return + get(io, :compact, false)::Bool && return if !ismalformed(c) print(io, ": ") if isoverlong(c) diff --git a/base/checked.jl b/base/checked.jl index c3c8a888dcd1c..d5b4112397e84 100644 --- a/base/checked.jl +++ b/base/checked.jl @@ -42,12 +42,12 @@ const UnsignedInt = Union{UInt8,UInt16,UInt32,UInt64,UInt128} # LLVM has several code generation bugs for checked integer arithmetic (see e.g. # #4905). We thus distinguish between operations that can be implemented via -# intrinsics, and operations for which we have to provide work-arounds. +# intrinsics, and operations for which we have to provide workarounds. # Note: As far as this code has been tested, most checked_* functions are # working fine in LLVM. (Note that division is still handled via `base/int.jl`, # which always checks for overflow, and which provides its own sets of -# work-arounds for LLVM codegen bugs.) However, the comments in `base/int.jl` +# workarounds for LLVM codegen bugs.) However, the comments in `base/int.jl` # and in issue #4905 are more pessimistic. For the time being, we thus retain # the ability to handle codegen bugs in LLVM, until the code here has been # tested on more systems and architectures. It also seems that things depend on diff --git a/base/client.jl b/base/client.jl index eba3c210ab68f..7cf6dc334b240 100644 --- a/base/client.jl +++ b/base/client.jl @@ -66,7 +66,15 @@ function repl_cmd(cmd, out) end cmd = `$shell -c $shell_escape_cmd` end - run(ignorestatus(cmd)) + try + run(ignorestatus(cmd)) + catch + # Windows doesn't shell out right now (complex issue), so Julia tries to run the program itself + # Julia throws an exception if it can't find the program, but the stack trace isn't useful + lasterr = current_exceptions() + lasterr = ExceptionStack([(exception = e[1], backtrace = [] ) for e in lasterr]) + invokelatest(display_error, lasterr) + end end nothing end diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 31e34506a9046..64839f0befb44 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -52,6 +52,7 @@ end function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f), arginfo::ArgInfo, @nospecialize(atype), sv::InferenceState, max_methods::Int) + ⊑ᵢ = ⊑(typeinf_lattice(interp)) if !should_infer_this_call(sv) add_remark!(interp, sv, "Skipped call in throw block") nonoverlayed = false @@ -125,21 +126,21 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f), for sig_n in splitsigs result = abstract_call_method(interp, method, sig_n, svec(), multiple_matches, sv) (; rt, edge, effects) = result - edge !== nothing && push!(edges, edge) this_argtypes = isa(matches, MethodMatches) ? argtypes : matches.applicable_argtypes[i] this_arginfo = ArgInfo(fargs, this_argtypes) const_call_result = abstract_call_method_with_const_args(interp, result, f, this_arginfo, match, sv) const_result = nothing if const_call_result !== nothing - if const_call_result.rt ⊑ rt + if const_call_result.rt ⊑ᵢ rt rt = const_call_result.rt - (; effects, const_result) = const_call_result + (; effects, const_result, edge) = const_call_result end end all_effects = merge_effects(all_effects, effects) push!(const_results, const_result) any_const_result |= const_result !== nothing + edge === nothing || push!(edges, edge) this_rt = tmerge(this_rt, rt) if bail_out_call(interp, this_rt, sv) break @@ -148,25 +149,10 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f), this_conditional = ignorelimited(this_rt) this_rt = widenwrappedconditional(this_rt) else - if infer_compilation_signature(interp) - # Also infer the compilation signature for this method, so it's available - # to the compiler in case it ends up needing it (which is likely). - csig = get_compileable_sig(method, sig, match.sparams) - if csig !== nothing && csig !== sig - # The result of this inference is not directly used, so temporarily empty - # the use set for the current SSA value. - saved_uses = sv.ssavalue_uses[sv.currpc] - sv.ssavalue_uses[sv.currpc] = empty_bitset - abstract_call_method(interp, method, csig, match.sparams, multiple_matches, sv) - sv.ssavalue_uses[sv.currpc] = saved_uses - end - end - result = abstract_call_method(interp, method, sig, match.sparams, multiple_matches, sv) (; rt, edge, effects) = result this_conditional = ignorelimited(rt) this_rt = widenwrappedconditional(rt) - edge !== nothing && push!(edges, edge) # try constant propagation with argtypes for this match # this is in preparation for inlining, or improving the return result this_argtypes = isa(matches, MethodMatches) ? argtypes : matches.applicable_argtypes[i] @@ -179,20 +165,21 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f), this_const_rt = widenwrappedconditional(const_call_result.rt) # return type of const-prop' inference can be wider than that of non const-prop' inference # e.g. in cases when there are cycles but cached result is still accurate - if this_const_rt ⊑ this_rt + if this_const_rt ⊑ᵢ this_rt this_conditional = this_const_conditional this_rt = this_const_rt - (; effects, const_result) = const_call_result + (; effects, const_result, edge) = const_call_result end end all_effects = merge_effects(all_effects, effects) push!(const_results, const_result) any_const_result |= const_result !== nothing + edge === nothing || push!(edges, edge) end @assert !(this_conditional isa Conditional) "invalid lattice element returned from inter-procedural context" seen += 1 - rettype = tmerge(rettype, this_rt) - if this_conditional !== Bottom && is_lattice_bool(rettype) && fargs !== nothing + rettype = tmerge(ipo_lattice(interp), rettype, this_rt) + if this_conditional !== Bottom && is_lattice_bool(ipo_lattice(interp), rettype) && fargs !== nothing if conditionals === nothing conditionals = Any[Bottom for _ in 1:length(argtypes)], Any[Bottom for _ in 1:length(argtypes)] @@ -223,7 +210,27 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f), all_effects = Effects(all_effects; nothrow=false) end - rettype = from_interprocedural!(rettype, sv, arginfo, conditionals) + rettype = from_interprocedural!(ipo_lattice(interp), rettype, sv, arginfo, conditionals) + + # Also considering inferring the compilation signature for this method, so + # it is available to the compiler in case it ends up needing it. + if infer_compilation_signature(interp) && 1 == seen == napplicable && rettype !== Any && rettype !== Union{} && !is_removable_if_unused(all_effects) + match = applicable[1]::MethodMatch + method = match.method + sig = match.spec_types + mi = specialize_method(match; preexisting=true) + if mi !== nothing && !const_prop_methodinstance_heuristic(interp, match, mi::MethodInstance, arginfo, sv) + csig = get_compileable_sig(method, sig, match.sparams) + if csig !== nothing && csig !== sig + # The result of this inference is not directly used, so temporarily empty + # the use set for the current SSA value. + saved_uses = sv.ssavalue_uses[sv.currpc] + sv.ssavalue_uses[sv.currpc] = empty_bitset + abstract_call_method(interp, method, csig, match.sparams, multiple_matches, sv) + sv.ssavalue_uses[sv.currpc] = saved_uses + end + end + end if call_result_unused(sv) && !(rettype === Bottom) add_remark!(interp, sv, "Call result type was widened because the return value is unused") @@ -293,7 +300,7 @@ function find_matching_methods(argtypes::Vector{Any}, @nospecialize(atype), meth if result === missing return FailedMethodMatch("For one of the union split cases, too many methods matched") end - matches, overlayed = result + (; matches, overlayed) = result nonoverlayed &= !overlayed push!(infos, MethodMatchInfo(matches)) for m in matches @@ -334,7 +341,7 @@ function find_matching_methods(argtypes::Vector{Any}, @nospecialize(atype), meth # (assume this will always be true, so we don't compute / update valid age in this case) return FailedMethodMatch("Too many methods matched") end - matches, overlayed = result + (; matches, overlayed) = result fullmatch = _any(match->(match::MethodMatch).fully_covers, matches) return MethodMatches(matches.matches, MethodMatchInfo(matches), @@ -346,7 +353,7 @@ function find_matching_methods(argtypes::Vector{Any}, @nospecialize(atype), meth end """ - from_interprocedural!(rt, sv::InferenceState, arginfo::ArgInfo, maybecondinfo) -> newrt + from_interprocedural!(ipo_lattice::AbstractLattice, rt, sv::InferenceState, arginfo::ArgInfo, maybecondinfo) -> newrt Converts inter-procedural return type `rt` into a local lattice element `newrt`, that is appropriate in the context of current local analysis frame `sv`, especially: @@ -365,13 +372,13 @@ In such cases `maybecondinfo` should be either of: When we deal with multiple `MethodMatch`es, it's better to precompute `maybecondinfo` by `tmerge`ing argument signature type of each method call. """ -function from_interprocedural!(@nospecialize(rt), sv::InferenceState, arginfo::ArgInfo, @nospecialize(maybecondinfo)) +function from_interprocedural!(ipo_lattice::AbstractLattice, @nospecialize(rt), sv::InferenceState, arginfo::ArgInfo, @nospecialize(maybecondinfo)) rt = collect_limitations!(rt, sv) - if is_lattice_bool(rt) + if is_lattice_bool(ipo_lattice, rt) if maybecondinfo === nothing rt = widenconditional(rt) else - rt = from_interconditional(rt, sv, arginfo, maybecondinfo) + rt = from_interconditional(ipo_lattice, rt, sv, arginfo, maybecondinfo) end end @assert !(rt isa InterConditional) "invalid lattice element returned from inter-procedural context" @@ -386,7 +393,9 @@ function collect_limitations!(@nospecialize(typ), sv::InferenceState) return typ end -function from_interconditional(@nospecialize(typ), sv::InferenceState, (; fargs, argtypes)::ArgInfo, @nospecialize(maybecondinfo)) +function from_interconditional(ipo_lattice::AbstractLattice, @nospecialize(typ), + sv::InferenceState, (; fargs, argtypes)::ArgInfo, @nospecialize(maybecondinfo)) + lattice = widenlattice(ipo_lattice) fargs === nothing && return widenconditional(typ) slot = 0 thentype = elsetype = Any @@ -412,21 +421,21 @@ function from_interconditional(@nospecialize(typ), sv::InferenceState, (; fargs, end if condval === false thentype = Bottom - elseif new_thentype ⊑ thentype + elseif ⊑(lattice, new_thentype, thentype) thentype = new_thentype else - thentype = tmeet(thentype, widenconst(new_thentype)) + thentype = tmeet(lattice, thentype, widenconst(new_thentype)) end if condval === true elsetype = Bottom - elseif new_elsetype ⊑ elsetype + elseif ⊑(lattice, new_elsetype, elsetype) elsetype = new_elsetype else - elsetype = tmeet(elsetype, widenconst(new_elsetype)) + elsetype = tmeet(lattice, elsetype, widenconst(new_elsetype)) end - if (slot > 0 || condval !== false) && thentype ⋤ old + if (slot > 0 || condval !== false) && ⋤(lattice, thentype, old) slot = id - elseif (slot > 0 || condval !== true) && elsetype ⋤ old + elseif (slot > 0 || condval !== true) && ⋤(lattice, elsetype, old) slot = id else # reset: no new useful information for this slot thentype = elsetype = Any @@ -474,15 +483,15 @@ function add_call_backedges!(interp::AbstractInterpreter, end end for edge in edges - add_backedge!(edge, sv) + add_backedge!(sv, edge) end # also need an edge to the method table in case something gets # added that did not intersect with any existing method if isa(matches, MethodMatches) - matches.fullmatch || add_mt_backedge!(matches.mt, atype, sv) + matches.fullmatch || add_mt_backedge!(sv, matches.mt, atype) else for (thisfullmatch, mt) in zip(matches.fullmatches, matches.mts) - thisfullmatch || add_mt_backedge!(mt, atype, sv) + thisfullmatch || add_mt_backedge!(sv, mt, atype) end end end @@ -545,7 +554,7 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp end if isdefined(method, :recursion_relation) - # We don't recquire the recursion_relation to be transitive, so + # We don't require the recursion_relation to be transitive, so # apply a hard limit hardlimit = true end @@ -741,7 +750,7 @@ function pure_eval_eligible(interp::AbstractInterpreter, return f !== nothing && length(applicable) == 1 && is_method_pure(applicable[1]::MethodMatch) && - is_all_const_arg(arginfo) + is_all_const_arg(arginfo, #=start=#2) end function is_method_pure(method::Method, @nospecialize(sig), sparams::SimpleVector) @@ -763,7 +772,7 @@ function pure_eval_call(interp::AbstractInterpreter, return _pure_eval_call(f, arginfo) end function _pure_eval_call(@nospecialize(f), arginfo::ArgInfo) - args = collect_const_args(arginfo) + args = collect_const_args(arginfo, #=start=#2) value = try Core._apply_pure(f, args) catch @@ -772,55 +781,85 @@ function _pure_eval_call(@nospecialize(f), arginfo::ArgInfo) return Const(value) end +# - true: eligible for concrete evaluation +# - false: eligible for semi-concrete evaluation +# - nothing: not eligible for either of it function concrete_eval_eligible(interp::AbstractInterpreter, @nospecialize(f), result::MethodCallResult, arginfo::ArgInfo, sv::InferenceState) - # disable concrete-evaluation if this function call is tainted by some overlayed + # disable all concrete-evaluation if this function call is tainted by some overlayed # method since currently there is no direct way to execute overlayed methods - isoverlayed(method_table(interp)) && !is_nonoverlayed(result.effects) && return false - return f !== nothing && - result.edge !== nothing && - is_foldable(result.effects) && - is_all_const_arg(arginfo) + isoverlayed(method_table(interp)) && !is_nonoverlayed(result.effects) && return nothing + if f !== nothing && result.edge !== nothing && is_foldable(result.effects) + if is_all_const_arg(arginfo, #=start=#2) + return true + else + # TODO: `is_nothrow` is not an actual requirement here, this is just a hack + # to avoid entering semi concrete eval while it doesn't properly override effects + return is_nothrow(result.effects) ? false : nothing + end + end + return nothing end -is_all_const_arg(arginfo::ArgInfo) = is_all_const_arg(arginfo.argtypes) -function is_all_const_arg(argtypes::Vector{Any}) - for i = 2:length(argtypes) +is_all_const_arg(arginfo::ArgInfo, start::Int) = is_all_const_arg(arginfo.argtypes, start::Int) +function is_all_const_arg(argtypes::Vector{Any}, start::Int) + for i = start:length(argtypes) a = widenconditional(argtypes[i]) isa(a, Const) || isconstType(a) || issingletontype(a) || return false end return true end -collect_const_args(arginfo::ArgInfo) = collect_const_args(arginfo.argtypes) -function collect_const_args(argtypes::Vector{Any}) +collect_const_args(arginfo::ArgInfo, start::Int) = collect_const_args(arginfo.argtypes, start) +function collect_const_args(argtypes::Vector{Any}, start::Int) return Any[ let a = widenconditional(argtypes[i]) isa(a, Const) ? a.val : isconstType(a) ? (a::DataType).parameters[1] : (a::DataType).instance - end for i = 2:length(argtypes) ] + end for i = start:length(argtypes) ] +end + +struct InvokeCall + types # ::Type + lookupsig # ::Type + InvokeCall(@nospecialize(types), @nospecialize(lookupsig)) = new(types, lookupsig) end function concrete_eval_call(interp::AbstractInterpreter, - @nospecialize(f), result::MethodCallResult, arginfo::ArgInfo, sv::InferenceState) - concrete_eval_eligible(interp, f, result, arginfo, sv) || return nothing - args = collect_const_args(arginfo) - world = get_world_counter(interp) - value = try - Core._call_in_world_total(world, f, args...) - catch - # The evaulation threw. By :consistent-cy, we're guaranteed this would have happened at runtime - return ConstCallResults(Union{}, ConcreteResult(result.edge::MethodInstance, result.effects), result.effects) - end - if is_inlineable_constant(value) || call_result_unused(sv) - # If the constant is not inlineable, still do the const-prop, since the - # code that led to the creation of the Const may be inlineable in the same - # circumstance and may be optimizable. - return ConstCallResults(Const(value), ConcreteResult(result.edge::MethodInstance, EFFECTS_TOTAL, value), EFFECTS_TOTAL) + @nospecialize(f), result::MethodCallResult, arginfo::ArgInfo, sv::InferenceState, + invokecall::Union{Nothing,InvokeCall}=nothing) + eligible = concrete_eval_eligible(interp, f, result, arginfo, sv) + eligible === nothing && return false + if eligible + args = collect_const_args(arginfo, #=start=#2) + if invokecall !== nothing + # this call should be `invoke`d, rewrite `args` back now + pushfirst!(args, f, invokecall.types) + f = invoke + end + world = get_world_counter(interp) + edge = result.edge::MethodInstance + value = try + Core._call_in_world_total(world, f, args...) + catch + # The evaluation threw. By :consistent-cy, we're guaranteed this would have happened at runtime + return ConstCallResults(Union{}, ConcreteResult(edge, result.effects), result.effects, edge) + end + if is_inlineable_constant(value) || call_result_unused(sv) + # If the constant is not inlineable, still do the const-prop, since the + # code that led to the creation of the Const may be inlineable in the same + # circumstance and may be optimizable. + return ConstCallResults(Const(value), ConcreteResult(edge, EFFECTS_TOTAL, value), EFFECTS_TOTAL, edge) + end + return false + else # eligible for semi-concrete evaluation + return true end - return nothing end +has_conditional(argtypes::Vector{Any}) = _any(@nospecialize(x)->isa(x, Conditional), argtypes) +has_conditional((; argtypes)::ArgInfo) = has_conditional(argtypes) + function const_prop_enabled(interp::AbstractInterpreter, sv::InferenceState, match::MethodMatch) if !InferenceParams(interp).ipo_constant_propagation add_remark!(interp, sv, "[constprop] Disabled by parameter") @@ -837,28 +876,41 @@ struct ConstCallResults rt::Any const_result::ConstResult effects::Effects + edge::MethodInstance ConstCallResults(@nospecialize(rt), const_result::ConstResult, - effects::Effects) = - new(rt, const_result, effects) + effects::Effects, + edge::MethodInstance) = + new(rt, const_result, effects, edge) end -function abstract_call_method_with_const_args(interp::AbstractInterpreter, result::MethodCallResult, - @nospecialize(f), arginfo::ArgInfo, match::MethodMatch, - sv::InferenceState) +function abstract_call_method_with_const_args(interp::AbstractInterpreter, + result::MethodCallResult, @nospecialize(f), arginfo::ArgInfo, match::MethodMatch, + sv::InferenceState, invokecall::Union{Nothing,InvokeCall}=nothing) if !const_prop_enabled(interp, sv, match) return nothing end - val = concrete_eval_call(interp, f, result, arginfo, sv) - if val !== nothing - add_backedge!(val.const_result.mi, sv) - return val - end + res = concrete_eval_call(interp, f, result, arginfo, sv, invokecall) + isa(res, ConstCallResults) && return res mi = maybe_get_const_prop_profitable(interp, result, f, arginfo, match, sv) mi === nothing && return nothing + # try semi-concrete evaluation + if res::Bool && !has_conditional(arginfo) + mi_cache = WorldView(code_cache(interp), sv.world) + code = get(mi_cache, mi, nothing) + if code !== nothing + ir = codeinst_to_ir(interp, code) + if isa(ir, IRCode) + T = ir_abstract_constant_propagation(interp, mi_cache, sv, mi, ir, arginfo.argtypes) + if !isa(T, Type) || typeintersect(T, Bool) === Union{} + return ConstCallResults(T, SemiConcreteResult(mi, ir, result.effects), result.effects, mi) + end + end + end + end # try constant prop' inf_cache = get_inference_cache(interp) - inf_result = cache_lookup(mi, arginfo.argtypes, inf_cache) + inf_result = cache_lookup(typeinf_lattice(interp), mi, arginfo.argtypes, inf_cache) if inf_result === nothing # if there might be a cycle, check to make sure we don't end up # calling ourselves here. @@ -884,8 +936,7 @@ function abstract_call_method_with_const_args(interp::AbstractInterpreter, resul result = inf_result.result # if constant inference hits a cycle, just bail out isa(result, InferenceState) && return nothing - add_backedge!(mi, sv) - return ConstCallResults(result, ConstPropResult(inf_result), inf_result.ipo_effects) + return ConstCallResults(result, ConstPropResult(inf_result), inf_result.ipo_effects, mi) end # if there's a possibility we could get a better result with these constant arguments @@ -962,14 +1013,14 @@ end # determines heuristically whether if constant propagation can be worthwhile # by checking if any of given `argtypes` is "interesting" enough to be propagated -function const_prop_argument_heuristic(_::AbstractInterpreter, (; fargs, argtypes)::ArgInfo, sv::InferenceState) +function const_prop_argument_heuristic(interp::AbstractInterpreter, (; fargs, argtypes)::ArgInfo, sv::InferenceState) for i in 1:length(argtypes) a = argtypes[i] if isa(a, Conditional) && fargs !== nothing is_const_prop_profitable_conditional(a, fargs, sv) && return true else a = widenconditional(a) - has_nontrivial_const_info(a) && is_const_prop_profitable_arg(a) && return true + has_nontrivial_const_info(typeinf_lattice(interp), a) && is_const_prop_profitable_arg(a) && return true end end return false @@ -1033,8 +1084,9 @@ function force_const_prop(interp::AbstractInterpreter, @nospecialize(f), method: end function const_prop_function_heuristic( - _::AbstractInterpreter, @nospecialize(f), (; argtypes)::ArgInfo, + interp::AbstractInterpreter, @nospecialize(f), (; argtypes)::ArgInfo, nargs::Int, all_overridden::Bool, still_nothrow::Bool, _::InferenceState) + ⊑ᵢ = ⊑(typeinf_lattice(interp)) if nargs > 1 if istopfunction(f, :getindex) || istopfunction(f, :setindex!) arrty = argtypes[2] @@ -1045,12 +1097,12 @@ function const_prop_function_heuristic( if !still_nothrow || ismutabletype(arrty) return false end - elseif arrty ⊑ Array + elseif arrty ⊑ᵢ Array return false end elseif istopfunction(f, :iterate) itrty = argtypes[2] - if itrty ⊑ Array + if itrty ⊑ᵢ Array return false end end @@ -1124,6 +1176,7 @@ end # This is only for use with `Conditional`. # In general, usage of this is wrong. +ssa_def_slot(@nospecialize(arg), sv::IRCode) = nothing function ssa_def_slot(@nospecialize(arg), sv::InferenceState) code = sv.src.code init = sv.currpc @@ -1178,7 +1231,8 @@ end # refine its type to an array of element types. # Union of Tuples of the same length is converted to Tuple of Unions. # returns an array of types -function precise_container_type(interp::AbstractInterpreter, @nospecialize(itft), @nospecialize(typ), sv::InferenceState) +function precise_container_type(interp::AbstractInterpreter, @nospecialize(itft), @nospecialize(typ), + sv::Union{InferenceState, IRCode}) if isa(typ, PartialStruct) && typ.typ.name === Tuple.name return typ.fields, nothing end @@ -1243,7 +1297,7 @@ function precise_container_type(interp::AbstractInterpreter, @nospecialize(itft) end # simulate iteration protocol on container type up to fixpoint -function abstract_iteration(interp::AbstractInterpreter, @nospecialize(itft), @nospecialize(itertype), sv::InferenceState) +function abstract_iteration(interp::AbstractInterpreter, @nospecialize(itft), @nospecialize(itertype), sv::Union{InferenceState, IRCode}) if isa(itft, Const) iteratef = itft.val else @@ -1278,7 +1332,7 @@ function abstract_iteration(interp::AbstractInterpreter, @nospecialize(itft), @n nstatetype = getfield_tfunc(stateordonet, Const(2)) # If there's no new information in this statetype, don't bother continuing, # the iterator won't be finite. - if nstatetype ⊑ statetype + if ⊑(typeinf_lattice(interp), nstatetype, statetype) return Any[Bottom], nothing end valtype = getfield_tfunc(stateordonet, Const(1)) @@ -1329,7 +1383,7 @@ function abstract_iteration(interp::AbstractInterpreter, @nospecialize(itft), @n end # do apply(af, fargs...), where af is a function value -function abstract_apply(interp::AbstractInterpreter, argtypes::Vector{Any}, sv::InferenceState, +function abstract_apply(interp::AbstractInterpreter, argtypes::Vector{Any}, sv::Union{InferenceState, IRCode}, max_methods::Int = get_max_methods(sv.mod, interp)) itft = argtype_by_index(argtypes, 2) aft = argtype_by_index(argtypes, 3) @@ -1380,7 +1434,7 @@ function abstract_apply(interp::AbstractInterpreter, argtypes::Vector{Any}, sv:: for j = 1:length(ctypes) ct = ctypes[j]::Vector{Any} if isvarargtype(ct[end]) - # This is vararg, we're not gonna be able to do any inling, + # This is vararg, we're not gonna be able to do any inlining, # drop the info info = nothing tail = tuple_tail_elem(unwrapva(ct[end]), cti) @@ -1445,9 +1499,11 @@ function argtype_tail(argtypes::Vector{Any}, i::Int) end function abstract_call_builtin(interp::AbstractInterpreter, f::Builtin, (; fargs, argtypes)::ArgInfo, - sv::InferenceState, max_methods::Int) + sv::Union{InferenceState, IRCode}, max_methods::Int) @nospecialize f la = length(argtypes) + lattice = typeinf_lattice(interp) + ⊑ᵢ = ⊑(lattice) if f === Core.ifelse && fargs isa Vector{Any} && la == 4 cnd = argtypes[2] if isa(cnd, Conditional) @@ -1462,12 +1518,12 @@ function abstract_call_builtin(interp::AbstractInterpreter, f::Builtin, (; fargs a = ssa_def_slot(fargs[3], sv) b = ssa_def_slot(fargs[4], sv) if isa(a, SlotNumber) && cnd.slot == slot_id(a) - tx = (cnd.thentype ⊑ tx ? cnd.thentype : tmeet(tx, widenconst(cnd.thentype))) + tx = (cnd.thentype ⊑ᵢ tx ? cnd.thentype : tmeet(lattice, tx, widenconst(cnd.thentype))) end if isa(b, SlotNumber) && cnd.slot == slot_id(b) - ty = (cnd.elsetype ⊑ ty ? cnd.elsetype : tmeet(ty, widenconst(cnd.elsetype))) + ty = (cnd.elsetype ⊑ᵢ ty ? cnd.elsetype : tmeet(lattice, ty, widenconst(cnd.elsetype))) end - return tmerge(tx, ty) + return tmerge(lattice, tx, ty) end end end @@ -1488,6 +1544,10 @@ function abstract_call_builtin(interp::AbstractInterpreter, f::Builtin, (; fargs tty_lb = tty_ub # TODO: this would be wrong if !isexact_tty, but instanceof_tfunc doesn't preserve this info if !has_free_typevars(tty_lb) && !has_free_typevars(tty_ub) ifty = typeintersect(aty, tty_ub) + if iskindtype(tty_ub) && ifty !== Bottom + # `typeintersect` may be unable narrow down `Type`-type + ifty = tty_ub + end valid_as_lattice(ifty) || (ifty = Union{}) elty = typesubtract(aty, tty_lb, InferenceParams(interp).MAX_UNION_SPLITTING) return Conditional(a, ifty, elty) @@ -1620,10 +1680,10 @@ function abstract_invoke(interp::AbstractInterpreter, (; fargs, argtypes)::ArgIn nargtype isa DataType || return CallMeta(Any, Effects(), false) # other cases are not implemented below isdispatchelem(ft) || return CallMeta(Any, Effects(), false) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below ft = ft::DataType - types = rewrap_unionall(Tuple{ft, unwrap_unionall(types).parameters...}, types)::Type + lookupsig = rewrap_unionall(Tuple{ft, unwrap_unionall(types).parameters...}, types)::Type nargtype = Tuple{ft, nargtype.parameters...} argtype = Tuple{ft, argtype.parameters...} - match, valid_worlds, overlayed = findsup(types, method_table(interp)) + match, valid_worlds, overlayed = findsup(lookupsig, method_table(interp)) match === nothing && return CallMeta(Any, Effects(), false) update_valid_age!(sv, valid_worlds) method = match.method @@ -1631,7 +1691,6 @@ function abstract_invoke(interp::AbstractInterpreter, (; fargs, argtypes)::ArgIn ti = tienv[1]; env = tienv[2]::SimpleVector result = abstract_call_method(interp, method, ti, env, false, sv) (; rt, edge, effects) = result - edge !== nothing && add_backedge!(edge::MethodInstance, sv) match = MethodMatch(ti, env, method, argtype <: method.sig) res = nothing sig = match.spec_types @@ -1643,16 +1702,19 @@ function abstract_invoke(interp::AbstractInterpreter, (; fargs, argtypes)::ArgIn # t, a = ti.parameters[i], argtypes′[i] # argtypes′[i] = t ⊑ a ? t : a # end - const_call_result = abstract_call_method_with_const_args(interp, result, - overlayed ? nothing : singleton_type(ft′), arginfo, match, sv) + f = overlayed ? nothing : singleton_type(ft′) + invokecall = InvokeCall(types, lookupsig) + const_call_result = abstract_call_method_with_const_args(interp, + result, f, arginfo, match, sv, invokecall) const_result = nothing if const_call_result !== nothing - if const_call_result.rt ⊑ rt - (; rt, effects, const_result) = const_call_result + if ⊑(typeinf_lattice(interp), const_call_result.rt, rt) + (; rt, effects, const_result, edge) = const_call_result end end effects = Effects(effects; nonoverlayed=!overlayed) - return CallMeta(from_interprocedural!(rt, sv, arginfo, sig), effects, InvokeCallInfo(match, const_result)) + edge !== nothing && add_invoke_backedge!(sv, lookupsig, edge) + return CallMeta(from_interprocedural!(ipo_lattice(interp), rt, sv, arginfo, sig), effects, InvokeCallInfo(match, const_result)) end function invoke_rewrite(xs::Vector{Any}) @@ -1673,8 +1735,8 @@ end # call where the function is known exactly function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f), - arginfo::ArgInfo, sv::InferenceState, - max_methods::Int = get_max_methods(f, sv.mod, interp)) + arginfo::ArgInfo, sv::Union{InferenceState, IRCode}, + max_methods::Int = isa(sv, InferenceState) ? get_max_methods(f, sv.mod, interp) : 0) (; fargs, argtypes) = arginfo la = length(argtypes) @@ -1689,7 +1751,7 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f), return abstract_finalizer(interp, argtypes, sv) end rt = abstract_call_builtin(interp, f, arginfo, sv, max_methods) - effects = builtin_effects(f, argtypes[2:end], rt) + effects = builtin_effects(typeinf_lattice(interp), f, argtypes[2:end], rt) return CallMeta(rt, effects, false) elseif isa(f, Core.OpaqueClosure) # calling an OpaqueClosure about which we have no information returns no information @@ -1771,7 +1833,7 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f), elseif la == 2 && istopfunction(f, :typename) return CallMeta(typename_static(argtypes[2]), EFFECTS_TOTAL, MethodResultPure()) elseif la == 3 && istopfunction(f, :typejoin) - if is_all_const_arg(arginfo) + if is_all_const_arg(arginfo, #=start=#2) val = _pure_eval_call(f, arginfo) return CallMeta(val === nothing ? Type : val, EFFECTS_TOTAL, MethodResultPure()) end @@ -1785,7 +1847,6 @@ function abstract_call_opaque_closure(interp::AbstractInterpreter, sig = argtypes_to_type(arginfo.argtypes) result = abstract_call_method(interp, closure.source, sig, Core.svec(), false, sv) (; rt, edge, effects) = result - edge !== nothing && add_backedge!(edge, sv) tt = closure.typ sigT = (unwrap_unionall(tt)::DataType).parameters[1] match = MethodMatch(sig, Core.svec(), closure.source, sig <: rewrap_unionall(sigT, tt)) @@ -1795,20 +1856,23 @@ function abstract_call_opaque_closure(interp::AbstractInterpreter, nothing, arginfo, match, sv) if const_call_result !== nothing if const_call_result.rt ⊑ rt - (; rt, effects, const_result) = const_call_result + (; rt, effects, const_result, edge) = const_call_result end end end info = OpaqueClosureCallInfo(match, const_result) + ipo = ipo_lattice(interp) + ⊑ₚ = ⊑(ipo) if check # analyze implicit type asserts on argument and return type ftt = closure.typ (aty, rty) = (unwrap_unionall(ftt)::DataType).parameters rty = rewrap_unionall(rty isa TypeVar ? rty.lb : rty, ftt) - if !(rt ⊑ rty && tuple_tfunc(arginfo.argtypes[2:end]) ⊑ rewrap_unionall(aty, ftt)) + if !(rt ⊑ₚ rty && tuple_tfunc(ipo, arginfo.argtypes[2:end]) ⊑ₚ rewrap_unionall(aty, ftt)) effects = Effects(effects; nothrow=false) end end - rt = from_interprocedural!(rt, sv, arginfo, match.spec_types) + rt = from_interprocedural!(ipo, rt, sv, arginfo, match.spec_types) + edge !== nothing && add_backedge!(sv, edge) return CallMeta(rt, effects, info) end @@ -1824,7 +1888,7 @@ end # call where the function is any lattice element function abstract_call(interp::AbstractInterpreter, arginfo::ArgInfo, - sv::InferenceState, max_methods::Union{Int, Nothing} = nothing) + sv::Union{InferenceState, IRCode}, max_methods::Union{Int, Nothing} = isa(sv, IRCode) ? 0 : nothing) argtypes = arginfo.argtypes ft = argtypes[1] f = singleton_type(ft) @@ -1897,7 +1961,7 @@ function abstract_eval_cfunction(interp::AbstractInterpreter, e::Expr, vtypes::V nothing end -function abstract_eval_value_expr(interp::AbstractInterpreter, e::Expr, vtypes::VarTable, sv::InferenceState) +function abstract_eval_value_expr(interp::AbstractInterpreter, e::Expr, sv::Union{InferenceState, IRCode}) head = e.head if head === :static_parameter n = e.args[1]::Int @@ -1909,36 +1973,43 @@ function abstract_eval_value_expr(interp::AbstractInterpreter, e::Expr, vtypes:: elseif head === :boundscheck return Bool elseif head === :the_exception - merge_effects!(sv, Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE)) + merge_effects!(interp, sv, Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE)) return Any end return Any end -function abstract_eval_special_value(interp::AbstractInterpreter, @nospecialize(e), vtypes::VarTable, sv::InferenceState) +function abstract_eval_special_value(interp::AbstractInterpreter, @nospecialize(e), vtypes::Union{VarTable, Nothing}, sv::Union{InferenceState, IRCode}) if isa(e, QuoteNode) return Const(e.value) elseif isa(e, SSAValue) return abstract_eval_ssavalue(e, sv) - elseif isa(e, SlotNumber) || isa(e, Argument) + elseif isa(e, SlotNumber) return vtypes[slot_id(e)].typ + elseif isa(e, Argument) + if !isa(vtypes, Nothing) + return vtypes[slot_id(e)].typ + else + @assert isa(sv, IRCode) + return sv.argtypes[e.n] + end elseif isa(e, GlobalRef) - return abstract_eval_global(e.mod, e.name, sv) + return abstract_eval_globalref(interp, e, sv) end return Const(e) end -function abstract_eval_value(interp::AbstractInterpreter, @nospecialize(e), vtypes::VarTable, sv::InferenceState) +function abstract_eval_value(interp::AbstractInterpreter, @nospecialize(e), vtypes::Union{VarTable, Nothing}, sv::Union{InferenceState, IRCode}) if isa(e, Expr) - return abstract_eval_value_expr(interp, e, vtypes, sv) + return abstract_eval_value_expr(interp, e, sv) else typ = abstract_eval_special_value(interp, e, vtypes, sv) return collect_limitations!(typ, sv) end end -function collect_argtypes(interp::AbstractInterpreter, ea::Vector{Any}, vtypes::VarTable, sv::InferenceState) +function collect_argtypes(interp::AbstractInterpreter, ea::Vector{Any}, vtypes::Union{VarTable, Nothing}, sv::Union{InferenceState, IRCode}) n = length(ea) argtypes = Vector{Any}(undef, n) @inbounds for i = 1:n @@ -1951,30 +2022,31 @@ function collect_argtypes(interp::AbstractInterpreter, ea::Vector{Any}, vtypes:: return argtypes end -function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), vtypes::VarTable, sv::InferenceState) - if !isa(e, Expr) - if isa(e, PhiNode) - rt = Union{} - for val in e.values - rt = tmerge(rt, abstract_eval_special_value(interp, val, vtypes, sv)) - end - return rt - end - return abstract_eval_special_value(interp, e, vtypes, sv) - end - e = e::Expr +struct RTEffects + rt + effects::Effects + RTEffects(@nospecialize(rt), effects::Effects) = new(rt, effects) +end + +function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtypes::Union{VarTable, Nothing}, + sv::Union{InferenceState, IRCode}, mi::Union{MethodInstance, Nothing})::RTEffects + effects = EFFECTS_UNKNOWN ehead = e.head + ⊑ᵢ = ⊑(typeinf_lattice(interp)) if ehead === :call ea = e.args argtypes = collect_argtypes(interp, ea, vtypes, sv) if argtypes === nothing - t = Bottom + rt = Bottom + effects = Effects() else - callinfo = abstract_call(interp, ArgInfo(ea, argtypes), sv) - merge_effects!(sv, callinfo.effects) - sv.stmt_info[sv.currpc] = callinfo.info - t = callinfo.rt + (; rt, effects, info) = abstract_call(interp, ArgInfo(ea, argtypes), sv) + merge_effects!(interp, sv, effects) + if isa(sv, InferenceState) + sv.stmt_info[sv.currpc] = info + end end + t = rt elseif ehead === :new t, isexact = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv)) nothrow = true @@ -1989,8 +2061,8 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), for i = 1:nargs at = widenconditional(abstract_eval_value(interp, e.args[i+1], vtypes, sv)) ft = fieldtype(t, i) - nothrow && (nothrow = at ⊑ ft) - at = tmeet(at, ft) + nothrow && (nothrow = at ⊑ᵢ ft) + at = tmeet(typeinf_lattice(interp), at, ft) at === Bottom && @goto always_throw if ismutable && !isconst(t, i) ats[i] = ft # can't constrain this field (as it may be modified later) @@ -1998,8 +2070,8 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), end allconst &= isa(at, Const) if !anyrefine - anyrefine = has_nontrivial_const_info(at) || # constant information - at ⋤ ft # just a type-level information, but more precise than the declared type + anyrefine = has_nontrivial_const_info(typeinf_lattice(interp), at) || # constant information + ⋤(typeinf_lattice(interp), at, ft) # just a type-level information, but more precise than the declared type end ats[i] = at end @@ -2032,7 +2104,8 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), consistent = ALWAYS_FALSE nothrow = false end - merge_effects!(sv, Effects(EFFECTS_TOTAL; consistent, nothrow)) + effects = Effects(EFFECTS_TOTAL; consistent, nothrow) + merge_effects!(interp, sv, effects) elseif ehead === :splatnew t, isexact = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv)) nothrow = false # TODO: More precision @@ -2043,26 +2116,29 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), let t = t, at = at; _all(i->getfield(at.val::Tuple, i) isa fieldtype(t, i), 1:n); end nothrow = isexact && isconcretedispatch(t) t = Const(ccall(:jl_new_structt, Any, (Any, Any), t, at.val)) - elseif isa(at, PartialStruct) && at ⊑ Tuple && n == length(at.fields::Vector{Any}) && - let t = t, at = at; _all(i->(at.fields::Vector{Any})[i] ⊑ fieldtype(t, i), 1:n); end + elseif isa(at, PartialStruct) && at ⊑ᵢ Tuple && n == length(at.fields::Vector{Any}) && + let t = t, at = at; _all(i->(at.fields::Vector{Any})[i] ⊑ᵢ fieldtype(t, i), 1:n); end nothrow = isexact && isconcretedispatch(t) t = PartialStruct(t, at.fields::Vector{Any}) end end consistent = !ismutabletype(t) ? ALWAYS_TRUE : CONSISTENT_IF_NOTRETURNED - merge_effects!(sv, Effects(EFFECTS_TOTAL; consistent, nothrow)) + effects = Effects(EFFECTS_TOTAL; consistent, nothrow) + merge_effects!(interp, sv, effects) elseif ehead === :new_opaque_closure - merge_effects!(sv, Effects()) # TODO t = Union{} + effects = Effects() # TODO + merge_effects!(interp, sv, effects) if length(e.args) >= 4 ea = e.args argtypes = collect_argtypes(interp, ea, vtypes, sv) if argtypes === nothing t = Bottom else + mi′ = isa(sv, InferenceState) ? sv.linfo : mi t = _opaque_closure_tfunc(argtypes[1], argtypes[2], argtypes[3], - argtypes[4], argtypes[5:end], sv.linfo) - if isa(t, PartialOpaque) + argtypes[4], argtypes[5:end], mi′) + if isa(t, PartialOpaque) && isa(sv, InferenceState) # Infer this now so that the specialization is available to # optimization. argtypes = most_general_argtypes(t) @@ -2074,39 +2150,22 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), end end elseif ehead === :foreigncall - abstract_eval_value(interp, e.args[1], vtypes, sv) - t = sp_type_rewrap(e.args[2], sv.linfo, true) - for i = 3:length(e.args) - if abstract_eval_value(interp, e.args[i], vtypes, sv) === Bottom - @goto always_throw - end - end - effects = foreigncall_effects(e) do @nospecialize x - abstract_eval_value(interp, x, vtypes, sv) - end - cconv = e.args[5] - if isa(cconv, QuoteNode) && (v = cconv.value; isa(v, Tuple{Symbol, UInt8})) - override = decode_effects_override(v[2]) - effects = Effects( - override.consistent ? ALWAYS_TRUE : effects.consistent, - override.effect_free ? ALWAYS_TRUE : effects.effect_free, - override.nothrow ? true : effects.nothrow, - override.terminates_globally ? true : effects.terminates, - override.notaskstate ? true : effects.notaskstate, - override.inaccessiblememonly ? ALWAYS_TRUE : effects.inaccessiblememonly, - effects.nonoverlayed) - end - merge_effects!(sv, effects) + (;rt, effects) = abstract_eval_foreigncall(interp, e, vtypes, sv, mi) + t = rt + merge_effects!(interp, sv, effects) elseif ehead === :cfunction - merge_effects!(sv, EFFECTS_UNKNOWN) + effects = EFFECTS_UNKNOWN + merge_effects!(interp, sv, effects) t = e.args[1] isa(t, Type) || (t = Any) abstract_eval_cfunction(interp, e, vtypes, sv) elseif ehead === :method - merge_effects!(sv, EFFECTS_UNKNOWN) t = (length(e.args) == 1) ? Any : Nothing + effects = EFFECTS_UNKNOWN + merge_effects!(interp, sv, effects) elseif ehead === :copyast - merge_effects!(sv, EFFECTS_UNKNOWN) + effects = EFFECTS_UNKNOWN + merge_effects!(interp, sv, effects) t = abstract_eval_value(interp, e.args[1], vtypes, sv) if t isa Const && t.val isa Expr # `copyast` makes copies of Exprs @@ -2144,37 +2203,89 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), elseif false @label always_throw t = Bottom - merge_effects!(sv, EFFECTS_THROWS) + effects = EFFECTS_THROWS + merge_effects!(interp, sv, effects) else - t = abstract_eval_value_expr(interp, e, vtypes, sv) + t = abstract_eval_value_expr(interp, e, sv) + end + return RTEffects(t, effects) +end + +function abstract_eval_foreigncall(interp::AbstractInterpreter, e::Expr, vtypes::Union{VarTable, Nothing}, sv::Union{InferenceState, IRCode}, mi::Union{MethodInstance, Nothing}=nothing) + abstract_eval_value(interp, e.args[1], vtypes, sv) + mi′ = isa(sv, InferenceState) ? sv.linfo : mi + t = sp_type_rewrap(e.args[2], mi′, true) + for i = 3:length(e.args) + if abstract_eval_value(interp, e.args[i], vtypes, sv) === Bottom + return RTEffects(Bottom, EFFECTS_THROWS) + end + end + effects = foreigncall_effects(e) do @nospecialize x + abstract_eval_value(interp, x, vtypes, sv) + end + cconv = e.args[5] + if isa(cconv, QuoteNode) && (v = cconv.value; isa(v, Tuple{Symbol, UInt8})) + override = decode_effects_override(v[2]) + effects = Effects( + override.consistent ? ALWAYS_TRUE : effects.consistent, + override.effect_free ? ALWAYS_TRUE : effects.effect_free, + override.nothrow ? true : effects.nothrow, + override.terminates_globally ? true : effects.terminates, + override.notaskstate ? true : effects.notaskstate, + override.inaccessiblememonly ? ALWAYS_TRUE : effects.inaccessiblememonly, + effects.nonoverlayed) + end + return RTEffects(t, effects) +end + +function abstract_eval_phi(interp::AbstractInterpreter, phi::PhiNode, vtypes::Union{VarTable, Nothing}, sv::Union{InferenceState, IRCode}) + rt = Union{} + for val in phi.values + rt = tmerge(typeinf_lattice(interp), rt, abstract_eval_special_value(interp, val, vtypes, sv)) end - @assert !isa(t, TypeVar) "unhandled TypeVar" - if isa(t, DataType) && isdefined(t, :instance) - # replace singleton types with their equivalent Const object - t = Const(t.instance) + return rt +end + +function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), vtypes::VarTable, sv::InferenceState) + if !isa(e, Expr) + if isa(e, PhiNode) + return abstract_eval_phi(interp, e, vtypes, sv) + end + return abstract_eval_special_value(interp, e, vtypes, sv) end + (;rt, effects) = abstract_eval_statement_expr(interp, e, vtypes, sv, nothing) + e = e::Expr + @assert !isa(rt, TypeVar) "unhandled TypeVar" + rt = maybe_singleton_const(rt) if !isempty(sv.pclimitations) - if t isa Const || t === Bottom + if rt isa Const || rt === Union{} empty!(sv.pclimitations) else - t = LimitedAccuracy(t, sv.pclimitations) + rt = LimitedAccuracy(rt, sv.pclimitations) sv.pclimitations = IdSet{InferenceState}() end end - return t + return rt +end + +function isdefined_globalref(g::GlobalRef) + g.binding != C_NULL && return ccall(:jl_binding_boundp, Cint, (Ptr{Cvoid},), g.binding) != 0 + return isdefined(g.mod, g.name) end -function abstract_eval_global(M::Module, s::Symbol) - if isdefined(M, s) && isconst(M, s) - return Const(getglobal(M, s)) +function abstract_eval_globalref(g::GlobalRef) + if isdefined_globalref(g) && isconst(g) + g.binding != C_NULL && return Const(ccall(:jl_binding_value, Any, (Ptr{Cvoid},), g.binding)) + return Const(getglobal(g.mod, g.name)) end - ty = ccall(:jl_binding_type, Any, (Any, Any), M, s) + ty = ccall(:jl_binding_type, Any, (Any, Any), g.mod, g.name) ty === nothing && return Any return ty end +abstract_eval_global(M::Module, s::Symbol) = abstract_eval_globalref(GlobalRef(M, s)) -function abstract_eval_global(M::Module, s::Symbol, frame::InferenceState) - rt = abstract_eval_global(M, s) +function abstract_eval_globalref(interp::AbstractInterpreter, g::GlobalRef, frame::Union{InferenceState, IRCode}) + rt = abstract_eval_globalref(g) consistent = inaccessiblememonly = ALWAYS_FALSE nothrow = false if isa(rt, Const) @@ -2185,10 +2296,10 @@ function abstract_eval_global(M::Module, s::Symbol, frame::InferenceState) else nothrow = true end - elseif isdefined(M,s) + elseif isdefined_globalref(g) nothrow = true end - merge_effects!(frame, Effects(EFFECTS_TOTAL; consistent, nothrow, inaccessiblememonly)) + merge_effects!(interp, frame, Effects(EFFECTS_TOTAL; consistent, nothrow, inaccessiblememonly)) return rt end @@ -2196,7 +2307,7 @@ function handle_global_assignment!(interp::AbstractInterpreter, frame::Inference effect_free = ALWAYS_FALSE nothrow = global_assignment_nothrow(lhs.mod, lhs.name, newty) inaccessiblememonly = ALWAYS_FALSE - merge_effects!(frame, Effects(EFFECTS_TOTAL; effect_free, nothrow, inaccessiblememonly)) + merge_effects!(interp, frame, Effects(EFFECTS_TOTAL; effect_free, nothrow, inaccessiblememonly)) return nothing end @@ -2210,8 +2321,11 @@ function abstract_eval_ssavalue(s::SSAValue, ssavaluetypes::Vector{Any}) return typ end -function widenreturn(@nospecialize(rt), @nospecialize(bestguess), nargs::Int, slottypes::Vector{Any}, changes::VarTable) - if !(bestguess ⊑ Bool) || bestguess === Bool +function widenreturn(ipo_lattice::AbstractLattice, @nospecialize(rt), @nospecialize(bestguess), nargs::Int, slottypes::Vector{Any}, changes::VarTable) + ⊑ₚ = ⊑(ipo_lattice) + inner_lattice = widenlattice(ipo_lattice) + ⊑ᵢ = ⊑(inner_lattice) + if !(bestguess ⊑ₚ Bool) || bestguess === Bool # give up inter-procedural constraint back-propagation # when tmerge would widen the result anyways (as an optimization) rt = widenconditional(rt) @@ -2220,8 +2334,8 @@ function widenreturn(@nospecialize(rt), @nospecialize(bestguess), nargs::Int, sl id = rt.slot if 1 ≤ id ≤ nargs old_id_type = widenconditional(slottypes[id]) # same as `(states[1]::VarTable)[id].typ` - if (!(rt.thentype ⊑ old_id_type) || old_id_type ⊑ rt.thentype) && - (!(rt.elsetype ⊑ old_id_type) || old_id_type ⊑ rt.elsetype) + if (!(rt.thentype ⊑ᵢ old_id_type) || old_id_type ⊑ᵢ rt.thentype) && + (!(rt.elsetype ⊑ᵢ old_id_type) || old_id_type ⊑ᵢ rt.elsetype) # discard this `Conditional` since it imposes # no new constraint on the argument type # (the caller will recreate it if needed) @@ -2236,7 +2350,7 @@ function widenreturn(@nospecialize(rt), @nospecialize(bestguess), nargs::Int, sl end if isa(rt, Conditional) rt = InterConditional(rt.slot, rt.thentype, rt.elsetype) - elseif is_lattice_bool(rt) + elseif is_lattice_bool(ipo_lattice, rt) if isa(bestguess, InterConditional) # if the bestguess so far is already `Conditional`, try to convert # this `rt` into `Conditional` on the slot to avoid overapproximation @@ -2258,10 +2372,10 @@ function widenreturn(@nospecialize(rt), @nospecialize(bestguess), nargs::Int, sl # and is valid and good inter-procedurally isa(rt, Conditional) && return InterConditional(rt) isa(rt, InterConditional) && return rt - return widenreturn_noconditional(rt) + return widenreturn_noconditional(widenlattice(ipo_lattice), rt) end -function widenreturn_noconditional(@nospecialize(rt)) +function widenreturn_noconditional(inner_lattice::AbstractLattice, @nospecialize(rt)) isa(rt, Const) && return rt isa(rt, Type) && return rt if isa(rt, PartialStruct) @@ -2269,11 +2383,11 @@ function widenreturn_noconditional(@nospecialize(rt)) local anyrefine = false for i in 1:length(fields) a = fields[i] - a = isvarargtype(a) ? a : widenreturn_noconditional(a) + a = isvarargtype(a) ? a : widenreturn_noconditional(inner_lattice, a) if !anyrefine # TODO: consider adding && const_prop_profitable(a) here? anyrefine = has_const_info(a) || - a ⊏ fieldtype(rt.typ, i) + ⊏(inner_lattice, a, fieldtype(rt.typ, i)) end fields[i] = a end @@ -2285,12 +2399,12 @@ function widenreturn_noconditional(@nospecialize(rt)) return widenconst(rt) end -function handle_control_backedge!(frame::InferenceState, from::Int, to::Int) +function handle_control_backedge!(interp::AbstractInterpreter, frame::InferenceState, from::Int, to::Int) if from > to if is_effect_overridden(frame, :terminates_locally) # this backedge is known to terminate else - merge_effects!(frame, Effects(EFFECTS_TOTAL; terminates=false)) + merge_effects!(interp, frame, Effects(EFFECTS_TOTAL; terminates=false)) end end return nothing @@ -2326,7 +2440,7 @@ end elseif isa(lhs, GlobalRef) handle_global_assignment!(interp, frame, lhs, t) elseif !isa(lhs, SSAValue) - merge_effects!(frame, EFFECTS_UNKNOWN) + merge_effects!(interp, frame, EFFECTS_UNKNOWN) end return BasicStmtChange(changes, t) elseif hd === :method @@ -2345,7 +2459,7 @@ end end end -function update_bbstate!(frame::InferenceState, bb::Int, vartable::VarTable) +function update_bbstate!(lattice::AbstractLattice, frame::InferenceState, bb::Int, vartable::VarTable) bbtable = frame.bb_vartables[bb] if bbtable === nothing # if a basic block hasn't been analyzed yet, @@ -2353,7 +2467,7 @@ function update_bbstate!(frame::InferenceState, bb::Int, vartable::VarTable) frame.bb_vartables[bb] = copy(vartable) return true else - return stupdate!(bbtable, vartable) + return stupdate!(lattice, bbtable, vartable) end end @@ -2400,7 +2514,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) @assert length(succs) == 1 nextbb = succs[1] ssavaluetypes[currpc] = Any - handle_control_backedge!(frame, currpc, stmt.label) + handle_control_backedge!(interp, frame, currpc, stmt.label) @goto branch elseif isa(stmt, GotoIfNot) condx = stmt.cond @@ -2438,7 +2552,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) falsebb = succs[1] == truebb ? succs[2] : succs[1] if condval === false nextbb = falsebb - handle_control_backedge!(frame, currpc, stmt.dest) + handle_control_backedge!(interp, frame, currpc, stmt.dest) @goto branch else # We continue with the true branch, but process the false @@ -2450,16 +2564,16 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) else false_vartable = currstate end - changed = update_bbstate!(frame, falsebb, false_vartable) + changed = update_bbstate!(typeinf_lattice(interp), frame, falsebb, false_vartable) then_change = conditional_change(currstate, condt.thentype, condt.slot) if then_change !== nothing stoverwrite1!(currstate, then_change) end else - changed = update_bbstate!(frame, falsebb, currstate) + changed = update_bbstate!(typeinf_lattice(interp), frame, falsebb, currstate) end if changed - handle_control_backedge!(frame, currpc, stmt.dest) + handle_control_backedge!(interp, frame, currpc, stmt.dest) push!(W, falsebb) end @goto fallthrough @@ -2468,7 +2582,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) elseif isa(stmt, ReturnNode) bestguess = frame.bestguess rt = abstract_eval_value(interp, stmt.val, currstate, frame) - rt = widenreturn(rt, bestguess, nargs, slottypes, currstate) + rt = widenreturn(ipo_lattice(interp), rt, bestguess, nargs, slottypes, currstate) # narrow representation of bestguess slightly to prepare for tmerge with rt if rt isa InterConditional && bestguess isa Const let slot_id = rt.slot @@ -2488,9 +2602,9 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) if !isempty(frame.limitations) rt = LimitedAccuracy(rt, copy(frame.limitations)) end - if tchanged(rt, bestguess) + if tchanged(ipo_lattice(interp), rt, bestguess) # new (wider) return type for frame - bestguess = tmerge(bestguess, rt) + bestguess = tmerge(ipo_lattice(interp), bestguess, rt) # TODO: if bestguess isa InterConditional && !interesting(bestguess); bestguess = widenconditional(bestguess); end frame.bestguess = bestguess for (caller, caller_pc) in frame.cycle_backedges @@ -2506,7 +2620,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) # Propagate entry info to exception handler l = stmt.args[1]::Int catchbb = block_for_inst(frame.cfg, l) - if update_bbstate!(frame, catchbb, currstate) + if update_bbstate!(typeinf_lattice(interp), frame, catchbb, currstate) push!(W, catchbb) end ssavaluetypes[currpc] = Any @@ -2531,7 +2645,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) # propagate new type info to exception handler # the handling for Expr(:enter) propagates all changes from before the try/catch # so this only needs to propagate any changes - if stupdate1!(states[exceptbb]::VarTable, changes) + if stupdate1!(typeinf_lattice(interp), states[exceptbb]::VarTable, changes) push!(W, exceptbb) end cur_hand = frame.handler_at[cur_hand] @@ -2556,7 +2670,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) # Case 2: Directly branch to a different BB begin @label branch - if update_bbstate!(frame, nextbb, currstate) + if update_bbstate!(typeinf_lattice(interp), frame, nextbb, currstate) push!(W, nextbb) end end @@ -2583,14 +2697,22 @@ end function conditional_change(state::VarTable, @nospecialize(typ), slot::Int) vtype = state[slot] oldtyp = vtype.typ - # approximate test for `typ ∩ oldtyp` being better than `oldtyp` - # since we probably formed these types with `typesubstract`, the comparison is likely simple - if ignorelimited(typ) ⊑ ignorelimited(oldtyp) - # typ is better unlimited, but we may still need to compute the tmeet with the limit "causes" since we ignored those in the comparison - oldtyp isa LimitedAccuracy && (typ = tmerge(typ, LimitedAccuracy(Bottom, oldtyp.causes))) - return StateUpdate(SlotNumber(slot), VarState(typ, vtype.undef), state, true) + if iskindtype(typ) + # this code path corresponds to the special handling for `isa(x, iskindtype)` check + # implemented within `abstract_call_builtin` + elseif ignorelimited(typ) ⊑ ignorelimited(oldtyp) + # approximate test for `typ ∩ oldtyp` being better than `oldtyp` + # since we probably formed these types with `typesubstract`, + # the comparison is likely simple + else + return nothing end - return nothing + if oldtyp isa LimitedAccuracy + # typ is better unlimited, but we may still need to compute the tmeet with the limit + # "causes" since we ignored those in the comparison + typ = tmerge(typ, LimitedAccuracy(Bottom, oldtyp.causes)) + end + return StateUpdate(SlotNumber(slot), VarState(typ, vtype.undef), state, true) end function bool_rt_to_conditional(@nospecialize(rt), slottypes::Vector{Any}, state::VarTable, slot_id::Int) diff --git a/base/compiler/abstractlattice.jl b/base/compiler/abstractlattice.jl new file mode 100644 index 0000000000000..83e64cd4a042f --- /dev/null +++ b/base/compiler/abstractlattice.jl @@ -0,0 +1,173 @@ +abstract type AbstractLattice; end +function widenlattice end + +""" + struct JLTypeLattice + +A singleton type representing the lattice of Julia types, without any inference +extensions. +""" +struct JLTypeLattice <: AbstractLattice; end +widenlattice(::JLTypeLattice) = error("Type lattice is the least-precise lattice available") +is_valid_lattice(::JLTypeLattice, @nospecialize(elem)) = isa(elem, Type) + +""" + struct ConstsLattice + +A lattice extending `JLTypeLattice` and adjoining `Const` and `PartialTypeVar`. +""" +struct ConstsLattice <: AbstractLattice; end +widenlattice(::ConstsLattice) = JLTypeLattice() +is_valid_lattice(lattice::ConstsLattice, @nospecialize(elem)) = + is_valid_lattice(widenlattice(lattice), elem) || isa(elem, Const) || isa(elem, PartialTypeVar) + +""" + struct PartialsLattice{L} + +A lattice extending lattice `L` and adjoining `PartialStruct` and `PartialOpaque`. +""" +struct PartialsLattice{L <: AbstractLattice} <: AbstractLattice + parent::L +end +widenlattice(L::PartialsLattice) = L.parent +is_valid_lattice(lattice::PartialsLattice, @nospecialize(elem)) = + is_valid_lattice(widenlattice(lattice), elem) || + isa(elem, PartialStruct) || isa(elem, PartialOpaque) + +""" + struct ConditionalsLattice{L} + +A lattice extending lattice `L` and adjoining `Conditional`. +""" +struct ConditionalsLattice{L <: AbstractLattice} <: AbstractLattice + parent::L +end +widenlattice(L::ConditionalsLattice) = L.parent +is_valid_lattice(lattice::ConditionalsLattice, @nospecialize(elem)) = + is_valid_lattice(widenlattice(lattice), elem) || isa(elem, Conditional) + +struct InterConditionalsLattice{L <: AbstractLattice} <: AbstractLattice + parent::L +end +widenlattice(L::InterConditionalsLattice) = L.parent +is_valid_lattice(lattice::InterConditionalsLattice, @nospecialize(elem)) = + is_valid_lattice(widenlattice(lattice), elem) || isa(elem, InterConditional) + +const AnyConditionalsLattice{L} = Union{ConditionalsLattice{L}, InterConditionalsLattice{L}} +const BaseInferenceLattice = typeof(ConditionalsLattice(PartialsLattice(ConstsLattice()))) +const IPOResultLattice = typeof(InterConditionalsLattice(PartialsLattice(ConstsLattice()))) + +""" + struct InferenceLattice{L} + +The full lattice used for abstract interpretation during inference. Takes +a base lattice and adjoins `LimitedAccuracy`. +""" +struct InferenceLattice{L} <: AbstractLattice + parent::L +end +widenlattice(L::InferenceLattice) = L.parent +is_valid_lattice(lattice::InferenceLattice, @nospecialize(elem)) = + is_valid_lattice(widenlattice(lattice), elem) || isa(elem, LimitedAccuracy) + +""" + struct OptimizerLattice + +The lattice used by the optimizer. Extends +`BaseInferenceLattice` with `MaybeUndef`. +""" +struct OptimizerLattice <: AbstractLattice; end +widenlattice(L::OptimizerLattice) = BaseInferenceLattice.instance +is_valid_lattice(lattice::OptimizerLattice, @nospecialize(elem)) = + is_valid_lattice(widenlattice(lattice), elem) || isa(elem, MaybeUndef) + +""" + tmeet(lattice, a, b::Type) + +Compute the lattice meet of lattice elements `a` and `b` over the lattice +`lattice`. If `lattice` is `JLTypeLattice`, this is equivalent to type +intersection. Note that currently `b` is restricted to being a type (interpreted +as a lattice element in the JLTypeLattice sub-lattice of `lattice`). +""" +function tmeet end + +function tmeet(::JLTypeLattice, @nospecialize(a::Type), @nospecialize(b::Type)) + ti = typeintersect(a, b) + valid_as_lattice(ti) || return Bottom + return ti +end + +""" + tmerge(lattice, a, b) + +Compute a lattice join of elements `a` and `b` over the lattice `lattice`. +Note that the computed element need not be the least upper bound of `a` and +`b`, but rather, we impose additional limitations on the complexity of the +joined element, ideally without losing too much precision in common cases and +remaining mostly associative and commutative. +""" +function tmerge end + +""" + ⊑(lattice, a, b) + +Compute the lattice ordering (i.e. less-than-or-equal) relationship between +lattice elements `a` and `b` over the lattice `lattice`. If `lattice` is +`JLTypeLattice`, this is equivalent to subtyping. +""" +function ⊑ end + +⊑(::JLTypeLattice, @nospecialize(a::Type), @nospecialize(b::Type)) = a <: b + +""" + ⊏(lattice, a, b) -> Bool + +The strict partial order over the type inference lattice. +This is defined as the irreflexive kernel of `⊑`. +""" +⊏(lattice::AbstractLattice, @nospecialize(a), @nospecialize(b)) = ⊑(lattice, a, b) && !⊑(lattice, b, a) + +""" + ⋤(lattice, a, b) -> Bool + +This order could be used as a slightly more efficient version of the strict order `⊏`, +where we can safely assume `a ⊑ b` holds. +""" +⋤(lattice::AbstractLattice, @nospecialize(a), @nospecialize(b)) = !⊑(lattice, b, a) + +""" + is_lattice_equal(lattice, a, b) -> Bool + +Check if two lattice elements are partial order equivalent. +This is basically `a ⊑ b && b ⊑ a` but (optionally) with extra performance optimizations. +""" +function is_lattice_equal(lattice::AbstractLattice, @nospecialize(a), @nospecialize(b)) + a === b && return true + ⊑(lattice, a, b) && ⊑(lattice, b, a) +end + +""" + has_nontrivial_const_info(lattice, t) -> Bool + +Determine whether the given lattice element `t` of `lattice` has non-trivial +constant information that would not be available from the type itself. +""" +has_nontrivial_const_info(lattice::AbstractLattice, @nospecialize t) = + has_nontrivial_const_info(widenlattice(lattice), t) +has_nontrivial_const_info(::JLTypeLattice, @nospecialize(t)) = false + +# Curried versions +⊑(lattice::AbstractLattice) = (@nospecialize(a), @nospecialize(b)) -> ⊑(lattice, a, b) +⊏(lattice::AbstractLattice) = (@nospecialize(a), @nospecialize(b)) -> ⊏(lattice, a, b) +⋤(lattice::AbstractLattice) = (@nospecialize(a), @nospecialize(b)) -> ⋤(lattice, a, b) + +# Fallbacks for external packages using these methods +const fallback_lattice = InferenceLattice(BaseInferenceLattice.instance) +const fallback_ipo_lattice = InferenceLattice(IPOResultLattice.instance) + +⊑(@nospecialize(a), @nospecialize(b)) = ⊑(fallback_lattice, a, b) +tmeet(@nospecialize(a), @nospecialize(b)) = tmeet(fallback_lattice, a, b) +tmerge(@nospecialize(a), @nospecialize(b)) = tmerge(fallback_lattice, a, b) +⊏(@nospecialize(a), @nospecialize(b)) = ⊏(fallback_lattice, a, b) +⋤(@nospecialize(a), @nospecialize(b)) = ⋤(fallback_lattice, a, b) +is_lattice_equal(@nospecialize(a), @nospecialize(b)) = is_lattice_equal(fallback_lattice, a, b) diff --git a/base/compiler/bootstrap.jl b/base/compiler/bootstrap.jl index f335cf31a8467..4b79cd57f9d11 100644 --- a/base/compiler/bootstrap.jl +++ b/base/compiler/bootstrap.jl @@ -7,9 +7,7 @@ time() = ccall(:jl_clock_now, Float64, ()) -let - world = get_world_counter() - interp = NativeInterpreter(world) +let interp = NativeInterpreter() analyze_escapes_tt = Tuple{typeof(analyze_escapes), IRCode, Int, Bool, typeof(null_escape_cache)} fs = Any[ diff --git a/base/compiler/compiler.jl b/base/compiler/compiler.jl index a366ee7648ce8..b6e8b2b57e383 100644 --- a/base/compiler/compiler.jl +++ b/base/compiler/compiler.jl @@ -121,10 +121,8 @@ import Core.Compiler.CoreDocs Core.atdoc!(CoreDocs.docm) # sorting -function sort end function sort! end function issorted end -function sortperm end include("ordering.jl") using .Order include("sort.jl") @@ -139,11 +137,11 @@ something(x::Any, y...) = x ############ 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/methodtable.jl") function argextype end # imported by EscapeAnalysis function stmt_effect_free end # imported by EscapeAnalysis @@ -153,6 +151,8 @@ include("compiler/ssair/basicblock.jl") include("compiler/ssair/domtree.jl") include("compiler/ssair/ir.jl") +include("compiler/abstractlattice.jl") + include("compiler/inferenceresult.jl") include("compiler/inferencestate.jl") @@ -164,22 +164,7 @@ include("compiler/stmtinfo.jl") include("compiler/abstractinterpretation.jl") include("compiler/typeinfer.jl") -include("compiler/optimize.jl") # TODO: break this up further + extract utilities - -# required for bootstrap because sort.jl uses extrema -# to decide whether to dispatch to counting sort. -# -# TODO: remove it. -function extrema(x::Array) - isempty(x) && throw(ArgumentError("collection must be non-empty")) - vmin = vmax = x[1] - for i in 2:length(x) - xi = x[i] - vmax = max(vmax, xi) - vmin = min(vmin, xi) - end - return vmin, vmax -end +include("compiler/optimize.jl") include("compiler/bootstrap.jl") ccall(:jl_set_typeinf_func, Cvoid, (Any,), typeinf_ext_toplevel) diff --git a/base/compiler/effects.jl b/base/compiler/effects.jl index 25de6a7d12f02..b935f2ab81385 100644 --- a/base/compiler/effects.jl +++ b/base/compiler/effects.jl @@ -166,6 +166,10 @@ is_removable_if_unused(effects::Effects) = is_terminates(effects) && is_nothrow(effects) +is_finalizer_inlineable(effects::Effects) = + is_nothrow(effects) && + is_notaskstate(effects) + is_consistent_if_notreturned(effects::Effects) = !iszero(effects.consistent & CONSISTENT_IF_NOTRETURNED) is_consistent_if_inaccessiblememonly(effects::Effects) = !iszero(effects.consistent & CONSISTENT_IF_INACCESSIBLEMEMONLY) diff --git a/base/compiler/inferenceresult.jl b/base/compiler/inferenceresult.jl index 1e570b943d968..471502b12d899 100644 --- a/base/compiler/inferenceresult.jl +++ b/base/compiler/inferenceresult.jl @@ -1,10 +1,11 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -function is_argtype_match(@nospecialize(given_argtype), +function is_argtype_match(lattice::AbstractLattice, + @nospecialize(given_argtype), @nospecialize(cache_argtype), overridden_by_const::Bool) if is_forwardable_argtype(given_argtype) - return is_lattice_equal(given_argtype, cache_argtype) + return is_lattice_equal(lattice, given_argtype, cache_argtype) end return !overridden_by_const end @@ -16,6 +17,36 @@ function is_forwardable_argtype(@nospecialize x) isa(x, PartialOpaque) end +function va_process_argtypes(given_argtypes::Vector{Any}, mi::MethodInstance, + condargs::Union{Vector{Tuple{Int,Int}}, Nothing}=nothing) + isva = mi.def.isva + nargs = Int(mi.def.nargs) + if isva || isvarargtype(given_argtypes[end]) + isva_given_argtypes = Vector{Any}(undef, nargs) + for i = 1:(nargs - isva) + isva_given_argtypes[i] = argtype_by_index(given_argtypes, i) + end + if isva + if length(given_argtypes) < nargs && isvarargtype(given_argtypes[end]) + last = length(given_argtypes) + else + last = nargs + end + isva_given_argtypes[nargs] = tuple_tfunc(given_argtypes[last:end]) + # invalidate `Conditional` imposed on varargs + if condargs !== nothing + for (slotid, i) in condargs + if slotid ≥ last + isva_given_argtypes[i] = widenconditional(isva_given_argtypes[i]) + end + end + end + end + return isva_given_argtypes + end + return given_argtypes +end + # In theory, there could be a `cache` containing a matching `InferenceResult` # for the provided `linfo` and `given_argtypes`. The purpose of this function is # to return a valid value for `cache_lookup(linfo, argtypes, cache).argtypes`, @@ -56,35 +87,12 @@ function matching_cache_argtypes( end given_argtypes[i] = widenconditional(argtype) end - isva = def.isva - if isva || isvarargtype(given_argtypes[end]) - isva_given_argtypes = Vector{Any}(undef, nargs) - for i = 1:(nargs - isva) - isva_given_argtypes[i] = argtype_by_index(given_argtypes, i) - end - if isva - if length(given_argtypes) < nargs && isvarargtype(given_argtypes[end]) - last = length(given_argtypes) - else - last = nargs - end - isva_given_argtypes[nargs] = tuple_tfunc(given_argtypes[last:end]) - # invalidate `Conditional` imposed on varargs - if condargs !== nothing - for (slotid, i) in condargs - if slotid ≥ last - isva_given_argtypes[i] = widenconditional(isva_given_argtypes[i]) - end - end - end - end - given_argtypes = isva_given_argtypes - end + given_argtypes = va_process_argtypes(given_argtypes, linfo, condargs) @assert length(given_argtypes) == nargs for i in 1:nargs given_argtype = given_argtypes[i] cache_argtype = cache_argtypes[i] - if !is_argtype_match(given_argtype, cache_argtype, false) + if !is_argtype_match(fallback_lattice, given_argtype, cache_argtype, false) # prefer the argtype we were given over the one computed from `linfo` cache_argtypes[i] = given_argtype overridden_by_const[i] = true @@ -200,7 +208,7 @@ function matching_cache_argtypes(linfo::MethodInstance, ::Nothing) return cache_argtypes, falses(length(cache_argtypes)) end -function cache_lookup(linfo::MethodInstance, given_argtypes::Vector{Any}, cache::Vector{InferenceResult}) +function cache_lookup(lattice::AbstractLattice, linfo::MethodInstance, given_argtypes::Vector{Any}, cache::Vector{InferenceResult}) method = linfo.def::Method nargs::Int = method.nargs method.isva && (nargs -= 1) @@ -211,7 +219,7 @@ function cache_lookup(linfo::MethodInstance, given_argtypes::Vector{Any}, cache: cache_argtypes = cached_result.argtypes cache_overridden_by_const = cached_result.overridden_by_const for i in 1:nargs - if !is_argtype_match(given_argtypes[i], + if !is_argtype_match(lattice, given_argtypes[i], cache_argtypes[i], cache_overridden_by_const[i]) cache_match = false @@ -219,7 +227,7 @@ function cache_lookup(linfo::MethodInstance, given_argtypes::Vector{Any}, cache: end end if method.isva && cache_match - cache_match = is_argtype_match(tuple_tfunc(given_argtypes[(nargs + 1):end]), + cache_match = is_argtype_match(lattice, tuple_tfunc(lattice, given_argtypes[(nargs + 1):end]), cache_argtypes[end], cache_overridden_by_const[end]) end diff --git a/base/compiler/inferencestate.jl b/base/compiler/inferencestate.jl index d81bdccb7fa1c..e1d20f01042c4 100644 --- a/base/compiler/inferencestate.jl +++ b/base/compiler/inferencestate.jl @@ -80,6 +80,12 @@ function in(idx::Int, bsbmp::BitSetBoundedMinPrioritySet) return idx in bsbmp.elems end +function append!(bsbmp::BitSetBoundedMinPrioritySet, itr) + for val in itr + push!(bsbmp, val) + end +end + mutable struct InferenceState #= information about this method instance =# linfo::MethodInstance @@ -206,11 +212,13 @@ end Effects(state::InferenceState) = state.ipo_effects -function merge_effects!(caller::InferenceState, effects::Effects) +function merge_effects!(::AbstractInterpreter, caller::InferenceState, effects::Effects) caller.ipo_effects = merge_effects(caller.ipo_effects, effects) end -merge_effects!(caller::InferenceState, callee::InferenceState) = - merge_effects!(caller, Effects(callee)) + +merge_effects!(interp::AbstractInterpreter, caller::InferenceState, callee::InferenceState) = + merge_effects!(interp, caller, Effects(callee)) +merge_effects!(interp::AbstractInterpreter, caller::IRCode, effects::Effects) = nothing is_effect_overridden(sv::InferenceState, effect::Symbol) = is_effect_overridden(sv.linfo, effect) function is_effect_overridden(linfo::MethodInstance, effect::Symbol) @@ -226,22 +234,22 @@ function InferenceResult( return _InferenceResult(linfo, arginfo) end -add_remark!(::AbstractInterpreter, sv::InferenceState, remark) = return +add_remark!(::AbstractInterpreter, sv::Union{InferenceState, IRCode}, remark) = return -function bail_out_toplevel_call(::AbstractInterpreter, @nospecialize(callsig), sv::InferenceState) - return sv.restrict_abstract_call_sites && !isdispatchtuple(callsig) +function bail_out_toplevel_call(::AbstractInterpreter, @nospecialize(callsig), sv::Union{InferenceState, IRCode}) + return isa(sv, InferenceState) && sv.restrict_abstract_call_sites && !isdispatchtuple(callsig) end -function bail_out_call(::AbstractInterpreter, @nospecialize(rt), sv::InferenceState) +function bail_out_call(::AbstractInterpreter, @nospecialize(rt), sv::Union{InferenceState, IRCode}) return rt === Any end -function bail_out_apply(::AbstractInterpreter, @nospecialize(rt), sv::InferenceState) +function bail_out_apply(::AbstractInterpreter, @nospecialize(rt), sv::Union{InferenceState, IRCode}) return rt === Any end function any_inbounds(code::Vector{Any}) - for i=1:length(code) + for i = 1:length(code) stmt = code[i] - if isa(stmt, Expr) && stmt.head === :inbounds + if isexpr(stmt, :inbounds) return true end end @@ -470,35 +478,49 @@ function record_ssa_assign!(ssa_id::Int, @nospecialize(new), frame::InferenceSta return nothing end -function add_cycle_backedge!(frame::InferenceState, caller::InferenceState, currpc::Int) +function add_cycle_backedge!(caller::InferenceState, frame::InferenceState, currpc::Int) update_valid_age!(frame, caller) backedge = (caller, currpc) contains_is(frame.cycle_backedges, backedge) || push!(frame.cycle_backedges, backedge) - add_backedge!(frame.linfo, caller) + add_backedge!(caller, frame.linfo) return frame end # temporarily accumulate our edges to later add as backedges in the callee -function add_backedge!(li::MethodInstance, caller::InferenceState) - isa(caller.linfo.def, Method) || return # don't add backedges to toplevel exprs - edges = caller.stmt_edges[caller.currpc] - if edges === nothing - edges = caller.stmt_edges[caller.currpc] = [] +function add_backedge!(caller::InferenceState, li::MethodInstance) + edges = get_stmt_edges!(caller) + if edges !== nothing + push!(edges, li) + end + return nothing +end + +function add_invoke_backedge!(caller::InferenceState, @nospecialize(invokesig::Type), li::MethodInstance) + edges = get_stmt_edges!(caller) + if edges !== nothing + push!(edges, invokesig, li) end - push!(edges, li) return nothing end # used to temporarily accumulate our no method errors to later add as backedges in the callee method table -function add_mt_backedge!(mt::Core.MethodTable, @nospecialize(typ), caller::InferenceState) - isa(caller.linfo.def, Method) || return # don't add backedges to toplevel exprs +function add_mt_backedge!(caller::InferenceState, mt::Core.MethodTable, @nospecialize(typ)) + edges = get_stmt_edges!(caller) + if edges !== nothing + push!(edges, mt, typ) + end + return nothing +end + +function get_stmt_edges!(caller::InferenceState) + if !isa(caller.linfo.def, Method) + return nothing # don't add backedges to toplevel exprs + end edges = caller.stmt_edges[caller.currpc] if edges === nothing edges = caller.stmt_edges[caller.currpc] = [] end - push!(edges, mt) - push!(edges, typ) - return nothing + return edges end function empty_backedges!(frame::InferenceState, currpc::Int = frame.currpc) diff --git a/base/compiler/methodtable.jl b/base/compiler/methodtable.jl index 7aa686009c1af..93ea00da4986e 100644 --- a/base/compiler/methodtable.jl +++ b/base/compiler/methodtable.jl @@ -2,6 +2,27 @@ abstract type MethodTableView; end +struct MethodLookupResult + # Really Vector{Core.MethodMatch}, but it's easier to represent this as + # and work with Vector{Any} on the C side. + matches::Vector{Any} + valid_worlds::WorldRange + ambig::Bool +end +length(result::MethodLookupResult) = length(result.matches) +function iterate(result::MethodLookupResult, args...) + r = iterate(result.matches, args...) + r === nothing && return nothing + match, state = r + return (match::MethodMatch, state) +end +getindex(result::MethodLookupResult, idx::Int) = getindex(result.matches, idx)::MethodMatch + +struct MethodMatchResult + matches::MethodLookupResult + overlayed::Bool +end + """ struct InternalMethodTable <: MethodTableView @@ -23,55 +44,60 @@ struct OverlayMethodTable <: MethodTableView mt::Core.MethodTable end -struct MethodLookupResult - # Really Vector{Core.MethodMatch}, but it's easier to represent this as - # and work with Vector{Any} on the C side. - matches::Vector{Any} - valid_worlds::WorldRange - ambig::Bool +struct MethodMatchKey + sig # ::Type + limit::Int + MethodMatchKey(@nospecialize(sig), limit::Int) = new(sig, limit) end -length(result::MethodLookupResult) = length(result.matches) -function iterate(result::MethodLookupResult, args...) - r = iterate(result.matches, args...) - r === nothing && return nothing - match, state = r - return (match::MethodMatch, state) + +""" + struct CachedMethodTable <: MethodTableView + +Overlays another method table view with an additional local fast path cache that +can respond to repeated, identical queries faster than the original method table. +""" +struct CachedMethodTable{T} <: MethodTableView + cache::IdDict{MethodMatchKey, Union{Missing,MethodMatchResult}} + table::T end -getindex(result::MethodLookupResult, idx::Int) = getindex(result.matches, idx)::MethodMatch +CachedMethodTable(table::T) where T = CachedMethodTable{T}(IdDict{MethodMatchKey, Union{Missing,MethodMatchResult}}(), table) """ - findall(sig::Type, view::MethodTableView; limit::Int=typemax(Int)) -> - (matches::MethodLookupResult, overlayed::Bool) or missing + findall(sig::Type, view::MethodTableView; limit::Int=-1) -> + MethodMatchResult(matches::MethodLookupResult, overlayed::Bool) or missing Find all methods in the given method table `view` that are applicable to the given signature `sig`. If no applicable methods are found, an empty result is returned. -If the number of applicable methods exceeded the specified limit, `missing` is returned. +If the number of applicable methods exceeded the specified `limit`, `missing` is returned. +Note that the default setting `limit=-1` does not limit the number of applicable methods. `overlayed` indicates if any of the matching methods comes from an overlayed method table. """ -function findall(@nospecialize(sig::Type), table::InternalMethodTable; limit::Int=Int(typemax(Int32))) +function findall(@nospecialize(sig::Type), table::InternalMethodTable; limit::Int=-1) result = _findall(sig, nothing, table.world, limit) result === missing && return missing - return result, false + return MethodMatchResult(result, false) end -function findall(@nospecialize(sig::Type), table::OverlayMethodTable; limit::Int=Int(typemax(Int32))) +function findall(@nospecialize(sig::Type), table::OverlayMethodTable; limit::Int=-1) result = _findall(sig, table.mt, table.world, limit) result === missing && return missing nr = length(result) if nr ≥ 1 && result[nr].fully_covers # no need to fall back to the internal method table - return result, true + return MethodMatchResult(result, true) end # fall back to the internal method table fallback_result = _findall(sig, nothing, table.world, limit) fallback_result === missing && return missing # merge the fallback match results with the internal method table - return MethodLookupResult( - vcat(result.matches, fallback_result.matches), - WorldRange( - max(result.valid_worlds.min_world, fallback_result.valid_worlds.min_world), - min(result.valid_worlds.max_world, fallback_result.valid_worlds.max_world)), - result.ambig | fallback_result.ambig), !isempty(result) + return MethodMatchResult( + MethodLookupResult( + vcat(result.matches, fallback_result.matches), + WorldRange( + max(result.valid_worlds.min_world, fallback_result.valid_worlds.min_world), + min(result.valid_worlds.max_world, fallback_result.valid_worlds.max_world)), + result.ambig | fallback_result.ambig), + !isempty(result)) end function _findall(@nospecialize(sig::Type), mt::Union{Nothing,Core.MethodTable}, world::UInt, limit::Int) @@ -85,6 +111,19 @@ function _findall(@nospecialize(sig::Type), mt::Union{Nothing,Core.MethodTable}, return MethodLookupResult(ms::Vector{Any}, WorldRange(_min_val[], _max_val[]), _ambig[] != 0) end +function findall(@nospecialize(sig::Type), table::CachedMethodTable; limit::Int=-1) + if isconcretetype(sig) + # as for concrete types, we cache result at on the next level + return findall(sig, table.table; limit) + end + key = MethodMatchKey(sig, limit) + if haskey(table.cache, key) + return table.cache[key] + else + return table.cache[key] = findall(sig, table.table; limit) + end +end + """ findsup(sig::Type, view::MethodTableView) -> (match::MethodMatch, valid_worlds::WorldRange, overlayed::Bool) or nothing @@ -129,6 +168,10 @@ function _findsup(@nospecialize(sig::Type), mt::Union{Nothing,Core.MethodTable}, return match, valid_worlds end +# This query is not cached +findsup(@nospecialize(sig::Type), table::CachedMethodTable) = findsup(sig, table.table) + isoverlayed(::MethodTableView) = error("unsatisfied MethodTableView interface") isoverlayed(::InternalMethodTable) = false isoverlayed(::OverlayMethodTable) = true +isoverlayed(mt::CachedMethodTable) = isoverlayed(mt.table) diff --git a/base/compiler/optimize.jl b/base/compiler/optimize.jl index e9c37a3054352..3f0f7e4522654 100644 --- a/base/compiler/optimize.jl +++ b/base/compiler/optimize.jl @@ -24,11 +24,14 @@ const IR_FLAG_INLINE = 0x01 << 1 # This statement is marked as @noinline by user const IR_FLAG_NOINLINE = 0x01 << 2 const IR_FLAG_THROW_BLOCK = 0x01 << 3 -# This statement may be removed if its result is unused. In particular it must -# thus be both pure and effect free. +# This statement may be removed if its result is unused. In particular, +# it must be both :effect_free and :nothrow. +# TODO: Separate these out. const IR_FLAG_EFFECT_FREE = 0x01 << 4 # This statement was proven not to throw const IR_FLAG_NOTHROW = 0x01 << 5 +# This is :consistent +const IR_FLAG_CONSISTENT = 0x01 << 6 const TOP_TUPLE = GlobalRef(Core, :tuple) @@ -61,10 +64,13 @@ EdgeTracker() = EdgeTracker(Any[], 0:typemax(UInt)) intersect!(et::EdgeTracker, range::WorldRange) = et.valid_worlds[] = intersect(et.valid_worlds[], range) -push!(et::EdgeTracker, mi::MethodInstance) = push!(et.edges, mi) -function push!(et::EdgeTracker, ci::CodeInstance) - intersect!(et, WorldRange(min_world(li), max_world(li))) - push!(et, ci.def) +function add_backedge!(et::EdgeTracker, mi::MethodInstance) + push!(et.edges, mi) + return nothing +end +function add_invoke_backedge!(et::EdgeTracker, @nospecialize(invokesig), mi::MethodInstance) + push!(et.edges, invokesig, mi) + return nothing end struct InliningState{S <: Union{EdgeTracker, Nothing}, MICache, I<:AbstractInterpreter} @@ -88,7 +94,7 @@ function inlining_policy(interp::AbstractInterpreter, @nospecialize(src), stmt_f # inferred source in the local cache # we still won't find a source for recursive call because the "single-level" inlining # seems to be more trouble and complex than it's worth - inf_result = cache_lookup(mi, argtypes, get_inference_cache(interp)) + inf_result = cache_lookup(optimizer_lattice(interp), mi, argtypes, get_inference_cache(interp)) inf_result === nothing && return nothing src = inf_result.src if isa(src, CodeInfo) @@ -148,7 +154,7 @@ mutable struct OptimizationState # This method is mostly used for unit testing the optimizer inlining = InliningState(params, nothing, - WorldView(code_cache(interp), get_world_counter()), + WorldView(code_cache(interp), get_world_counter(interp)), interp) return new(linfo, src, nothing, stmt_info, mod, sptypes, slottypes, inlining, nothing) @@ -201,21 +207,23 @@ function stmt_affects_purity(@nospecialize(stmt), ir) end """ - stmt_effect_flags(stmt, rt, src::Union{IRCode,IncrementalCompact}) + stmt_effect_flags(stmt, rt, src::Union{IRCode,IncrementalCompact}) -> + (consistent::Bool, effect_free_and_nothrow::Bool, nothrow::Bool) -Returns a tuple of (effect_free_and_nothrow, nothrow) for a given statement. +Returns a tuple of `(:consistent, :effect_free_and_nothrow, :nothrow)` flags for a given statement. """ -function stmt_effect_flags(@nospecialize(stmt), @nospecialize(rt), src::Union{IRCode,IncrementalCompact}) +function stmt_effect_flags(lattice::AbstractLattice, @nospecialize(stmt), @nospecialize(rt), src::Union{IRCode,IncrementalCompact}) # TODO: We're duplicating analysis from inference here. - isa(stmt, PiNode) && return (true, true) - isa(stmt, PhiNode) && return (true, true) - isa(stmt, ReturnNode) && return (false, true) - isa(stmt, GotoNode) && return (false, true) - isa(stmt, GotoIfNot) && return (false, argextype(stmt.cond, src) ⊑ Bool) - isa(stmt, Slot) && return (false, false) # Slots shouldn't occur in the IR at this point, but let's be defensive here + isa(stmt, PiNode) && return (true, true, true) + isa(stmt, PhiNode) && return (true, true, true) + isa(stmt, ReturnNode) && return (true, false, true) + isa(stmt, GotoNode) && return (true, false, true) + isa(stmt, GotoIfNot) && return (true, false, argextype(stmt.cond, src) ⊑ₒ Bool) + isa(stmt, Slot) && return (true, false, false) # Slots shouldn't occur in the IR at this point, but let's be defensive here if isa(stmt, GlobalRef) nothrow = isdefined(stmt.mod, stmt.name) - return (nothrow, nothrow) + consistent = nothrow && isconst(stmt.mod, stmt.name) + return (consistent, nothrow, nothrow) end if isa(stmt, Expr) (; head, args) = stmt @@ -223,72 +231,85 @@ function stmt_effect_flags(@nospecialize(stmt), @nospecialize(rt), src::Union{IR etyp = (isa(src, IRCode) ? src.sptypes : src.ir.sptypes)[args[1]::Int] # if we aren't certain enough about the type, it might be an UndefVarError at runtime nothrow = isa(etyp, Const) - return (nothrow, nothrow) + return (true, nothrow, nothrow) end if head === :call f = argextype(args[1], src) f = singleton_type(f) - f === nothing && return (false, false) - if isa(f, IntrinsicFunction) - nothrow = intrinsic_nothrow(f, - Any[argextype(args[i], src) for i = 2:length(args)]) - nothrow || return (false, false) - return (intrinsic_effect_free_if_nothrow(f), nothrow) - end - contains_is(_PURE_BUILTINS, f) && return (true, true) - # `get_binding_type` sets the type to Any if the binding doesn't exist yet - if f === Core.get_binding_type - length(args) == 3 || return false - M, s = argextype(args[2], src), argextype(args[3], src) - total = get_binding_type_effect_free(M, s) - return (total, total) + f === nothing && return (false, false, false) + if f === UnionAll + # TODO: This is a weird special case - should be determined in inference + argtypes = Any[argextype(args[arg], src) for arg in 2:length(args)] + nothrow = _builtin_nothrow(lattice, f, argtypes, rt) + return (true, nothrow, nothrow) end - rt === Bottom && return (false, false) - nothrow = _builtin_nothrow(f, Any[argextype(args[i], src) for i = 2:length(args)], rt) - nothrow || return (false, false) - return (contains_is(_EFFECT_FREE_BUILTINS, f), nothrow) + isa(f, Builtin) || return (false, false, false) + # Needs to be handled in inlining to look at the callee effects + f === Core._apply_iterate && return (false, false, false) + argtypes = Any[argextype(args[arg], src) for arg in 2:length(args)] + effects = builtin_effects(lattice, f, argtypes, rt) + consistent = is_consistent(effects) + effect_free = is_effect_free(effects) + nothrow = is_nothrow(effects) + return (consistent, effect_free & nothrow, nothrow) elseif head === :new - typ = argextype(args[1], src) + atyp = argextype(args[1], src) # `Expr(:new)` of unknown type could raise arbitrary TypeError. - typ, isexact = instanceof_tfunc(typ) - isexact || return (false, false) - isconcretedispatch(typ) || return (false, false) + typ, isexact = instanceof_tfunc(atyp) + if !isexact + atyp = unwrap_unionall(widenconst(atyp)) + if isType(atyp) && isTypeDataType(atyp.parameters[1]) + typ = atyp.parameters[1] + else + return (false, false, false) + end + isabstracttype(typ) && return (false, false, false) + else + isconcretedispatch(typ) || return (false, false, false) + end typ = typ::DataType - fieldcount(typ) >= length(args) - 1 || return (false, false) + fieldcount(typ) >= length(args) - 1 || return (false, false, false) for fld_idx in 1:(length(args) - 1) eT = argextype(args[fld_idx + 1], src) fT = fieldtype(typ, fld_idx) - eT ⊑ fT || return (false, false) + # Currently, we cannot represent any type equality constraints + # in the lattice, so if we see any type of type parameter, + # there is very little we can say about it + if !isexact && has_free_typevars(fT) + return (false, false, false) + end + eT ⊑ₒ fT || return (false, false, false) end - return (true, true) + return (false, true, true) elseif head === :foreigncall effects = foreigncall_effects(stmt) do @nospecialize x argextype(x, src) end + consistent = is_consistent(effects) effect_free = is_effect_free(effects) nothrow = is_nothrow(effects) - return (effect_free & nothrow, nothrow) + return (consistent, effect_free & nothrow, nothrow) elseif head === :new_opaque_closure - length(args) < 4 && return (false, false) + length(args) < 4 && return (false, false, false) typ = argextype(args[1], src) typ, isexact = instanceof_tfunc(typ) - isexact || return (false, false) - typ ⊑ Tuple || return (false, false) + isexact || return (false, false, false) + typ ⊑ₒ Tuple || return (false, false, false) rt_lb = argextype(args[2], src) rt_ub = argextype(args[3], src) source = argextype(args[4], src) - if !(rt_lb ⊑ Type && rt_ub ⊑ Type && source ⊑ Method) - return (false, false) + if !(rt_lb ⊑ₒ Type && rt_ub ⊑ₒ Type && source ⊑ₒ Method) + return (false, false, false) end - return (true, true) + return (false, true, true) elseif head === :isdefined || head === :the_exception || head === :copyast || head === :inbounds || head === :boundscheck - return (true, true) + return (true, true, true) else # e.g. :loopinfo - return (false, false) + return (false, false, false) end end - return (true, true) + return (true, true, true) end """ @@ -329,7 +350,7 @@ function argextype( elseif isa(x, QuoteNode) return Const(x.value) elseif isa(x, GlobalRef) - return abstract_eval_global(x.mod, x.name) + return abstract_eval_globalref(x) elseif isa(x, PhiNode) return Any elseif isa(x, PiNode) @@ -379,7 +400,7 @@ function finish(interp::AbstractInterpreter, opt::OptimizationState, for i in 1:length(ir.stmts) node = ir.stmts[i] stmt = node[:inst] - if stmt_affects_purity(stmt, ir) && !stmt_effect_flags(stmt, node[:type], ir)[1] + if stmt_affects_purity(stmt, ir) && !stmt_effect_flags(optimizer_lattice(interp), stmt, node[:type], ir)[2] proven_pure = false break end @@ -444,7 +465,7 @@ function finish(interp::AbstractInterpreter, opt::OptimizationState, else # compute the cost (size) of inlining this code cost_threshold = default = params.inline_cost_threshold - if result ⊑ Tuple && !isconcretetype(widenconst(result)) + if ⊑(optimizer_lattice(interp), result, Tuple) && !isconcretetype(widenconst(result)) cost_threshold += params.inline_tupleret_bonus end # if the method is declared as `@inline`, increase the cost threshold 20x diff --git a/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl b/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl index 272ea0e8edbbc..a60cfde597f4c 100644 --- a/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl +++ b/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl @@ -27,11 +27,11 @@ import ._TOP_MOD: # Base definitions pop!, push!, pushfirst!, empty!, delete!, max, min, enumerate, unwrap_unionall, ismutabletype import Core.Compiler: # Core.Compiler specific definitions - Bottom, InferenceResult, IRCode, IR_FLAG_EFFECT_FREE, + Bottom, InferenceResult, IRCode, IR_FLAG_NOTHROW, isbitstype, isexpr, is_meta_expr_head, println, widenconst, argextype, singleton_type, fieldcount_noerror, try_compute_field, try_compute_fieldidx, hasintersect, ⊑, intrinsic_nothrow, array_builtin_common_typecheck, arrayset_typecheck, - setfield!_nothrow, alloc_array_ndims, check_effect_free! + setfield!_nothrow, alloc_array_ndims, stmt_effect_free, check_effect_free! include(x) = _TOP_MOD.include(@__MODULE__, x) if _TOP_MOD === Core.Compiler @@ -772,7 +772,7 @@ A preparatory linear scan before the escape analysis on `ir` to find: This array dimension analysis to compute `arrayinfo` is very local and doesn't account for flow-sensitivity nor complex aliasing. Ideally this dimension analysis should be done as a part of type inference that - propagates array dimenstions in a flow sensitive way. + propagates array dimensions in a flow sensitive way. """ function compute_frameinfo(ir::IRCode, call_resolved::Bool) nstmts, nnewnodes = length(ir.stmts), length(ir.new_nodes.stmts) @@ -1078,7 +1078,7 @@ end error("unexpected assignment found: inspect `Main.pc` and `Main.pc`") end -is_effect_free(ir::IRCode, pc::Int) = getinst(ir, pc)[:flag] & IR_FLAG_EFFECT_FREE ≠ 0 +is_nothrow(ir::IRCode, pc::Int) = getinst(ir, pc)[:flag] & IR_FLAG_NOTHROW ≠ 0 # NOTE if we don't maintain the alias set that is separated from the lattice state, we can do # something like below: it essentially incorporates forward escape propagation in our default @@ -1259,7 +1259,7 @@ function escape_foreigncall!(astate::AnalysisState, pc::Int, args::Vector{Any}) # end end # NOTE array allocations might have been proven as nothrow (https://github.com/JuliaLang/julia/pull/43565) - nothrow = is_effect_free(astate.ir, pc) + nothrow = is_nothrow(astate.ir, pc) name_info = nothrow ? ⊥ : ThrownEscape(pc) add_escape_change!(astate, name, name_info) add_liveness_change!(astate, name, pc) @@ -1335,7 +1335,7 @@ function escape_call!(astate::AnalysisState, pc::Int, args::Vector{Any}) # we escape statements with the `ThrownEscape` property using the effect-freeness # computed by `stmt_effect_flags` invoked within inlining # TODO throwness ≠ "effect-free-ness" - if is_effect_free(astate.ir, pc) + if is_nothrow(astate.ir, pc) add_liveness_changes!(astate, pc, args, 2) else add_fallback_changes!(astate, pc, args, 2) @@ -1441,7 +1441,7 @@ function escape_new!(astate::AnalysisState, pc::Int, args::Vector{Any}) add_liveness_change!(astate, arg, pc) end end - if !is_effect_free(astate.ir, pc) + if !is_nothrow(astate.ir, pc) add_thrown_escapes!(astate, pc, args) end end @@ -1503,6 +1503,8 @@ function escape_builtin!(::typeof(getfield), astate::AnalysisState, pc::Int, arg if isa(obj, SSAValue) || isa(obj, Argument) objinfo = estate[obj] else + # unanalyzable object, so the return value is also unanalyzable + add_escape_change!(astate, SSAValue(pc), ⊤) return false end AliasInfo = objinfo.AliasInfo @@ -1622,6 +1624,8 @@ function escape_builtin!(::typeof(arrayref), astate::AnalysisState, pc::Int, arg if isa(ary, SSAValue) || isa(ary, Argument) aryinfo = estate[ary] else + # unanalyzable object, so the return value is also unanalyzable + add_escape_change!(astate, SSAValue(pc), ⊤) return true end AliasInfo = aryinfo.AliasInfo @@ -1875,13 +1879,13 @@ end # # COMBAK do we want to enable this (and also backport this to Base for array allocations?) # import Core.Compiler: Cint, svec # function validate_foreigncall_args(args::Vector{Any}, -# name::Symbol, @nospecialize(rt), argtypes::SimpleVector, nreq::Int, convension::Symbol) +# name::Symbol, @nospecialize(rt), argtypes::SimpleVector, nreq::Int, convention::Symbol) # length(args) ≥ 5 || return false # normalize(args[1]) === name || return false # args[2] === rt || return false # args[3] === argtypes || return false # args[4] === vararg || return false -# normalize(args[5]) === convension || return false +# normalize(args[5]) === convention || return false # return true # end diff --git a/base/compiler/ssair/EscapeAnalysis/interprocedural.jl b/base/compiler/ssair/EscapeAnalysis/interprocedural.jl index 5d75db990e6f4..dcbc37df84635 100644 --- a/base/compiler/ssair/EscapeAnalysis/interprocedural.jl +++ b/base/compiler/ssair/EscapeAnalysis/interprocedural.jl @@ -1,7 +1,7 @@ # TODO this file contains many duplications with the inlining analysis code, factor them out import Core.Compiler: - MethodInstance, InferenceResult, Signature, ConstPropResult, ConcreteResult, + MethodInstance, InferenceResult, Signature, ConstPropResult, ConcreteResult, SemiConcreteResult, MethodResultPure, MethodMatchInfo, UnionSplitInfo, ConstCallInfo, InvokeCallInfo, call_sig, argtypes_to_type, is_builtin, is_return_type, istopfunction, validate_sparams, specialize_method, invoke_rewrite @@ -64,6 +64,10 @@ function analyze_invoke_call(sig::Signature, info::InvokeCallInfo) result = info.result if isa(result, ConstPropResult) return CallInfo(Linfo[result.result], true) + elseif isa(result, ConcreteResult) + return CallInfo(Linfo[result.mi], true) + elseif isa(result, SemiConcreteResult) + return CallInfo(Linfo[result.mi], true) else argtypes = invoke_rewrite(sig.argtypes) mi = analyze_match(match, length(argtypes)) @@ -98,6 +102,8 @@ function analyze_const_call(sig::Signature, cinfo::ConstCallInfo) elseif isa(result, ConcreteResult) # TODO we may want to feedback information that this call always throws if !isdefined(result, :result) push!(linfos, result.mi) + elseif isa(result, SemiConcreteResult) + push!(linfos, result.mi) elseif isa(result, ConstPropResult) push!(linfos, result.result) end diff --git a/base/compiler/ssair/domtree.jl b/base/compiler/ssair/domtree.jl index 984de95a4b58d..eaa21b52aa811 100644 --- a/base/compiler/ssair/domtree.jl +++ b/base/compiler/ssair/domtree.jl @@ -109,10 +109,16 @@ end length(D::DFSTree) = length(D.from_pre) -function DFS!(D::DFSTree, blocks::Vector{BasicBlock}) +function DFS!(D::DFSTree, blocks::Vector{BasicBlock}, is_post_dominator::Bool) copy!(D, DFSTree(length(blocks))) - to_visit = Tuple{BBNumber, PreNumber, Bool}[(1, 0, false)] - pre_num = 1 + if is_post_dominator + # TODO: We're using -1 as the virtual exit node here. Would it make + # sense to actually have a real BB for the exit always? + to_visit = Tuple{BBNumber, PreNumber, Bool}[(-1, 0, false)] + else + to_visit = Tuple{BBNumber, PreNumber, Bool}[(1, 0, false)] + end + pre_num = is_post_dominator ? 0 : 1 post_num = 1 while !isempty(to_visit) # Because we want the postorder number as well as the preorder number, @@ -123,12 +129,14 @@ function DFS!(D::DFSTree, blocks::Vector{BasicBlock}) if pushed_children # Going up the DFS tree, so all we need to do is record the # postorder number, then move on - D.to_post[current_node_bb] = post_num - D.from_post[post_num] = current_node_bb + if current_node_bb != -1 + D.to_post[current_node_bb] = post_num + D.from_post[post_num] = current_node_bb + end post_num += 1 pop!(to_visit) - elseif D.to_pre[current_node_bb] != 0 + elseif current_node_bb != -1 && D.to_pre[current_node_bb] != 0 # Node has already been visited, move on pop!(to_visit) continue @@ -136,15 +144,24 @@ function DFS!(D::DFSTree, blocks::Vector{BasicBlock}) # Going down the DFS tree # Record preorder number - D.to_pre[current_node_bb] = pre_num - D.from_pre[pre_num] = current_node_bb - D.to_parent_pre[pre_num] = parent_pre + if current_node_bb != -1 + D.to_pre[current_node_bb] = pre_num + D.from_pre[pre_num] = current_node_bb + D.to_parent_pre[pre_num] = parent_pre + end # Record that children (will) have been pushed to_visit[end] = (current_node_bb, parent_pre, true) + if is_post_dominator && current_node_bb == -1 + edges = Int[bb for bb in 1:length(blocks) if isempty(blocks[bb].succs)] + else + edges = is_post_dominator ? blocks[current_node_bb].preds : + blocks[current_node_bb].succs + end + # Push children to the stack - for succ_bb in blocks[current_node_bb].succs + for succ_bb in edges push!(to_visit, (succ_bb, pre_num, false)) end @@ -161,7 +178,7 @@ function DFS!(D::DFSTree, blocks::Vector{BasicBlock}) return D end -DFS(blocks::Vector{BasicBlock}) = DFS!(DFSTree(0), blocks) +DFS(blocks::Vector{BasicBlock}, is_post_dominator::Bool=false) = DFS!(DFSTree(0), blocks, is_post_dominator) """ Keeps the per-BB state of the Semi NCA algorithm. In the original formulation, @@ -184,7 +201,7 @@ end DomTreeNode() = DomTreeNode(1, Vector{BBNumber}()) "Data structure that encodes which basic block dominates which." -struct DomTree +struct GenericDomTree{IsPostDom} # These can be reused when updating domtree dynamically dfs_tree::DFSTree snca_state::Vector{SNCAData} @@ -195,19 +212,25 @@ struct DomTree # The nodes in the tree (ordered by BB indices) nodes::Vector{DomTreeNode} end +const DomTree = GenericDomTree{false} +const PostDomTree = GenericDomTree{true} -function DomTree() - return DomTree(DFSTree(0), SNCAData[], BBNumber[], DomTreeNode[]) +function (T::Type{<:GenericDomTree})() + return T(DFSTree(0), SNCAData[], BBNumber[], DomTreeNode[]) end function construct_domtree(blocks::Vector{BasicBlock}) return update_domtree!(blocks, DomTree(), true, 0) end -function update_domtree!(blocks::Vector{BasicBlock}, domtree::DomTree, - recompute_dfs::Bool, max_pre::PreNumber) +function construct_postdomtree(blocks::Vector{BasicBlock}) + return update_domtree!(blocks, PostDomTree(), true, 0) +end + +function update_domtree!(blocks::Vector{BasicBlock}, domtree::GenericDomTree{IsPostDom}, + recompute_dfs::Bool, max_pre::PreNumber) where {IsPostDom} if recompute_dfs - DFS!(domtree.dfs_tree, blocks) + DFS!(domtree.dfs_tree, blocks, IsPostDom) end if max_pre == 0 @@ -219,17 +242,24 @@ function update_domtree!(blocks::Vector{BasicBlock}, domtree::DomTree, return domtree end -function compute_domtree_nodes!(domtree::DomTree) +function compute_domtree_nodes!(domtree::GenericDomTree{IsPostDom}) where {IsPostDom} # Compute children copy!(domtree.nodes, DomTreeNode[DomTreeNode() for _ in 1:length(domtree.idoms_bb)]) for (idx, idom) in Iterators.enumerate(domtree.idoms_bb) - (idx == 1 || idom == 0) && continue + ((!IsPostDom && idx == 1) || idom == 0) && continue push!(domtree.nodes[idom].children, idx) end # n.b. now issorted(domtree.nodes[*].children) since idx is sorted above # Recursively set level - update_level!(domtree.nodes, 1, 1) + if IsPostDom + for (node, idom) in enumerate(domtree.idoms_bb) + idom == 0 || continue + update_level!(domtree.nodes, node, 1) + end + else + update_level!(domtree.nodes, 1, 1) + end return domtree.nodes end @@ -244,13 +274,18 @@ function update_level!(nodes::Vector{DomTreeNode}, node::BBNumber, level::Int) end end +dom_edges(domtree::DomTree, blocks::Vector{BasicBlock}, idx::BBNumber) = + blocks[idx].preds +dom_edges(domtree::PostDomTree, blocks::Vector{BasicBlock}, idx::BBNumber) = + blocks[idx].succs + """ The main Semi-NCA algorithm. Matches Figure 2.8 in [LG05]. Note that the pseudocode in [LG05] is not entirely accurate. The best way to understand what's happening is to read [LT79], then the description of SLT in [LG05] (warning: inconsistent notation), then the description of Semi-NCA. """ -function SNCA!(domtree::DomTree, blocks::Vector{BasicBlock}, max_pre::PreNumber) +function SNCA!(domtree::GenericDomTree{IsPostDom}, blocks::Vector{BasicBlock}, max_pre::PreNumber) where {IsPostDom} D = domtree.dfs_tree state = domtree.snca_state # There may be more blocks than are reachable in the DFS / dominator tree @@ -289,13 +324,14 @@ function SNCA!(domtree::DomTree, blocks::Vector{BasicBlock}, max_pre::PreNumber) # Calculate semidominators, but only for blocks with preorder number up to # max_pre ancestors = copy(D.to_parent_pre) - for w::PreNumber in reverse(2:max_pre) + relevant_blocks = IsPostDom ? (1:max_pre) : (2:max_pre) + for w::PreNumber in reverse(relevant_blocks) # LLVM initializes this to the parent, the paper initializes this to # `w`, but it doesn't really matter (the parent is a predecessor, so at # worst we'll discover it below). Save a memory reference here. semi_w = typemax(PreNumber) last_linked = PreNumber(w + 1) - for v ∈ blocks[D.from_pre[w]].preds + for v ∈ dom_edges(domtree, blocks, D.from_pre[w]) # For the purpose of the domtree, ignore virtual predecessors into # catch blocks. v == 0 && continue @@ -331,7 +367,7 @@ function SNCA!(domtree::DomTree, blocks::Vector{BasicBlock}, max_pre::PreNumber) # ancestor in the (immediate) dominator tree between its semidominator and # its parent (see Lemma 2.6 in [LG05]). idoms_pre = copy(D.to_parent_pre) - for v in 2:n_nodes + for v in (IsPostDom ? (1:n_nodes) : (2:n_nodes)) idom = idoms_pre[v] vsemi = state[v].semi while idom > vsemi @@ -343,10 +379,11 @@ function SNCA!(domtree::DomTree, blocks::Vector{BasicBlock}, max_pre::PreNumber) # Express idoms in BB indexing resize!(domtree.idoms_bb, n_blocks) for i::BBNumber in 1:n_blocks - if i == 1 || D.to_pre[i] == 0 + if (!IsPostDom && i == 1) || D.to_pre[i] == 0 domtree.idoms_bb[i] = 0 else - domtree.idoms_bb[i] = D.from_pre[idoms_pre[D.to_pre[i]]] + ip = idoms_pre[D.to_pre[i]] + domtree.idoms_bb[i] = ip == 0 ? 0 : D.from_pre[ip] end end end @@ -542,12 +579,28 @@ function rename_nodes!(D::DFSTree, rename_bb::Vector{BBNumber}) end """ -Checks if bb1 dominates bb2. -bb1 and bb2 are indexes into the CFG blocks. -bb1 dominates bb2 if the only way to enter bb2 is via bb1. -(Other blocks may be in between, e.g bb1->bbX->bb2). + dominates(domtree::DomTree, bb1::Int, bb2::Int) -> Bool + +Checks if `bb1` dominates `bb2`. +`bb1` and `bb2` are indexes into the `CFG` blocks. +`bb1` dominates `bb2` if the only way to enter `bb2` is via `bb1`. +(Other blocks may be in between, e.g `bb1->bbx->bb2`). +""" +dominates(domtree::DomTree, bb1::BBNumber, bb2::BBNumber) = + _dominates(domtree, bb1, bb2) + +""" + postdominates(domtree::DomTree, bb1::Int, bb2::Int) -> Bool + +Checks if `bb1` post-dominates `bb2`. +`bb1` and `bb2` are indexes into the `CFG` blocks. +`bb1` post-dominates `bb2` if every pass from `bb2` to the exit is via `bb1`. +(Other blocks may be in between, e.g `bb2->bbx->bb1->exit`). """ -function dominates(domtree::DomTree, bb1::BBNumber, bb2::BBNumber) +postdominates(domtree::PostDomTree, bb1::BBNumber, bb2::BBNumber) = + _dominates(domtree, bb1, bb2) + +function _dominates(domtree::GenericDomTree, bb1::BBNumber, bb2::BBNumber) bb1 == bb2 && return true target_level = domtree.nodes[bb1].level source_level = domtree.nodes[bb2].level @@ -582,19 +635,48 @@ function iterate(doms::DominatedBlocks, state::Nothing=nothing) return (bb, nothing) end -function naive_idoms(blocks::Vector{BasicBlock}) +""" + nearest_common_dominator(domtree::GenericDomTree, a::BBNumber, b::BBNumber) + +Compute the nearest common (post-)dominator of `a` and `b`. +""" +function nearest_common_dominator(domtree::GenericDomTree, a::BBNumber, b::BBNumber) + alevel = domtree.nodes[a].level + blevel = domtree.nodes[b].level + # W.l.g. assume blevel <= alevel + if alevel < blevel + a, b = b, a + alevel, blevel = blevel, alevel + end + while alevel > blevel + a = domtree.idoms_bb[a] + alevel -= 1 + end + while a != b && a != 0 + a = domtree.idoms_bb[a] + b = domtree.idoms_bb[b] + end + @assert a == b + return a +end + +function naive_idoms(blocks::Vector{BasicBlock}, is_post_dominator::Bool=false) nblocks = length(blocks) # The extra +1 helps us detect unreachable blocks below dom_all = BitSet(1:nblocks+1) - dominators = BitSet[n == 1 ? BitSet(1) : copy(dom_all) for n = 1:nblocks] + dominators = is_post_dominator ? + BitSet[isempty(blocks[n].succs) ? BitSet(n) : copy(dom_all) for n = 1:nblocks] : + BitSet[n == 1 ? BitSet(1) : copy(dom_all) for n = 1:nblocks] changed = true + relevant_blocks = (is_post_dominator ? (1:nblocks) : (2:nblocks)) while changed changed = false - for n = 2:nblocks - if isempty(blocks[n].preds) + for n in relevant_blocks + edges = is_post_dominator ? blocks[n].succs : blocks[n].preds + if isempty(edges) continue end - firstp, rest = Iterators.peel(Iterators.filter(p->p != 0, blocks[n].preds))::NTuple{2,Any} + firstp, rest = Iterators.peel(Iterators.filter(p->p != 0, edges))::NTuple{2,Any} new_doms = copy(dominators[firstp]) for p in rest intersect!(new_doms, dominators[p]) @@ -606,7 +688,7 @@ function naive_idoms(blocks::Vector{BasicBlock}) end # Compute idoms idoms = fill(0, nblocks) - for i = 2:nblocks + for i in relevant_blocks if dominators[i] == dom_all idoms[i] = 0 continue diff --git a/base/compiler/ssair/driver.jl b/base/compiler/ssair/driver.jl index 6c17bbc7868f2..1946a76714e57 100644 --- a/base/compiler/ssair/driver.jl +++ b/base/compiler/ssair/driver.jl @@ -3,14 +3,22 @@ if false import Base: Base, @show else - macro show(s) - return :(println(stdout, $(QuoteNode(s)), " = ", $(esc(s)))) + macro show(ex...) + blk = Expr(:block) + for s in ex + push!(blk.args, :(println(stdout, $(QuoteNode(s)), " = ", + begin local value = $(esc(s)) end))) + end + isempty(ex) || push!(blk.args, :value) + blk end end +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") diff --git a/base/compiler/ssair/heap.jl b/base/compiler/ssair/heap.jl new file mode 100644 index 0000000000000..6e9883bc4ec60 --- /dev/null +++ b/base/compiler/ssair/heap.jl @@ -0,0 +1,74 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +# Heap operations on flat vectors +# ------------------------------- + + +# Binary heap indexing +heapleft(i::Integer) = 2i +heapright(i::Integer) = 2i + 1 +heapparent(i::Integer) = div(i, 2) + + +# Binary min-heap percolate down. +function percolate_down!(xs::Vector, i::Integer, x, o::Ordering, len::Integer=length(xs)) + @inbounds while (l = heapleft(i)) <= len + r = heapright(i) + j = r > len || lt(o, xs[l], xs[r]) ? l : r + lt(o, xs[j], x) || break + xs[i] = xs[j] + i = j + end + xs[i] = x +end + +# Binary min-heap percolate up. +function percolate_up!(xs::Vector, i::Integer, x, o::Ordering) + @inbounds while (j = heapparent(i)) >= 1 + lt(o, x, xs[j]) || break + xs[i] = xs[j] + i = j + end + xs[i] = x +end + +""" + heappop!(v, ord) + +Given a binary heap-ordered array, remove and return the lowest ordered element. +For efficiency, this function does not check that the array is indeed heap-ordered. +""" +function heappop!(xs::Vector, o::Ordering) + x = xs[1] + y = pop!(xs) + if !isempty(xs) + percolate_down!(xs, 1, y, o) + end + return x +end + +""" + heappush!(v, x, ord) + +Given a binary heap-ordered array, push a new element `x`, preserving the heap property. +For efficiency, this function does not check that the array is indeed heap-ordered. +""" +function heappush!(xs::Vector, x, o::Ordering) + push!(xs, x) + i = lastindex(xs) + percolate_up!(xs, i, @inbounds(xs[i]), o) + return xs +end + + +""" + heapify!(v, ord::Ordering) + +Turn an arbitrary vector into a binary min-heap in linear time. +""" +function heapify!(xs::Vector, o::Ordering) + for i in heapparent(lastindex(xs)):-1:1 + percolate_down!(xs, i, @inbounds(xs[i]), o) + end + return xs +end diff --git a/base/compiler/ssair/inlining.jl b/base/compiler/ssair/inlining.jl index a80090f3dc7e0..6508d320e0910 100644 --- a/base/compiler/ssair/inlining.jl +++ b/base/compiler/ssair/inlining.jl @@ -29,7 +29,9 @@ pass to apply its own inlining policy decisions. struct DelayedInliningSpec match::Union{MethodMatch, InferenceResult} argtypes::Vector{Any} + invokesig # either nothing or a signature (signature is for an `invoke` call) end +DelayedInliningSpec(match, argtypes) = DelayedInliningSpec(match, argtypes, nothing) struct InliningTodo # The MethodInstance to be inlined @@ -37,11 +39,11 @@ struct InliningTodo spec::Union{ResolvedInliningSpec, DelayedInliningSpec} end -InliningTodo(mi::MethodInstance, match::MethodMatch, argtypes::Vector{Any}) = - InliningTodo(mi, DelayedInliningSpec(match, argtypes)) +InliningTodo(mi::MethodInstance, match::MethodMatch, argtypes::Vector{Any}, invokesig=nothing) = + InliningTodo(mi, DelayedInliningSpec(match, argtypes, invokesig)) -InliningTodo(result::InferenceResult, argtypes::Vector{Any}) = - InliningTodo(result.linfo, DelayedInliningSpec(result, argtypes)) +InliningTodo(result::InferenceResult, argtypes::Vector{Any}, invokesig=nothing) = + InliningTodo(result.linfo, DelayedInliningSpec(result, argtypes, invokesig)) struct ConstantCase val::Any @@ -76,10 +78,27 @@ struct UnionSplit new(fully_covered, atype, cases, Int[]) end +struct InliningEdgeTracker + et::Union{Nothing,EdgeTracker} + invokesig # ::Union{Nothing,Type} + InliningEdgeTracker(et::Union{Nothing,EdgeTracker}, @nospecialize(invokesig=nothing)) = new(et, invokesig) +end + @specialize +function add_inlining_backedge!((; et, invokesig)::InliningEdgeTracker, mi::MethodInstance) + if et !== nothing + if invokesig === nothing + add_backedge!(et, mi) + else + add_invoke_backedge!(et, invokesig, mi) + end + end + return nothing +end + function ssa_inlining_pass!(ir::IRCode, linetable::Vector{LineInfoNode}, state::InliningState, propagate_inbounds::Bool) - # Go through the function, performing simple ininlingin (e.g. replacing call by constants + # Go through the function, performing simple inlining (e.g. replacing call by constants # and analyzing legality of inlining). @timeit "analysis" todo = assemble_inline_todo!(ir, state) isempty(todo) && return ir @@ -112,6 +131,8 @@ function CFGInliningState(ir::IRCode) ) end +⊑ₒ(@nospecialize(a), @nospecialize(b)) = ⊑(OptimizerLattice(), a, b) + # Tells the inliner that we're now inlining into block `block`, meaning # all previous blocks have been processed and can be added to the new cfg function inline_into_block!(state::CFGInliningState, block::Int) @@ -343,32 +364,47 @@ function ir_inline_linetable!(linetable::Vector{LineInfoNode}, inlinee_ir::IRCod return linetable_offset, extra_coverage_line end -function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector{Any}, - linetable::Vector{LineInfoNode}, item::InliningTodo, - boundscheck::Symbol, todo_bbs::Vector{Tuple{Int, Int}}) - # Ok, do the inlining here - spec = item.spec::ResolvedInliningSpec - sparam_vals = item.mi.sparam_vals - def = item.mi.def::Method - inlined_at = compact.result[idx][:line] - linetable_offset::Int32 = length(linetable) - topline::Int32 = linetable_offset + Int32(1) - linetable_offset, extra_coverage_line = ir_inline_linetable!(linetable, item.spec.ir, def, inlined_at) +function ir_prepare_inlining!(insert_node!::Inserter, inline_target::Union{IRCode, IncrementalCompact}, + linetable::Vector{LineInfoNode}, ir′::IRCode, sparam_vals::SimpleVector, + def::Method, inlined_at::Int32, argexprs::Vector{Any}) + topline::Int32 = length(linetable) + Int32(1) + linetable_offset, extra_coverage_line = ir_inline_linetable!(linetable, ir′, def, inlined_at) if extra_coverage_line != 0 - insert_node_here!(compact, NewInstruction(Expr(:code_coverage_effect), Nothing, extra_coverage_line)) + insert_node!(NewInstruction(Expr(:code_coverage_effect), Nothing, extra_coverage_line)) + end + sp_ssa = nothing + if !validate_sparams(sparam_vals) + # N.B. This works on the caller-side argexprs, (i.e. before the va fixup below) + sp_ssa = insert_node!( + effect_free(NewInstruction(Expr(:call, Core._compute_sparams, def, argexprs...), SimpleVector, topline))) end if def.isva nargs_def = Int(def.nargs::Int32) if nargs_def > 0 - argexprs = fix_va_argexprs!(compact, argexprs, nargs_def, topline) + argexprs = fix_va_argexprs!(insert_node!, inline_target, argexprs, nargs_def, topline) end end if def.is_for_opaque_closure # Replace the first argument by a load of the capture environment - argexprs[1] = insert_node_here!(compact, + argexprs[1] = insert_node!( NewInstruction(Expr(:call, GlobalRef(Core, :getfield), argexprs[1], QuoteNode(:captures)), - spec.ir.argtypes[1], topline)) + ir′.argtypes[1], topline)) end + return (Pair{Union{Nothing, SSAValue}, Vector{Any}}(sp_ssa, argexprs), linetable_offset) +end + +function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector{Any}, + linetable::Vector{LineInfoNode}, item::InliningTodo, + boundscheck::Symbol, todo_bbs::Vector{Tuple{Int, Int}}) + # Ok, do the inlining here + spec = item.spec::ResolvedInliningSpec + sparam_vals = item.mi.sparam_vals + def = item.mi.def::Method + inlined_at = compact.result[idx][:line] + + ((sp_ssa, argexprs), linetable_offset) = ir_prepare_inlining!(InsertHere(compact), compact, linetable, + item.spec.ir, sparam_vals, def, inlined_at, argexprs) + if boundscheck === :default || boundscheck === :propagate if (compact.result[idx][:flag] & IR_FLAG_INBOUNDS) != 0 boundscheck = :off @@ -379,6 +415,8 @@ function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector local return_value sig = def.sig # Special case inlining that maintains the current basic block if there's only one BB in the target + new_new_offset = length(compact.new_new_nodes) + late_fixup_offset = length(compact.late_fixup) if spec.linear_inline_eligible #compact[idx] = nothing inline_compact = IncrementalCompact(compact, spec.ir, compact.result_idx) @@ -387,7 +425,7 @@ function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector # face of rename_arguments! mutating in place - should figure out # something better eventually. inline_compact[idx′] = nothing - stmt′ = ssa_substitute!(idx′, stmt′, argexprs, sig, sparam_vals, linetable_offset, boundscheck, compact) + stmt′ = ssa_substitute!(InsertBefore(inline_compact, SSAValue(idx′)), inline_compact[SSAValue(idx′)], stmt′, argexprs, sig, sparam_vals, sp_ssa, linetable_offset, boundscheck) if isa(stmt′, ReturnNode) val = stmt′.val return_value = SSAValue(idx′) @@ -400,7 +438,7 @@ function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector end inline_compact[idx′] = stmt′ end - just_fixup!(inline_compact) + just_fixup!(inline_compact, new_new_offset, late_fixup_offset) compact.result_idx = inline_compact.result_idx else bb_offset, post_bb_id = popfirst!(todo_bbs) @@ -414,7 +452,7 @@ function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector inline_compact = IncrementalCompact(compact, spec.ir, compact.result_idx) for ((_, idx′), stmt′) in inline_compact inline_compact[idx′] = nothing - stmt′ = ssa_substitute!(idx′, stmt′, argexprs, sig, sparam_vals, linetable_offset, boundscheck, compact) + stmt′ = ssa_substitute!(InsertBefore(inline_compact, SSAValue(idx′)), inline_compact[SSAValue(idx′)], stmt′, argexprs, sig, sparam_vals, sp_ssa, linetable_offset, boundscheck) if isa(stmt′, ReturnNode) if isdefined(stmt′, :val) val = stmt′.val @@ -434,7 +472,7 @@ function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector end inline_compact[idx′] = stmt′ end - just_fixup!(inline_compact) + just_fixup!(inline_compact, new_new_offset, late_fixup_offset) compact.result_idx = inline_compact.result_idx compact.active_result_bb = inline_compact.active_result_bb if length(pn.edges) == 1 @@ -447,7 +485,7 @@ function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector return_value end -function fix_va_argexprs!(compact::IncrementalCompact, +function fix_va_argexprs!(insert_node!::Inserter, inline_target::Union{IRCode, IncrementalCompact}, argexprs::Vector{Any}, nargs_def::Int, line_idx::Int32) newargexprs = argexprs[1:(nargs_def-1)] tuple_call = Expr(:call, TOP_TUPLE) @@ -455,10 +493,11 @@ function fix_va_argexprs!(compact::IncrementalCompact, for i in nargs_def:length(argexprs) arg = argexprs[i] push!(tuple_call.args, arg) - push!(tuple_typs, argextype(arg, compact)) + push!(tuple_typs, argextype(arg, inline_target)) end - tuple_typ = tuple_tfunc(tuple_typs) - push!(newargexprs, insert_node_here!(compact, NewInstruction(tuple_call, tuple_typ, line_idx))) + tuple_typ = tuple_tfunc(OptimizerLattice(), tuple_typs) + tuple_inst = NewInstruction(tuple_call, tuple_typ, line_idx) + push!(newargexprs, insert_node!(tuple_inst)) return newargexprs end @@ -578,10 +617,9 @@ function ir_inline_unionsplit!(compact::IncrementalCompact, idx::Int, if isa(case, InliningTodo) val = ir_inline_item!(compact, idx, argexprs′, linetable, case, boundscheck, todo_bbs) elseif isa(case, InvokeCase) - effect_free = is_removable_if_unused(case.effects) - val = insert_node_here!(compact, - NewInstruction(Expr(:invoke, case.invoke, argexprs′...), typ, nothing, - line, effect_free ? IR_FLAG_EFFECT_FREE : IR_FLAG_NULL, effect_free)) + inst = Expr(:invoke, case.invoke, argexprs′...) + flag = flags_for_effects(case.effects) + val = insert_node_here!(compact, NewInstruction(inst, typ, nothing, line, flag, true)) else case = case::ConstantCase val = case.val @@ -790,35 +828,36 @@ function rewrite_apply_exprargs!( return new_argtypes end -function compileable_specialization(et::Union{EdgeTracker, Nothing}, match::MethodMatch, effects::Effects) - mi = specialize_method(match; compilesig=true) +function compileable_specialization(match::MethodMatch, effects::Effects, + et::InliningEdgeTracker; compilesig_invokes::Bool=true) + mi = specialize_method(match; compilesig=compilesig_invokes) mi === nothing && return nothing - et !== nothing && push!(et, mi) + add_inlining_backedge!(et, mi) return InvokeCase(mi, effects) end -function compileable_specialization(et::Union{EdgeTracker, Nothing}, linfo::MethodInstance, effects::Effects) - mi = specialize_method(linfo.def::Method, linfo.specTypes, linfo.sparam_vals; compilesig=true) +function compileable_specialization(linfo::MethodInstance, effects::Effects, + et::InliningEdgeTracker; compilesig_invokes::Bool=true) + mi = specialize_method(linfo.def::Method, linfo.specTypes, linfo.sparam_vals; compilesig=compilesig_invokes) mi === nothing && return nothing - et !== nothing && push!(et, mi) + add_inlining_backedge!(et, mi) return InvokeCase(mi, effects) end -function compileable_specialization(et::Union{EdgeTracker, Nothing}, result::InferenceResult, effects::Effects) - return compileable_specialization(et, result.linfo, effects) -end +compileable_specialization(result::InferenceResult, args...; kwargs...) = (@nospecialize; + compileable_specialization(result.linfo, args...; kwargs...)) function resolve_todo(todo::InliningTodo, state::InliningState, flag::UInt8) mi = todo.mi - (; match, argtypes) = todo.spec::DelayedInliningSpec - et = state.et + (; match, argtypes, invokesig) = todo.spec::DelayedInliningSpec + et = InliningEdgeTracker(state.et, invokesig) #XXX: update_valid_age!(min_valid[1], max_valid[1], sv) if isa(match, InferenceResult) inferred_src = match.src if isa(inferred_src, ConstAPI) # use constant calling convention - et !== nothing && push!(et, mi) + add_inlining_backedge!(et, mi) return ConstantCase(quoted(inferred_src.val)) else src = inferred_src # ::Union{Nothing,CodeInfo} for NativeInterpreter @@ -829,7 +868,7 @@ function resolve_todo(todo::InliningTodo, state::InliningState, flag::UInt8) if code isa CodeInstance if use_const_api(code) # in this case function can be inlined to a constant - et !== nothing && push!(et, mi) + add_inlining_backedge!(et, mi) return ConstantCase(quoted(code.rettype_const)) else src = @atomic :monotonic code.inferred @@ -844,14 +883,16 @@ function resolve_todo(todo::InliningTodo, state::InliningState, flag::UInt8) # the duplicated check might have been done already within `analyze_method!`, but still # we need it here too since we may come here directly using a constant-prop' result if !state.params.inlining || is_stmt_noinline(flag) - return compileable_specialization(et, match, effects) + return compileable_specialization(match, effects, et; + compilesig_invokes=state.params.compilesig_invokes) end src = inlining_policy(state.interp, src, flag, mi, argtypes) - src === nothing && return compileable_specialization(et, match, effects) + src === nothing && return compileable_specialization(match, effects, et; + compilesig_invokes=state.params.compilesig_invokes) - et !== nothing && push!(et, mi) + add_inlining_backedge!(et, mi) return InliningTodo(mi, retrieve_ir_for_inlining(mi, src), effects) end @@ -873,8 +914,26 @@ function validate_sparams(sparams::SimpleVector) return true end -function analyze_method!(match::MethodMatch, argtypes::Vector{Any}, - flag::UInt8, state::InliningState) +function may_have_fcalls(m::Method) + may_have_fcall = true + if isdefined(m, :source) + src = m.source + isa(src, Vector{UInt8}) && (src = uncompressed_ir(m)) + if isa(src, CodeInfo) + may_have_fcall = src.has_fcall + end + end + return may_have_fcall +end + +function can_inline_typevars(method::Method, argtypes::Vector{Any}) + may_have_fcalls(method) && return false + return true +end +can_inline_typevars(m::MethodMatch, argtypes::Vector{Any}) = can_inline_typevars(m.method, argtypes) + +function analyze_method!(match::MethodMatch, argtypes::Vector{Any}, @nospecialize(invokesig), + flag::UInt8, state::InliningState, allow_typevars::Bool = false) method = match.method spec_types = match.spec_types @@ -896,16 +955,19 @@ function analyze_method!(match::MethodMatch, argtypes::Vector{Any}, end end - # Bail out if any static parameters are left as TypeVar - validate_sparams(match.sparams) || return nothing - - et = state.et + if !validate_sparams(match.sparams) + (allow_typevars && can_inline_typevars(match, argtypes)) || return nothing + end # See if there exists a specialization for this method signature mi = specialize_method(match; preexisting=true) # Union{Nothing, MethodInstance} - isa(mi, MethodInstance) || return compileable_specialization(et, match, Effects()) + if mi === nothing + et = InliningEdgeTracker(state.et, invokesig) + return compileable_specialization(match, Effects(), et; + compilesig_invokes=state.params.compilesig_invokes) + end - todo = InliningTodo(mi, match, argtypes) + todo = InliningTodo(mi, match, argtypes, invokesig) # If we don't have caches here, delay resolving this MethodInstance # until the batch inlining step (or an external post-processing pass) state.mi_cache === nothing && return todo @@ -923,6 +985,19 @@ end retrieve_ir_for_inlining(mi::MethodInstance, src::CodeInfo) = inflate_ir(src, mi) retrieve_ir_for_inlining(mi::MethodInstance, ir::IRCode) = copy(ir) +function flags_for_effects(effects::Effects) + flags::UInt8 = 0 + if is_consistent(effects) + flags |= IR_FLAG_CONSISTENT + end + if is_removable_if_unused(effects) + flags |= IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW + elseif is_nothrow(effects) + flags |= IR_FLAG_NOTHROW + end + return flags +end + function handle_single_case!( ir::IRCode, idx::Int, stmt::Expr, @nospecialize(case), todo::Vector{Pair{Int, Any}}, params::OptimizationParams, isinvoke::Bool = false) @@ -933,11 +1008,7 @@ function handle_single_case!( isinvoke && rewrite_invoke_exprargs!(stmt) stmt.head = :invoke pushfirst!(stmt.args, case.invoke) - if is_removable_if_unused(case.effects) - ir[SSAValue(idx)][:flag] |= IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW - elseif is_nothrow(case.effects) - ir[SSAValue(idx)][:flag] |= IR_FLAG_NOTHROW - end + ir[SSAValue(idx)][:flag] |= flags_for_effects(case.effects) elseif case === nothing # Do, well, nothing else @@ -1041,8 +1112,8 @@ function inline_apply!( nonempty_idx = 0 for i = (arg_start + 1):length(argtypes) ti = argtypes[i] - ti ⊑ Tuple{} && continue - if ti ⊑ Tuple && nonempty_idx == 0 + ti ⊑ₒ Tuple{} && continue + if ti ⊑ₒ Tuple && nonempty_idx == 0 nonempty_idx = i continue end @@ -1084,9 +1155,9 @@ end # TODO: this test is wrong if we start to handle Unions of function types later is_builtin(s::Signature) = isa(s.f, IntrinsicFunction) || - s.ft ⊑ IntrinsicFunction || + s.ft ⊑ₒ IntrinsicFunction || isa(s.f, Builtin) || - s.ft ⊑ Builtin + s.ft ⊑ₒ Builtin function inline_invoke!( ir::IRCode, idx::Int, stmt::Expr, info::InvokeCallInfo, flag::UInt8, @@ -1097,12 +1168,13 @@ function inline_invoke!( return nothing end result = info.result + invokesig = invoke_signature(sig.argtypes) if isa(result, ConcreteResult) - item = concrete_result_item(result, state) + item = concrete_result_item(result, state, invokesig) else argtypes = invoke_rewrite(sig.argtypes) if isa(result, ConstPropResult) - (; mi) = item = InliningTodo(result.result, argtypes) + (; mi) = item = InliningTodo(result.result, argtypes, invokesig) validate_sparams(mi.sparam_vals) || return nothing if argtypes_to_type(argtypes) <: mi.def.sig state.mi_cache !== nothing && (item = resolve_todo(item, state, flag)) @@ -1110,12 +1182,17 @@ function inline_invoke!( return nothing end end - item = analyze_method!(match, argtypes, flag, state) + item = analyze_method!(match, argtypes, invokesig, flag, state) end handle_single_case!(ir, idx, stmt, item, todo, state.params, true) return nothing end +function invoke_signature(argtypes::Vector{Any}) + ft, argtyps = widenconst(argtypes[2]), instanceof_tfunc(widenconst(argtypes[3]))[1] + return rewrap_unionall(Tuple{ft, unwrap_unionall(argtyps).parameters...}, argtyps) +end + function narrow_opaque_closure!(ir::IRCode, stmt::Expr, @nospecialize(info), state::InliningState) if isa(info, OpaqueClosureCreateInfo) lbt = argextype(stmt.args[2], ir) @@ -1125,9 +1202,9 @@ function narrow_opaque_closure!(ir::IRCode, stmt::Expr, @nospecialize(info), sta ub, exact = instanceof_tfunc(ubt) exact || return # Narrow opaque closure type - newT = widenconst(tmeet(tmerge(lb, info.unspec.rt), ub)) + newT = widenconst(tmeet(OptimizerLattice(), tmerge(OptimizerLattice(), lb, info.unspec.rt), ub)) if newT != ub - # N.B.: Narrowing the ub requires a backdge on the mi whose type + # N.B.: Narrowing the ub requires a backedge on the mi whose type # information we're using, since a change in that function may # invalidate ub result. stmt.args[3] = newT @@ -1139,13 +1216,16 @@ end # For primitives, we do that right here. For proper calls, we will # discover this when we consult the caches. function check_effect_free!(ir::IRCode, idx::Int, @nospecialize(stmt), @nospecialize(rt)) - (total, nothrow) = stmt_effect_flags(stmt, rt, ir) - if total + (consistent, effect_free_and_nothrow, nothrow) = stmt_effect_flags(OptimizerLattice(), stmt, rt, ir) + if consistent + ir.stmts[idx][:flag] |= IR_FLAG_CONSISTENT + end + if effect_free_and_nothrow ir.stmts[idx][:flag] |= IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW elseif nothrow ir.stmts[idx][:flag] |= IR_FLAG_NOTHROW end - return total + return effect_free_and_nothrow end # Handles all analysis and inlining of intrinsics and builtins. In particular, @@ -1182,7 +1262,7 @@ function process_simple!(ir::IRCode, idx::Int, state::InliningState, todo::Vecto ir.stmts[idx][:inst] = earlyres.val return nothing end - if (sig.f === modifyfield! || sig.ft ⊑ typeof(modifyfield!)) && 5 <= length(stmt.args) <= 6 + if (sig.f === modifyfield! || sig.ft ⊑ₒ typeof(modifyfield!)) && 5 <= length(stmt.args) <= 6 let info = ir.stmts[idx][:info] info isa MethodResultPure && (info = info.info) info isa ConstCallInfo && (info = info.call) @@ -1190,7 +1270,8 @@ function process_simple!(ir::IRCode, idx::Int, state::InliningState, todo::Vecto length(info.results) == 1 || return nothing match = info.results[1]::MethodMatch match.fully_covers || return nothing - case = compileable_specialization(state.et, match, Effects()) + case = compileable_specialization(match, Effects(), InliningEdgeTracker(state.et); + compilesig_invokes=state.params.compilesig_invokes) case === nothing && return nothing stmt.head = :invoke_modify pushfirst!(stmt.args, case.invoke) @@ -1200,7 +1281,7 @@ function process_simple!(ir::IRCode, idx::Int, state::InliningState, todo::Vecto end if check_effect_free!(ir, idx, stmt, rt) - if sig.f === typeassert || sig.ft ⊑ typeof(typeassert) + if sig.f === typeassert || sig.ft ⊑ₒ typeof(typeassert) # typeassert is a no-op if effect free ir.stmts[idx][:inst] = stmt.args[2] return nothing @@ -1208,7 +1289,7 @@ function process_simple!(ir::IRCode, idx::Int, state::InliningState, todo::Vecto end if sig.f !== Core.invoke && sig.f !== Core.finalizer && is_builtin(sig) - # No inlining for builtins (other invoke/apply/typeassert) + # No inlining for builtins (other invoke/apply/typeassert/finalizer) return nothing end @@ -1223,47 +1304,59 @@ function process_simple!(ir::IRCode, idx::Int, state::InliningState, todo::Vecto return stmt, sig end -# TODO inline non-`isdispatchtuple`, union-split callsites? -function compute_inlining_cases(infos::Vector{MethodMatchInfo}, - flag::UInt8, sig::Signature, state::InliningState) - argtypes = sig.argtypes - cases = InliningCase[] - local any_fully_covered = false - local handled_all_cases = true - for i in 1:length(infos) - meth = infos[i].results - if meth.ambig - # Too many applicable methods - # Or there is a (partial?) ambiguity - return nothing - elseif length(meth) == 0 - # No applicable methods; try next union split - handled_all_cases = false - continue - end - for match in meth - handled_all_cases &= handle_match!(match, argtypes, flag, state, cases, #=allow_abstract=#true) - any_fully_covered |= match.fully_covers - end +function handle_any_const_result!(cases::Vector{InliningCase}, @nospecialize(result), match::MethodMatch, argtypes::Vector{Any}, flag::UInt8, state::InliningState, allow_typevars::Bool=false) + if isa(result, ConcreteResult) + case = concrete_result_item(result, state) + push!(cases, InliningCase(result.mi.specTypes, case)) + return true + elseif isa(result, ConstPropResult) + return handle_const_prop_result!(result, argtypes, flag, state, cases, #=allow_abstract=#true, allow_typevars) + elseif isa(result, SemiConcreteResult) + return handle_semi_concrete_result!(result, cases, #=allow_abstract=#true) + else + @assert result === nothing + return handle_match!(match, argtypes, flag, state, cases, #=allow_abstract=#true, allow_typevars) end +end - if !handled_all_cases - # if we've not seen all candidates, union split is valid only for dispatch tuples - filter!(case::InliningCase->isdispatchtuple(case.sig), cases) +function info_effects(@nospecialize(result), match::MethodMatch, state::InliningState) + if isa(result, ConcreteResult) + return result.effects + elseif isa(result, SemiConcreteResult) + return result.effects + elseif isa(result, ConstPropResult) + return result.result.ipo_effects + else + mi = specialize_method(match; preexisting=true) + if isa(mi, MethodInstance) + code = get(state.mi_cache, mi, nothing) + if code isa CodeInstance + return decode_effects(code.ipo_purity_bits) + end + end + return Effects() end - - return cases, handled_all_cases & any_fully_covered end -function compute_inlining_cases(info::ConstCallInfo, +function compute_inlining_cases(info::Union{ConstCallInfo, Vector{MethodMatchInfo}}, flag::UInt8, sig::Signature, state::InliningState) argtypes = sig.argtypes - (; call, results) = info - infos = isa(call, MethodMatchInfo) ? MethodMatchInfo[call] : call.matches + if isa(info, ConstCallInfo) + (; call, results) = info + infos = isa(call, MethodMatchInfo) ? MethodMatchInfo[call] : call.matches + else + results = nothing + infos = info + end cases = InliningCase[] local any_fully_covered = false - local handled_all_cases = true - local j = 0 + local handled_all_cases::Bool = true + local revisit_idx = nothing + local only_method = nothing + local meth::MethodLookupResult + local all_result_count = 0 + local joint_effects::Effects = EFFECTS_TOTAL + local nothrow::Bool = true for i in 1:length(infos) meth = infos[i].results if meth.ambig @@ -1274,29 +1367,72 @@ function compute_inlining_cases(info::ConstCallInfo, # No applicable methods; try next union split handled_all_cases = false continue + else + if length(meth) == 1 && only_method !== false + if only_method === nothing + only_method = meth[1].method + elseif only_method !== meth[1].method + only_method = false + end + else + only_method = false + end end - for match in meth - j += 1 - result = results[j] + for (j, match) in enumerate(meth) + all_result_count += 1 + result = results === nothing ? nothing : results[all_result_count] + joint_effects = merge_effects(joint_effects, info_effects(result, match, state)) + nothrow &= match.fully_covers any_fully_covered |= match.fully_covers - if isa(result, ConcreteResult) - case = concrete_result_item(result, state) - push!(cases, InliningCase(result.mi.specTypes, case)) - elseif isa(result, ConstPropResult) - handled_all_cases &= handle_const_prop_result!(result, argtypes, flag, state, cases, true) + if !validate_sparams(match.sparams) + if !match.fully_covers + handled_all_cases = false + continue + end + if revisit_idx === nothing + revisit_idx = (i, j, all_result_count) + else + handled_all_cases = false + revisit_idx = nothing + end else - @assert result === nothing - handled_all_cases &= handle_match!(match, argtypes, flag, state, cases, #=allow_abstract=#true) + handled_all_cases &= handle_any_const_result!(cases, result, match, argtypes, flag, state, false) end end end - if !handled_all_cases + joint_effects = Effects(joint_effects; nothrow) + + if handled_all_cases && revisit_idx !== nothing + # we handled everything except one match with unmatched sparams, + # so try to handle it by bypassing validate_sparams + (i, j, k) = revisit_idx + match = infos[i].results[j] + result = results === nothing ? nothing : results[k] + handled_all_cases &= handle_any_const_result!(cases, result, match, argtypes, flag, state, true) + elseif length(cases) == 0 && only_method isa Method + # if the signature is fully covered and there is only one applicable method, + # we can try to inline it even in the presence of unmatched sparams + # -- But don't try it if we already tried to handle the match in the revisit_idx + # case, because that'll (necessarily) be the same method. + if length(infos) > 1 + atype = argtypes_to_type(argtypes) + (metharg, methsp) = ccall(:jl_type_intersection_with_env, Any, (Any, Any), atype, only_method.sig)::SimpleVector + match = MethodMatch(metharg, methsp::SimpleVector, only_method, true) + result = nothing + else + @assert length(meth) == 1 + match = meth[1] + result = results === nothing ? nothing : results[1] + end + handle_any_const_result!(cases, result, match, argtypes, flag, state, true) + any_fully_covered = handled_all_cases = match.fully_covers + elseif !handled_all_cases # if we've not seen all candidates, union split is valid only for dispatch tuples filter!(case::InliningCase->isdispatchtuple(case.sig), cases) end - return cases, handled_all_cases & any_fully_covered + return cases, (handled_all_cases & any_fully_covered), joint_effects end function handle_call!( @@ -1304,9 +1440,9 @@ function handle_call!( sig::Signature, state::InliningState, todo::Vector{Pair{Int, Any}}) cases = compute_inlining_cases(infos, flag, sig, state) cases === nothing && return nothing - cases, all_covered = cases + cases, all_covered, joint_effects = cases handle_cases!(ir, idx, stmt, argtypes_to_type(sig.argtypes), cases, - all_covered, todo, state.params) + all_covered, todo, state.params, joint_effects) end function handle_const_call!( @@ -1314,21 +1450,21 @@ function handle_const_call!( sig::Signature, state::InliningState, todo::Vector{Pair{Int, Any}}) cases = compute_inlining_cases(info, flag, sig, state) cases === nothing && return nothing - cases, all_covered = cases + cases, all_covered, joint_effects = cases handle_cases!(ir, idx, stmt, argtypes_to_type(sig.argtypes), cases, - all_covered, todo, state.params) + all_covered, todo, state.params, joint_effects) end function handle_match!( match::MethodMatch, argtypes::Vector{Any}, flag::UInt8, state::InliningState, - cases::Vector{InliningCase}, allow_abstract::Bool = false) + cases::Vector{InliningCase}, allow_abstract::Bool, allow_typevars::Bool) spec_types = match.spec_types allow_abstract || isdispatchtuple(spec_types) || return false - # we may see duplicated dispatch signatures here when a signature gets widened + # We may see duplicated dispatch signatures here when a signature gets widened # during abstract interpretation: for the purpose of inlining, we can just skip - # processing this dispatch candidate - _any(case->case.sig === spec_types, cases) && return true - item = analyze_method!(match, argtypes, flag, state) + # processing this dispatch candidate (unless unmatched type parameters are present) + !allow_typevars && _any(case->case.sig === spec_types, cases) && return true + item = analyze_method!(match, argtypes, nothing, flag, state, allow_typevars) item === nothing && return false push!(cases, InliningCase(spec_types, item)) return true @@ -1336,20 +1472,33 @@ end function handle_const_prop_result!( result::ConstPropResult, argtypes::Vector{Any}, flag::UInt8, state::InliningState, - cases::Vector{InliningCase}, allow_abstract::Bool = false) + cases::Vector{InliningCase}, allow_abstract::Bool, allow_typevars::Bool = false) (; mi) = item = InliningTodo(result.result, argtypes) spec_types = mi.specTypes allow_abstract || isdispatchtuple(spec_types) || return false - validate_sparams(mi.sparam_vals) || return false + if !validate_sparams(mi.sparam_vals) + (allow_typevars && can_inline_typevars(mi.def, argtypes)) || return false + end state.mi_cache !== nothing && (item = resolve_todo(item, state, flag)) item === nothing && return false push!(cases, InliningCase(spec_types, item)) return true end -function concrete_result_item(result::ConcreteResult, state::InliningState) +function handle_semi_concrete_result!(result::SemiConcreteResult, cases::Vector{InliningCase}, allow_abstract::Bool = false) + mi = result.mi + spec_types = mi.specTypes + allow_abstract || isdispatchtuple(spec_types) || return false + validate_sparams(mi.sparam_vals) || return false + push!(cases, InliningCase(spec_types, InliningTodo(mi, result.ir, result.effects))) + return true +end + +function concrete_result_item(result::ConcreteResult, state::InliningState, @nospecialize(invokesig=nothing)) if !isdefined(result, :result) || !is_inlineable_constant(result.result) - case = compileable_specialization(state.et, result.mi, result.effects) + et = InliningEdgeTracker(state.et, invokesig) + case = compileable_specialization(result.mi, result.effects, et; + compilesig_invokes=state.params.compilesig_invokes) @assert case !== nothing "concrete evaluation should never happen for uncompileable callsite" return case end @@ -1359,7 +1508,7 @@ end function handle_cases!(ir::IRCode, idx::Int, stmt::Expr, @nospecialize(atype), cases::Vector{InliningCase}, fully_covered::Bool, todo::Vector{Pair{Int, Any}}, - params::OptimizationParams) + params::OptimizationParams, joint_effects::Effects) # If we only have one case and that case is fully covered, we may either # be able to do the inlining now (for constant cases), or push it directly # onto the todo list @@ -1371,6 +1520,8 @@ function handle_cases!(ir::IRCode, idx::Int, stmt::Expr, @nospecialize(atype), isa(case.sig, DataType) || return nothing end push!(todo, idx=>UnionSplit(fully_covered, atype, cases)) + else + ir[SSAValue(idx)][:flag] |= flags_for_effects(joint_effects) end return nothing end @@ -1386,20 +1537,29 @@ function handle_const_opaque_closure_call!( end function handle_finalizer_call!( - ir::IRCode, stmt::Expr, info::FinalizerInfo, state::InliningState) + ir::IRCode, idx::Int, stmt::Expr, info::FinalizerInfo, state::InliningState) + + # Finalizers don't return values, so if their execution is not observable, + # we can just not register them + if is_removable_if_unused(info.effects) + ir[SSAValue(idx)] = nothing + return nothing + end + # Only inline finalizers that are known nothrow and notls. # This avoids having to set up state for finalizer isolation - (is_nothrow(info.effects) && is_notaskstate(info.effects)) || return nothing + is_finalizer_inlineable(info.effects) || return nothing info = info.info + if isa(info, ConstCallInfo) + # NOTE currently mutable objects are not represented as `Const` + # but `finalizer` function can be + info = info.call + end if isa(info, MethodMatchInfo) infos = MethodMatchInfo[info] elseif isa(info, UnionSplitInfo) infos = info.matches - # elseif isa(info, ConstCallInfo) - # # NOTE currently this code path isn't active as constant propagation won't happen - # # for `Core.finalizer` call because inference currently isn't able to fold a mutable - # # object as a constant else return nothing end @@ -1414,7 +1574,7 @@ function handle_finalizer_call!( cases = compute_inlining_cases(infos, #=flag=#UInt8(0), sig, state) cases === nothing && return nothing - cases, all_covered = cases + cases, all_covered, _ = cases if all_covered && length(cases) == 1 # NOTE we don't append `item1` to `stmt` here so that we don't serialize # `Core.Compiler` data structure into the global cache @@ -1475,7 +1635,7 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState) if isa(result, ConcreteResult) item = concrete_result_item(result, state) else - item = analyze_method!(info.match, sig.argtypes, flag, state) + item = analyze_method!(info.match, sig.argtypes, nothing, flag, state) end handle_single_case!(ir, idx, stmt, item, todo, state.params) end @@ -1490,7 +1650,7 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState) # Handle finalizer if isa(info, FinalizerInfo) - handle_finalizer_call!(ir, stmt, info, state) + handle_finalizer_call!(ir, idx, stmt, info, state) continue end @@ -1550,7 +1710,7 @@ function early_inline_special_case( elseif ispuretopfunction(f) || contains_is(_PURE_BUILTINS, f) return SomeCase(quoted(val)) elseif contains_is(_EFFECT_FREE_BUILTINS, f) - if _builtin_nothrow(f, argtypes[2:end], type) + if _builtin_nothrow(OptimizerLattice(), f, argtypes[2:end], type) return SomeCase(quoted(val)) end elseif f === Core.get_binding_type @@ -1569,7 +1729,7 @@ function early_inline_special_case( setting = setting.val isa(setting, Symbol) || return nothing setting === :const || setting === :conditional || setting === :type || return nothing - # barrierred successfully already, eliminate it + # barriered successfully already, eliminate it return SomeCase(stmt.args[3]) end return nothing @@ -1596,17 +1756,17 @@ function late_inline_special_case!( elseif length(argtypes) == 3 && istopfunction(f, :(>:)) # special-case inliner for issupertype # that works, even though inference generally avoids inferring the `>:` Method - if isa(type, Const) && _builtin_nothrow(<:, Any[argtypes[3], argtypes[2]], type) + if isa(type, Const) && _builtin_nothrow(OptimizerLattice(), <:, Any[argtypes[3], argtypes[2]], type) return SomeCase(quoted(type.val)) end subtype_call = Expr(:call, GlobalRef(Core, :(<:)), stmt.args[3], stmt.args[2]) return SomeCase(subtype_call) - elseif f === TypeVar && 2 <= length(argtypes) <= 4 && (argtypes[2] ⊑ Symbol) + elseif f === TypeVar && 2 <= length(argtypes) <= 4 && (argtypes[2] ⊑ₒ Symbol) typevar_call = Expr(:call, GlobalRef(Core, :_typevar), stmt.args[2], length(stmt.args) < 4 ? Bottom : stmt.args[3], length(stmt.args) == 2 ? Any : stmt.args[end]) return SomeCase(typevar_call) - elseif f === UnionAll && length(argtypes) == 3 && (argtypes[2] ⊑ TypeVar) + elseif f === UnionAll && length(argtypes) == 3 && (argtypes[2] ⊑ₒ TypeVar) unionall_call = Expr(:foreigncall, QuoteNode(:jl_type_unionall), Any, svec(Any, Any), 0, QuoteNode(:ccall), stmt.args[2], stmt.args[3]) return SomeCase(unionall_call) @@ -1620,16 +1780,35 @@ function late_inline_special_case!( return nothing end -function ssa_substitute!(idx::Int, @nospecialize(val), arg_replacements::Vector{Any}, +function ssa_substitute!(insert_node!::Inserter, + subst_inst::Instruction, @nospecialize(val), arg_replacements::Vector{Any}, @nospecialize(spsig), spvals::SimpleVector, - linetable_offset::Int32, boundscheck::Symbol, compact::IncrementalCompact) - compact.result[idx][:flag] &= ~IR_FLAG_INBOUNDS - compact.result[idx][:line] += linetable_offset - return ssa_substitute_op!(val, arg_replacements, spsig, spvals, boundscheck) + spvals_ssa::Union{Nothing, SSAValue}, + linetable_offset::Int32, boundscheck::Symbol) + subst_inst[:flag] &= ~IR_FLAG_INBOUNDS + subst_inst[:line] += linetable_offset + return ssa_substitute_op!(insert_node!, subst_inst, + val, arg_replacements, spsig, spvals, spvals_ssa, boundscheck) +end + +function insert_spval!(insert_node!::Inserter, spvals_ssa::SSAValue, spidx::Int, do_isdefined::Bool) + ret = insert_node!( + effect_free(NewInstruction(Expr(:call, Core._svec_ref, false, spvals_ssa, spidx), Any))) + tcheck_not = nothing + if do_isdefined + tcheck = insert_node!( + effect_free(NewInstruction(Expr(:call, Core.isa, ret, Core.TypeVar), Bool))) + tcheck_not = insert_node!( + effect_free(NewInstruction(Expr(:call, not_int, tcheck), Bool))) + end + return (ret, tcheck_not) end -function ssa_substitute_op!(@nospecialize(val), arg_replacements::Vector{Any}, - @nospecialize(spsig), spvals::SimpleVector, boundscheck::Symbol) +function ssa_substitute_op!(insert_node!::Inserter, subst_inst::Instruction, + @nospecialize(val), arg_replacements::Vector{Any}, + @nospecialize(spsig), spvals::SimpleVector, + spvals_ssa::Union{Nothing, SSAValue}, + boundscheck::Symbol) if isa(val, Argument) return arg_replacements[val.n] end @@ -1637,14 +1816,36 @@ function ssa_substitute_op!(@nospecialize(val), arg_replacements::Vector{Any}, e = val::Expr head = e.head if head === :static_parameter - return quoted(spvals[e.args[1]::Int]) - elseif head === :cfunction + spidx = e.args[1]::Int + val = spvals[spidx] + if !isa(val, TypeVar) && val !== Vararg + return quoted(val) + else + flag = subst_inst[:flag] + maybe_undef = (flag & IR_FLAG_NOTHROW) == 0 && isa(val, TypeVar) + (ret, tcheck_not) = insert_spval!(insert_node!, spvals_ssa, spidx, maybe_undef) + if maybe_undef + insert_node!( + non_effect_free(NewInstruction(Expr(:throw_undef_if_not, val.name, tcheck_not), Nothing))) + end + return ret + end + elseif head === :isdefined && isa(e.args[1], Expr) && e.args[1].head === :static_parameter + spidx = (e.args[1]::Expr).args[1]::Int + val = spvals[spidx] + if !isa(val, TypeVar) + return true + else + (_, tcheck_not) = insert_spval!(insert_node!, spvals_ssa, spidx, true) + return tcheck_not + end + elseif head === :cfunction && spvals_ssa === nothing @assert !isa(spsig, UnionAll) || !isempty(spvals) e.args[3] = ccall(:jl_instantiate_type_in_env, Any, (Any, Any, Ptr{Any}), e.args[3], spsig, spvals) e.args[4] = svec(Any[ ccall(:jl_instantiate_type_in_env, Any, (Any, Any, Ptr{Any}), argt, spsig, spvals) for argt in e.args[4]::SimpleVector ]...) - elseif head === :foreigncall + elseif head === :foreigncall && spvals_ssa === nothing @assert !isa(spsig, UnionAll) || !isempty(spvals) for i = 1:length(e.args) if i == 2 @@ -1668,7 +1869,7 @@ function ssa_substitute_op!(@nospecialize(val), arg_replacements::Vector{Any}, isa(val, Union{SSAValue, NewSSAValue}) && return val # avoid infinite loop urs = userefs(val) for op in urs - op[] = ssa_substitute_op!(op[], arg_replacements, spsig, spvals, boundscheck) + op[] = ssa_substitute_op!(insert_node!, subst_inst, op[], arg_replacements, spsig, spvals, spvals_ssa, boundscheck) end return urs[] end diff --git a/base/compiler/ssair/ir.jl b/base/compiler/ssair/ir.jl index b2a6ee4d65586..a8c832f2ba09a 100644 --- a/base/compiler/ssair/ir.jl +++ b/base/compiler/ssair/ir.jl @@ -28,12 +28,18 @@ function cfg_delete_edge!(cfg::CFG, from::Int, to::Int) nothing end +function bb_ordering() + lt=(<=) + by=x->first(x.stmts) + ord(lt, by, nothing, Forward) +end + function block_for_inst(index::Vector{Int}, inst::Int) return searchsortedfirst(index, inst, lt=(<=)) end function block_for_inst(index::Vector{BasicBlock}, inst::Int) - return searchsortedfirst(index, BasicBlock(StmtRange(inst, inst)), by=x->first(x.stmts), lt=(<=))-1 + return searchsortedfirst(index, BasicBlock(StmtRange(inst, inst)), bb_ordering())-1 end block_for_inst(cfg::CFG, inst::Int) = block_for_inst(cfg.index, inst) @@ -307,6 +313,9 @@ effect_free(inst::NewInstruction) = NewInstruction(inst.stmt, inst.type, inst.info, inst.line, inst.flag | IR_FLAG_EFFECT_FREE, true) non_effect_free(inst::NewInstruction) = NewInstruction(inst.stmt, inst.type, inst.info, inst.line, inst.flag & ~IR_FLAG_EFFECT_FREE, true) +with_flags(inst::NewInstruction, flags::UInt8) = + NewInstruction(inst.stmt, inst.type, inst.info, inst.line, inst.flag | flags, true) + struct IRCode stmts::InstructionStream @@ -394,7 +403,7 @@ struct UndefToken end; const UNDEF_TOKEN = UndefToken() isdefined(stmt, :val) || return OOB_TOKEN op == 1 || return OOB_TOKEN return stmt.val - elseif isa(stmt, Union{SSAValue, NewSSAValue}) + elseif isa(stmt, Union{SSAValue, NewSSAValue, GlobalRef}) op == 1 || return OOB_TOKEN return stmt elseif isa(stmt, UpsilonNode) @@ -446,7 +455,7 @@ end elseif isa(stmt, ReturnNode) op == 1 || throw(BoundsError()) stmt = typeof(stmt)(v) - elseif isa(stmt, Union{SSAValue, NewSSAValue}) + elseif isa(stmt, Union{SSAValue, NewSSAValue, GlobalRef}) op == 1 || throw(BoundsError()) stmt = v elseif isa(stmt, UpsilonNode) @@ -504,12 +513,15 @@ scan_ssa_use!(@specialize(push!), used, @nospecialize(stmt)) = foreachssa(ssa::S # Manually specialized copy of the above with push! === Compiler.push! scan_ssa_use!(used::IdSet, @nospecialize(stmt)) = foreachssa(ssa::SSAValue -> push!(used, ssa.id), stmt) -function insert_node!(ir::IRCode, pos::Int, inst::NewInstruction, attach_after::Bool=false) - node = add!(ir.new_nodes, pos, attach_after) - node[:line] = something(inst.line, ir.stmts[pos][:line]) +function insert_node!(ir::IRCode, pos::SSAValue, inst::NewInstruction, attach_after::Bool=false) + node = add!(ir.new_nodes, pos.id, attach_after) + node[:line] = something(inst.line, ir[pos][:line]) flag = inst.flag if !inst.effect_free_computed - (effect_free_and_nothrow, nothrow) = stmt_effect_flags(inst.stmt, inst.type, ir) + (consistent, effect_free_and_nothrow, nothrow) = stmt_effect_flags(fallback_lattice, inst.stmt, inst.type, ir) + if consistent + flag |= IR_FLAG_CONSISTENT + end if effect_free_and_nothrow flag |= IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW elseif nothrow @@ -519,6 +531,8 @@ function insert_node!(ir::IRCode, pos::Int, inst::NewInstruction, attach_after:: node[:inst], node[:type], node[:flag] = inst.stmt, inst.type, flag return SSAValue(length(ir.stmts) + node.idx) end +insert_node!(ir::IRCode, pos::Int, inst::NewInstruction, attach_after::Bool=false) = + insert_node!(ir, SSAValue(pos), inst, attach_after) # For bootstrapping function my_sortperm(v) @@ -618,16 +632,13 @@ mutable struct IncrementalCompact perm = my_sortperm(Int[code.new_nodes.info[i].pos for i in 1:length(code.new_nodes)]) new_len = length(code.stmts) + length(code.new_nodes) ssa_rename = Any[SSAValue(i) for i = 1:new_len] - new_new_used_ssas = Vector{Int}() - late_fixup = Vector{Int}() bb_rename = Vector{Int}() - new_new_nodes = NewNodeStream() pending_nodes = NewNodeStream() pending_perm = Int[] return new(code, parent.result, parent.result_bbs, ssa_rename, bb_rename, bb_rename, parent.used_ssas, - late_fixup, perm, 1, - new_new_nodes, new_new_used_ssas, pending_nodes, pending_perm, + parent.late_fixup, perm, 1, + parent.new_new_nodes, parent.new_new_used_ssas, pending_nodes, pending_perm, 1, result_offset, parent.active_result_bb, false, false, false) end end @@ -669,7 +680,8 @@ end function block_for_inst(compact::IncrementalCompact, idx::SSAValue) id = idx.id if id < compact.result_idx # if ssa within result - return block_for_inst(compact.result_bbs, id) + return searchsortedfirst(compact.result_bbs, BasicBlock(StmtRange(id, id)), + 1, compact.active_result_bb, bb_ordering())-1 else return block_for_inst(compact.ir.cfg, id) end @@ -678,7 +690,8 @@ end function block_for_inst(compact::IncrementalCompact, idx::OldSSAValue) id = idx.id if id < compact.idx # if ssa within result - return block_for_inst(compact.result_bbs, compact.ssa_rename[id]) + id = compact.ssa_rename[id] + return block_for_inst(compact, SSAValue(id)) else return block_for_inst(compact.ir.cfg, id) end @@ -834,7 +847,10 @@ function insert_node_here!(compact::IncrementalCompact, inst::NewInstruction, re end flag = inst.flag if !inst.effect_free_computed - (effect_free_and_nothrow, nothrow) = stmt_effect_flags(inst.stmt, inst.type, compact) + (consistent, effect_free_and_nothrow, nothrow) = stmt_effect_flags(fallback_lattice, inst.stmt, inst.type, compact) + if consistent + flag |= IR_FLAG_CONSISTENT + end if effect_free_and_nothrow flag |= IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW elseif nothrow @@ -1053,15 +1069,22 @@ function renumber_ssa2!(@nospecialize(stmt), ssanums::Vector{Any}, used_ssas::Ve end # Used in inlining before we start compacting - Only works at the CFG level -function kill_edge!(bbs::Vector{BasicBlock}, from::Int, to::Int) +function kill_edge!(bbs::Vector{BasicBlock}, from::Int, to::Int, callback=nothing) preds, succs = bbs[to].preds, bbs[from].succs deleteat!(preds, findfirst(x->x === from, preds)::Int) deleteat!(succs, findfirst(x->x === to, succs)::Int) if length(preds) == 0 for succ in copy(bbs[to].succs) - kill_edge!(bbs, to, succ) + kill_edge!(bbs, to, succ, callback) end end + if callback !== nothing + callback(from, to) + end +end + +function kill_edge!(ir::IRCode, from::Int, to::Int, callback=nothing) + kill_edge!(ir.cfg.blocks, from, to, callback) end # N.B.: from and to are non-renamed indices @@ -1129,12 +1152,21 @@ function process_node!(compact::IncrementalCompact, result_idx::Int, inst::Instr elseif isa(stmt, OldSSAValue) ssa_rename[idx] = ssa_rename[stmt.id] elseif isa(stmt, GotoNode) && cfg_transforms_enabled - result[result_idx][:inst] = GotoNode(compact.bb_rename_succ[stmt.label]) + label = compact.bb_rename_succ[stmt.label] + @assert label > 0 + result[result_idx][:inst] = GotoNode(label) result_idx += 1 elseif isa(stmt, GlobalRef) - result[result_idx][:inst] = stmt - result[result_idx][:type] = argextype(stmt, compact) - result_idx += 1 + total_flags = IR_FLAG_CONSISTENT | IR_FLAG_EFFECT_FREE + flag = result[result_idx][:flag] + if (flag & total_flags) == total_flags + ssa_rename[idx] = stmt + else + result[result_idx][:inst] = stmt + result[result_idx][:type] = argextype(stmt, compact) + result[result_idx][:flag] = flag + result_idx += 1 + end elseif isa(stmt, GotoNode) result[result_idx][:inst] = stmt result_idx += 1 @@ -1154,19 +1186,25 @@ function process_node!(compact::IncrementalCompact, result_idx::Int, inst::Instr kill_edge!(compact, active_bb, active_bb, stmt.dest) # Don't increment result_idx => Drop this statement else - result[result_idx][:inst] = GotoNode(compact.bb_rename_succ[stmt.dest]) + label = compact.bb_rename_succ[stmt.dest] + @assert label > 0 + result[result_idx][:inst] = GotoNode(label) kill_edge!(compact, active_bb, active_bb, active_bb+1) result_idx += 1 end else @label bail - result[result_idx][:inst] = GotoIfNot(cond, compact.bb_rename_succ[stmt.dest]) + label = compact.bb_rename_succ[stmt.dest] + @assert label > 0 + result[result_idx][:inst] = GotoIfNot(cond, label) result_idx += 1 end elseif isa(stmt, Expr) stmt = renumber_ssa2!(stmt, ssa_rename, used_ssas, new_new_used_ssas, late_fixup, result_idx, do_rename_ssa)::Expr if cfg_transforms_enabled && isexpr(stmt, :enter) - stmt.args[1] = compact.bb_rename_succ[stmt.args[1]::Int] + label = compact.bb_rename_succ[stmt.args[1]::Int] + @assert label > 0 + stmt.args[1] = label end result[result_idx][:inst] = stmt result_idx += 1 @@ -1339,10 +1377,7 @@ function process_newnode!(compact::IncrementalCompact, new_idx::Int, new_node_en active_bb += 1 finish_current_bb!(compact, active_bb, old_result_idx) end - (old_result_idx == result_idx) && return iterate(compact, (idx, active_bb)) - return Pair{Pair{Int, Int}, Any}( - Pair{Int,Int}(new_idx,old_result_idx), - compact.result[old_result_idx][:inst]), (idx, active_bb) + return (new_idx, old_result_idx, result_idx, idx, active_bb) end struct CompactPeekIterator @@ -1385,7 +1420,15 @@ function iterate(it::CompactPeekIterator, (idx, aidx, bidx)::NTuple{3, Int}=(it. return (compact.ir.stmts[idx][:inst], (idx + 1, aidx, bidx)) end -function iterate(compact::IncrementalCompact, (idx, active_bb)::Tuple{Int, Int}=(compact.idx, 1)) +# This Union{Nothing, Pair{Pair{Int,Int},Any}} cannot be stack allocated, so we inline it +@inline function iterate(compact::IncrementalCompact, st::Tuple{Int, Int}=(compact.idx, 1)) + st = iterate_compact(compact, st) + st === nothing && return nothing + old_result_idx = st[1][2] + return Pair{Pair{Int,Int},Any}(st[1], compact.result[old_result_idx][:inst]), st[2] +end + +function iterate_compact(compact::IncrementalCompact, (idx, active_bb)::Tuple{Int, Int}) # Create label to dodge recursion so that we don't stack overflow @label restart @@ -1418,9 +1461,9 @@ function iterate(compact::IncrementalCompact, (idx, active_bb)::Tuple{Int, Int}= # Move to next block compact.idx += 1 if finish_current_bb!(compact, active_bb, old_result_idx, true) - return iterate(compact, (compact.idx, active_bb + 1)) + return iterate_compact(compact, (compact.idx, active_bb + 1)) else - return Pair{Pair{Int, Int}, Any}(Pair{Int,Int}(compact.idx-1, old_result_idx), compact.result[old_result_idx][:inst]), (compact.idx, active_bb + 1) + return Pair{Int,Int}(compact.idx-1, old_result_idx), (compact.idx, active_bb + 1) end end if compact.new_nodes_idx <= length(compact.perm) && @@ -1431,7 +1474,10 @@ function iterate(compact::IncrementalCompact, (idx, active_bb)::Tuple{Int, Int}= new_node_entry = compact.ir.new_nodes.stmts[new_idx] new_node_info = compact.ir.new_nodes.info[new_idx] new_idx += length(compact.ir.stmts) - return process_newnode!(compact, new_idx, new_node_entry, new_node_info, idx, active_bb, true) + (new_idx, old_result_idx, result_idx, idx, active_bb) = + process_newnode!(compact, new_idx, new_node_entry, new_node_info, idx, active_bb, true) + old_result_idx == result_idx && @goto restart + return Pair{Int,Int}(new_idx, old_result_idx), (idx, active_bb) elseif !isempty(compact.pending_perm) && (info = compact.pending_nodes.info[compact.pending_perm[1]]; info.attach_after ? info.pos == idx - 1 : info.pos == idx) @@ -1439,7 +1485,10 @@ function iterate(compact::IncrementalCompact, (idx, active_bb)::Tuple{Int, Int}= new_node_entry = compact.pending_nodes.stmts[new_idx] new_node_info = compact.pending_nodes.info[new_idx] new_idx += length(compact.ir.stmts) + length(compact.ir.new_nodes) - return process_newnode!(compact, new_idx, new_node_entry, new_node_info, idx, active_bb, false) + (new_idx, old_result_idx, result_idx, idx, active_bb) = + process_newnode!(compact, new_idx, new_node_entry, new_node_info, idx, active_bb, false) + old_result_idx == result_idx && @goto restart + return Pair{Int,Int}(new_idx, old_result_idx), (idx, active_bb) end # This will get overwritten in future iterations if # result_idx is not, incremented, but that's ok and expected @@ -1456,8 +1505,7 @@ function iterate(compact::IncrementalCompact, (idx, active_bb)::Tuple{Int, Int}= @goto restart end @assert isassigned(compact.result.inst, old_result_idx) - return Pair{Pair{Int,Int}, Any}(Pair{Int,Int}(compact.idx-1, old_result_idx), - compact.result[old_result_idx][:inst]), (compact.idx, active_bb) + return Pair{Int,Int}(compact.idx-1, old_result_idx), (compact.idx, active_bb) end function maybe_erase_unused!( @@ -1490,63 +1538,89 @@ function maybe_erase_unused!( return false end -function fixup_phinode_values!(compact::IncrementalCompact, old_values::Vector{Any}) +struct FixedNode + node::Any + needs_fixup::Bool + FixedNode(@nospecialize(node), needs_fixup::Bool) = new(node, needs_fixup) +end + +function fixup_phinode_values!(compact::IncrementalCompact, old_values::Vector{Any}, reify_new_nodes::Bool) values = Vector{Any}(undef, length(old_values)) + fixup = false for i = 1:length(old_values) isassigned(old_values, i) || continue - val = old_values[i] - if isa(val, Union{OldSSAValue, NewSSAValue}) - val = fixup_node(compact, val) - end - values[i] = val + (; node, needs_fixup) = fixup_node(compact, old_values[i], reify_new_nodes) + fixup |= needs_fixup + values[i] = node end - values + return (values, fixup) end -function fixup_node(compact::IncrementalCompact, @nospecialize(stmt)) + +function fixup_node(compact::IncrementalCompact, @nospecialize(stmt), reify_new_nodes::Bool) if isa(stmt, PhiNode) - return PhiNode(stmt.edges, fixup_phinode_values!(compact, stmt.values)) + (node, needs_fixup) = fixup_phinode_values!(compact, stmt.values, reify_new_nodes) + return FixedNode(PhiNode(stmt.edges, node), needs_fixup) elseif isa(stmt, PhiCNode) - return PhiCNode(fixup_phinode_values!(compact, stmt.values)) + (node, needs_fixup) = fixup_phinode_values!(compact, stmt.values, reify_new_nodes) + return FixedNode(PhiCNode(node), needs_fixup) elseif isa(stmt, NewSSAValue) @assert stmt.id < 0 - return SSAValue(length(compact.result) - stmt.id) + if reify_new_nodes + val = SSAValue(length(compact.result) - stmt.id) + return FixedNode(val, false) + else + return FixedNode(stmt, true) + end elseif isa(stmt, OldSSAValue) val = compact.ssa_rename[stmt.id] if isa(val, SSAValue) - # If `val.id` is greater than the length of `compact.result` or - # `compact.used_ssas`, this SSA value is in `new_new_nodes`, so - # don't count the use compact.used_ssas[val.id] += 1 end - return val + return FixedNode(val, false) else urs = userefs(stmt) + fixup = false for ur in urs val = ur[] if isa(val, Union{NewSSAValue, OldSSAValue}) - ur[] = fixup_node(compact, val) + (;node, needs_fixup) = fixup_node(compact, val, reify_new_nodes) + fixup |= needs_fixup + ur[] = node end end - return urs[] + return FixedNode(urs[], fixup) end end -function just_fixup!(compact::IncrementalCompact) - resize!(compact.used_ssas, length(compact.result)) - append!(compact.used_ssas, compact.new_new_used_ssas) - empty!(compact.new_new_used_ssas) - for idx in compact.late_fixup +function just_fixup!(compact::IncrementalCompact, new_new_nodes_offset::Union{Int, Nothing} = nothing, late_fixup_offset::Union{Int, Nothing} = nothing) + if new_new_nodes_offset === late_fixup_offset === nothing # only do this appending in non_dce_finish! + resize!(compact.used_ssas, length(compact.result)) + append!(compact.used_ssas, compact.new_new_used_ssas) + empty!(compact.new_new_used_ssas) + end + off = late_fixup_offset === nothing ? 1 : (late_fixup_offset+1) + set_off = off + for i in off:length(compact.late_fixup) + idx = compact.late_fixup[i] stmt = compact.result[idx][:inst] - new_stmt = fixup_node(compact, stmt) - (stmt === new_stmt) || (compact.result[idx][:inst] = new_stmt) - end - for idx in 1:length(compact.new_new_nodes) - node = compact.new_new_nodes.stmts[idx] - stmt = node[:inst] - new_stmt = fixup_node(compact, stmt) - if new_stmt !== stmt - node[:inst] = new_stmt + (;node, needs_fixup) = fixup_node(compact, stmt, late_fixup_offset === nothing) + (stmt === node) || (compact.result[idx][:inst] = node) + if needs_fixup + compact.late_fixup[set_off] = idx + set_off += 1 + end + end + if late_fixup_offset !== nothing + resize!(compact.late_fixup, set_off-1) + end + off = new_new_nodes_offset === nothing ? 1 : (new_new_nodes_offset+1) + for idx in off:length(compact.new_new_nodes) + new_node = compact.new_new_nodes.stmts[idx] + stmt = new_node[:inst] + (;node) = fixup_node(compact, stmt, late_fixup_offset === nothing) + if node !== stmt + new_node[:inst] = node end end end @@ -1614,3 +1688,18 @@ function iterate(x::BBIdxIter, (idx, bb)::Tuple{Int, Int}=(1, 1)) end return (bb, idx), (idx + 1, next_bb) end + +# Inserters + +abstract type Inserter; end + +struct InsertHere <: Inserter + compact::IncrementalCompact +end +(i::InsertHere)(new_inst::NewInstruction) = insert_node_here!(i.compact, new_inst) + +struct InsertBefore{T<:Union{IRCode, IncrementalCompact}} <: Inserter + src::T + pos::SSAValue +end +(i::InsertBefore)(new_inst::NewInstruction) = insert_node!(i.src, i.pos, new_inst) diff --git a/base/compiler/ssair/irinterp.jl b/base/compiler/ssair/irinterp.jl new file mode 100644 index 0000000000000..0a561b4107125 --- /dev/null +++ b/base/compiler/ssair/irinterp.jl @@ -0,0 +1,407 @@ +function codeinst_to_ir(interp::AbstractInterpreter, code::CodeInstance) + src = code.inferred + mi = code.def + + if isa(src, Vector{UInt8}) + src = ccall(:jl_uncompress_ir, Any, (Any, Ptr{Cvoid}, Any), mi.def, C_NULL, src)::CodeInfo + end + + isa(src, CodeInfo) || return src + + return inflate_ir(src, mi) +end + +function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f), + arginfo::ArgInfo, @nospecialize(atype), + sv::IRCode, max_methods::Int) + return CallMeta(Any, Effects(), false) +end + +function collect_limitations!(@nospecialize(typ), ::IRCode) + @assert !isa(typ, LimitedAccuracy) "semi-concrete eval on recursive call graph" + return typ +end + +mutable struct TwoPhaseVectorView <: AbstractVector{Int} + const data::Vector{Int} + count::Int + const range::UnitRange{Int} +end +size(tpvv::TwoPhaseVectorView) = (tpvv.count,) +function getindex(tpvv::TwoPhaseVectorView, i::Int) + checkbounds(tpvv, i) + @inbounds tpvv.data[first(tpvv.range) + i - 1] +end +function push!(tpvv::TwoPhaseVectorView, v::Int) + tpvv.count += 1 + tpvv.data[first(tpvv.range) + tpvv.count - 1] = v + return nothing +end + +""" + mutable struct TwoPhaseDefUseMap + +This struct is intended as a memory- and GC-pressure-efficient mechanism +for incrementally computing def-use maps. The idea is that the def-use map +is constructed into two passes over the IR. In the first, we simply count the +the number of uses, computing the number of uses for each def as well as the +total number of uses. In the second pass, we actually fill in the def-use +information. + +The idea is that either of these two phases can be combined with other useful +work that needs to scan the instruction stream anyway, while avoiding the +significant allocation pressure of e.g. allocating an array for every SSA value +or attempting to dynamically move things around as new uses are discovered. + +The def-use map is presented as a vector of vectors. For every def, indexing +into the map will return a vector of uses. +""" +mutable struct TwoPhaseDefUseMap <: AbstractVector{TwoPhaseVectorView} + ssa_uses::Vector{Int} + data::Vector{Int} + complete::Bool +end + +function complete!(tpdum::TwoPhaseDefUseMap) + cumsum = 0 + for i = 1:length(tpdum.ssa_uses) + this_val = cumsum + 1 + cumsum += tpdum.ssa_uses[i] + tpdum.ssa_uses[i] = this_val + end + resize!(tpdum.data, cumsum) + fill!(tpdum.data, 0) + tpdum.complete = true +end + +function TwoPhaseDefUseMap(nssas::Int) + ssa_uses = zeros(Int, nssas) + data = Int[] + complete = false + return TwoPhaseDefUseMap(ssa_uses, data, complete) +end + +function count!(tpdum::TwoPhaseDefUseMap, arg::SSAValue) + @assert !tpdum.complete + tpdum.ssa_uses[arg.id] += 1 +end + +function kill_def_use!(tpdum::TwoPhaseDefUseMap, def::Int, use::Int) + if !tpdum.complete + tpdum.ssa_uses[def] -= 1 + else + @assert false && "TODO" + end +end +kill_def_use!(tpdum::TwoPhaseDefUseMap, def::SSAValue, use::Int) = + kill_def_use!(tpdum, def.id, use) + +function getindex(tpdum::TwoPhaseDefUseMap, idx::Int) + @assert tpdum.complete + range = tpdum.ssa_uses[idx]:(idx == length(tpdum.ssa_uses) ? length(tpdum.data) : (tpdum.ssa_uses[idx + 1] - 1)) + # TODO: Make logarithmic + nelems = 0 + for i in range + tpdum.data[i] == 0 && break + nelems += 1 + end + return TwoPhaseVectorView(tpdum.data, nelems, range) +end + +function concrete_eval_invoke(interp::AbstractInterpreter, ir::IRCode, mi_cache, + inst::Expr, mi::MethodInstance) + code = get(mi_cache, mi, nothing) + code === nothing && return nothing + argtypes = collect_argtypes(interp, inst.args[2:end], nothing, ir) + effects = decode_effects(code.ipo_purity_bits) + if is_foldable(effects) && is_all_const_arg(argtypes, #=start=#1) + args = collect_const_args(argtypes, #=start=#1) + world = get_world_counter(interp) + value = try + Core._call_in_world_total(world, args...) + catch + return Union{} + end + if is_inlineable_constant(value) + return Const(value) + end + else + ir′ = codeinst_to_ir(interp, code) + if ir′ !== nothing + return _ir_abstract_constant_propagation(interp, mi_cache, mi, ir′, argtypes) + end + end + return nothing +end + +function reprocess_instruction!(interp::AbstractInterpreter, ir::IRCode, mi::MethodInstance, + mi_cache, + tpdum::TwoPhaseDefUseMap, idx::Int, bb::Union{Int, Nothing}, + @nospecialize(inst), @nospecialize(typ), + phi_revisit::BitSet) + function update_phi!(from::Int, to::Int) + if length(ir.cfg.blocks[to].preds) == 0 + return + end + for idx in ir.cfg.blocks[to].stmts + stmt = ir.stmts[idx][:inst] + isa(stmt, Nothing) && continue + isa(stmt, PhiNode) || break + for (i, edge) in enumerate(stmt.edges) + if edge == from + deleteat!(stmt.edges, i) + deleteat!(stmt.values, i) + push!(phi_revisit, idx) + break + end + end + end + end + + if isa(inst, GotoIfNot) + cond = argextype(inst.cond, ir) + if isa(cond, Const) + if isa(inst.cond, SSAValue) + kill_def_use!(tpdum, inst.cond, idx) + end + if bb === nothing + bb = block_for_inst(ir, idx) + end + if (cond.val)::Bool + ir.stmts[idx][:inst] = nothing + kill_edge!(ir, bb, inst.dest, update_phi!) + else + ir.stmts[idx][:inst] = GotoNode(inst.dest) + kill_edge!(ir, bb, bb+1, update_phi!) + end + return true + end + return false + else + if isa(inst, Expr) || isa(inst, PhiNode) + if isa(inst, PhiNode) || inst.head === :call || inst.head === :foreigncall || inst.head === :new + if isa(inst, PhiNode) + rt = abstract_eval_phi(interp, inst, nothing, ir) + else + (;rt, effects) = abstract_eval_statement_expr(interp, inst, nothing, ir, mi) + # All other effects already guaranteed effect free by construction + if is_nothrow(effects) + if isa(rt, Const) && is_inlineable_constant(rt.val) + ir.stmts[idx][:inst] = quoted(rt.val) + else + ir.stmts[idx][:flag] |= IR_FLAG_EFFECT_FREE + end + end + end + if !⊑(typeinf_lattice(interp), typ, rt) + ir.stmts[idx][:type] = rt + return true + end + elseif inst.head === :invoke + mi′ = inst.args[1]::MethodInstance + if mi′ !== mi # prevent infinite loop + rr = concrete_eval_invoke(interp, ir, mi_cache, inst, mi′) + if rr !== nothing + if !⊑(typeinf_lattice(interp), typ, rr) + ir.stmts[idx][:type] = rr + return true + end + end + end + else + ccall(:jl_, Cvoid, (Any,), inst) + error() + end + elseif isa(inst, ReturnNode) + # Handled at the very end + return false + elseif isa(inst, PiNode) + rr = tmeet(argextype(inst.val, ir), inst.typ) + if !⊑(typeinf_lattice(interp), typ, rr) + ir.stmts[idx][:type] = rr + return true + end + else + ccall(:jl_, Cvoid, (Any,), inst) + error() + end + end + return false +end + +function _ir_abstract_constant_propagation(interp::AbstractInterpreter, mi_cache, + mi::MethodInstance, ir::IRCode, argtypes::Vector{Any}; extra_reprocess = nothing) + argtypes = va_process_argtypes(argtypes, mi) + argtypes_refined = Bool[!⊑(typeinf_lattice(interp), ir.argtypes[i], argtypes[i]) for i = 1:length(argtypes)] + empty!(ir.argtypes) + append!(ir.argtypes, argtypes) + ssa_refined = BitSet() + + bbs = ir.cfg.blocks + ip = BitSetBoundedMinPrioritySet(length(bbs)) + push!(ip, 1) + all_rets = Int[] + + tpdum = TwoPhaseDefUseMap(length(ir.stmts)) + + """ + process_terminator! + + Process the terminator and add the successor to `ip`. Returns whether a + backedge was seen. + """ + function process_terminator!(ip::BitSetBoundedMinPrioritySet, bb::Int, idx::Int) + inst = ir.stmts[idx][:inst] + if isa(inst, ReturnNode) + if isdefined(inst, :val) + push!(all_rets, idx) + end + return false + elseif isa(inst, GotoNode) + backedge = inst.label < bb + !backedge && push!(ip, inst.label) + return backedge + elseif isa(inst, GotoIfNot) + backedge = inst.dest < bb + !backedge && push!(ip, inst.dest) + push!(ip, bb + 1) + return backedge + elseif isexpr(inst, :enter) + dest = inst.args[1]::Int + @assert dest > bb + push!(ip, dest) + push!(ip, bb + 1) + return false + else + push!(ip, bb + 1) + return false + end + end + + # Fast path: Scan both use counts and refinement in one single pass of + # of the instructions. In the absence of backedges, this will + # converge. + while !isempty(ip) + bb = popfirst!(ip) + stmts = bbs[bb].stmts + lstmt = last(stmts) + for idx = stmts + inst = ir.stmts[idx][:inst] + typ = ir.stmts[idx][:type] + any_refined = extra_reprocess === nothing ? false : (idx in extra_reprocess) + for ur in userefs(inst) + val = ur[] + if isa(val, Argument) + any_refined |= argtypes_refined[val.n] + elseif isa(val, SSAValue) + any_refined |= val.id in ssa_refined + count!(tpdum, val) + end + end + if isa(inst, PhiNode) && idx in ssa_refined + any_refined = true + delete!(ssa_refined, idx) + end + if any_refined && reprocess_instruction!(interp, ir, mi, mi_cache, + tpdum, idx, bb, inst, typ, ssa_refined) + push!(ssa_refined, idx) + end + if idx == lstmt && process_terminator!(ip, bb, idx) + @goto residual_scan + end + if typ === Bottom && !isa(inst, PhiNode) + break + end + end + end + @goto compute_rt + +@label residual_scan + stmt_ip = BitSetBoundedMinPrioritySet(length(ir.stmts)) + # Slow Path Phase 1.A: Complete use scanning + while !isempty(ip) + bb = popfirst!(ip) + stmts = bbs[bb].stmts + lstmt = last(stmts) + for idx = stmts + inst = ir.stmts[idx][:inst] + for ur in userefs(inst) + val = ur[] + if isa(val, Argument) + if argtypes_refined[val.n] + push!(stmt_ip, idx) + end + elseif isa(val, SSAValue) + count!(tpdum, val) + end + end + idx == lstmt && process_terminator!(ip, bb, idx) + end + end + + # Slow Path Phase 1.B: Assemble def-use map + complete!(tpdum) + push!(ip, 1) + while !isempty(ip) + bb = popfirst!(ip) + stmts = bbs[bb].stmts + lstmt = last(stmts) + for idx = stmts + inst = ir.stmts[idx][:inst] + for ur in userefs(inst) + val = ur[] + if isa(val, SSAValue) + push!(tpdum[val.id], idx) + end + end + idx == lstmt && process_terminator!(ip, bb, idx) + end + end + + # Slow Path Phase 2: Use def-use map to converge cycles. + # TODO: It would be possible to return to the fast path after converging + # each cycle, but that's somewhat complicated. + for val in ssa_refined + append!(stmt_ip, tpdum[val]) + end + + while !isempty(stmt_ip) + idx = popfirst!(stmt_ip) + inst = ir.stmts[idx][:inst] + typ = ir.stmts[idx][:type] + if reprocess_instruction!(interp, ir, mi, mi_cache, + tpdum, idx, nothing, inst, typ, ssa_refined) + append!(stmt_ip, tpdum[idx]) + end + end + +@label compute_rt + ultimate_rt = Union{} + for idx in all_rets + bb = block_for_inst(ir.cfg, idx) + if bb != 1 && length(ir.cfg.blocks[bb].preds) == 0 + # Could have discovered this block is dead after the initial scan + continue + end + inst = ir.stmts[idx][:inst]::ReturnNode + rt = argextype(inst.val, ir) + ultimate_rt = tmerge(typeinf_lattice(interp), ultimate_rt, rt) + end + + return ultimate_rt +end + +function ir_abstract_constant_propagation(interp::AbstractInterpreter, mi_cache, + frame::InferenceState, mi::MethodInstance, ir::IRCode, argtypes::Vector{Any}) + if __measure_typeinf__[] + inf_frame = Timings.InferenceFrameInfo(mi, frame.world, Any[], Any[], length(ir.argtypes)) + Timings.enter_new_timer(inf_frame) + v = _ir_abstract_constant_propagation(interp, mi_cache, mi, ir, argtypes) + append!(inf_frame.slottypes, ir.argtypes) + Timings.exit_current_timer(inf_frame) + return v + else + T = _ir_abstract_constant_propagation(interp, mi_cache, mi, ir, argtypes) + return T + end +end diff --git a/base/compiler/ssair/passes.jl b/base/compiler/ssair/passes.jl index 594b77b38654a..48dea77539111 100644 --- a/base/compiler/ssair/passes.jl +++ b/base/compiler/ssair/passes.jl @@ -75,7 +75,7 @@ end function find_curblock(domtree::DomTree, allblocks::Vector{Int}, curblock::Int) # TODO: This can be much faster by looking at current level and only # searching for those blocks in a sorted order - while !(curblock in allblocks) + while !(curblock in allblocks) && curblock !== 0 curblock = domtree.idoms_bb[curblock] end return curblock @@ -140,7 +140,7 @@ function has_safe_def( # if this block has already been examined, bail out to avoid infinite cycles pred in seen && return false idx = last(ir.cfg.blocks[pred].stmts) - # NOTE `idx` isn't a load, thus we can use inclusive coondition within the `find_def_for_use` + # NOTE `idx` isn't a load, thus we can use inclusive condition within the `find_def_for_use` def, _, _ = find_def_for_use(ir, domtree, allblocks, du, idx, true) # will throw since we already checked this `:new` site doesn't define this field def == newidx && return false @@ -289,7 +289,7 @@ function walk_to_defs(compact::IncrementalCompact, @nospecialize(defssa), @nospe # path, with a different type constraint. We may have # to redo some work here with the wider typeconstraint push!(worklist_defs, new_def) - push!(worklist_constraints, tmerge(new_constraint, visited_constraints[new_def])) + push!(worklist_constraints, tmerge(OptimizerLattice(), new_constraint, visited_constraints[new_def])) end continue end @@ -348,12 +348,12 @@ function is_getfield_captures(@nospecialize(def), compact::IncrementalCompact) isa(which, Const) || return false which.val === :captures || return false oc = argextype(def.args[2], compact) - return oc ⊑ Core.OpaqueClosure + return oc ⊑ₒ Core.OpaqueClosure end struct LiftedValue - x - LiftedValue(@nospecialize x) = new(x) + val + LiftedValue(@nospecialize val) = new(val) end const LiftedLeaves = IdDict{Any, Union{Nothing,LiftedValue}} @@ -528,13 +528,15 @@ function lift_comparison!(::typeof(===), compact::IncrementalCompact, lift_comparison_leaves!(egal_tfunc, compact, val, cmp, lifting_cache, idx) end +isa_tfunc_opt(@nospecialize(v), @nospecialize(t)) = isa_tfunc(OptimizerLattice(), v, t) + function lift_comparison!(::typeof(isa), compact::IncrementalCompact, idx::Int, stmt::Expr, lifting_cache::IdDict{Pair{AnySSAValue, Any}, AnySSAValue}) args = stmt.args length(args) == 3 || return cmp = argextype(args[3], compact) val = args[2] - lift_comparison_leaves!(isa_tfunc, compact, val, cmp, lifting_cache, idx) + lift_comparison_leaves!(isa_tfunc_opt, compact, val, cmp, lifting_cache, idx) end function lift_comparison!(::typeof(isdefined), compact::IncrementalCompact, @@ -578,7 +580,7 @@ function lift_comparison_leaves!(@specialize(tfunc), visited_phinodes, cmp, lifting_cache, Bool, lifted_leaves::LiftedLeaves, val, nothing)::LiftedValue - compact[idx] = lifted_val.x + compact[idx] = lifted_val.val end struct LiftedPhi @@ -593,16 +595,21 @@ function is_old(compact, @nospecialize(old_node_ssa)) !already_inserted(compact, old_node_ssa) end -mutable struct LazyDomtree +mutable struct LazyGenericDomtree{IsPostDom} ir::IRCode - domtree::DomTree - LazyDomtree(ir::IRCode) = new(ir) + domtree::GenericDomTree{IsPostDom} + LazyGenericDomtree{IsPostDom}(ir::IRCode) where {IsPostDom} = new{IsPostDom}(ir) end -function get(x::LazyDomtree) +function get!(x::LazyGenericDomtree{IsPostDom}) where {IsPostDom} isdefined(x, :domtree) && return x.domtree - return @timeit "domtree 2" x.domtree = construct_domtree(x.ir.cfg.blocks) + return @timeit "domtree 2" x.domtree = IsPostDom ? + construct_postdomtree(x.ir.cfg.blocks) : + construct_domtree(x.ir.cfg.blocks) end +const LazyDomtree = LazyGenericDomtree{false} +const LazyPostDomtree = LazyGenericDomtree{true} + function perform_lifting!(compact::IncrementalCompact, visited_phinodes::Vector{AnySSAValue}, @nospecialize(cache_key), lifting_cache::IdDict{Pair{AnySSAValue, Any}, AnySSAValue}, @@ -626,7 +633,7 @@ function perform_lifting!(compact::IncrementalCompact, end end - the_leaf_val = isa(the_leaf, LiftedValue) ? the_leaf.x : nothing + the_leaf_val = isa(the_leaf, LiftedValue) ? the_leaf.val : nothing if !isa(the_leaf_val, SSAValue) all_same = false end @@ -634,7 +641,7 @@ function perform_lifting!(compact::IncrementalCompact, if all_same dominates_all = true if lazydomtree !== nothing - domtree = get(lazydomtree) + domtree = get!(lazydomtree) for item in visited_phinodes if !dominates_ssa(compact, domtree, the_leaf_val, item) dominates_all = false @@ -690,7 +697,7 @@ function perform_lifting!(compact::IncrementalCompact, resize!(new_node.values, length(new_node.values)+1) continue end - val = lifted_val.x + val = lifted_val.val if isa(val, AnySSAValue) callback = (@nospecialize(pi), @nospecialize(idx)) -> true val = simple_walk(compact, val, callback) @@ -720,6 +727,93 @@ function perform_lifting!(compact::IncrementalCompact, return stmt_val # N.B. should never happen end +function lift_svec_ref!(compact::IncrementalCompact, idx::Int, stmt::Expr) + length(stmt.args) != 4 && return + + vec = stmt.args[3] + val = stmt.args[4] + valT = argextype(val, compact) + (isa(valT, Const) && isa(valT.val, Int)) || return + valI = valT.val::Int + valI >= 1 || return + + if isa(vec, SimpleVector) + valI <= length(vec) || return + compact[idx] = quoted(vec[valI]) + elseif isa(vec, SSAValue) + def = compact[vec][:inst] + if is_known_call(def, Core.svec, compact) + valI <= length(def.args) - 1 || return + compact[idx] = def.args[valI+1] + elseif is_known_call(def, Core._compute_sparams, compact) + valI != 1 && return # TODO generalize this for more values of valI + res = _lift_svec_ref(def, compact) + res === nothing && return + compact[idx] = res.val + end + end + return +end + +# TODO: We could do the whole lifing machinery here, but really all +# we want to do is clean this up when it got inserted by inlining, +# which always targets simple `svec` call or `_compute_sparams`, +# so this specialized lifting would be enough +@inline function _lift_svec_ref(def::Expr, compact::IncrementalCompact) + length(def.args) >= 3 || return nothing + m = argextype(def.args[2], compact) + isa(m, Const) || return nothing + m = m.val + isa(m, Method) || return nothing + + # TODO: More general structural analysis of the intersection + sig = m.sig + isa(sig, UnionAll) || return nothing + tvar = sig.var + sig = sig.body + isa(sig, DataType) || return nothing + sig.name === Tuple.name || return nothing + length(sig.parameters) >= 1 || return nothing + + i = let sig=sig + findfirst(j->has_typevar(sig.parameters[j], tvar), 1:length(sig.parameters)) + end + i === nothing && return nothing + let sig=sig + any(j->has_typevar(sig.parameters[j], tvar), i+1:length(sig.parameters)) + end && return nothing + + arg = sig.parameters[i] + isa(arg, DataType) || return nothing + + rarg = def.args[2 + i] + isa(rarg, SSAValue) || return nothing + argdef = compact[rarg][:inst] + if isexpr(argdef, :new) + rarg = argdef.args[1] + isa(rarg, SSAValue) || return nothing + argdef = compact[rarg][:inst] + end + + is_known_call(argdef, Core.apply_type, compact) || return nothing + length(argdef.args) == 3 || return nothing + + applyT = argextype(argdef.args[2], compact) + isa(applyT, Const) || return nothing + applyT = applyT.val + + isa(applyT, UnionAll) || return nothing + applyTvar = applyT.var + applyTbody = applyT.body + + isa(applyTbody, DataType) || return nothing + applyTbody.name == arg.name || return nothing + length(applyTbody.parameters) == length(arg.parameters) == 1 || return nothing + applyTbody.parameters[1] === applyTvar || return nothing + arg.parameters[1] === tvar || return nothing + return LiftedValue(argdef.args[3]) +end + # NOTE we use `IdSet{Int}` instead of `BitSet` for in these passes since they work on IR after inlining, # which can be very large sometimes, and program counters in question are often very sparse const SPCSet = IdSet{Int} @@ -776,10 +870,15 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing, InliningState} = nothin end elseif is_known_call(stmt, Core.finalizer, compact) 3 <= length(stmt.args) <= 5 || continue - # Inlining performs legality checks on the finalizer to determine - # whether or not we may inline it. If so, it appends extra arguments - # at the end of the intrinsic. Detect that here. - length(stmt.args) == 5 || continue + info = compact[SSAValue(idx)][:info] + if isa(info, FinalizerInfo) + is_finalizer_inlineable(info.effects) || continue + else + # Inlining performs legality checks on the finalizer to determine + # whether or not we may inline it. If so, it appends extra arguments + # at the end of the intrinsic. Detect that here. + length(stmt.args) == 5 || continue + end is_finalizer = true elseif isexpr(stmt, :foreigncall) nccallargs = length(stmt.args[3]::SimpleVector) @@ -828,6 +927,8 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing, InliningState} = nothin else # TODO: This isn't the best place to put these if is_known_call(stmt, typeassert, compact) canonicalize_typeassert!(compact, idx, stmt) + elseif is_known_call(stmt, Core._svec_ref, compact) + lift_svec_ref!(compact, idx, stmt) elseif is_known_call(stmt, (===), compact) lift_comparison!(===, compact, idx, stmt, lifting_cache) elseif is_known_call(stmt, isa, compact) @@ -924,7 +1025,7 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing, InliningState} = nothin @assert val !== nothing end - compact[idx] = val === nothing ? nothing : val.x + compact[idx] = val === nothing ? nothing : val.val end non_dce_finish!(compact) @@ -947,13 +1048,13 @@ end # NOTE we resolve the inlining source here as we don't want to serialize `Core.Compiler` # data structure into the global cache (see the comment in `handle_finalizer_call!`) -function try_inline_finalizer!(ir::IRCode, argexprs::Vector{Any}, idx::Int, mi::MethodInstance, inlining::InliningState) +function try_inline_finalizer!(ir::IRCode, argexprs::Vector{Any}, idx::Int, mi::MethodInstance, inlining::InliningState, attach_after::Bool) code = get(inlining.mi_cache, mi, nothing) - et = inlining.et + et = InliningEdgeTracker(inlining.et) if code isa CodeInstance if use_const_api(code) # No code in the function - Nothing to do - et !== nothing && push!(et, mi) + add_inlining_backedge!(et, mi) return true end src = @atomic :monotonic code.inferred @@ -969,83 +1070,163 @@ function try_inline_finalizer!(ir::IRCode, argexprs::Vector{Any}, idx::Int, mi:: length(src.cfg.blocks) == 1 || return false # Ok, we're committed to inlining the finalizer - et !== nothing && push!(et, mi) + add_inlining_backedge!(et, mi) - linetable_offset, extra_coverage_line = ir_inline_linetable!(ir.linetable, src, mi.def, ir[SSAValue(idx)][:line]) - if extra_coverage_line != 0 - insert_node!(ir, idx, NewInstruction(Expr(:code_coverage_effect), Nothing, extra_coverage_line)) - end + # TOOD: Should there be a special line number node for inlined finalizers? + inlined_at = ir[SSAValue(idx)][:line] + ((sp_ssa, argexprs), linetable_offset) = ir_prepare_inlining!(InsertBefore(ir, SSAValue(idx)), ir, + ir.linetable, src, mi.sparam_vals, mi.def, inlined_at, argexprs) # TODO: Use the actual inliner here rather than open coding this special purpose inliner. spvals = mi.sparam_vals ssa_rename = Vector{Any}(undef, length(src.stmts)) for idx′ = 1:length(src.stmts) - urs = userefs(src[SSAValue(idx′)][:inst]) - for ur in urs - if isa(ur[], SSAValue) - ur[] = ssa_rename[ur[].id] - elseif isa(ur[], Argument) - ur[] = argexprs[ur[].n] - elseif isexpr(ur[], :static_parameter) - ur[] = spvals[ur[].args[1]] - end - end - # TODO: Scan newly added statement into the sroa defuse struct - stmt = urs[] - isa(stmt, ReturnNode) && continue inst = src[SSAValue(idx′)] - ssa_rename[idx′] = insert_node!(ir, idx, NewInstruction(stmt, inst; line = inst[:line] + linetable_offset), true) + stmt′ = inst[:inst] + isa(stmt′, ReturnNode) && continue + stmt′ = ssamap(stmt′) do ssa::SSAValue + ssa_rename[ssa.id] + end + stmt′ = ssa_substitute_op!(InsertBefore(ir, SSAValue(idx)), inst, stmt′, argexprs, mi.specTypes, mi.sparam_vals, sp_ssa, :default) + ssa_rename[idx′] = insert_node!(ir, idx, NewInstruction(stmt′, inst; line = inst[:line] + linetable_offset), attach_after) end + return true end -is_nothrow(ir::IRCode, pc::Int) = ir.stmts[pc][:flag] & (IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW) ≠ 0 +is_nothrow(ir::IRCode, pc::Int) = (ir.stmts[pc][:flag] & IR_FLAG_NOTHROW) ≠ 0 -function try_resolve_finalizer!(ir::IRCode, idx::Int, finalizer_idx::Int, defuse::SSADefUse, inlining::InliningState) - # For now: Require that all uses and defs are in the same basic block, - # so that live range calculations are easy. - bb = ir.cfg.blocks[block_for_inst(ir.cfg, first(defuse.uses).idx)] - minval::Int = typemax(Int) - maxval::Int = 0 +function reachable_blocks(cfg::CFG, from_bb::Int, to_bb::Union{Nothing,Int} = nothing) + worklist = Int[from_bb] + visited = BitSet(from_bb) + if to_bb !== nothing + push!(visited, to_bb) + end + function visit!(bb::Int) + if bb ∉ visited + push!(visited, bb) + push!(worklist, bb) + end + end + while !isempty(worklist) + foreach(visit!, cfg.blocks[pop!(worklist)].succs) + end + return visited +end - function check_in_range(x::Union{Int,SSAUse}) - if isa(x, SSAUse) - didx = x.idx +function try_resolve_finalizer!(ir::IRCode, idx::Int, finalizer_idx::Int, defuse::SSADefUse, + inlining::InliningState, lazydomtree::LazyDomtree, + lazypostdomtree::LazyPostDomtree, info::Union{FinalizerInfo, Nothing}) + # For now, require that: + # 1. The allocation dominates the finalizer registration + # 2. The finalizer registration dominates all uses reachable from the + # finalizer registration. + # 3. The insertion block for the finalizer is the post-dominator of all + # uses and the finalizer registration block. The insertion block must + # be dominated by the finalizer registration block. + # 4. The path from the finalizer registration to the finalizer inlining + # location is nothrow + # + # TODO: We could relax item 3, by inlining the finalizer multiple times. + + # Check #1: The allocation dominates the finalizer registration + domtree = get!(lazydomtree) + finalizer_bb = block_for_inst(ir, finalizer_idx) + alloc_bb = block_for_inst(ir, idx) + dominates(domtree, alloc_bb, finalizer_bb) || return nothing + + bb_insert_block::Int = finalizer_bb + bb_insert_idx::Union{Int,Nothing} = finalizer_idx + function note_block_use!(usebb::Int, useidx::Int) + new_bb_insert_block = nearest_common_dominator(get!(lazypostdomtree), + bb_insert_block, usebb) + if new_bb_insert_block == bb_insert_block == usebb + if bb_insert_idx !== nothing + bb_insert_idx = max(bb_insert_idx, useidx) + else + bb_insert_idx = useidx + end else - didx = x + bb_insert_idx = nothing end - didx in bb.stmts || return false - if didx < minval - minval = didx - end - if didx > maxval - maxval = didx + bb_insert_block = new_bb_insert_block + nothing + end + + # Collect all reachable blocks between the finalizer registration and the + # insertion point + blocks = reachable_blocks(ir.cfg, finalizer_bb, alloc_bb) + + # Check #2 + function check_defuse(x::Union{Int,SSAUse}) + duidx = x isa SSAUse ? x.idx : x + duidx == finalizer_idx && return true + bb = block_for_inst(ir, duidx) + # Not reachable from finalizer registration - we're ok + bb ∉ blocks && return true + note_block_use!(bb, duidx) + if dominates(domtree, finalizer_bb, bb) + return true + else + return false end - return true end + all(check_defuse, defuse.uses) || return nothing + all(check_defuse, defuse.defs) || return nothing + + # Check #3 + dominates(domtree, finalizer_bb, bb_insert_block) || return nothing + + if !inlining.params.assume_fatal_throw + # Collect all reachable blocks between the finalizer registration and the + # insertion point + blocks = finalizer_bb == bb_insert_block ? Int[finalizer_bb] : + reachable_blocks(ir.cfg, finalizer_bb, bb_insert_block) - check_in_range(idx) || return nothing - all(check_in_range, defuse.uses) || return nothing - all(check_in_range, defuse.defs) || return nothing + # Check #4 + function check_range_nothrow(ir::IRCode, s::Int, e::Int) + return all(s:e) do sidx::Int + sidx == finalizer_idx && return true + sidx == idx && return true + return is_nothrow(ir, sidx) + end + end + for bb in blocks + range = ir.cfg.blocks[bb].stmts + s, e = first(range), last(range) + if bb == bb_insert_block + bb_insert_idx === nothing && continue + e = bb_insert_idx + end + if bb == finalizer_bb + s = finalizer_idx + end + check_range_nothrow(ir, s, e) || return nothing + end + end - # For now: Require all statements in the basic block range to be nothrow. - all(minval:maxval) do idx::Int - return is_nothrow(ir, idx) || idx == finalizer_idx - end || return nothing + # Ok, legality check complete. Figure out the exact statement where we're + # gonna inline the finalizer. + loc = bb_insert_idx === nothing ? first(ir.cfg.blocks[bb_insert_block].stmts) : bb_insert_idx::Int + attach_after = bb_insert_idx !== nothing - # Ok, `finalizer` rewrite is legal. finalizer_stmt = ir[SSAValue(finalizer_idx)][:inst] argexprs = Any[finalizer_stmt.args[2], finalizer_stmt.args[3]] - inline = finalizer_stmt.args[4] - if inline === nothing - # No code in the function - Nothing to do - else - mi = finalizer_stmt.args[5]::MethodInstance - if inline::Bool && try_inline_finalizer!(ir, argexprs, maxval, mi, inlining) - # the finalizer body has been inlined + flags = info === nothing ? UInt8(0) : flags_for_effects(info.effects) + if length(finalizer_stmt.args) >= 4 + inline = finalizer_stmt.args[4] + if inline === nothing + # No code in the function - Nothing to do else - insert_node!(ir, maxval, NewInstruction(Expr(:invoke, mi, argexprs...), Nothing), true) + mi = finalizer_stmt.args[5]::MethodInstance + if inline::Bool && try_inline_finalizer!(ir, argexprs, loc, mi, inlining, attach_after) + # the finalizer body has been inlined + else + insert_node!(ir, loc, with_flags(NewInstruction(Expr(:invoke, mi, argexprs...), Nothing), flags), attach_after) + end end + else + insert_node!(ir, loc, with_flags(NewInstruction(Expr(:call, argexprs...), Nothing), flags), attach_after) end # Erase the call to `finalizer` ir[SSAValue(finalizer_idx)][:inst] = nothing @@ -1053,6 +1234,7 @@ function try_resolve_finalizer!(ir::IRCode, idx::Int, finalizer_idx::Int, defuse end function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse}}, used_ssas::Vector{Int}, lazydomtree::LazyDomtree, inlining::Union{Nothing, InliningState}) + lazypostdomtree = LazyPostDomtree(ir) for (idx, (intermediaries, defuse)) in defuses intermediaries = collect(intermediaries) # Check if there are any uses we did not account for. If so, the variable @@ -1085,7 +1267,8 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse end end if finalizer_idx !== nothing && inlining !== nothing - try_resolve_finalizer!(ir, idx, finalizer_idx, defuse, inlining) + try_resolve_finalizer!(ir, idx, finalizer_idx, defuse, inlining, + lazydomtree, lazypostdomtree, ir[SSAValue(finalizer_idx)][:info]) continue end # Partition defuses by field @@ -1132,7 +1315,7 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse if isempty(ldu.live_in_bbs) phiblocks = Int[] else - phiblocks = iterated_dominance_frontier(ir.cfg, ldu, get(lazydomtree)) + phiblocks = iterated_dominance_frontier(ir.cfg, ldu, get!(lazydomtree)) end allblocks = sort!(vcat(phiblocks, ldu.def_bbs); alg=QuickSort) blocks[fidx] = phiblocks, allblocks @@ -1140,7 +1323,7 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse for i = 1:length(du.uses) use = du.uses[i] if use.kind === :isdefined - if has_safe_def(ir, get(lazydomtree), allblocks, du, newidx, use.idx) + if has_safe_def(ir, get!(lazydomtree), allblocks, du, newidx, use.idx) ir[SSAValue(use.idx)][:inst] = true else all_eliminated = false @@ -1153,7 +1336,7 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse continue end end - has_safe_def(ir, get(lazydomtree), allblocks, du, newidx, use.idx) || @goto skip + has_safe_def(ir, get!(lazydomtree), allblocks, du, newidx, use.idx) || @goto skip end else # always have some definition at the allocation site for i = 1:length(du.uses) @@ -1168,7 +1351,7 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse # Compute domtree now, needed below, now that we have finished compacting the IR. # This needs to be after we iterate through the IR with `IncrementalCompact` # because removing dead blocks can invalidate the domtree. - domtree = get(lazydomtree) + domtree = get!(lazydomtree) local preserve_uses = nothing for fidx in 1:ndefuse du = fielddefuse[fidx] @@ -1310,7 +1493,8 @@ end function is_union_phi(compact::IncrementalCompact, idx::Int) inst = compact.result[idx] - return isa(inst[:inst], PhiNode) && is_some_union(inst[:type]) + isa(inst[:inst], PhiNode) || return false + return is_some_union(inst[:type]) end """ @@ -1349,7 +1533,7 @@ function adce_pass!(ir::IRCode) r = searchsorted(unionphis, val.id; by = first) if !isempty(r) unionphi = unionphis[first(r)] - t = tmerge(unionphi[2], stmt.typ) + t = tmerge(OptimizerLattice(), unionphi[2], stmt.typ) unionphis[first(r)] = Pair{Int,Any}(unionphi[1], t) end end @@ -1357,7 +1541,7 @@ function adce_pass!(ir::IRCode) if is_known_call(stmt, typeassert, compact) && length(stmt.args) == 3 # nullify safe `typeassert` calls ty, isexact = instanceof_tfunc(argextype(stmt.args[3], compact)) - if isexact && argextype(stmt.args[2], compact) ⊑ ty + if isexact && argextype(stmt.args[2], compact) ⊑ₒ ty compact[idx] = nothing continue end @@ -1386,7 +1570,7 @@ function adce_pass!(ir::IRCode) if !isempty(r) unionphi = unionphis[first(r)] unionphis[first(r)] = Pair{Int,Any}(unionphi[1], - tmerge(unionphi[2], inst[:type])) + tmerge(OptimizerLattice(), unionphi[2], inst[:type])) end end end @@ -1402,7 +1586,7 @@ function adce_pass!(ir::IRCode) continue elseif t === Any continue - elseif compact.result[phi][:type] ⊑ t + elseif compact.result[phi][:type] ⊑ₒ t continue end to_drop = Int[] @@ -1643,6 +1827,12 @@ function cfg_simplify!(ir::IRCode) end return idx end + function ascend_eliminated_preds(pred) + while pred != 1 && length(bbs[pred].preds) == 1 && length(bbs[pred].succs) == 1 + pred = bbs[pred].preds[1] + end + return pred + end # Walk the CFG from the entry block and aggressively combine blocks for (idx, bb) in enumerate(bbs) @@ -1659,12 +1849,14 @@ function cfg_simplify!(ir::IRCode) # If this BB is empty, we can still merge it as long as none of our successor's phi nodes # reference our predecessors. found_interference = false + preds = Int[ascend_eliminated_preds(pred) for pred in bb.preds] for idx in bbs[succ].stmts stmt = ir[SSAValue(idx)][:inst] stmt === nothing && continue isa(stmt, PhiNode) || break for edge in stmt.edges - for pred in bb.preds + edge = ascend_eliminated_preds(edge) + for pred in preds if pred == edge found_interference = true @goto done @@ -1680,47 +1872,62 @@ function cfg_simplify!(ir::IRCode) end end - # Assign new BB numbers + # Assign new BB numbers in DFS order, dropping unreachable blocks max_bb_num = 1 - bb_rename_succ = zeros(Int, length(bbs)) - for i = 1:length(bbs) + bb_rename_succ = fill(0, length(bbs)) + worklist = BitSetBoundedMinPrioritySet(length(bbs)) + push!(worklist, 1) + while !isempty(worklist) + i = popfirst!(worklist) # Drop blocks that will be merged away if merge_into[i] != 0 bb_rename_succ[i] = -1 end - # Drop blocks with no predecessors - if i != 1 && length(ir.cfg.blocks[i].preds) == 0 - bb_rename_succ[i] = -1 - end # Mark dropped blocks for fixup if !isempty(searchsorted(dropped_bbs, i)) - bb_rename_succ[i] = -bbs[i].succs[1] + succ = bbs[i].succs[1] + push!(worklist, succ) + bb_rename_succ[i] = -succ end - bb_rename_succ[i] != 0 && continue - - curr = i - while true - bb_rename_succ[curr] = max_bb_num - max_bb_num += 1 - # Now walk the chain of blocks we merged. - # If we end in something that may fall through, - # we have to schedule that block next - curr = follow_merged_succ(curr) - terminator = ir.stmts[ir.cfg.blocks[curr].stmts[end]][:inst] - if isa(terminator, GotoNode) || isa(terminator, ReturnNode) - break + if bb_rename_succ[i] == 0 + curr = i + while true + @assert bb_rename_succ[curr] == 0 + bb_rename_succ[curr] = max_bb_num + max_bb_num += 1 + # Now walk the chain of blocks we merged. + # If we end in something that may fall through, + # we have to schedule that block next + while merged_succ[curr] != 0 + if bb_rename_succ[curr] == 0 + bb_rename_succ[curr] = -1 + end + curr = merged_succ[curr] + end + terminator = ir.stmts[ir.cfg.blocks[curr].stmts[end]][:inst] + if isa(terminator, GotoNode) || isa(terminator, ReturnNode) + break + elseif isa(terminator, GotoIfNot) + if bb_rename_succ[terminator.dest] == 0 + push!(worklist, terminator.dest) + end + end + ncurr = curr + 1 + if !isempty(searchsorted(dropped_bbs, ncurr)) + break + end + curr = ncurr end - curr += 1 - if !isempty(searchsorted(dropped_bbs, curr)) - break + + for succ in bbs[curr].succs + if bb_rename_succ[succ] == 0 + push!(worklist, succ) + end end end end - # Compute map from new to old blocks - result_bbs = Int[findfirst(j->i==j, bb_rename_succ) for i = 1:max_bb_num-1] - # Fixup dropped BBs resolved_all = false while !resolved_all @@ -1739,8 +1946,24 @@ function cfg_simplify!(ir::IRCode) end end - # Figure out how predecessors should be renamed + # Drop remaining unvisited bbs bb_rename_pred = zeros(Int, length(bbs)) + for i = 1:length(bbs) + if bb_rename_succ[i] == 0 + bb_rename_succ[i] = -1 + bb_rename_pred[i] = -2 + end + end + + # Compute map from new to old blocks + result_bbs = zeros(Int, max_bb_num-1) + for (o, bb) in enumerate(bb_rename_succ) + bb > 0 || continue + isempty(searchsorted(dropped_bbs, o)) || continue + result_bbs[bb] = o + end + + # Figure out how predecessors should be renamed for i = 1:length(bbs) if merged_succ[i] != 0 # Block `i` should no longer be a predecessor (before renaming) @@ -1749,11 +1972,32 @@ function cfg_simplify!(ir::IRCode) continue end pred = i + is_unreachable = false + is_multi = false while pred !== 1 && !isempty(searchsorted(dropped_bbs, pred)) - pred = bbs[pred].preds[1] + preds = bbs[pred].preds + if length(preds) == 0 + is_unreachable = true + break + elseif length(preds) > 1 + # This block has multiple predecessors - the only way this is + # legal is if we proved above that our successors don't have + # any phi nodes that would interfere with the renaming. Mark + # this specially. + is_multi = true + break + end + @assert length(preds) == 1 + pred = preds[1] + end + if is_unreachable + @assert bb_rename_pred[i] == -2 + elseif is_multi + bb_rename_pred[i] = -3 + else + bbnum = follow_merge_into(pred) + bb_rename_pred[i] = bb_rename_succ[bbnum] end - bbnum = follow_merge_into(pred) - bb_rename_pred[i] = bb_rename_succ[bbnum] end # Compute new block lengths @@ -1787,7 +2031,20 @@ function cfg_simplify!(ir::IRCode) function compute_preds(i) orig_bb = result_bbs[i] preds = bbs[orig_bb].preds - return Int[bb_rename_pred[pred] for pred in preds] + res = Int[] + function scan_preds!(preds) + for pred in preds + r = bb_rename_pred[pred] + r == -2 && continue + if r == -3 + scan_preds!(bbs[pred].preds) + else + push!(res, r) + end + end + end + scan_preds!(preds) + return res end BasicBlock[ @@ -1804,8 +2061,10 @@ function cfg_simplify!(ir::IRCode) @assert length(new_bb.succs) <= 2 length(new_bb.succs) <= 1 && continue if new_bb.succs[1] == new_bb.succs[2] - terminator = ir[SSAValue(last(bbs[old_bb].stmts))] + old_bb2 = findfirst(x->x==bbidx, bb_rename_pred) + terminator = ir[SSAValue(last(bbs[old_bb2].stmts))] @assert isa(terminator[:inst], GotoIfNot) + # N.B.: The dest will be renamed in process_node! below terminator[:inst] = GotoNode(terminator[:inst].dest) pop!(new_bb.succs) new_succ = cresult_bbs[new_bb.succs[1]] @@ -1846,6 +2105,7 @@ function cfg_simplify!(ir::IRCode) ms = merged_succ[ms] end end + compact.idx = length(ir.stmts) compact.active_result_bb = length(bb_starts) return finish(compact) end diff --git a/base/compiler/ssair/show.jl b/base/compiler/ssair/show.jl index f58a1cc6e0d49..8ba47f5769deb 100644 --- a/base/compiler/ssair/show.jl +++ b/base/compiler/ssair/show.jl @@ -1,5 +1,8 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +# This file is not loaded into `Core.Compiler` but rather loaded into the context of +# `Base.IRShow` and thus does not participate in bootstrapping. + @nospecialize if Pair != Base.Pair @@ -154,9 +157,10 @@ function should_print_ssa_type(@nospecialize node) !isa(node, QuoteNode) end -function default_expr_type_printer(io::IO, @nospecialize(typ), used::Bool) - printstyled(io, "::", typ, color=(used ? :cyan : :light_black)) - nothing +function default_expr_type_printer(io::IO; @nospecialize(type), used::Bool, show_type::Bool=true, _...) + show_type || return nothing + printstyled(io, "::", type, color=(used ? :cyan : :light_black)) + return nothing end normalize_method_name(m::Method) = m.name @@ -494,14 +498,18 @@ function DILineInfoPrinter(linetable::Vector, showtypes::Bool=false) return emit_lineinfo_update end -# line_info_preprinter(io::IO, indent::String, idx::Int) may print relevant info -# at the beginning of the line, and should at least print `indent`. It returns a -# string that will be printed after the final basic-block annotation. -# line_info_postprinter(io::IO, typ, used::Bool) prints the type-annotation at the end -# of the statement -# should_print_stmt(idx::Int) -> Bool: whether the statement at index `idx` should be -# printed as part of the IR or not -# bb_color: color used for printing the basic block brackets on the left +""" + IRShowConfig + +- `line_info_preprinter(io::IO, indent::String, idx::Int)`` may print relevant info + at the beginning of the line, and should at least print `indent`. It returns a + string that will be printed after the final basic-block annotation. +- `line_info_postprinter(io::IO; type, used::Bool, show_type::Bool, idx::Int)` prints + relevant information like type-annotation at the end of the statement +- `should_print_stmt(idx::Int) -> Bool`: whether the statement at index `idx` should be + printed as part of the IR or not +- `bb_color`: color used for printing the basic block brackets on the left +""" struct IRShowConfig line_info_preprinter line_info_postprinter @@ -644,8 +652,8 @@ function show_ir_stmt(io::IO, code::Union{IRCode, CodeInfo, IncrementalCompact}, if new_node_type === UNDEF # try to be robust against errors printstyled(io, "::#UNDEF", color=:red) - elseif show_type - line_info_postprinter(IOContext(io, :idx => node_idx), new_node_type, node_idx in used) + else + line_info_postprinter(io; type = new_node_type, used = node_idx in used, show_type, idx = node_idx) end println(io) i += 1 @@ -659,8 +667,8 @@ function show_ir_stmt(io::IO, code::Union{IRCode, CodeInfo, IncrementalCompact}, if type === UNDEF # This is an error, but can happen if passes don't update their type information printstyled(io, "::#UNDEF", color=:red) - elseif show_type - line_info_postprinter(IOContext(io, :idx => idx), type, idx in used) + else + line_info_postprinter(io; type, used = idx in used, show_type, idx) end end println(io) @@ -728,7 +736,7 @@ function inline_linfo_printer(code::IRCode) end # Print location information right aligned. If the line below is too long, it'll overwrite this, # but that's what we want. - if get(io, :color, false) + if get(io, :color, false)::Bool method_start_column = cols - max_method_width - max_loc_width - 2 filler = " "^(max_loc_width-length(annotation)) printstyled(io, "\e[$(method_start_column)G$(annotation)$(filler)$(loc_method)\e[1G", color = :light_black) @@ -810,7 +818,9 @@ function show_ir(io::IO, ir::IRCode, config::IRShowConfig=default_config(ir); pop_new_node! = new_nodes_iter(ir)) used = stmts_used(io, ir) cfg = ir.cfg - show_ir_stmts(io, ir, 1:length(ir.stmts), config, used, cfg, 1; pop_new_node!) + let io = IOContext(io, :maxssaid=>length(ir.stmts)) + show_ir_stmts(io, ir, 1:length(ir.stmts), config, used, cfg, 1; pop_new_node!) + end finish_show_ir(io, cfg, config) end @@ -818,11 +828,14 @@ function show_ir(io::IO, ci::CodeInfo, config::IRShowConfig=default_config(ci); pop_new_node! = Returns(nothing)) used = stmts_used(io, ci) cfg = compute_basic_blocks(ci.code) - show_ir_stmts(io, ci, 1:length(ci.code), config, used, cfg, 1; pop_new_node!) + let io = IOContext(io, :maxssaid=>length(ci.code)) + show_ir_stmts(io, ci, 1:length(ci.code), config, used, cfg, 1; pop_new_node!) + end finish_show_ir(io, cfg, config) end function show_ir(io::IO, compact::IncrementalCompact, config::IRShowConfig=default_config(compact.ir)) + compact_cfg = CFG(compact.result_bbs, Int[first(compact.result_bbs[i].stmts) for i in 2:length(compact.result_bbs)]) cfg = compact.ir.cfg (_, width) = displaysize(io) @@ -837,7 +850,9 @@ function show_ir(io::IO, compact::IncrementalCompact, config::IRShowConfig=defau end end pop_new_node! = new_nodes_iter(compact) - bb_idx = show_ir_stmts(io, compact, 1:compact.result_idx-1, config, used_compacted, cfg, 1; pop_new_node!) + bb_idx = let io = IOContext(io, :maxssaid=>length(compact.result)) + show_ir_stmts(io, compact, 1:compact.result_idx-1, config, used_compacted, compact_cfg, 1; pop_new_node!) + end # Print uncompacted nodes from the original IR stmts = compact.ir.stmts @@ -847,8 +862,9 @@ function show_ir(io::IO, compact::IncrementalCompact, config::IRShowConfig=defau # config.line_info_preprinter(io, "", compact.idx) printstyled(io, "─"^(width-indent-1), '\n', color=:red) end - - show_ir_stmts(io, compact.ir, compact.idx:length(stmts), config, used_uncompacted, cfg, bb_idx; pop_new_node!) + let io = IOContext(io, :maxssaid=>length(compact.ir.stmts)) + show_ir_stmts(io, compact.ir, compact.idx:length(stmts), config, used_uncompacted, cfg, bb_idx; pop_new_node!) + end finish_show_ir(io, cfg, config) end diff --git a/base/compiler/ssair/slot2ssa.jl b/base/compiler/ssair/slot2ssa.jl index 29a3b093c9abf..6a9a128104b30 100644 --- a/base/compiler/ssair/slot2ssa.jl +++ b/base/compiler/ssair/slot2ssa.jl @@ -216,7 +216,7 @@ function typ_for_val(@nospecialize(x), ci::CodeInfo, sptypes::Vector{Any}, idx:: end return (ci.ssavaluetypes::Vector{Any})[idx] end - isa(x, GlobalRef) && return abstract_eval_global(x.mod, x.name) + isa(x, GlobalRef) && return abstract_eval_globalref(x) isa(x, SSAValue) && return (ci.ssavaluetypes::Vector{Any})[x.id] isa(x, Argument) && return slottypes[x.n] isa(x, NewSSAValue) && return DelayedTyp(x) @@ -273,19 +273,19 @@ needs to make sure that we always visit `B` before `A`. DOI: . """ function iterated_dominance_frontier(cfg::CFG, liveness::BlockLiveness, domtree::DomTree) - # This should be a priority queue, but TODO - sorted array for now defs = liveness.def_bbs - pq = Tuple{Int, Int}[(defs[i], domtree.nodes[defs[i]].level) for i in 1:length(defs)] - sort!(pq, by=x->x[2]) + heap = Tuple{Int, Int}[(defs[i], domtree.nodes[defs[i]].level) for i in 1:length(defs)] + heap_order = By(x -> -x[2]) + heapify!(heap, heap_order) phiblocks = Int[] # This bitset makes sure we only add a phi node to a given block once. processed = BitSet() # This bitset implements the `key insight` mentioned above. In particular, it prevents # us from visiting a subtree that we have already visited before. visited = BitSet() - while !isempty(pq) + while !isempty(heap) # We pop from the end of the array - i.e. the element with the highest level. - node, level = pop!(pq) + node, level = heappop!(heap, heap_order) worklist = Int[] push!(worklist, node) while !isempty(worklist) @@ -315,8 +315,7 @@ function iterated_dominance_frontier(cfg::CFG, liveness::BlockLiveness, domtree: # because succ_level <= level, which is the greatest level we have currently # processed. Thus, we have not yet processed any subtrees of level < succ_level. if !(succ in defs) - push!(pq, (succ, succ_level)) - sort!(pq, by=x->x[2]) + heappush!(heap, (succ, succ_level), heap_order) end end # Recurse down the current subtree @@ -523,23 +522,23 @@ function compute_live_ins(cfg::CFG, defs::Vector{Int}, uses::Vector{Int}) # We remove from `uses` any block where all uses are dominated # by a def. This prevents insertion of dead phi nodes at the top # of such a block if that block happens to be in a loop - ordered = Tuple{Int, Int, Bool}[(x, block_for_inst(cfg, x), true) for x in uses] - for x in defs - push!(ordered, (x, block_for_inst(cfg, x), false)) - end - ordered = sort(ordered, by=x->x[1]) - bb_defs = Int[] - bb_uses = Int[] - last_bb = last_def_bb = 0 - for (_, bb, is_use) in ordered - if bb != last_bb && is_use - push!(bb_uses, bb) - end - last_bb = bb - if last_def_bb != bb && !is_use - push!(bb_defs, bb) - last_def_bb = bb - end + bb_defs = Int[] # blocks with a def + bb_uses = Int[] # blocks with a use that is not dominated by a def + + # We do a sorted joint iteration over the instructions listed + # in defs and uses following a pattern similar to mergesort + last_block, block_has_def = 0, false + defs_i = uses_i = 1 + while defs_i <= lastindex(defs) || uses_i <= lastindex(uses) + is_def = uses_i > lastindex(uses) || defs_i <= lastindex(defs) && defs[defs_i] < uses[uses_i] + block = block_for_inst(cfg, is_def ? defs[defs_i] : uses[uses_i]) + defs_i += is_def + uses_i += !is_def + if last_block != block || is_def && !block_has_def + push!(is_def ? bb_defs : bb_uses, block) + block_has_def = is_def + end + last_block = block end # To obtain live ins from bb_uses, recursively add predecessors extra_liveins = BitSet() @@ -576,7 +575,7 @@ function recompute_type(node::Union{PhiNode, PhiCNode}, ci::CodeInfo, ir::IRCode while isa(typ, DelayedTyp) typ = types(ir)[new_to_regular(typ.phi::NewSSAValue, nstmts)] end - new_typ = tmerge(new_typ, was_maybe_undef ? MaybeUndef(typ) : typ) + new_typ = tmerge(OptimizerLattice(), new_typ, was_maybe_undef ? MaybeUndef(typ) : typ) end return new_typ end @@ -586,6 +585,8 @@ function construct_ssa!(ci::CodeInfo, ir::IRCode, domtree::DomTree, code = ir.stmts.inst cfg = ir.cfg catch_entry_blocks = Tuple{Int, Int}[] + lattice = OptimizerLattice() + ⊑ₒ = ⊑(lattice) for idx in 1:length(code) stmt = code[idx] if isexpr(stmt, :enter) @@ -719,7 +720,7 @@ function construct_ssa!(ci::CodeInfo, ir::IRCode, domtree::DomTree, if isa(typ, DelayedTyp) push!(type_refine_phi, ssaval.id) end - new_typ = isa(typ, DelayedTyp) ? Union{} : tmerge(old_entry[:type], typ) + new_typ = isa(typ, DelayedTyp) ? Union{} : tmerge(lattice, old_entry[:type], typ) old_entry[:type] = new_typ old_entry[:inst] = node incoming_vals[slot] = ssaval @@ -853,7 +854,7 @@ function construct_ssa!(ci::CodeInfo, ir::IRCode, domtree::DomTree, while isa(typ, DelayedTyp) typ = types(ir)[new_to_regular(typ.phi::NewSSAValue, nstmts)] end - new_typ = tmerge(new_typ, typ) + new_typ = tmerge(lattice, new_typ, typ) end node[:type] = new_typ end @@ -867,7 +868,7 @@ function construct_ssa!(ci::CodeInfo, ir::IRCode, domtree::DomTree, for new_idx in type_refine_phi node = new_nodes.stmts[new_idx] new_typ = recompute_type(node[:inst]::Union{PhiNode,PhiCNode}, ci, ir, ir.sptypes, slottypes, nstmts) - if !(node[:type] ⊑ new_typ) || !(new_typ ⊑ node[:type]) + if !(node[:type] ⊑ₒ new_typ) || !(new_typ ⊑ₒ node[:type]) node[:type] = new_typ changed = true end diff --git a/base/compiler/ssair/verify.jl b/base/compiler/ssair/verify.jl index ec43a0e142699..ca460b10ca67d 100644 --- a/base/compiler/ssair/verify.jl +++ b/base/compiler/ssair/verify.jl @@ -1,13 +1,22 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +function maybe_show_ir(ir::IRCode) + if isdefined(Core, :Main) + Core.Main.Base.display(ir) + end +end + if !isdefined(@__MODULE__, Symbol("@verify_error")) macro verify_error(arg) arg isa String && return esc(:(print && println(stderr, $arg))) - (arg isa Expr && arg.head === :string) || error("verify_error macro expected a string expression") + isexpr(arg, :string) || error("verify_error macro expected a string expression") pushfirst!(arg.args, GlobalRef(Core, :stderr)) pushfirst!(arg.args, :println) arg.head = :call - return esc(arg) + return esc(quote + $arg + maybe_show_ir(ir) + end) end end @@ -72,7 +81,8 @@ function count_int(val::Int, arr::Vector{Int}) n end -function verify_ir(ir::IRCode, print::Bool=true, allow_frontend_forms::Bool=false) +function verify_ir(ir::IRCode, print::Bool=true, allow_frontend_forms::Bool=false, + lattice = OptimizerLattice()) # For now require compact IR # @assert isempty(ir.new_nodes) # Verify CFG @@ -182,7 +192,7 @@ function verify_ir(ir::IRCode, print::Bool=true, allow_frontend_forms::Bool=fals val = stmt.values[i] phiT = ir.stmts[idx][:type] if isa(val, SSAValue) - if !(types(ir)[val] ⊑ phiT) + if !⊑(lattice, types(ir)[val], phiT) #@verify_error """ # PhiNode $idx, has operand $(val.id), whose type is not a sub lattice element. # PhiNode type was $phiT diff --git a/base/compiler/stmtinfo.jl b/base/compiler/stmtinfo.jl index 72b4c8b829c06..966ee32338b48 100644 --- a/base/compiler/stmtinfo.jl +++ b/base/compiler/stmtinfo.jl @@ -60,7 +60,13 @@ struct ConcreteResult ConcreteResult(mi::MethodInstance, effects::Effects, @nospecialize val) = new(mi, effects, val) end -const ConstResult = Union{ConstPropResult,ConcreteResult} +struct SemiConcreteResult + mi::MethodInstance + ir::IRCode + effects::Effects +end + +const ConstResult = Union{ConstPropResult,ConcreteResult, SemiConcreteResult} """ info::ConstCallInfo diff --git a/base/compiler/tfuncs.jl b/base/compiler/tfuncs.jl index ab1c8401c4738..60af6a6fdb9b0 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -25,6 +25,7 @@ function find_tfunc(@nospecialize f) end const DATATYPE_TYPES_FIELDINDEX = fieldindex(DataType, :types) +const DATATYPE_NAME_FIELDINDEX = fieldindex(DataType, :name) ########## # tfuncs # @@ -254,17 +255,18 @@ function isdefined_nothrow(argtypes::Array{Any, 1}) return a2 ⊑ Symbol || a2 ⊑ Int end end + isdefined_tfunc(arg1, sym, order) = (@nospecialize; isdefined_tfunc(arg1, sym)) function isdefined_tfunc(@nospecialize(arg1), @nospecialize(sym)) if isa(arg1, Const) - a1 = typeof(arg1.val) + arg1t = typeof(arg1.val) else - a1 = widenconst(arg1) + arg1t = widenconst(arg1) end - if isType(a1) + if isType(arg1t) return Bool end - a1 = unwrap_unionall(a1) + a1 = unwrap_unionall(arg1t) if isa(a1, DataType) && !isabstracttype(a1) if a1 === Module hasintersect(widenconst(sym), Symbol) || return Bottom @@ -307,11 +309,14 @@ function isdefined_tfunc(@nospecialize(arg1), @nospecialize(sym)) end end elseif isa(a1, Union) - return tmerge(isdefined_tfunc(a1.a, sym), - isdefined_tfunc(a1.b, sym)) + # Results can only be `Const` or `Bool` + return tmerge(fallback_lattice, + isdefined_tfunc(rewrap_unionall(a1.a, arg1t), sym), + isdefined_tfunc(rewrap_unionall(a1.b, arg1t), sym)) end return Bool end + add_tfunc(isdefined, 2, 3, isdefined_tfunc, 1) function sizeof_nothrow(@nospecialize(x)) @@ -653,7 +658,7 @@ function typeassert_tfunc(@nospecialize(v), @nospecialize(t)) end add_tfunc(typeassert, 2, 2, typeassert_tfunc, 4) -function isa_tfunc(@nospecialize(v), @nospecialize(tt)) +function isa_tfunc(@specialize(𝕃::AbstractLattice), @nospecialize(v), @nospecialize(tt)) t, isexact = instanceof_tfunc(tt) if t === Bottom # check if t could be equivalent to typeof(Bottom), since that's valid in `isa`, but the set of `v` is empty @@ -662,7 +667,7 @@ function isa_tfunc(@nospecialize(v), @nospecialize(tt)) return Const(false) end if !has_free_typevars(t) - if v ⊑ t + if ⊑(𝕃, v, t) if isexact && isnotbrokensubtype(v, t) return Const(true) end @@ -686,6 +691,7 @@ function isa_tfunc(@nospecialize(v), @nospecialize(tt)) # TODO: handle non-leaftype(t) by testing against lower and upper bounds return Bool end +isa_tfunc(@nospecialize(v), @nospecialize(t)) = isa_tfunc(fallback_lattice, v, t) add_tfunc(isa, 2, 2, isa_tfunc, 1) function subtype_tfunc(@nospecialize(a), @nospecialize(b)) @@ -818,7 +824,10 @@ function getfield_nothrow(@nospecialize(s00), @nospecialize(name), boundscheck:: if isa(s, Union) return getfield_nothrow(rewrap_unionall(s.a, s00), name, boundscheck) && getfield_nothrow(rewrap_unionall(s.b, s00), name, boundscheck) - elseif isa(s, DataType) + elseif isType(s) && isTypeDataType(s.parameters[1]) + s = s0 = DataType + end + if isa(s, DataType) # Can't say anything about abstract types isabstracttype(s) && return false s.name.atomicfields == C_NULL || return false # TODO: currently we're only testing for ordering === :not_atomic @@ -858,15 +867,40 @@ function getfield_tfunc(s00, name, order, boundscheck) return getfield_tfunc(s00, name) end getfield_tfunc(@nospecialize(s00), @nospecialize(name)) = _getfield_tfunc(s00, name, false) + +function _getfield_fieldindex(@nospecialize(s), name::Const) + nv = name.val + if isa(nv, Symbol) + nv = fieldindex(s, nv, false) + end + if isa(nv, Int) + return nv + end + return nothing +end + +function _getfield_tfunc_const(@nospecialize(sv), name::Const, setfield::Bool) + if isa(name, Const) + nv = _getfield_fieldindex(typeof(sv), name) + nv === nothing && return Bottom + if isa(sv, DataType) && nv == DATATYPE_TYPES_FIELDINDEX && isdefined(sv, nv) + return Const(getfield(sv, nv)) + end + if isconst(typeof(sv), nv) + if isdefined(sv, nv) + return Const(getfield(sv, nv)) + end + return Union{} + end + end + return nothing +end + function _getfield_tfunc(@nospecialize(s00), @nospecialize(name), setfield::Bool) if isa(s00, Conditional) return Bottom # Bool has no fields - elseif isa(s00, Const) || isconstType(s00) - if !isa(s00, Const) - sv = s00.parameters[1] - else - sv = s00.val - end + elseif isa(s00, Const) + sv = s00.val if isa(name, Const) nv = name.val if isa(sv, Module) @@ -876,31 +910,15 @@ function _getfield_tfunc(@nospecialize(s00), @nospecialize(name), setfield::Bool end return Bottom end - if isa(nv, Symbol) - nv = fieldindex(typeof(sv), nv, false) - end - if !isa(nv, Int) - return Bottom - end - if isa(sv, DataType) && nv == DATATYPE_TYPES_FIELDINDEX && isdefined(sv, nv) - return Const(getfield(sv, nv)) - end - if isconst(typeof(sv), nv) - if isdefined(sv, nv) - return Const(getfield(sv, nv)) - end - return Union{} - end + r = _getfield_tfunc_const(sv, name, setfield) + r !== nothing && return r end s = typeof(sv) elseif isa(s00, PartialStruct) s = widenconst(s00) sty = unwrap_unionall(s)::DataType if isa(name, Const) - nv = name.val - if isa(nv, Symbol) - nv = fieldindex(sty, nv, false) - end + nv = _getfield_fieldindex(sty, name) if isa(nv, Int) && 1 <= nv <= length(s00.fields) return unwrapva(s00.fields[nv]) end @@ -912,6 +930,27 @@ function _getfield_tfunc(@nospecialize(s00), @nospecialize(name), setfield::Bool return tmerge(_getfield_tfunc(rewrap_unionall(s.a, s00), name, setfield), _getfield_tfunc(rewrap_unionall(s.b, s00), name, setfield)) end + if isType(s) + if isconstType(s) + sv = s00.parameters[1] + if isa(name, Const) + r = _getfield_tfunc_const(sv, name, setfield) + r !== nothing && return r + end + s = typeof(sv) + else + sv = s.parameters[1] + if isTypeDataType(sv) && isa(name, Const) + nv = _getfield_fieldindex(DataType, name) + if nv == DATATYPE_NAME_FIELDINDEX + # N.B. This only works for fields that do not depend on type + # parameters (which we do not know here). + return Const(sv.name) + end + s = DataType + end + end + end isa(s, DataType) || return Any isabstracttype(s) && return Any if s <: Tuple && !hasintersect(widenconst(name), Int) @@ -967,13 +1006,8 @@ function _getfield_tfunc(@nospecialize(s00), @nospecialize(name), setfield::Bool end return t end - fld = name.val - if isa(fld, Symbol) - fld = fieldindex(s, fld, false) - end - if !isa(fld, Int) - return Bottom - end + fld = _getfield_fieldindex(s, name) + fld === nothing && return Bottom if s <: Tuple && fld >= nf && isvarargtype(ftypes[nf]) return rewrap_unionall(unwrapva(ftypes[nf]), s00) end @@ -1135,7 +1169,7 @@ function abstract_modifyfield!(interp::AbstractInterpreter, argtypes::Vector{Any TF2 = tmeet(callinfo.rt, widenconst(TF)) if TF2 === Bottom RT = Bottom - elseif isconcretetype(RT) && has_nontrivial_const_info(TF2) # isconcrete condition required to form a PartialStruct + elseif isconcretetype(RT) && has_nontrivial_const_info(typeinf_lattice(interp), TF2) # isconcrete condition required to form a PartialStruct RT = PartialStruct(RT, Any[TF, TF2]) end info = callinfo.info @@ -1351,22 +1385,11 @@ end add_tfunc(fieldtype, 2, 3, fieldtype_tfunc, 0) # Like `valid_tparam`, but in the type domain. -function valid_tparam_type(T::DataType) - T === Symbol && return true - isbitstype(T) && return true - if T <: Tuple - isconcretetype(T) || return false - for P in T.parameters - (P === Symbol || isbitstype(P)) || return false - end - return true - end - return false -end +valid_tparam_type(T::DataType) = valid_typeof_tparam(T) valid_tparam_type(U::Union) = valid_tparam_type(U.a) && valid_tparam_type(U.b) valid_tparam_type(U::UnionAll) = valid_tparam_type(unwrap_unionall(U)) -function apply_type_nothrow(argtypes::Array{Any, 1}, @nospecialize(rt)) +function apply_type_nothrow(@specialize(lattice::AbstractLattice), argtypes::Array{Any, 1}, @nospecialize(rt)) rt === Type && return false length(argtypes) >= 1 || return false headtypetype = argtypes[1] @@ -1385,7 +1408,7 @@ function apply_type_nothrow(argtypes::Array{Any, 1}, @nospecialize(rt)) for i = 2:length(argtypes) isa(u, UnionAll) || return false ai = widenconditional(argtypes[i]) - if ai ⊑ TypeVar || ai === DataType + if ⊑(lattice, ai, TypeVar) || ai === DataType # We don't know anything about the bounds of this typevar, but as # long as the UnionAll is not constrained, that's ok. if !(u.var.lb === Union{} && u.var.ub === Any) @@ -1422,6 +1445,7 @@ function apply_type_nothrow(argtypes::Array{Any, 1}, @nospecialize(rt)) end return true end +apply_type_nothrow(argtypes::Array{Any, 1}, @nospecialize(rt)) = apply_type_nothrow(fallback_lattice, argtypes, rt) const _tvarnames = Symbol[:_A, :_B, :_C, :_D, :_E, :_F, :_G, :_H, :_I, :_J, :_K, :_L, :_M, :_N, :_O, :_P, :_Q, :_R, :_S, :_T, :_U, :_V, :_W, :_X, :_Y, :_Z] @@ -1583,15 +1607,9 @@ function apply_type_tfunc(@nospecialize(headtypetype), @nospecialize args...) end add_tfunc(apply_type, 1, INT_INF, apply_type_tfunc, 10) -function has_struct_const_info(x) - isa(x, PartialTypeVar) && return true - isa(x, Conditional) && return true - return has_nontrivial_const_info(x) -end - # convert the dispatch tuple type argtype to the real (concrete) type of # the tuple of those values -function tuple_tfunc(argtypes::Vector{Any}) +function tuple_tfunc(@specialize(lattice::AbstractLattice), argtypes::Vector{Any}) argtypes = anymap(widenconditional, argtypes) all_are_const = true for i in 1:length(argtypes) @@ -1607,7 +1625,7 @@ function tuple_tfunc(argtypes::Vector{Any}) anyinfo = false for i in 1:length(argtypes) x = argtypes[i] - if has_struct_const_info(x) + if has_nontrivial_const_info(lattice, x) anyinfo = true else if !isvarargtype(x) @@ -1645,6 +1663,7 @@ function tuple_tfunc(argtypes::Vector{Any}) isdefined(typ, :instance) && return Const(typ.instance) return anyinfo ? PartialStruct(typ, argtypes) : typ end +tuple_tfunc(argtypes::Vector{Any}) = tuple_tfunc(fallback_lattice, argtypes) arrayref_tfunc(@nospecialize(boundscheck), @nospecialize(ary), @nospecialize idxs...) = _arrayref_tfunc(boundscheck, ary, idxs) @@ -1764,18 +1783,24 @@ function arrayset_typecheck(@nospecialize(arytype), @nospecialize(elmtype)) end # Query whether the given builtin is guaranteed not to throw given the argtypes -function _builtin_nothrow(@nospecialize(f), argtypes::Array{Any,1}, @nospecialize(rt)) +function _builtin_nothrow(@specialize(lattice::AbstractLattice), @nospecialize(f), argtypes::Array{Any,1}, @nospecialize(rt)) + ⊑ₗ = ⊑(lattice) if f === arrayset array_builtin_common_nothrow(argtypes, 4) || return false # Additionally check element type compatibility return arrayset_typecheck(argtypes[2], argtypes[3]) elseif f === arrayref || f === const_arrayref return array_builtin_common_nothrow(argtypes, 3) - elseif f === arraysize - return arraysize_nothrow(argtypes) elseif f === Core._expr length(argtypes) >= 1 || return false - return argtypes[1] ⊑ Symbol + return argtypes[1] ⊑ₗ Symbol + end + + # These builtins are not-vararg, so if we have varars, here, we can't guarantee + # the correct number of arguments. + (!isempty(argtypes) && isvarargtype(argtypes[end])) && return false + if f === arraysize + return arraysize_nothrow(argtypes) elseif f === Core._typevar length(argtypes) == 3 || return false return typevar_nothrow(argtypes[1], argtypes[2], argtypes[3]) @@ -1789,16 +1814,16 @@ function _builtin_nothrow(@nospecialize(f), argtypes::Array{Any,1}, @nospecializ length(argtypes) == 2 || return false return fieldtype_nothrow(argtypes[1], argtypes[2]) elseif f === apply_type - return apply_type_nothrow(argtypes, rt) + return apply_type_nothrow(lattice, argtypes, rt) elseif f === isa length(argtypes) == 2 || return false - return argtypes[2] ⊑ Type + return argtypes[2] ⊑ₗ Type elseif f === (<:) length(argtypes) == 2 || return false - return argtypes[1] ⊑ Type && argtypes[2] ⊑ Type + return argtypes[1] ⊑ₗ Type && argtypes[2] ⊑ₗ Type elseif f === UnionAll return length(argtypes) == 2 && - (argtypes[1] ⊑ TypeVar && argtypes[2] ⊑ Type) + (argtypes[1] ⊑ₗ TypeVar && argtypes[2] ⊑ₗ Type) elseif f === isdefined return isdefined_nothrow(argtypes) elseif f === Core.sizeof @@ -1809,12 +1834,12 @@ function _builtin_nothrow(@nospecialize(f), argtypes::Array{Any,1}, @nospecializ return isa(rt, Const) elseif f === Core.ifelse length(argtypes) == 3 || return false - return argtypes[1] ⊑ Bool + return argtypes[1] ⊑ₗ Bool elseif f === typeassert length(argtypes) == 2 || return false a3 = argtypes[2] - if (isType(a3) && !has_free_typevars(a3) && argtypes[1] ⊑ a3.parameters[1]) || - (isa(a3, Const) && isa(a3.val, Type) && argtypes[1] ⊑ a3.val) + if (isType(a3) && !has_free_typevars(a3) && argtypes[1] ⊑ₗ a3.parameters[1]) || + (isa(a3, Const) && isa(a3.val, Type) && argtypes[1] ⊑ₗ a3.val) return true end return false @@ -1824,13 +1849,17 @@ function _builtin_nothrow(@nospecialize(f), argtypes::Array{Any,1}, @nospecializ return setglobal!_nothrow(argtypes) elseif f === Core.get_binding_type length(argtypes) == 2 || return false - return argtypes[1] ⊑ Module && argtypes[2] ⊑ Symbol + return argtypes[1] ⊑ₗ Module && argtypes[2] ⊑ₗ Symbol elseif f === donotdelete return true elseif f === Core.finalizer 2 <= length(argtypes) <= 4 || return false # Core.finalizer does no error checking - that's done in Base.finalizer return true + elseif f === Core.compilerbarrier + length(argtypes) == 2 || return false + a1 = argtypes[1] + return isa(a1, Const) && contains_is((:type, :const, :conditional), a1.val) end return false end @@ -1843,7 +1872,7 @@ const _EFFECT_FREE_BUILTINS = [ fieldtype, apply_type, isa, UnionAll, getfield, arrayref, const_arrayref, isdefined, Core.sizeof, Core.kwfunc, Core.ifelse, Core._typevar, (<:), - typeassert, throw, arraysize, getglobal, + typeassert, throw, arraysize, getglobal, compilerbarrier ] const _CONSISTENT_BUILTINS = Any[ @@ -1862,7 +1891,7 @@ const _CONSISTENT_BUILTINS = Any[ (<:), typeassert, throw, - setfield!, + setfield! ] const _INACCESSIBLEMEM_BUILTINS = Any[ @@ -1881,6 +1910,7 @@ const _INACCESSIBLEMEM_BUILTINS = Any[ tuple, typeassert, typeof, + compilerbarrier, ] const _ARGMEM_BUILTINS = Any[ @@ -1924,9 +1954,8 @@ function isdefined_effects(argtypes::Vector{Any}) # consistent if the first arg is immutable isempty(argtypes) && return EFFECTS_THROWS obj = argtypes[1] - isvarargtype(obj) && return Effects(EFFECTS_THROWS; consistent=ALWAYS_FALSE) - consistent = is_immutable_argtype(obj) ? ALWAYS_TRUE : ALWAYS_FALSE - nothrow = isdefined_nothrow(argtypes) + consistent = is_immutable_argtype(unwrapva(obj)) ? ALWAYS_TRUE : ALWAYS_FALSE + nothrow = !isvarargtype(argtypes[end]) && isdefined_nothrow(argtypes) return Effects(EFFECTS_TOTAL; consistent, nothrow) end @@ -1986,7 +2015,7 @@ function getglobal_effects(argtypes::Vector{Any}, @nospecialize(rt)) return Effects(EFFECTS_TOTAL; consistent, nothrow, inaccessiblememonly) end -function builtin_effects(f::Builtin, argtypes::Vector{Any}, @nospecialize(rt)) +function builtin_effects(@specialize(lattice::AbstractLattice), f::Builtin, argtypes::Vector{Any}, @nospecialize(rt)) if isa(f, IntrinsicFunction) return intrinsic_effects(f, argtypes) end @@ -1999,6 +2028,10 @@ function builtin_effects(f::Builtin, argtypes::Vector{Any}, @nospecialize(rt)) return getfield_effects(argtypes, rt) elseif f === getglobal return getglobal_effects(argtypes, rt) + elseif f === Core.get_binding_type + length(argtypes) == 2 || return EFFECTS_THROWS + effect_free = get_binding_type_effect_free(argtypes[1], argtypes[2]) ? ALWAYS_TRUE : ALWAYS_FALSE + return Effects(EFFECTS_TOTAL; effect_free) else consistent = contains_is(_CONSISTENT_BUILTINS, f) ? ALWAYS_TRUE : ALWAYS_FALSE if f === setfield! || f === arrayset @@ -2008,7 +2041,7 @@ function builtin_effects(f::Builtin, argtypes::Vector{Any}, @nospecialize(rt)) else effect_free = ALWAYS_FALSE end - nothrow = (!(!isempty(argtypes) && isvarargtype(argtypes[end])) && builtin_nothrow(f, argtypes, rt)) + nothrow = (!(!isempty(argtypes) && isvarargtype(argtypes[end])) && builtin_nothrow(lattice, f, argtypes, rt)) if contains_is(_INACCESSIBLEMEM_BUILTINS, f) inaccessiblememonly = ALWAYS_TRUE elseif contains_is(_ARGMEM_BUILTINS, f) @@ -2020,16 +2053,16 @@ function builtin_effects(f::Builtin, argtypes::Vector{Any}, @nospecialize(rt)) end end -function builtin_nothrow(@nospecialize(f), argtypes::Vector{Any}, @nospecialize(rt)) +function builtin_nothrow(@specialize(lattice::AbstractLattice), @nospecialize(f), argtypes::Vector{Any}, @nospecialize(rt)) rt === Bottom && return false contains_is(_PURE_BUILTINS, f) && return true - return _builtin_nothrow(f, argtypes, rt) + return _builtin_nothrow(lattice, f, argtypes, rt) end function builtin_tfunction(interp::AbstractInterpreter, @nospecialize(f), argtypes::Vector{Any}, - sv::Union{InferenceState,Nothing}) + sv::Union{InferenceState,IRCode,Nothing}) if f === tuple - return tuple_tfunc(argtypes) + return tuple_tfunc(typeinf_lattice(interp), argtypes) end if isa(f, IntrinsicFunction) if is_pure_intrinsic_infer(f) && _all(@nospecialize(a) -> isa(a, Const), argtypes) @@ -2193,7 +2226,7 @@ end # TODO: this function is a very buggy and poor model of the return_type function # since abstract_call_gf_by_type is a very inaccurate model of _method and of typeinf_type, # while this assumes that it is an absolutely precise and accurate and exact model of both -function return_type_tfunc(interp::AbstractInterpreter, argtypes::Vector{Any}, sv::InferenceState) +function return_type_tfunc(interp::AbstractInterpreter, argtypes::Vector{Any}, sv::Union{InferenceState, IRCode}) if length(argtypes) == 3 tt = argtypes[3] if isa(tt, Const) || (isType(tt) && !has_free_typevars(tt)) @@ -2209,10 +2242,14 @@ function return_type_tfunc(interp::AbstractInterpreter, argtypes::Vector{Any}, s # Run the abstract_call without restricting abstract call # sites. Otherwise, our behavior model of abstract_call # below will be wrong. - old_restrict = sv.restrict_abstract_call_sites - sv.restrict_abstract_call_sites = false - call = abstract_call(interp, ArgInfo(nothing, argtypes_vec), sv, -1) - sv.restrict_abstract_call_sites = old_restrict + if isa(sv, InferenceState) + old_restrict = sv.restrict_abstract_call_sites + sv.restrict_abstract_call_sites = false + call = abstract_call(interp, ArgInfo(nothing, argtypes_vec), sv, -1) + sv.restrict_abstract_call_sites = old_restrict + else + call = abstract_call(interp, ArgInfo(nothing, argtypes_vec), sv, -1) + end info = verbose_stmt_info(interp) ? MethodResultPure(ReturnTypeCallInfo(call.info)) : MethodResultPure() rt = widenconditional(call.rt) if isa(rt, Const) @@ -2223,7 +2260,7 @@ function return_type_tfunc(interp::AbstractInterpreter, argtypes::Vector{Any}, s if rt === Bottom || (isconcretetype(rt) && !iskindtype(rt)) # output cannot be improved so it is known for certain return CallMeta(Const(rt), EFFECTS_TOTAL, info) - elseif !isempty(sv.pclimitations) + elseif isa(sv, InferenceState) && !isempty(sv.pclimitations) # conservatively express uncertainty of this result # in two ways: both as being a subtype of this, and # because of LimitedAccuracy causes diff --git a/base/compiler/typeinfer.jl b/base/compiler/typeinfer.jl index 2c66083b9024b..6db3c42a6ca54 100644 --- a/base/compiler/typeinfer.jl +++ b/base/compiler/typeinfer.jl @@ -45,6 +45,8 @@ function _typeinf_identifier(frame::Core.Compiler.InferenceState) return mi_info end +_typeinf_identifier(frame::InferenceFrameInfo) = frame + """ Core.Compiler.Timing(mi_info, start_time, ...) @@ -312,7 +314,9 @@ function CodeInstance( const_flags = 0x00 end end - relocatability = isa(inferred_result, Vector{UInt8}) ? inferred_result[end] : UInt8(0) + relocatability = isa(inferred_result, Vector{UInt8}) ? inferred_result[end] : + inferred_result === nothing ? UInt8(1) : UInt8(0) + # relocatability = isa(inferred_result, Vector{UInt8}) ? inferred_result[end] : UInt8(0) return CodeInstance(result.linfo, widenconst(result_type), rettype_const, inferred_result, const_flags, first(valid_worlds), last(valid_worlds), @@ -346,9 +350,9 @@ function maybe_compress_codeinfo(interp::AbstractInterpreter, linfo::MethodInsta end end -function transform_result_for_cache(interp::AbstractInterpreter, linfo::MethodInstance, - valid_worlds::WorldRange, @nospecialize(inferred_result), - ipo_effects::Effects) +function transform_result_for_cache(interp::AbstractInterpreter, + linfo::MethodInstance, valid_worlds::WorldRange, result::InferenceResult) + inferred_result = result.src # If we decided not to optimize, drop the OptimizationState now. # External interpreters can override as necessary to cache additional information if inferred_result isa OptimizationState @@ -383,12 +387,14 @@ function cache_result!(interp::AbstractInterpreter, result::InferenceResult) # TODO: also don't store inferred code if we've previously decided to interpret this function if !already_inferred - inferred_result = transform_result_for_cache(interp, linfo, valid_worlds, result.src, result.ipo_effects) + inferred_result = transform_result_for_cache(interp, linfo, valid_worlds, result) code_cache(interp)[linfo] = CodeInstance(result, inferred_result, valid_worlds) if track_newly_inferred[] m = linfo.def - if isa(m, Method) - m.module != Core && push!(newly_inferred, linfo) + if isa(m, Method) && m.module != Core + ccall(:jl_typeinf_lock_begin, Cvoid, ()) + push!(newly_inferred, linfo) + ccall(:jl_typeinf_lock_end, Cvoid, ()) end end end @@ -537,7 +543,8 @@ function finish(me::InferenceState, interp::AbstractInterpreter) # annotate fulltree with type information, # either because we are the outermost code, or we might use this later doopt = (me.cached || me.parent !== nothing) - recompute_cfg = type_annotate!(me, doopt) + changemap = type_annotate!(interp, me, doopt) + recompute_cfg = changemap !== nothing if doopt && may_optimize(interp) me.result.src = OptimizationState(me, OptimizationParams(interp), interp, recompute_cfg) else @@ -560,18 +567,13 @@ function store_backedges(frame::InferenceResult, edges::Vector{Any}) nothing end -function store_backedges(caller::MethodInstance, edges::Vector{Any}) - i = 1 - while i <= length(edges) - to = edges[i] - if isa(to, MethodInstance) - ccall(:jl_method_instance_add_backedge, Cvoid, (Any, Any), to, caller) - i += 1 +function store_backedges(frame::MethodInstance, edges::Vector{Any}) + for (; sig, caller) in BackedgeIterator(edges) + if isa(caller, MethodInstance) + ccall(:jl_method_instance_add_backedge, Cvoid, (Any, Any, Any), caller, sig, frame) else - typeassert(to, Core.MethodTable) - typ = edges[i + 1] - ccall(:jl_method_table_add_backedge, Cvoid, (Any, Any, Any), to, typ, caller) - i += 2 + typeassert(caller, Core.MethodTable) + ccall(:jl_method_table_add_backedge, Cvoid, (Any, Any, Any), caller, sig, frame) end end end @@ -651,7 +653,7 @@ function annotate_slot_load!(undefs::Vector{Bool}, idx::Int, sv::InferenceState, @assert typ !== NOT_FOUND "active slot in unreached region" end # add type annotations where needed - if !(sv.slottypes[id] ⊑ typ) + if !⊑(typeinf_lattice(sv.interp), sv.slottypes[id], typ) return TypedSlot(id, typ) end return x @@ -680,7 +682,7 @@ end # returns `nothing` otherwise function find_dominating_assignment(id::Int, idx::Int, sv::InferenceState) block = block_for_inst(sv.cfg, idx) - for pc in reverse(sv.cfg.blocks[block].stmts) # N.B. reverse since the last assignement is dominating this block + for pc in reverse(sv.cfg.blocks[block].stmts) # N.B. reverse since the last assignment is dominating this block pc < idx || continue # N.B. needs pc ≠ idx as `id` can be assigned at `idx` stmt = sv.src.code[pc] isexpr(stmt, :(=)) || continue @@ -693,7 +695,7 @@ function find_dominating_assignment(id::Int, idx::Int, sv::InferenceState) end # annotate types of all symbols in AST -function type_annotate!(sv::InferenceState, run_optimizer::Bool) +function type_annotate!(interp::AbstractInterpreter, sv::InferenceState, run_optimizer::Bool) # compute the required type for each slot # to hold all of the items assigned into it record_slot_assign!(sv) @@ -770,9 +772,9 @@ function type_annotate!(sv::InferenceState, run_optimizer::Bool) deleteat!(stmt_info, inds) deleteat!(ssaflags, inds) renumber_ir_elements!(body, changemap) - return true + return changemap else - return false + return nothing end end @@ -795,18 +797,18 @@ function union_caller_cycle!(a::InferenceState, b::InferenceState) return end -function merge_call_chain!(parent::InferenceState, ancestor::InferenceState, child::InferenceState) +function merge_call_chain!(interp::AbstractInterpreter, parent::InferenceState, ancestor::InferenceState, child::InferenceState) # add backedge of parent <- child # then add all backedges of parent <- parent.parent # and merge all of the callers into ancestor.callers_in_cycle # and ensure that walking the parent list will get the same result (DAG) from everywhere # Also taint the termination effect, because we can no longer guarantee the absence # of recursion. - merge_effects!(parent, Effects(EFFECTS_TOTAL; terminates=false)) + merge_effects!(interp, parent, Effects(EFFECTS_TOTAL; terminates=false)) while true - add_cycle_backedge!(child, parent, parent.currpc) + add_cycle_backedge!(parent, child, parent.currpc) union_caller_cycle!(ancestor, child) - merge_effects!(child, Effects(EFFECTS_TOTAL; terminates=false)) + merge_effects!(interp, child, Effects(EFFECTS_TOTAL; terminates=false)) child = parent child === ancestor && break parent = child.parent::InferenceState @@ -842,7 +844,7 @@ function resolve_call_cycle!(interp::AbstractInterpreter, linfo::MethodInstance, poison_callstack(parent, frame) return true end - merge_call_chain!(parent, frame, frame) + merge_call_chain!(interp, parent, frame, frame) return frame end for caller in frame.callers_in_cycle @@ -851,7 +853,7 @@ function resolve_call_cycle!(interp::AbstractInterpreter, linfo::MethodInstance, poison_callstack(parent, frame) return true end - merge_call_chain!(parent, frame, caller) + merge_call_chain!(interp, parent, frame, caller) return caller end end @@ -976,10 +978,10 @@ function typeinf_ircode( sparams::SimpleVector, optimize_until::Union{Integer,AbstractString,Nothing}, ) - ccall(:jl_typeinf_begin, Cvoid, ()) + ccall(:jl_typeinf_timing_begin, Cvoid, ()) frame = typeinf_frame(interp, method, atype, sparams, false) if frame === nothing - ccall(:jl_typeinf_end, Cvoid, ()) + ccall(:jl_typeinf_timing_end, Cvoid, ()) return nothing, Any end (; result) = frame @@ -987,19 +989,19 @@ function typeinf_ircode( opt = OptimizationState(frame, opt_params, interp) ir = run_passes(opt.src, opt, result, optimize_until) rt = widenconst(ignorelimited(result.result)) - ccall(:jl_typeinf_end, Cvoid, ()) + ccall(:jl_typeinf_timing_end, Cvoid, ()) return ir, rt end # compute an inferred frame function typeinf_frame(interp::AbstractInterpreter, method::Method, @nospecialize(atype), sparams::SimpleVector, run_optimizer::Bool) mi = specialize_method(method, atype, sparams)::MethodInstance - ccall(:jl_typeinf_begin, Cvoid, ()) + ccall(:jl_typeinf_timing_begin, Cvoid, ()) result = InferenceResult(mi) frame = InferenceState(result, run_optimizer ? :global : :no, interp) frame === nothing && return nothing typeinf(interp, frame) - ccall(:jl_typeinf_end, Cvoid, ()) + ccall(:jl_typeinf_timing_end, Cvoid, ()) return frame end @@ -1007,13 +1009,13 @@ end function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance) method = mi.def::Method for i = 1:2 # test-and-lock-and-test - i == 2 && ccall(:jl_typeinf_begin, Cvoid, ()) + i == 2 && ccall(:jl_typeinf_timing_begin, Cvoid, ()) code = get(code_cache(interp), mi, nothing) if code isa CodeInstance # see if this code already exists in the cache inf = @atomic :monotonic code.inferred if use_const_api(code) - i == 2 && ccall(:jl_typeinf_end, Cvoid, ()) + i == 2 && ccall(:jl_typeinf_timing_end, Cvoid, ()) tree = ccall(:jl_new_code_info_uninit, Ref{CodeInfo}, ()) rettype_const = code.rettype_const tree.code = Any[ ReturnNode(quoted(rettype_const)) ] @@ -1033,7 +1035,7 @@ function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance) tree.max_world = code.max_world return tree elseif isa(inf, CodeInfo) - i == 2 && ccall(:jl_typeinf_end, Cvoid, ()) + i == 2 && ccall(:jl_typeinf_timing_end, Cvoid, ()) if !(inf.min_world == code.min_world && inf.max_world == code.max_world && inf.rettype === code.rettype) @@ -1044,7 +1046,7 @@ function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance) end return inf elseif isa(inf, Vector{UInt8}) - i == 2 && ccall(:jl_typeinf_end, Cvoid, ()) + i == 2 && ccall(:jl_typeinf_timing_end, Cvoid, ()) inf = _uncompressed_ir(code, inf) return inf end @@ -1057,7 +1059,7 @@ function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance) frame = InferenceState(InferenceResult(mi), #=cache=#:global, interp) frame === nothing && return nothing typeinf(interp, frame) - ccall(:jl_typeinf_end, Cvoid, ()) + ccall(:jl_typeinf_timing_end, Cvoid, ()) frame.src.inferred || return nothing return frame.src end @@ -1069,17 +1071,17 @@ function typeinf_type(interp::AbstractInterpreter, method::Method, @nospecialize end mi = specialize_method(method, atype, sparams)::MethodInstance for i = 1:2 # test-and-lock-and-test - i == 2 && ccall(:jl_typeinf_begin, Cvoid, ()) + i == 2 && ccall(:jl_typeinf_timing_begin, Cvoid, ()) code = get(code_cache(interp), mi, nothing) if code isa CodeInstance # see if this rettype already exists in the cache - i == 2 && ccall(:jl_typeinf_end, Cvoid, ()) + i == 2 && ccall(:jl_typeinf_timing_end, Cvoid, ()) return code.rettype end end result = InferenceResult(mi) typeinf(interp, result, :global) - ccall(:jl_typeinf_end, Cvoid, ()) + ccall(:jl_typeinf_timing_end, Cvoid, ()) result.result isa InferenceState && return nothing return widenconst(ignorelimited(result.result)) end @@ -1094,7 +1096,7 @@ function typeinf_ext_toplevel(interp::AbstractInterpreter, linfo::MethodInstance src = linfo.uninferred::CodeInfo if !src.inferred # toplevel lambda - infer directly - ccall(:jl_typeinf_begin, Cvoid, ()) + ccall(:jl_typeinf_timing_begin, Cvoid, ()) if !src.inferred result = InferenceResult(linfo) frame = InferenceState(result, src, #=cache=#:global, interp) @@ -1102,7 +1104,7 @@ function typeinf_ext_toplevel(interp::AbstractInterpreter, linfo::MethodInstance @assert frame.inferred # TODO: deal with this better src = frame.src end - ccall(:jl_typeinf_end, Cvoid, ()) + ccall(:jl_typeinf_timing_end, Cvoid, ()) end end return src diff --git a/base/compiler/typelattice.jl b/base/compiler/typelattice.jl index 1001765ae074e..5c57443d70656 100644 --- a/base/compiler/typelattice.jl +++ b/base/compiler/typelattice.jl @@ -78,7 +78,7 @@ InterConditional(var::SlotNumber, @nospecialize(thentype), @nospecialize(elsetyp InterConditional(slot_id(var), thentype, elsetype) const AnyConditional = Union{Conditional,InterConditional} -Conditional(cnd::InterConditional) = Conditinal(cnd.slot, cnd.thentype, cnd.elsetype) +Conditional(cnd::InterConditional) = Conditional(cnd.slot, cnd.thentype, cnd.elsetype) InterConditional(cnd::Conditional) = InterConditional(cnd.slot, cnd.thentype, cnd.elsetype) struct PartialTypeVar @@ -106,7 +106,7 @@ struct StateUpdate end # Represent that the type estimate has been approximated, due to "causes" -# (only used in abstract interpretion, doesn't appear in optimization) +# (only used in abstract interpretation, doesn't appear in optimization) # N.B. in the lattice, this is epsilon smaller than `typ` (except Union{}) struct LimitedAccuracy typ @@ -174,10 +174,10 @@ widenwrappedconditional(typ::LimitedAccuracy) = LimitedAccuracy(widenconditional # `Conditional` and `InterConditional` are valid in opposite contexts # (i.e. local inference and inter-procedural call), as such they will never be compared -function issubconditional(a::C, b::C) where {C<:AnyConditional} +function issubconditional(lattice::AbstractLattice, a::C, b::C) where {C<:AnyConditional} if is_same_conditionals(a, b) - if a.thentype ⊑ b.thentype - if a.elsetype ⊑ b.elsetype + if ⊑(lattice, a.thentype, b.thentype) + if ⊑(lattice, a.elsetype, b.elsetype) return true end end @@ -187,7 +187,7 @@ end is_same_conditionals(a::C, b::C) where C<:AnyConditional = a.slot == b.slot -is_lattice_bool(@nospecialize(typ)) = typ !== Bottom && typ ⊑ Bool +is_lattice_bool(lattice::AbstractLattice, @nospecialize(typ)) = typ !== Bottom && ⊑(lattice, typ, Bool) maybe_extract_const_bool(c::Const) = (val = c.val; isa(val, Bool)) ? val : nothing function maybe_extract_const_bool(c::AnyConditional) @@ -206,12 +206,7 @@ ignorelimited(typ::LimitedAccuracy) = typ.typ # lattice order # ============= -""" - a ⊑ b -> Bool - -The non-strict partial order over the type inference lattice. -""" -@nospecialize(a) ⊑ @nospecialize(b) = begin +function ⊑(lattice::InferenceLattice, @nospecialize(a), @nospecialize(b)) if isa(b, LimitedAccuracy) if !isa(a, LimitedAccuracy) return false @@ -222,52 +217,80 @@ The non-strict partial order over the type inference lattice. b = b.typ end isa(a, LimitedAccuracy) && (a = a.typ) + return ⊑(widenlattice(lattice), a, b) +end + +function ⊑(lattice::OptimizerLattice, @nospecialize(a), @nospecialize(b)) if isa(a, MaybeUndef) && !isa(b, MaybeUndef) return false end isa(a, MaybeUndef) && (a = a.typ) isa(b, MaybeUndef) && (b = b.typ) + return ⊑(widenlattice(lattice), a, b) +end + +function ⊑(lattice::AnyConditionalsLattice, @nospecialize(a), @nospecialize(b)) + # Fast paths for common cases b === Any && return true a === Any && return false a === Union{} && return true b === Union{} && return false - @assert !isa(a, TypeVar) "invalid lattice item" - @assert !isa(b, TypeVar) "invalid lattice item" - if isa(a, AnyConditional) - if isa(b, AnyConditional) - return issubconditional(a, b) + T = isa(lattice, ConditionalsLattice) ? Conditional : InterConditional + if isa(a, T) + if isa(b, T) + return issubconditional(lattice, a, b) elseif isa(b, Const) && isa(b.val, Bool) return maybe_extract_const_bool(a) === b.val end a = Bool - elseif isa(b, AnyConditional) + elseif isa(b, T) return false end + return ⊑(widenlattice(lattice), a, b) +end + +function ⊑(lattice::PartialsLattice, @nospecialize(a), @nospecialize(b)) if isa(a, PartialStruct) if isa(b, PartialStruct) if !(length(a.fields) == length(b.fields) && a.typ <: b.typ) return false end for i in 1:length(b.fields) - # XXX: let's handle varargs later - ⊑(a.fields[i], b.fields[i]) || return false + af = a.fields[i] + bf = b.fields[i] + if i == length(b.fields) + if isvarargtype(af) + # If `af` is vararg, so must bf by the <: above + @assert isvarargtype(bf) + continue + elseif isvarargtype(bf) + # If `bf` is vararg, it must match the information + # in the type, so there's nothing to check here. + continue + end + end + ⊑(lattice, af, bf) || return false end return true end return isa(b, Type) && a.typ <: b elseif isa(b, PartialStruct) if isa(a, Const) - nfields(a.val) == length(b.fields) || return false + nf = nfields(a.val) + nf == length(b.fields) || return false widenconst(b).name === widenconst(a).name || return false # We can skip the subtype check if b is a Tuple, since in that # case, the ⊑ of the elements is sufficient. if b.typ.name !== Tuple.name && !(widenconst(a) <: widenconst(b)) return false end - for i in 1:nfields(a.val) - # XXX: let's handle varargs later + for i in 1:nf isdefined(a.val, i) || continue # since ∀ T Union{} ⊑ T - ⊑(Const(getfield(a.val, i)), b.fields[i]) || return false + bf = b.fields[i] + if i == nf + bf = unwrapva(bf) + end + ⊑(lattice, Const(getfield(a.val, i)), bf) || return false end return true end @@ -277,10 +300,16 @@ The non-strict partial order over the type inference lattice. if isa(b, PartialOpaque) (a.parent === b.parent && a.source === b.source) || return false return (widenconst(a) <: widenconst(b)) && - ⊑(a.env, b.env) + ⊑(lattice, a.env, b.env) end - return widenconst(a) ⊑ b + return ⊑(widenlattice(lattice), widenconst(a), b) + elseif isa(b, PartialOpaque) + return false end + return ⊑(widenlattice(lattice), a, b) +end + +function ⊑(lattice::ConstsLattice, @nospecialize(a), @nospecialize(b)) if isa(a, Const) if isa(b, Const) return a.val === b.val @@ -294,93 +323,94 @@ The non-strict partial order over the type inference lattice. return a.instance === b.val end return false - elseif isa(a, PartialTypeVar) && b === TypeVar - return true - elseif isa(a, Type) && isa(b, Type) - return a <: b - else # handle this conservatively in the remaining cases - return a === b + elseif isa(a, PartialTypeVar) + return b === TypeVar || a === b + elseif isa(b, PartialTypeVar) + return false end + return ⊑(widenlattice(lattice), a, b) end -""" - a ⊏ b -> Bool - -The strict partial order over the type inference lattice. -This is defined as the irreflexive kernel of `⊑`. -""" -@nospecialize(a) ⊏ @nospecialize(b) = a ⊑ b && !⊑(b, a) - -""" - a ⋤ b -> Bool +function is_lattice_equal(lattice::InferenceLattice, @nospecialize(a), @nospecialize(b)) + if isa(a, LimitedAccuracy) || isa(b, LimitedAccuracy) + # TODO: Unwrap these and recurse to is_lattice_equal + return ⊑(lattice, a, b) && ⊑(lattice, b, a) + end + return is_lattice_equal(widenlattice(lattice), a, b) +end -This order could be used as a slightly more efficient version of the strict order `⊏`, -where we can safely assume `a ⊑ b` holds. -""" -@nospecialize(a) ⋤ @nospecialize(b) = !⊑(b, a) +function is_lattice_equal(lattice::OptimizerLattice, @nospecialize(a), @nospecialize(b)) + if isa(a, MaybeUndef) || isa(b, MaybeUndef) + # TODO: Unwrap these and recurse to is_lattice_equal + return ⊑(lattice, a, b) && ⊑(lattice, b, a) + end + return is_lattice_equal(widenlattice(lattice), a, b) +end -""" - is_lattice_equal(a, b) -> Bool +function is_lattice_equal(lattice::AnyConditionalsLattice, @nospecialize(a), @nospecialize(b)) + if isa(a, AnyConditional) || isa(b, AnyConditional) + # TODO: Unwrap these and recurse to is_lattice_equal + return ⊑(lattice, a, b) && ⊑(lattice, b, a) + end + return is_lattice_equal(widenlattice(lattice), a, b) +end -Check if two lattice elements are partial order equivalent. -This is basically `a ⊑ b && b ⊑ a` but with extra performance optimizations. -""" -function is_lattice_equal(@nospecialize(a), @nospecialize(b)) - a === b && return true +function is_lattice_equal(lattice::PartialsLattice, @nospecialize(a), @nospecialize(b)) if isa(a, PartialStruct) isa(b, PartialStruct) || return false length(a.fields) == length(b.fields) || return false widenconst(a) == widenconst(b) || return false + a.fields === b.fields && return true # fast path for i in 1:length(a.fields) - is_lattice_equal(a.fields[i], b.fields[i]) || return false + is_lattice_equal(lattice, a.fields[i], b.fields[i]) || return false end return true end isa(b, PartialStruct) && return false + if isa(a, PartialOpaque) + isa(b, PartialOpaque) || return false + widenconst(a) == widenconst(b) || return false + a.source === b.source || return false + a.parent === b.parent || return false + return is_lattice_equal(lattice, a.env, b.env) + end + isa(b, PartialOpaque) && return false + return is_lattice_equal(widenlattice(lattice), a, b) +end + +function is_lattice_equal(lattice::ConstsLattice, @nospecialize(a), @nospecialize(b)) + a === b && return true if a isa Const if issingletontype(b) return a.val === b.instance end + # N.B. Assumes a === b checked above return false end if b isa Const if issingletontype(a) return a.instance === b.val end + # N.B. Assumes a === b checked above return false end - if isa(a, PartialOpaque) - isa(b, PartialOpaque) || return false - widenconst(a) == widenconst(b) || return false - a.source === b.source || return false - a.parent === b.parent || return false - return is_lattice_equal(a.env, b.env) + if isa(a, PartialTypeVar) || isa(b, PartialTypeVar) + return false end - return a ⊑ b && b ⊑ a + return is_lattice_equal(widenlattice(lattice), a, b) end # lattice operations # ================== -""" - tmeet(v, t::Type) -> x - -Computes typeintersect over the extended inference lattice, as precisely as we can, -where `v` is in the extended lattice, and `t` is a `Type`. -""" -function tmeet(@nospecialize(v), @nospecialize(t::Type)) - if isa(v, Const) - if !has_free_typevars(t) && !isa(v.val, t) - return Bottom - end - return v - elseif isa(v, PartialStruct) +function tmeet(lattice::PartialsLattice, @nospecialize(v), @nospecialize(t::Type)) + if isa(v, PartialStruct) has_free_typevars(t) && return v widev = widenconst(v) - if widev <: t + ti = typeintersect(widev, t) + if ti === widev return v end - ti = typeintersect(widev, t) valid_as_lattice(ti) || return Bottom @assert widev <: Tuple new_fields = Vector{Any}(undef, length(v.fields)) @@ -389,13 +419,13 @@ function tmeet(@nospecialize(v), @nospecialize(t::Type)) if isvarargtype(vfi) new_fields[i] = vfi else - new_fields[i] = tmeet(vfi, widenconst(getfield_tfunc(t, Const(i)))) + new_fields[i] = tmeet(lattice, vfi, widenconst(getfield_tfunc(t, Const(i)))) if new_fields[i] === Bottom return Bottom end end end - return tuple_tfunc(new_fields) + return tuple_tfunc(lattice, new_fields) elseif isa(v, PartialOpaque) has_free_typevars(t) && return v widev = widenconst(v) @@ -405,15 +435,46 @@ function tmeet(@nospecialize(v), @nospecialize(t::Type)) ti = typeintersect(widev, t) valid_as_lattice(ti) || return Bottom return PartialOpaque(ti, v.env, v.parent, v.source) - elseif isa(v, Conditional) + end + return tmeet(widenlattice(lattice), v, t) +end + +function tmeet(lattice::ConstsLattice, @nospecialize(v), @nospecialize(t::Type)) + if isa(v, Const) + if !has_free_typevars(t) && !isa(v.val, t) + return Bottom + end + return v + end + tmeet(widenlattice(lattice), widenconst(v), t) +end + +function tmeet(lattice::ConditionalsLattice, @nospecialize(v), @nospecialize(t::Type)) + if isa(v, Conditional) if !(Bool <: t) return Bottom end return v end - ti = typeintersect(widenconst(v), t) - valid_as_lattice(ti) || return Bottom - return ti + tmeet(widenlattice(lattice), v, t) +end + +function tmeet(lattice::InferenceLattice, @nospecialize(v), @nospecialize(t::Type)) + # TODO: This can probably happen and should be handled + @assert !isa(v, LimitedAccuracy) + tmeet(widenlattice(lattice), v, t) +end + +function tmeet(lattice::InterConditionalsLattice, @nospecialize(v), @nospecialize(t::Type)) + # TODO: This can probably happen and should be handled + @assert !isa(v, AnyConditional) + tmeet(widenlattice(lattice), v, t) +end + +function tmeet(lattice::OptimizerLattice, @nospecialize(v), @nospecialize(t::Type)) + # TODO: This can probably happen and should be handled + @assert !isa(v, MaybeUndef) + tmeet(widenlattice(lattice), v, t) end """ @@ -436,19 +497,22 @@ widenconst(::LimitedAccuracy) = error("unhandled LimitedAccuracy") # state management # #################### -issubstate(a::VarState, b::VarState) = (a.typ ⊑ b.typ && a.undef <= b.undef) +issubstate(lattice::AbstractLattice, a::VarState, b::VarState) = + ⊑(lattice, a.typ, b.typ) && a.undef <= b.undef -function smerge(sa::Union{NotFound,VarState}, sb::Union{NotFound,VarState}) +function smerge(lattice::AbstractLattice, sa::Union{NotFound,VarState}, sb::Union{NotFound,VarState}) sa === sb && return sa sa === NOT_FOUND && return sb sb === NOT_FOUND && return sa - issubstate(sa, sb) && return sb - issubstate(sb, sa) && return sa - return VarState(tmerge(sa.typ, sb.typ), sa.undef | sb.undef) + issubstate(lattice, sa, sb) && return sb + issubstate(lattice, sb, sa) && return sa + return VarState(tmerge(lattice, sa.typ, sb.typ), sa.undef | sb.undef) end -@inline tchanged(@nospecialize(n), @nospecialize(o)) = o === NOT_FOUND || (n !== NOT_FOUND && !(n ⊑ o)) -@inline schanged(@nospecialize(n), @nospecialize(o)) = (n !== o) && (o === NOT_FOUND || (n !== NOT_FOUND && !issubstate(n::VarState, o::VarState))) +@inline tchanged(lattice::AbstractLattice, @nospecialize(n), @nospecialize(o)) = + o === NOT_FOUND || (n !== NOT_FOUND && !⊑(lattice, n, o)) +@inline schanged(lattice::AbstractLattice, @nospecialize(n), @nospecialize(o)) = + (n !== o) && (o === NOT_FOUND || (n !== NOT_FOUND && !issubstate(lattice, n::VarState, o::VarState))) # remove any lattice elements that wrap the reassigned slot object from the vartable function invalidate_slotwrapper(vt::VarState, changeid::Int, ignore_conditional::Bool) @@ -460,7 +524,7 @@ function invalidate_slotwrapper(vt::VarState, changeid::Int, ignore_conditional: return nothing end -function stupdate!(state::VarTable, changes::StateUpdate) +function stupdate!(lattice::AbstractLattice, state::VarTable, changes::StateUpdate) changed = false changeid = slot_id(changes.var) for i = 1:length(state) @@ -474,28 +538,28 @@ function stupdate!(state::VarTable, changes::StateUpdate) newtype = invalidated end oldtype = state[i] - if schanged(newtype, oldtype) - state[i] = smerge(oldtype, newtype) + if schanged(lattice, newtype, oldtype) + state[i] = smerge(lattice, oldtype, newtype) changed = true end end return changed end -function stupdate!(state::VarTable, changes::VarTable) +function stupdate!(lattice::AbstractLattice, state::VarTable, changes::VarTable) changed = false for i = 1:length(state) newtype = changes[i] oldtype = state[i] - if schanged(newtype, oldtype) - state[i] = smerge(oldtype, newtype) + if schanged(lattice, newtype, oldtype) + state[i] = smerge(lattice, oldtype, newtype) changed = true end end return changed end -function stupdate1!(state::VarTable, change::StateUpdate) +function stupdate1!(lattice::AbstractLattice, state::VarTable, change::StateUpdate) changeid = slot_id(change.var) for i = 1:length(state) invalidated = invalidate_slotwrapper(state[i], changeid, change.conditional) @@ -506,8 +570,8 @@ function stupdate1!(state::VarTable, change::StateUpdate) # and update the type of it newtype = change.vtype oldtype = state[changeid] - if schanged(newtype, oldtype) - state[changeid] = smerge(oldtype, newtype) + if schanged(lattice, newtype, oldtype) + state[changeid] = smerge(lattice, oldtype, newtype) return true end return false diff --git a/base/compiler/typelimits.jl b/base/compiler/typelimits.jl index d44619fa508df..231148b7afbb8 100644 --- a/base/compiler/typelimits.jl +++ b/base/compiler/typelimits.jl @@ -304,7 +304,7 @@ end # A simplified type_more_complex query over the extended lattice # (assumes typeb ⊑ typea) -function issimplertype(@nospecialize(typea), @nospecialize(typeb)) +function issimplertype(lattice::AbstractLattice, @nospecialize(typea), @nospecialize(typeb)) typea = ignorelimited(typea) typeb = ignorelimited(typeb) typea isa MaybeUndef && (typea = typea.typ) # n.b. does not appear in inference @@ -315,14 +315,14 @@ function issimplertype(@nospecialize(typea), @nospecialize(typeb)) for i = 1:length(typea.fields) ai = unwrapva(typea.fields[i]) bi = fieldtype(aty, i) - is_lattice_equal(ai, bi) && continue + is_lattice_equal(lattice, ai, bi) && continue tni = _typename(widenconst(ai)) if tni isa Const bi = (tni.val::Core.TypeName).wrapper - is_lattice_equal(ai, bi) && continue + is_lattice_equal(lattice, ai, bi) && continue end bi = getfield_tfunc(typeb, Const(i)) - is_lattice_equal(ai, bi) && continue + is_lattice_equal(lattice, ai, bi) && continue # It is not enough for ai to be simpler than bi: it must exactly equal # (for this, an invariant struct field, by contrast to # type_more_complex above which handles covariant tuples). @@ -335,34 +335,51 @@ function issimplertype(@nospecialize(typea), @nospecialize(typeb)) typeb isa Const && return true typeb isa Conditional || return false is_same_conditionals(typea, typeb) || return false - issimplertype(typea.thentype, typeb.thentype) || return false - issimplertype(typea.elsetype, typeb.elsetype) || return false + issimplertype(lattice, typea.thentype, typeb.thentype) || return false + issimplertype(lattice, typea.elsetype, typeb.elsetype) || return false elseif typea isa InterConditional # ibid typeb isa Const && return true typeb isa InterConditional || return false is_same_conditionals(typea, typeb) || return false - issimplertype(typea.thentype, typeb.thentype) || return false - issimplertype(typea.elsetype, typeb.elsetype) || return false + issimplertype(lattice, typea.thentype, typeb.thentype) || return false + issimplertype(lattice, typea.elsetype, typeb.elsetype) || return false elseif typea isa PartialOpaque # TODO end return true end -# pick a wider type that contains both typea and typeb, -# with some limits on how "large" it can get, -# but without losing too much precision in common cases -# and also trying to be mostly associative and commutative -function tmerge(@nospecialize(typea), @nospecialize(typeb)) +@inline function tmerge_fast_path(lattice::AbstractLattice, @nospecialize(typea), @nospecialize(typeb)) + # Fast paths typea === Union{} && return typeb typeb === Union{} && return typea typea === typeb && return typea - suba = typea ⊑ typeb - suba && issimplertype(typeb, typea) && return typeb - subb = typeb ⊑ typea + suba = ⊑(lattice, typea, typeb) + suba && issimplertype(lattice, typeb, typea) && return typeb + subb = ⊑(lattice, typeb, typea) suba && subb && return typea - subb && issimplertype(typea, typeb) && return typea + subb && issimplertype(lattice, typea, typeb) && return typea + return nothing +end + + +function tmerge(lattice::OptimizerLattice, @nospecialize(typea), @nospecialize(typeb)) + r = tmerge_fast_path(lattice, typea, typeb) + r !== nothing && return r + + # type-lattice for MaybeUndef wrapper + if isa(typea, MaybeUndef) || isa(typeb, MaybeUndef) + return MaybeUndef(tmerge( + isa(typea, MaybeUndef) ? typea.typ : typea, + isa(typeb, MaybeUndef) ? typeb.typ : typeb)) + end + return tmerge(widenlattice(lattice), typea, typeb) +end + +function tmerge(lattice::InferenceLattice, @nospecialize(typea), @nospecialize(typeb)) + r = tmerge_fast_path(lattice, typea, typeb) + r !== nothing && return r # type-lattice for LimitedAccuracy wrapper # the merge create a slightly narrower type than needed, but we can't @@ -376,20 +393,17 @@ function tmerge(@nospecialize(typea), @nospecialize(typeb)) else causes = union!(copy(typea.causes), typeb.causes) end - return LimitedAccuracy(tmerge(typea.typ, typeb.typ), causes) + return LimitedAccuracy(tmerge(widenlattice(lattice), typea.typ, typeb.typ), causes) elseif isa(typea, LimitedAccuracy) - return LimitedAccuracy(tmerge(typea.typ, typeb), typea.causes) + return LimitedAccuracy(tmerge(widenlattice(lattice), typea.typ, typeb), typea.causes) elseif isa(typeb, LimitedAccuracy) - return LimitedAccuracy(tmerge(typea, typeb.typ), typeb.causes) + return LimitedAccuracy(tmerge(widenlattice(lattice), typea, typeb.typ), typeb.causes) end - # type-lattice for MaybeUndef wrapper - if isa(typea, MaybeUndef) || isa(typeb, MaybeUndef) - return MaybeUndef(tmerge( - isa(typea, MaybeUndef) ? typea.typ : typea, - isa(typeb, MaybeUndef) ? typeb.typ : typeb)) - end + return tmerge(widenlattice(lattice), typea, typeb) +end +function tmerge(lattice::ConditionalsLattice, @nospecialize(typea), @nospecialize(typeb)) # type-lattice for Conditional wrapper (NOTE never be merged with InterConditional) if isa(typea, Conditional) && isa(typeb, Const) if typeb.val === true @@ -419,6 +433,10 @@ function tmerge(@nospecialize(typea), @nospecialize(typeb)) end return Bool end + return tmerge(widenlattice(lattice), typea, typeb) +end + +function tmerge(lattice::InterConditionalsLattice, @nospecialize(typea), @nospecialize(typeb)) # type-lattice for InterConditional wrapper (NOTE never be merged with Conditional) if isa(typea, InterConditional) && isa(typeb, Const) if typeb.val === true @@ -448,7 +466,10 @@ function tmerge(@nospecialize(typea), @nospecialize(typeb)) end return Bool end + return tmerge(widenlattice(lattice), typea, typeb) +end +function tmerge(lattice::PartialsLattice, @nospecialize(typea), @nospecialize(typeb)) # type-lattice for Const and PartialStruct wrappers if ((isa(typea, PartialStruct) || isa(typea, Const)) && (isa(typeb, PartialStruct) || isa(typeb, Const))) @@ -469,11 +490,11 @@ function tmerge(@nospecialize(typea), @nospecialize(typeb)) ai = getfield_tfunc(typea, Const(i)) bi = getfield_tfunc(typeb, Const(i)) ft = fieldtype(aty, i) - if is_lattice_equal(ai, bi) || is_lattice_equal(ai, ft) + if is_lattice_equal(lattice, ai, bi) || is_lattice_equal(lattice, ai, ft) # Since ai===bi, the given type has no restrictions on complexity. # and can be used to refine ft tyi = ai - elseif is_lattice_equal(bi, ft) + elseif is_lattice_equal(lattice, bi, ft) tyi = bi else # Otherwise choose between using the fieldtype or some other simple merged type. @@ -493,8 +514,8 @@ function tmerge(@nospecialize(typea), @nospecialize(typeb)) end fields[i] = tyi if !anyrefine - anyrefine = has_nontrivial_const_info(tyi) || # constant information - tyi ⋤ ft # just a type-level information, but more precise than the declared type + anyrefine = has_nontrivial_const_info(lattice, tyi) || # constant information + ⋤(lattice, tyi, ft) # just a type-level information, but more precise than the declared type end end return anyrefine ? PartialStruct(aty, fields) : aty @@ -513,10 +534,12 @@ function tmerge(@nospecialize(typea), @nospecialize(typeb)) # no special type-inference lattice, join the types typea, typeb = widenconst(typea), widenconst(typeb) - if !isa(typea, Type) || !isa(typeb, Type) - # XXX: this should never happen - return Any - end + @assert isa(typea, Type); @assert isa(typeb, Type) + + return tmerge(JLTypeLattice(), typea, typeb) +end + +function tmerge(::JLTypeLattice, @nospecialize(typea::Type), @nospecialize(typeb::Type)) typea == typeb && return typea # it's always ok to form a Union of two concrete types if (isconcretetype(typea) || isType(typea)) && (isconcretetype(typeb) || isType(typeb)) diff --git a/base/compiler/types.jl b/base/compiler/types.jl index 21075b3e87d16..1f51cf02ed346 100644 --- a/base/compiler/types.jl +++ b/base/compiler/types.jl @@ -60,13 +60,20 @@ struct OptimizationParams inline_tupleret_bonus::Int # extra inlining willingness for non-concrete tuple return types (in hopes of splitting it up) inline_error_path_cost::Int # cost of (un-optimized) calls in blocks that throw + compilesig_invokes::Bool trust_inference::Bool - # Duplicating for now because optimizer inlining requires it. - # Keno assures me this will be removed in the near future - MAX_METHODS::Int + """ + assume_fatal_throw::Bool + + If `true`, gives the optimizer license to assume that any `throw` is fatal + and thus the state after a `throw` is not externally observable. In particular, + this gives the optimizer license to move side effects (that are proven not observed + within a particular code path) across a throwing call. Defaults to `false`. + """ + assume_fatal_throw::Bool + MAX_TUPLE_SPLAT::Int - MAX_UNION_SPLITTING::Int function OptimizationParams(; inlining::Bool = inlining_enabled(), @@ -74,10 +81,10 @@ struct OptimizationParams inline_nonleaf_penalty::Int = 1000, inline_tupleret_bonus::Int = 250, inline_error_path_cost::Int = 20, - max_methods::Int = 3, tuple_splat::Int = 32, - union_splitting::Int = 4, - trust_inference::Bool = false + compilesig_invokes::Bool = true, + trust_inference::Bool = false, + assume_fatal_throw::Bool = false ) return new( inlining, @@ -85,10 +92,10 @@ struct OptimizationParams inline_nonleaf_penalty, inline_tupleret_bonus, inline_error_path_cost, + compilesig_invokes, trust_inference, - max_methods, + assume_fatal_throw, tuple_splat, - union_splitting ) end end @@ -158,6 +165,8 @@ struct NativeInterpreter <: AbstractInterpreter cache::Vector{InferenceResult} # The world age we're working inside of world::UInt + # method table to lookup for during inference on this world age + method_table::CachedMethodTable{InternalMethodTable} # Parameters for inference and optimization inf_params::InferenceParams @@ -167,27 +176,21 @@ struct NativeInterpreter <: AbstractInterpreter inf_params = InferenceParams(), opt_params = OptimizationParams(), ) + cache = Vector{InferenceResult}() # Initially empty cache + # Sometimes the caller is lazy and passes typemax(UInt). # we cap it to the current world age if world == typemax(UInt) world = get_world_counter() end + method_table = CachedMethodTable(InternalMethodTable(world)) + # If they didn't pass typemax(UInt) but passed something more subtly # incorrect, fail out loudly. @assert world <= get_world_counter() - return new( - # Initially empty cache - Vector{InferenceResult}(), - - # world age counter - world, - - # parameters for inference and optimization - inf_params, - opt_params, - ) + return new(cache, world, method_table, inf_params, opt_params) end end @@ -251,6 +254,7 @@ External `AbstractInterpreter` can optionally return `OverlayMethodTable` here to incorporate customized dispatches for the overridden methods. """ method_table(interp::AbstractInterpreter) = InternalMethodTable(get_world_counter(interp)) +method_table(interp::NativeInterpreter) = interp.method_table """ By default `AbstractInterpreter` implements the following inference bail out logic: @@ -276,3 +280,7 @@ to the call site signature. """ infer_compilation_signature(::AbstractInterpreter) = false infer_compilation_signature(::NativeInterpreter) = true + +typeinf_lattice(::AbstractInterpreter) = InferenceLattice(BaseInferenceLattice.instance) +ipo_lattice(::AbstractInterpreter) = InferenceLattice(IPOResultLattice.instance) +optimizer_lattice(::AbstractInterpreter) = OptimizerLattice() diff --git a/base/compiler/typeutils.jl b/base/compiler/typeutils.jl index 0e59fc9daa8ae..d2992fc6113ba 100644 --- a/base/compiler/typeutils.jl +++ b/base/compiler/typeutils.jl @@ -23,12 +23,41 @@ function hasuniquerep(@nospecialize t) return false end -function has_nontrivial_const_info(@nospecialize t) +""" + isTypeDataType(@nospecialize t) + +For a type `t` test whether ∀S s.t. `isa(S, rewrap_unionall(Type{t}, ...))`, +we have `isa(S, DataType)`. In particular, if a statement is typed as `Type{t}` +(potentially wrapped in some UnionAll), then we are guaranteed that this statement +will be a DataType at runtime (and not e.g. a Union or UnionAll typeequal to it). +""" +function isTypeDataType(@nospecialize t) + isa(t, DataType) || return false + isType(t) && return false + # Could be Union{} at runtime + t === Core.TypeofBottom && return false + if t.name === Tuple.name + # If we have a Union parameter, could have been redistributed at runtime, + # e.g. `Tuple{Union{Int, Float64}, Int}` is a DataType, but + # `Union{Tuple{Int, Int}, Tuple{Float64, Int}}` is typeequal to it and + # is not. + return _all(isTypeDataType, t.parameters) + end + return true +end + +function has_nontrivial_const_info(lattice::PartialsLattice, @nospecialize t) isa(t, PartialStruct) && return true isa(t, PartialOpaque) && return true - isa(t, Const) || return false - val = t.val - return !isdefined(typeof(val), :instance) && !(isa(val, Type) && hasuniquerep(val)) + return has_nontrivial_const_info(widenlattice(lattice), t) +end +function has_nontrivial_const_info(lattice::ConstsLattice, @nospecialize t) + isa(t, PartialTypeVar) && return true + if isa(t, Const) + val = t.val + return !isdefined(typeof(val), :instance) && !(isa(val, Type) && hasuniquerep(val)) + end + return has_nontrivial_const_info(widenlattice(lattice), t) end has_const_info(@nospecialize x) = (!isa(x, Type) && !isvarargtype(x)) || isType(x) @@ -102,17 +131,26 @@ function valid_as_lattice(@nospecialize(x)) return false end -# test if non-Type, non-TypeVar `x` can be used to parameterize a type -function valid_tparam(@nospecialize(x)) - if isa(x, Tuple) - for t in x - isa(t, Symbol) || isbits(t) || return false +function valid_typeof_tparam(@nospecialize(t)) + if t === Symbol || isbitstype(t) + return true + end + isconcretetype(t) || return false + if t <: NamedTuple + t = t.parameters[2] + end + if t <: Tuple + for p in t.parameters + valid_typeof_tparam(p) || return false end return true end - return isa(x, Symbol) || isbits(x) + return false end +# test if non-Type, non-TypeVar `x` can be used to parameterize a type +valid_tparam(@nospecialize(x)) = valid_typeof_tparam(typeof(x)) + function compatible_vatuple(a::DataType, b::DataType) vaa = a.parameters[end] vab = a.parameters[end] diff --git a/base/compiler/utilities.jl b/base/compiler/utilities.jl index d793660195492..aa55093ac3cf1 100644 --- a/base/compiler/utilities.jl +++ b/base/compiler/utilities.jl @@ -173,6 +173,8 @@ function subst_trivial_bounds(@nospecialize(atype)) return UnionAll(v, subst_trivial_bounds(atype.body)) end +has_typevar(@nospecialize(t), v::TypeVar) = ccall(:jl_has_typevar, Cint, (Any, Any), t, v) != 0 + # If removing trivial vars from atype results in an equivalent type, use that # instead. Otherwise we can get a case like issue #38888, where a signature like # f(x::S) where S<:Int @@ -223,6 +225,64 @@ Check if `method` is declared as `Base.@constprop :none`. """ is_no_constprop(method::Union{Method,CodeInfo}) = method.constprop == 0x02 +############# +# backedges # +############# + +""" + BackedgeIterator(backedges::Vector{Any}) + +Return an iterator over a list of backedges. Iteration returns `(sig, caller)` elements, +which will be one of the following: + +- `BackedgePair(nothing, caller::MethodInstance)`: a call made by ordinary inferrable dispatch +- `BackedgePair(invokesig, caller::MethodInstance)`: a call made by `invoke(f, invokesig, args...)` +- `BackedgePair(specsig, mt::MethodTable)`: an abstract call + +# Examples + +```julia +julia> callme(x) = x+1 +callme (generic function with 1 method) + +julia> callyou(x) = callme(x) +callyou (generic function with 1 method) + +julia> callyou(2.0) +3.0 + +julia> mi = first(which(callme, (Any,)).specializations) +MethodInstance for callme(::Float64) + +julia> @eval Core.Compiler for (; sig, caller) in BackedgeIterator(Main.mi.backedges) + println(sig) + println(caller) + end +nothing +callyou(Float64) from callyou(Any) +``` +""" +struct BackedgeIterator + backedges::Vector{Any} +end + +const empty_backedge_iter = BackedgeIterator(Any[]) + +struct BackedgePair + sig # ::Union{Nothing,Type} + caller::Union{MethodInstance,Core.MethodTable} + BackedgePair(@nospecialize(sig), caller::Union{MethodInstance,Core.MethodTable}) = new(sig, caller) +end + +function iterate(iter::BackedgeIterator, i::Int=1) + backedges = iter.backedges + i > length(backedges) && return nothing + item = backedges[i] + isa(item, MethodInstance) && return BackedgePair(nothing, item), i+1 # regular dispatch + isa(item, Core.MethodTable) && return BackedgePair(backedges[i+1], item), i+2 # abstract dispatch + return BackedgePair(item, backedges[i+1]::MethodInstance), i+2 # `invoke` calls +end + ######### # types # ######### @@ -238,6 +298,17 @@ function singleton_type(@nospecialize(ft)) return nothing end +function maybe_singleton_const(@nospecialize(t)) + if isa(t, DataType) + if isdefined(t, :instance) + return Const(t.instance) + elseif isconstType(t) + return Const(t.parameters[1]) + end + end + return t +end + ################### # SSAValues/Slots # ################### @@ -310,7 +381,7 @@ function is_throw_call(e::Expr) if e.head === :call f = e.args[1] if isa(f, GlobalRef) - ff = abstract_eval_global(f.mod, f.name) + ff = abstract_eval_globalref(f) if isa(ff, Const) && ff.val === Core.throw return true end diff --git a/base/complex.jl b/base/complex.jl index 3af32e483bfaf..a9590328a8c56 100644 --- a/base/complex.jl +++ b/base/complex.jl @@ -133,6 +133,9 @@ is true. julia> isreal(5.) true +julia> isreal(1 - 3im) +false + julia> isreal(Inf + 0im) true @@ -192,7 +195,7 @@ flipsign(x::Complex, y::Real) = ifelse(signbit(y), -x, x) function show(io::IO, z::Complex) r, i = reim(z) - compact = get(io, :compact, false) + compact = get(io, :compact, false)::Bool show(io, r) if signbit(i) && !isnan(i) print(io, compact ? "-" : " - ") @@ -1064,18 +1067,32 @@ end #Requires two different RoundingModes for the real and imaginary components """ round(z::Complex[, RoundingModeReal, [RoundingModeImaginary]]) - round(z::Complex[, RoundingModeReal, [RoundingModeImaginary]]; digits=, base=10) - round(z::Complex[, RoundingModeReal, [RoundingModeImaginary]]; sigdigits=, base=10) + round(z::Complex[, RoundingModeReal, [RoundingModeImaginary]]; digits=0, base=10) + round(z::Complex[, RoundingModeReal, [RoundingModeImaginary]]; sigdigits, base=10) Return the nearest integral value of the same type as the complex-valued `z` to `z`, breaking ties using the specified [`RoundingMode`](@ref)s. The first [`RoundingMode`](@ref) is used for rounding the real components while the second is used for rounding the imaginary components. + +`RoundingModeReal` and `RoundingModeImaginary` default to [`RoundNearest`](@ref), +which rounds to the nearest integer, with ties (fractional values of 0.5) +being rounded to the nearest even integer. + # Example ```jldoctest julia> round(3.14 + 4.5im) 3.0 + 4.0im + +julia> round(3.14 + 4.5im, RoundUp, RoundNearestTiesUp) +4.0 + 5.0im + +julia> round(3.14159 + 4.512im; digits = 1) +3.1 + 4.5im + +julia> round(3.14159 + 4.512im; sigdigits = 3) +3.14 + 4.51im ``` """ function round(z::Complex, rr::RoundingMode=RoundNearest, ri::RoundingMode=rr; kwargs...) diff --git a/base/deepcopy.jl b/base/deepcopy.jl index 74c9d2b49c123..eae8974326d06 100644 --- a/base/deepcopy.jl +++ b/base/deepcopy.jl @@ -21,7 +21,7 @@ so far within the recursion. Within the definition, `deepcopy_internal` should b in place of `deepcopy`, and the `dict` variable should be updated as appropriate before returning. """ -function deepcopy(x) +function deepcopy(@nospecialize x) isbitstype(typeof(x)) && return x return deepcopy_internal(x, IdDict())::typeof(x) end diff --git a/base/deprecated.jl b/base/deprecated.jl index 61ba282f390de..87fc670cd594a 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -36,9 +36,18 @@ julia> @deprecate old(x) new(x) false old (generic function with 1 method) ``` -Calls to `@deprecate` without explicit type-annotations will define deprecated methods -accepting arguments of type `Any`. To restrict deprecation to a specific signature, annotate -the arguments of `old`. For example, +Calls to `@deprecate` without explicit type-annotations will define +deprecated methods accepting any number of positional and keyword +arguments of type `Any`. + +!!! compat "Julia 1.9" + Keyword arguments are forwarded when there is no explicit type + annotation as of Julia 1.9. For older versions, you can manually + forward positional and keyword arguments by doing `@deprecate + old(args...; kwargs...) new(args...; kwargs...)`. + +To restrict deprecation to a specific signature, annotate the +arguments of `old`. For example, ```jldoctest; filter = r"@ .*" julia> new(x::Int) = x; @@ -101,10 +110,10 @@ macro deprecate(old, new, export_old=true) end Expr(:toplevel, export_old ? Expr(:export, esc(old)) : nothing, - :(function $(esc(old))(args...) + :(function $(esc(old))(args...; kwargs...) $meta depwarn($"`$old` is deprecated, use `$new` instead.", Core.Typeof($(esc(old))).name.mt.name) - $(esc(new))(args...) + $(esc(new))(args...; kwargs...) end)) end end @@ -281,7 +290,7 @@ cat_shape(dims, shape::Tuple{}) = () # make sure `cat_shape(dims, ())` do not re @deprecate unsafe_indices(A) axes(A) false @deprecate unsafe_length(r) length(r) false -# these were internal type aliases, but some pacakges seem to be relying on them +# these were internal type aliases, but some packages seem to be relying on them const Any16{N} = Tuple{Any,Any,Any,Any,Any,Any,Any,Any, Any,Any,Any,Any,Any,Any,Any,Any,Vararg{Any,N}} const All16{T,N} = Tuple{T,T,T,T,T,T,T,T, diff --git a/base/dict.jl b/base/dict.jl index 22fd8a3a9f844..5f725f82ac57b 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -205,7 +205,7 @@ end end end - @assert h.age == age0 "Muliple concurent writes to Dict detected!" + @assert h.age == age0 "Muliple concurrent writes to Dict detected!" h.age += 1 h.slots = slots h.keys = keys @@ -359,7 +359,7 @@ end function setindex!(h::Dict{K,V}, v0, key0) where V where K key = convert(K, key0) - if !isequal(key, key0) + if !(isequal(key, key0)::Bool) throw(ArgumentError("$(limitrepr(key0)) is not a valid key for type $K")) end setindex!(h, v0, key) diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index 454d4b394e503..16eee40ce69fa 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -795,7 +795,7 @@ julia> f(2) 7 ``` -Anonymous functions can also be defined for multiple argumets. +Anonymous functions can also be defined for multiple arguments. ```jldoctest julia> g = (x,y) -> x^2 + y^2 #2 (generic function with 1 method) @@ -3088,7 +3088,7 @@ unused and delete the entire benchmark code). ```julia function loop() for i = 1:1000 - # The complier must guarantee that there are 1000 program points (in the correct + # The compiler must guarantee that there are 1000 program points (in the correct # order) at which the value of `i` is in a register, but has otherwise # total control over the program. donotdelete(i) @@ -3167,11 +3167,11 @@ but there are a number of small differences. They are documented here for completeness only and (unlike `Base.finalizer`) have no stability guarantees. The current differences are: - - `Core.finalizer` does not check for mutability of `o`. Attempting to register - a finalizer for an immutable object is undefined behavior. - - The value `f` must be a Julia object. `Core.finalizer` does not support a - raw C function pointer. - - `Core.finalizer` returns `nothing` rather than `o`. +- `Core.finalizer` does not check for mutability of `o`. Attempting to register + a finalizer for an immutable object is undefined behavior. +- The value `f` must be a Julia object. `Core.finalizer` does not support a + raw C function pointer. +- `Core.finalizer` returns `nothing` rather than `o`. """ Core.finalizer diff --git a/base/env.jl b/base/env.jl index 4fdc02e582a4c..41914c30e5c7d 100644 --- a/base/env.jl +++ b/base/env.jl @@ -117,7 +117,7 @@ if Sys.iswindows() m = nothing end if m === nothing - @warn "malformed environment entry: $env" + @warn "malformed environment entry" env continue end return (Pair{String,String}(winuppercase(env[1:prevind(env, m)]), env[nextind(env, m):end]), (pos, blk)) @@ -131,8 +131,8 @@ else # !windows env = env::String m = findfirst('=', env) if m === nothing - @warn "malformed environment entry: $env" - nothing + @warn "malformed environment entry" env + continue end return (Pair{String,String}(env[1:prevind(env, m)], env[nextind(env, m):end]), i+1) end diff --git a/base/errorshow.jl b/base/errorshow.jl index 9218abe02a187..2d9ada0ff29cb 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -107,8 +107,8 @@ showerror(io::IO, ex::InitError) = showerror(io, ex, []) function showerror(io::IO, ex::DomainError) if isa(ex.val, AbstractArray) - compact = get(io, :compact, true) - limit = get(io, :limit, true) + compact = get(io, :compact, true)::Bool + limit = get(io, :limit, true)::Bool print(IOContext(io, :compact => compact, :limit => limit), "DomainError with ", ex.val) else @@ -451,7 +451,7 @@ function show_method_candidates(io::IO, ex::MethodError, @nospecialize kwargs=() # the type of the first argument is not matched. t_in === Union{} && special && i == 1 && break if t_in === Union{} - if get(io, :color, false) + if get(io, :color, false)::Bool let sigstr=sigstr Base.with_output_color(Base.error_color(), iob) do iob print(iob, "::", sigstr...) @@ -495,7 +495,7 @@ function show_method_candidates(io::IO, ex::MethodError, @nospecialize kwargs=() if !((min(length(t_i), length(sig)) == 0) && k==1) print(iob, ", ") end - if get(io, :color, false) + if get(io, :color, false)::Bool let sigstr=sigstr Base.with_output_color(Base.error_color(), iob) do iob print(iob, "::", sigstr...) @@ -915,6 +915,19 @@ end Experimental.register_error_hint(noncallable_number_hint_handler, MethodError) +# Display a hint in case the user tries to use the + operator on strings +# (probably attempting concatenation) +function string_concatenation_hint_handler(io, ex, arg_types, kwargs) + @nospecialize + if (ex.f == +) && all(i -> i <: AbstractString, arg_types) + print(io, "\nString concatenation is performed with ") + printstyled(io, "*", color=:cyan) + print(io, " (See also: https://docs.julialang.org/en/v1/manual/strings/#man-concatenation).") + end +end + +Experimental.register_error_hint(string_concatenation_hint_handler, MethodError) + # ExceptionStack implementation size(s::ExceptionStack) = size(s.stack) getindex(s::ExceptionStack, i::Int) = s.stack[i] diff --git a/base/essentials.jl b/base/essentials.jl index 50cdde9f3adc2..1d02c3ffdf1b1 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -13,6 +13,8 @@ length(a::Array) = arraylen(a) eval(:(getindex(A::Array, i1::Int) = arrayref($(Expr(:boundscheck)), A, i1))) eval(:(getindex(A::Array, i1::Int, i2::Int, I::Int...) = (@inline; arrayref($(Expr(:boundscheck)), A, i1, i2, I...)))) +==(a::GlobalRef, b::GlobalRef) = a.mod === b.mod && a.name === b.name + """ AbstractSet{T} @@ -451,7 +453,7 @@ end """ oftype(x, y) -Convert `y` to the type of `x` (`convert(typeof(x), y)`). +Convert `y` to the type of `x` i.e. `convert(typeof(x), y)`. # Examples ```jldoctest @@ -686,13 +688,7 @@ end # SimpleVector -function getindex(v::SimpleVector, i::Int) - @boundscheck if !(1 <= i <= length(v)) - throw(BoundsError(v,i)) - end - return ccall(:jl_svec_ref, Any, (Any, Int), v, i - 1) -end - +@eval getindex(v::SimpleVector, i::Int) = Core._svec_ref($(Expr(:boundscheck)), v, i) function length(v::SimpleVector) return ccall(:jl_svec_len, Int, (Any,), v) end @@ -769,6 +765,7 @@ struct Colon <: Function end const (:) = Colon() + """ Val(c) diff --git a/base/exports.jl b/base/exports.jl index f64c3b2913260..d09f18bb57831 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -772,6 +772,7 @@ export # syntax esc, gensym, + @kwdef, macroexpand, @macroexpand1, @macroexpand, diff --git a/base/expr.jl b/base/expr.jl index 2a46be767f3f0..27217447de756 100644 --- a/base/expr.jl +++ b/base/expr.jl @@ -388,6 +388,7 @@ end !!! compat "Julia 1.8" Using `Base.@assume_effects` requires Julia version 1.8. +# Examples ```jldoctest julia> Base.@assume_effects :terminates_locally function pow(x) # this :terminates_locally allows `pow` to be constant-folded @@ -874,7 +875,7 @@ the global scope or depending on mutable elements. See [Metaprogramming](@ref) for further details. -## Example: +# Examples ```jldoctest julia> @generated function bar(x) if x <: Integer @@ -948,6 +949,7 @@ This operation translates to a `modifyproperty!(a.b, :x, func, arg2)` call. See [Per-field atomics](@ref man-atomics) section in the manual for more details. +# Examples ```jldoctest julia> mutable struct Atomic{T}; @atomic x::T; end @@ -1047,6 +1049,7 @@ This operation translates to a `swapproperty!(a.b, :x, new)` call. See [Per-field atomics](@ref man-atomics) section in the manual for more details. +# Examples ```jldoctest julia> mutable struct Atomic{T}; @atomic x::T; end @@ -1093,6 +1096,7 @@ This operation translates to a `replaceproperty!(a.b, :x, expected, desired)` ca See [Per-field atomics](@ref man-atomics) section in the manual for more details. +# Examples ```jldoctest julia> mutable struct Atomic{T}; @atomic x::T; end diff --git a/base/file.jl b/base/file.jl index eaff9efae43d3..b449a68bfa5da 100644 --- a/base/file.jl +++ b/base/file.jl @@ -1062,7 +1062,7 @@ See also: [`hardlink`](@ref). !!! compat "Julia 1.6" The `dir_target` keyword argument was added in Julia 1.6. Prior to this, - symlinks to nonexistant paths on windows would always be file symlinks, and + symlinks to nonexistent paths on windows would always be file symlinks, and relative symlinks to directories were not supported. """ function symlink(target::AbstractString, link::AbstractString; diff --git a/base/float.jl b/base/float.jl index eb1cc36e6c215..57a0786132154 100644 --- a/base/float.jl +++ b/base/float.jl @@ -135,6 +135,17 @@ i.e. the maximum integer value representable by [`exponent_bits(T)`](@ref) bits. """ function exponent_raw_max end +""" + uabs(x::Integer) + +Return the absolute value of `x`, possibly returning a different type should the +operation be susceptible to overflow. This typically arises when `x` is a two's complement +signed integer, so that `abs(typemin(x)) == typemin(x) < 0`, in which case the result of +`uabs(x)` will be an unsigned integer of the same size. +""" +uabs(x::Integer) = abs(x) +uabs(x::BitSigned) = unsigned(abs(x)) + ## conversions to floating-point ## # TODO: deprecate in 2.0 @@ -165,33 +176,45 @@ promote_rule(::Type{Float16}, ::Type{UInt128}) = Float16 promote_rule(::Type{Float16}, ::Type{Int128}) = Float16 function Float64(x::UInt128) - x == 0 && return 0.0 - n = 128-leading_zeros(x) # ndigits0z(x,2) - if n <= 53 - y = ((x % UInt64) << (53-n)) & 0x000f_ffff_ffff_ffff - else - y = ((x >> (n-54)) % UInt64) & 0x001f_ffff_ffff_ffff # keep 1 extra bit - y = (y+1)>>1 # round, ties up (extra leading bit in case of next exponent) - y &= ~UInt64(trailing_zeros(x) == (n-54)) # fix last bit to round to even + if x < UInt128(1) << 104 # Can fit it in two 52 bits mantissas + low_exp = 0x1p52 + high_exp = 0x1p104 + low_bits = (x % UInt64) & Base.significand_mask(Float64) + low_value = reinterpret(Float64, reinterpret(UInt64, low_exp) | low_bits) - low_exp + high_bits = ((x >> 52) % UInt64) + high_value = reinterpret(Float64, reinterpret(UInt64, high_exp) | high_bits) - high_exp + low_value + high_value + else # Large enough that low bits only affect rounding, pack low bits + low_exp = 0x1p76 + high_exp = 0x1p128 + low_bits = ((x >> 12) % UInt64) >> 12 | (x % UInt64) & 0xFFFFFF + low_value = reinterpret(Float64, reinterpret(UInt64, low_exp) | low_bits) - low_exp + high_bits = ((x >> 76) % UInt64) + high_value = reinterpret(Float64, reinterpret(UInt64, high_exp) | high_bits) - high_exp + low_value + high_value end - d = ((n+1022) % UInt64) << 52 - reinterpret(Float64, d + y) end function Float64(x::Int128) - x == 0 && return 0.0 - s = ((x >>> 64) % UInt64) & 0x8000_0000_0000_0000 # sign bit - x = abs(x) % UInt128 - n = 128-leading_zeros(x) # ndigits0z(x,2) - if n <= 53 - y = ((x % UInt64) << (53-n)) & 0x000f_ffff_ffff_ffff - else - y = ((x >> (n-54)) % UInt64) & 0x001f_ffff_ffff_ffff # keep 1 extra bit - y = (y+1)>>1 # round, ties up (extra leading bit in case of next exponent) - y &= ~UInt64(trailing_zeros(x) == (n-54)) # fix last bit to round to even + sign_bit = ((x >> 127) % UInt64) << 63 + ux = uabs(x) + if ux < UInt128(1) << 104 # Can fit it in two 52 bits mantissas + low_exp = 0x1p52 + high_exp = 0x1p104 + low_bits = (ux % UInt64) & Base.significand_mask(Float64) + low_value = reinterpret(Float64, reinterpret(UInt64, low_exp) | low_bits) - low_exp + high_bits = ((ux >> 52) % UInt64) + high_value = reinterpret(Float64, reinterpret(UInt64, high_exp) | high_bits) - high_exp + reinterpret(Float64, sign_bit | reinterpret(UInt64, low_value + high_value)) + else # Large enough that low bits only affect rounding, pack low bits + low_exp = 0x1p76 + high_exp = 0x1p128 + low_bits = ((ux >> 12) % UInt64) >> 12 | (ux % UInt64) & 0xFFFFFF + low_value = reinterpret(Float64, reinterpret(UInt64, low_exp) | low_bits) - low_exp + high_bits = ((ux >> 76) % UInt64) + high_value = reinterpret(Float64, reinterpret(UInt64, high_exp) | high_bits) - high_exp + reinterpret(Float64, sign_bit | reinterpret(UInt64, low_value + high_value)) end - d = ((n+1022) % UInt64) << 52 - reinterpret(Float64, s | d + y) end function Float32(x::UInt128) @@ -225,8 +248,8 @@ function Float32(x::Int128) end # TODO: optimize -Float16(x::UInt128) = convert(Float16, Float32(x)) -Float16(x::Int128) = convert(Float16, Float32(x)) +Float16(x::UInt128) = convert(Float16, Float64(x)) +Float16(x::Int128) = convert(Float16, Float64(x)) Float16(x::Float32) = fptrunc(Float16, x) Float16(x::Float64) = fptrunc(Float16, x) @@ -662,17 +685,6 @@ end precision(::Type{T}; base::Integer=2) where {T<:AbstractFloat} = _precision(T, base) precision(::T; base::Integer=2) where {T<:AbstractFloat} = precision(T; base) -""" - uabs(x::Integer) - -Return the absolute value of `x`, possibly returning a different type should the -operation be susceptible to overflow. This typically arises when `x` is a two's complement -signed integer, so that `abs(typemin(x)) == typemin(x) < 0`, in which case the result of -`uabs(x)` will be an unsigned integer of the same size. -""" -uabs(x::Integer) = abs(x) -uabs(x::BitSigned) = unsigned(abs(x)) - """ nextfloat(x::AbstractFloat, n::Integer) diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index 4276ec0daecaf..b3db0f087d211 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -99,12 +99,12 @@ julia> round(357.913; sigdigits=4, base=2) value represented by `1.15` is actually *less* than 1.15, yet will be rounded to 1.2. For example: - ```jldoctest; setup = :(using Printf) + ```jldoctest julia> x = 1.15 1.15 - julia> @sprintf "%.20f" x - "1.14999999999999991118" + julia> big(1.15) + 1.149999999999999911182158029987476766109466552734375 julia> x < 115//100 true diff --git a/base/gmp.jl b/base/gmp.jl index 5d3cabac87e40..8e0c51e6259d6 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -668,8 +668,12 @@ function prod(arr::AbstractArray{BigInt}) # to account for the rounding to limbs in MPZ.mul! # (BITS_PER_LIMB-1 would typically be enough, to which we add # 1 for the initial multiplication by init=1 in foldl) - nbits = GC.@preserve arr sum(arr; init=BITS_PER_LIMB) do x - abs(x.size) * BITS_PER_LIMB - leading_zeros(unsafe_load(x.d)) + nbits = BITS_PER_LIMB + for x in arr + iszero(x) && return zero(BigInt) + xsize = abs(x.size) + lz = GC.@preserve x leading_zeros(unsafe_load(x.d, xsize)) + nbits += xsize * BITS_PER_LIMB - lz end init = BigInt(; nbits) MPZ.set_si!(init, 1) diff --git a/base/indices.jl b/base/indices.jl index c12d4fac69745..0584b32941132 100644 --- a/base/indices.jl +++ b/base/indices.jl @@ -476,7 +476,7 @@ struct LinearIndices{N,R<:NTuple{N,AbstractUnitRange{Int}}} <: AbstractArray{Int indices::R end convert(::Type{LinearIndices{N,R}}, inds::LinearIndices{N}) where {N,R<:NTuple{N,AbstractUnitRange{Int}}} = - LinearIndices{N,R}(convert(R, inds.indices)) + LinearIndices{N,R}(convert(R, inds.indices))::LinearIndices{N,R} LinearIndices(::Tuple{}) = LinearIndices{0,typeof(())}(()) LinearIndices(inds::NTuple{N,AbstractUnitRange{<:Integer}}) where {N} = diff --git a/base/int.jl b/base/int.jl index 73485520509c7..f5a415a6b3822 100644 --- a/base/int.jl +++ b/base/int.jl @@ -772,13 +772,24 @@ promote_rule(::Type{UInt128}, ::Type{Int128}) = UInt128 The lowest value representable by the given (real) numeric DataType `T`. +See also: [`floatmin`](@ref), [`typemax`](@ref), [`eps`](@ref). + # Examples ```jldoctest +julia> typemin(Int8) +-128 + +julia> typemin(UInt32) +0x00000000 + julia> typemin(Float16) -Inf16 julia> typemin(Float32) -Inf32 + +julia> nextfloat(-Inf32) # smallest finite Float32 floating point number +-3.4028235f38 ``` """ function typemin end @@ -801,7 +812,10 @@ julia> typemax(UInt32) julia> typemax(Float64) Inf -julia> floatmax(Float32) # largest finite floating point number +julia> typemax(Float32) +Inf32 + +julia> floatmax(Float32) # largest finite Float32 floating point number 3.4028235f38 ``` """ diff --git a/base/io.jl b/base/io.jl index 59bce5eb4de6d..c2d6ad592bf0c 100644 --- a/base/io.jl +++ b/base/io.jl @@ -1001,7 +1001,7 @@ function read(s::IO, nb::Integer = typemax(Int)) return resize!(b, nr) end -read(s::IO, ::Type{String}) = String(read(s)) +read(s::IO, ::Type{String}) = String(read(s)::Vector{UInt8}) read(s::IO, T::Type) = error("The IO stream does not support reading objects of type $T.") ## high-level iterator interfaces ## diff --git a/base/irrationals.jl b/base/irrationals.jl index d147034382842..3c4a422a74147 100644 --- a/base/irrationals.jl +++ b/base/irrationals.jl @@ -31,7 +31,7 @@ struct Irrational{sym} <: AbstractIrrational end show(io::IO, x::Irrational{sym}) where {sym} = print(io, sym) function show(io::IO, ::MIME"text/plain", x::Irrational{sym}) where {sym} - if get(io, :compact, false) + if get(io, :compact, false)::Bool print(io, sym) else print(io, sym, " = ", string(float(x))[1:min(end,15)], "...") @@ -170,6 +170,28 @@ round(x::Irrational, r::RoundingMode) = round(float(x), r) Define a new `Irrational` value, `sym`, with pre-computed `Float64` value `val`, and arbitrary-precision definition in terms of `BigFloat`s given by the expression `def`. + +An `AssertionError` is thrown when either `big(def) isa BigFloat` or `Float64(val) == Float64(def)` +returns `false`. + +# Examples +```jldoctest +julia> Base.@irrational(twoπ, 6.2831853071795864769, 2*big(π)) + +julia> twoπ +twoπ = 6.2831853071795... + +julia> Base.@irrational sqrt2 1.4142135623730950488 √big(2) + +julia> sqrt2 +sqrt2 = 1.4142135623730... + +julia> Base.@irrational sqrt2 1.4142135623730950488 big(2) +ERROR: AssertionError: big($(Expr(:escape, :sqrt2))) isa BigFloat + +julia> Base.@irrational sqrt2 1.41421356237309 √big(2) +ERROR: AssertionError: Float64($(Expr(:escape, :sqrt2))) == Float64(big($(Expr(:escape, :sqrt2)))) +``` """ macro irrational(sym, val, def) esym = esc(sym) diff --git a/base/iterators.jl b/base/iterators.jl index 2c8ce70ac0079..a93214e67d181 100644 --- a/base/iterators.jl +++ b/base/iterators.jl @@ -1381,24 +1381,41 @@ julia> peek(a) julia> sum(a) # Sum the remaining elements 7 ``` -""" mutable struct Stateful{T, VS} +""" +mutable struct Stateful{T, VS, N<:Integer} itr::T # A bit awkward right now, but adapted to the new iteration protocol nextvalstate::Union{VS, Nothing} - taken::Int + + # Number of remaining elements, if itr is HasLength or HasShape. + # if not, store -1 - number_of_consumed_elements. + # This allows us to defer calculating length until asked for. + # See PR #45924 + remaining::N @inline function Stateful{<:Any, Any}(itr::T) where {T} - new{T, Any}(itr, iterate(itr), 0) + itl = iterlength(itr) + new{T, Any, typeof(itl)}(itr, iterate(itr), itl) end @inline function Stateful(itr::T) where {T} VS = approx_iter_type(T) - return new{T, VS}(itr, iterate(itr)::VS, 0) + itl = iterlength(itr) + return new{T, VS, typeof(itl)}(itr, iterate(itr)::VS, itl) + end +end + +function iterlength(it)::Signed + if IteratorSize(it) isa Union{HasShape, HasLength} + return length(it) + else + -1 end end function reset!(s::Stateful{T,VS}, itr::T=s.itr) where {T,VS} s.itr = itr + itl = iterlength(itr) setfield!(s, :nextvalstate, iterate(itr)) - s.taken = 0 + s.remaining = itl s end @@ -1432,7 +1449,8 @@ convert(::Type{Stateful}, itr) = Stateful(itr) else val, state = vs Core.setfield!(s, :nextvalstate, iterate(s.itr, state)) - s.taken += 1 + rem = s.remaining + s.remaining = rem - typeof(rem)(1) return val end end @@ -1442,11 +1460,21 @@ end return ns !== nothing ? ns[1] : sentinel end @inline iterate(s::Stateful, state=nothing) = s.nextvalstate === nothing ? nothing : (popfirst!(s), nothing) -IteratorSize(::Type{Stateful{T,VS}}) where {T,VS} = IteratorSize(T) isa HasShape ? HasLength() : IteratorSize(T) -eltype(::Type{Stateful{T, VS}} where VS) where {T} = eltype(T) -IteratorEltype(::Type{Stateful{T,VS}}) where {T,VS} = IteratorEltype(T) -length(s::Stateful) = length(s.itr) - s.taken +IteratorSize(::Type{<:Stateful{T}}) where {T} = IteratorSize(T) isa HasShape ? HasLength() : IteratorSize(T) +eltype(::Type{<:Stateful{T}}) where {T} = eltype(T) +IteratorEltype(::Type{<:Stateful{T}}) where {T} = IteratorEltype(T) + +function length(s::Stateful) + rem = s.remaining + # If rem is actually remaining length, return it. + # else, rem is number of consumed elements. + if rem >= 0 + rem + else + length(s.itr) - (typeof(rem)(1) - rem) + end end +end # if statement several hundred lines above """ only(x) diff --git a/base/loading.jl b/base/loading.jl index f8100fc0915a2..81919dfea0770 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -298,11 +298,41 @@ end # Used by Pkg but not used in loading itself function find_package(arg) - pkg = identify_package(arg) - pkg === nothing && return nothing - return locate_package(pkg) + pkgenv = identify_package_env(arg) + pkgenv === nothing && return nothing + pkg, env = pkgenv + return locate_package(pkg, env) end +""" + Base.identify_package_env(name::String)::Union{Tuple{PkgId, String}, Nothing} + Base.identify_package_env(where::Union{Module,PkgId}, name::String)::Union{Tuple{PkgId, String} Nothing} + +Same as [`Base.identify_package`](@ref) except that the path to the environment where the package is identified +is also returned. +""" +identify_package_env(where::Module, name::String) = identify_package_env(PkgId(where), name) +function identify_package_env(where::PkgId, name::String) + where.name === name && return where, nothing + where.uuid === nothing && return identify_package_env(name) # ignore `where` + for env in load_path() + pkgid = manifest_deps_get(env, where, name) + pkgid === nothing && continue # not found--keep looking + pkgid.uuid === nothing || return pkgid, env # found in explicit environment--use it + return nothing # found in implicit environment--return "not found" + end + return nothing +end +function identify_package_env(name::String) + for env in load_path() + uuid = project_deps_get(env, name) + uuid === nothing || return uuid, env # found--return it + end + return nothing +end + +_nothing_or_first(x) = x === nothing ? nothing : first(x) + """ Base.identify_package(name::String)::Union{PkgId, Nothing} Base.identify_package(where::Union{Module,PkgId}, name::String)::Union{PkgId, Nothing} @@ -317,7 +347,7 @@ There `where` argument provides the context from where to search for the package: in this case it first checks if the name matches the context itself, otherwise it searches all recursive dependencies (from the resolved manifest of each environment) until it locates the context `where`, and from there -identifies the depdencency with with the corresponding name. +identifies the dependency with with the corresponding name. ```julia-repl julia> Base.identify_package("Pkg") # Pkg is a dependency of the default environment @@ -329,25 +359,10 @@ julia> Base.identify_package(LinearAlgebra, "Pkg") # Pkg is not a dependency of ```` """ -identify_package(where::Module, name::String) = identify_package(PkgId(where), name) -function identify_package(where::PkgId, name::String)::Union{Nothing,PkgId} - where.name === name && return where - where.uuid === nothing && return identify_package(name) # ignore `where` - for env in load_path() - pkgid = manifest_deps_get(env, where, name) - pkgid === nothing && continue # not found--keep looking - pkgid.uuid === nothing || return pkgid # found in explicit environment--use it - return nothing # found in implicit environment--return "not found" - end - return nothing -end -function identify_package(name::String)::Union{Nothing,PkgId} - for env in load_path() - uuid = project_deps_get(env, name) - uuid === nothing || return uuid # found--return it - end - return nothing -end +identify_package(where::Module, name::String) = _nothing_or_first(identify_package_env(where, name)) +identify_package(where::PkgId, name::String) = _nothing_or_first(identify_package_env(where, name)) +identify_package(name::String) = _nothing_or_first(identify_package_env(name)) + """ Base.locate_package(pkg::PkgId)::Union{String, Nothing} @@ -363,7 +378,7 @@ julia> Base.locate_package(pkg) "/path/to/julia/stdlib/v$(VERSION.major).$(VERSION.minor)/Pkg/src/Pkg.jl" ``` """ -function locate_package(pkg::PkgId)::Union{Nothing,String} +function locate_package(pkg::PkgId, stopenv::Union{String, Nothing}=nothing)::Union{Nothing,String} if pkg.uuid === nothing for env in load_path() # look for the toplevel pkg `pkg.name` in this entry @@ -377,16 +392,20 @@ function locate_package(pkg::PkgId)::Union{Nothing,String} return implicit_manifest_uuid_path(env, pkg) end end + stopenv == env && return nothing end else for env in load_path() path = manifest_uuid_path(env, pkg) + # missing is used as a sentinel to stop looking further down in envs + path === missing && return nothing path === nothing || return entry_path(path, pkg.name) + stopenv == env && break end # Allow loading of stdlibs if the name/uuid are given # e.g. if they have been explicitly added to the project/manifest path = manifest_uuid_path(Sys.STDLIB, pkg) - path === nothing || return entry_path(path, pkg.name) + path isa String && return entry_path(path, pkg.name) end return nothing end @@ -441,6 +460,18 @@ function pkgdir(m::Module, paths::String...) return joinpath(dirname(dirname(path)), paths...) end +function get_pkgversion_from_path(path) + project_file = locate_project_file(path) + if project_file isa String + d = parsed_toml(project_file) + v = get(d, "version", nothing) + if v !== nothing + return VersionNumber(v::String) + end + end + return nothing +end + """ pkgversion(m::Module) @@ -458,12 +489,17 @@ the form `pkgversion(@__MODULE__)` can be used. This function was introduced in Julia 1.9. """ function pkgversion(m::Module) - rootmodule = moduleroot(m) - pkg = PkgId(rootmodule) - pkgorigin = @lock require_lock begin - get(pkgorigins, pkg, nothing) + path = pkgdir(m) + path === nothing && return nothing + @lock require_lock begin + v = get_pkgversion_from_path(path) + pkgorigin = get(pkgorigins, PkgId(moduleroot(m)), nothing) + # Cache the version + if pkgorigin !== nothing && pkgorigin.version === nothing + pkgorigin.version = v + end + return v end - return pkgorigin === nothing ? nothing : pkgorigin.version end ## generic project & manifest API ## @@ -483,7 +519,7 @@ function locate_project_file(env::String) end # classify the LOAD_PATH entry to be one of: -# - `false`: nonexistant / nothing to see here +# - `false`: nonexistent / nothing to see here # - `true`: `env` is an implicit environment # - `path`: the path of an explicit project file function env_project_file(env::String)::Union{Bool,String} @@ -539,7 +575,7 @@ function manifest_deps_get(env::String, where::PkgId, name::String)::Union{Nothi return nothing end -function manifest_uuid_path(env::String, pkg::PkgId)::Union{Nothing,String} +function manifest_uuid_path(env::String, pkg::PkgId)::Union{Nothing,String,Missing} project_file = env_project_file(env) if project_file isa String proj = project_file_name_uuid(project_file, pkg.name) @@ -730,7 +766,7 @@ function explicit_manifest_deps_get(project_file::String, where::UUID, name::Str end # find `uuid` stanza, return the corresponding path -function explicit_manifest_uuid_path(project_file::String, pkg::PkgId)::Union{Nothing,String} +function explicit_manifest_uuid_path(project_file::String, pkg::PkgId)::Union{Nothing,String,Missing} manifest_file = project_file_manifest_path(project_file) manifest_file === nothing && return nothing # no manifest, skip env @@ -765,7 +801,8 @@ function explicit_manifest_entry_path(manifest_file::String, pkg::PkgId, entry:: ispath(path) && return abspath(path) end end - return nothing + # no depot contains the package, return missing to stop looking + return missing end ## implicit project & manifest API ## @@ -1204,9 +1241,9 @@ function require(into::Module, mod::Symbol) @lock require_lock begin LOADING_CACHE[] = LoadingCache() try - uuidkey = identify_package(into, String(mod)) - # Core.println("require($(PkgId(into)), $mod) -> $uuidkey") - if uuidkey === nothing + uuidkey_env = identify_package_env(into, String(mod)) + # Core.println("require($(PkgId(into)), $mod) -> $uuidkey from env \"$env\"") + if uuidkey_env === nothing where = PkgId(into) if where.uuid === nothing hint, dots = begin @@ -1234,10 +1271,11 @@ function require(into::Module, mod::Symbol) - Otherwise you may need to report an issue with $(where.name)""")) end end + uuidkey, env = uuidkey_env if _track_dependencies[] push!(_require_dependencies, (into, binpack(uuidkey), 0.0)) end - return _require_prelocked(uuidkey) + return _require_prelocked(uuidkey, env) finally LOADING_CACHE[] = nothing end @@ -1254,10 +1292,10 @@ const pkgorigins = Dict{PkgId,PkgOrigin}() require(uuidkey::PkgId) = @lock require_lock _require_prelocked(uuidkey) -function _require_prelocked(uuidkey::PkgId) +function _require_prelocked(uuidkey::PkgId, env=nothing) assert_havelock(require_lock) if !root_module_exists(uuidkey) - newm = _require(uuidkey) + newm = _require(uuidkey, env) if newm === nothing error("package `$(uuidkey.name)` did not define the expected \ module `$(uuidkey.name)`, check for typos in package module name") @@ -1335,13 +1373,9 @@ function set_pkgorigin_version_path(pkg::PkgId, path::Union{String,Nothing}) assert_havelock(require_lock) pkgorigin = get!(PkgOrigin, pkgorigins, pkg) if path !== nothing - project_file = locate_project_file(joinpath(dirname(path), "..")) - if project_file isa String - d = parsed_toml(project_file) - v = get(d, "version", nothing) - if v !== nothing - pkgorigin.version = VersionNumber(v::AbstractString) - end + # Pkg needs access to the version of packages in the sysimage. + if Core.Compiler.generating_sysimg() + pkgorigin.version = get_pkgversion_from_path(joinpath(dirname(path), "..")) end end pkgorigin.path = path @@ -1349,7 +1383,7 @@ function set_pkgorigin_version_path(pkg::PkgId, path::Union{String,Nothing}) end # Returns `nothing` or the new(ish) module -function _require(pkg::PkgId) +function _require(pkg::PkgId, env=nothing) assert_havelock(require_lock) # handle recursive calls to require loading = get(package_locks, pkg, false) @@ -1364,7 +1398,7 @@ function _require(pkg::PkgId) try toplevel_load[] = false # perform the search operation to select the module file require intends to load - path = locate_package(pkg) + path = locate_package(pkg, env) if path === nothing throw(ArgumentError(""" Package $pkg is required but does not seem to be installed: @@ -1650,12 +1684,14 @@ function create_expr_cache(pkg::PkgId, input::String, output::String, concrete_d deps_eltype = sprint(show, eltype(concrete_deps); context = :module=>nothing) deps = deps_eltype * "[" * join(deps_strs, ",") * "]" trace = isassigned(PRECOMPILE_TRACE_COMPILE) ? `--trace-compile=$(PRECOMPILE_TRACE_COMPILE[])` : `` - io = open(pipeline(`$(julia_cmd()::Cmd) -O0 - --output-ji $output --output-incremental=yes - --startup-file=no --history-file=no --warn-overwrite=yes - --color=$(have_color === nothing ? "auto" : have_color ? "yes" : "no") - $trace - -`, stderr = internal_stderr, stdout = internal_stdout), + io = open(pipeline(addenv(`$(julia_cmd()::Cmd) -O0 + --output-ji $output --output-incremental=yes + --startup-file=no --history-file=no --warn-overwrite=yes + --color=$(have_color === nothing ? "auto" : have_color ? "yes" : "no") + $trace + -`, + "OPENBLAS_NUM_THREADS" => 1), + stderr = internal_stderr, stdout = internal_stdout), "w", stdout) # write data over stdin to avoid the (unlikely) case of exceeding max command line size write(io.in, """ @@ -2262,12 +2298,12 @@ macro __DIR__() end """ - precompile(f, args::Tuple{Vararg{Any}}) + precompile(f, argtypes::Tuple{Vararg{Any}}) -Compile the given function `f` for the argument tuple (of types) `args`, but do not execute it. +Compile the given function `f` for the argument tuple (of types) `argtypes`, but do not execute it. """ -function precompile(@nospecialize(f), @nospecialize(args::Tuple)) - precompile(Tuple{Core.Typeof(f), args...}) +function precompile(@nospecialize(f), @nospecialize(argtypes::Tuple)) + precompile(Tuple{Core.Typeof(f), argtypes...}) end const ENABLE_PRECOMPILE_WARNINGS = Ref(false) @@ -2279,6 +2315,27 @@ function precompile(@nospecialize(argt::Type)) return ret end +# Variants that work for `invoke`d calls for which the signature may not be sufficient +precompile(mi::Core.MethodInstance, world::UInt=get_world_counter()) = + (ccall(:jl_compile_method_instance, Cvoid, (Any, Any, UInt), mi, C_NULL, world); return true) + +""" + precompile(f, argtypes::Tuple{Vararg{Any}}, m::Method) + +Precompile a specific method for the given argument types. This may be used to precompile +a different method than the one that would ordinarily be chosen by dispatch, thus +mimicking `invoke`. +""" +function precompile(@nospecialize(f), @nospecialize(argtypes::Tuple), m::Method) + precompile(Tuple{Core.Typeof(f), argtypes...}, m) +end + +function precompile(@nospecialize(argt::Type), m::Method) + atype, sparams = ccall(:jl_type_intersection_with_env, Any, (Any, Any), argt, m.sig)::SimpleVector + mi = Core.Compiler.specialize_method(m, atype, sparams) + return precompile(mi) +end + precompile(include_package_for_output, (PkgId, String, Vector{String}, Vector{String}, Vector{String}, typeof(_concrete_dependencies), Nothing)) precompile(include_package_for_output, (PkgId, String, Vector{String}, Vector{String}, Vector{String}, typeof(_concrete_dependencies), String)) precompile(create_expr_cache, (PkgId, String, String, typeof(_concrete_dependencies), IO, IO)) diff --git a/base/logging.jl b/base/logging.jl index d2b6fa637c1bc..f60a9a1a80eab 100644 --- a/base/logging.jl +++ b/base/logging.jl @@ -672,7 +672,7 @@ function handle_message(logger::SimpleLogger, level::LogLevel, message, _module, end buf = IOBuffer() stream = logger.stream - if !isopen(stream) + if !(isopen(stream)::Bool) stream = stderr end iob = IOContext(buf, stream) diff --git a/base/math.jl b/base/math.jl index f1ee129305418..968eb0eee8bc0 100644 --- a/base/math.jl +++ b/base/math.jl @@ -190,6 +190,7 @@ end evalpoly(x, p::AbstractVector) = _evalpoly(x, p) function _evalpoly(x, p) + Base.require_one_based_indexing(p) N = length(p) ex = p[end] for i in N-1:-1:1 @@ -229,6 +230,7 @@ evalpoly(z::Complex, p::Tuple{<:Any}) = p[1] evalpoly(z::Complex, p::AbstractVector) = _evalpoly(z, p) function _evalpoly(z::Complex, p) + Base.require_one_based_indexing(p) length(p) == 1 && return p[1] N = length(p) a = p[end] @@ -928,18 +930,27 @@ end ldexp(x::Float16, q::Integer) = Float16(ldexp(Float32(x), q)) """ - exponent(x::AbstractFloat) -> Int + exponent(x) -> Int -Get the exponent of a normalized floating-point number. Returns the largest integer `y` such that `2^y ≤ abs(x)`. +For a normalized floating-point number `x`, this corresponds to the exponent of `x`. # Examples ```jldoctest +julia> exponent(8) +3 + +julia> exponent(64//1) +6 + julia> exponent(6.5) 2 julia> exponent(16.0) 4 + +julia> exponent(3.142e-4) +-12 ``` """ function exponent(x::T) where T<:IEEEFloat @@ -1160,7 +1171,7 @@ end n == 3 && return x*x*x # keep compatibility with literal_pow if n < 0 rx = inv(x) - n==-2 && return rx*rx #keep compatability with literal_pow + n==-2 && return rx*rx #keep compatibility with literal_pow isfinite(x) && (xnlo = -fma(x, rx, -1.) * rx) x = rx n = -n @@ -1176,8 +1187,8 @@ end xnlo += err n >>>= 1 end - !isfinite(x) && return x*y - return muladd(x, y, muladd(y, xnlo, x*ynlo)) + err = muladd(y, xnlo, x*ynlo) + return ifelse(isfinite(x) & isfinite(err), muladd(x, y, err), x*y) end function ^(x::Float32, n::Integer) diff --git a/base/methodshow.jl b/base/methodshow.jl index 9e815765dc382..4bd29f75c361d 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -11,7 +11,7 @@ function strip_gensym(sym) end function argtype_decl(env, n, @nospecialize(sig::DataType), i::Int, nargs, isva::Bool) # -> (argname, argtype) - t = sig.parameters[unwrapva(min(i, end))] + t = unwrapva(sig.parameters[min(i, end)]) if i == nargs && isva va = sig.parameters[end] if isvarargtype(va) && (!isdefined(va, :N) || !isa(va.N, Int)) @@ -247,7 +247,7 @@ function show_method(io::IO, m::Method; modulecolor = :light_black, digit_align_ end # module & file, re-using function from errorshow.jl - if get(io, :compact, false) # single-line mode + if get(io, :compact, false)::Bool # single-line mode print_module_path_file(io, m.module, string(file), line; modulecolor, digit_align_width) else println(io) @@ -268,7 +268,7 @@ function show_method_list_header(io::IO, ms::MethodList, namefmt::Function) if hasname what = (startswith(sname, '@') ? "macro" - : mt.module === Core && last(ms).sig === Tuple ? + : mt.module === Core && mt.defs isa Core.TypeMapEntry && (mt.defs.func::Method).sig === Tuple ? "builtin function" : # else "generic function") @@ -472,6 +472,8 @@ function show(io::IO, mime::MIME"text/plain", mt::AbstractVector{Method}) push!(last_shown_line_infos, (string(file), line)) end end + first && summary(io, mt) + nothing end function show(io::IO, mime::MIME"text/html", mt::AbstractVector{Method}) @@ -484,4 +486,5 @@ function show(io::IO, mime::MIME"text/html", mt::AbstractVector{Method}) end print(io, "") end + nothing end diff --git a/base/mpfr.jl b/base/mpfr.jl index 97e4535c065d2..119b0dd67b79f 100644 --- a/base/mpfr.jl +++ b/base/mpfr.jl @@ -1026,7 +1026,7 @@ string(b::BigFloat) = _string(b) print(io::IO, b::BigFloat) = print(io, string(b)) function show(io::IO, b::BigFloat) - if get(io, :compact, false) + if get(io, :compact, false)::Bool print(io, _string(b, 5)) else print(io, _string(b)) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 487be1d9b42a0..ae69b13c2f9ad 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -325,7 +325,7 @@ module IteratorsMD convert(Tuple{Vararg{UnitRange{Int}}}, R) convert(::Type{CartesianIndices{N,R}}, inds::CartesianIndices{N}) where {N,R} = - CartesianIndices(convert(R, inds.indices)) + CartesianIndices(convert(R, inds.indices))::CartesianIndices{N,R} # equality Base.:(==)(a::CartesianIndices{N}, b::CartesianIndices{N}) where N = @@ -1348,7 +1348,7 @@ end # Note: the next two functions rely on the following definition of the conversion to Bool: # convert(::Type{Bool}, x::Real) = x==0 ? false : x==1 ? true : throw(InexactError(...)) -# they're used to pre-emptively check in bulk when possible, which is much faster. +# they're used to preemptively check in bulk when possible, which is much faster. # Also, the functions can be overloaded for custom types T<:Real : # a) in the unlikely eventuality that they use a different logic for Bool conversion # b) to skip the check if not necessary diff --git a/base/namedtuple.jl b/base/namedtuple.jl index 70ebba34abe87..3e9f1272d588e 100644 --- a/base/namedtuple.jl +++ b/base/namedtuple.jl @@ -111,7 +111,8 @@ function NamedTuple{names}(nt::NamedTuple) where {names} types = Tuple{(fieldtype(nt, idx[n]) for n in 1:length(idx))...} Expr(:new, :(NamedTuple{names, $types}), Any[ :(getfield(nt, $(idx[n]))) for n in 1:length(idx) ]...) else - types = Tuple{(fieldtype(typeof(nt), names[n]) for n in 1:length(names))...} + length_names = length(names)::Integer + types = Tuple{(fieldtype(typeof(nt), names[n]) for n in 1:length_names)...} NamedTuple{names, types}(map(Fix1(getfield, nt), names)) end end @@ -148,7 +149,7 @@ convert(::Type{NamedTuple{names,T}}, nt::NamedTuple{names,T}) where {names,T<:Tu convert(::Type{NamedTuple{names}}, nt::NamedTuple{names}) where {names} = nt function convert(::Type{NamedTuple{names,T}}, nt::NamedTuple{names}) where {names,T<:Tuple} - NamedTuple{names,T}(T(nt)) + NamedTuple{names,T}(T(nt))::NamedTuple{names,T} end if nameof(@__MODULE__) === :Base @@ -318,8 +319,8 @@ values(nt::NamedTuple) = Tuple(nt) haskey(nt::NamedTuple, key::Union{Integer, Symbol}) = isdefined(nt, key) get(nt::NamedTuple, key::Union{Integer, Symbol}, default) = isdefined(nt, key) ? getfield(nt, key) : default get(f::Callable, nt::NamedTuple, key::Union{Integer, Symbol}) = isdefined(nt, key) ? getfield(nt, key) : f() -tail(t::NamedTuple{names}) where names = NamedTuple{tail(names)}(t) -front(t::NamedTuple{names}) where names = NamedTuple{front(names)}(t) +tail(t::NamedTuple{names}) where names = NamedTuple{tail(names::Tuple)}(t) +front(t::NamedTuple{names}) where names = NamedTuple{front(names::Tuple)}(t) reverse(nt::NamedTuple) = NamedTuple{reverse(keys(nt))}(reverse(values(nt))) @assume_effects :total function diff_names(an::Tuple{Vararg{Symbol}}, bn::Tuple{Vararg{Symbol}}) diff --git a/base/number.jl b/base/number.jl index f92b61d81d969..c90e2ce4a3875 100644 --- a/base/number.jl +++ b/base/number.jl @@ -4,7 +4,7 @@ # Numbers are convertible convert(::Type{T}, x::T) where {T<:Number} = x -convert(::Type{T}, x::Number) where {T<:Number} = T(x) +convert(::Type{T}, x::Number) where {T<:Number} = T(x)::T """ isinteger(x) -> Bool @@ -95,12 +95,12 @@ keys(::Number) = OneTo(1) getindex(x::Number) = x function getindex(x::Number, i::Integer) @inline - @boundscheck i == 1 || throw(BoundsError()) + @boundscheck i == 1 || throw(BoundsError(x, i)) x end function getindex(x::Number, I::Integer...) @inline - @boundscheck all(isone, I) || throw(BoundsError()) + @boundscheck all(isone, I) || throw(BoundsError(x, I)) x end get(x::Number, i::Integer, default) = isone(i) ? x : default diff --git a/base/operators.jl b/base/operators.jl index 7d68761eace3f..eb8a3a487c949 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -185,7 +185,7 @@ Not the inverse of `isless`! Test whether `x` is greater than `y`, according to a fixed total order compatible with `min`. Defined with `isless`, this function is usually `isless(y, x)`, but `NaN` and -[`missing`](@ref) are ordered as smaller than any ordinary value with `missing` +[`missing`](@ref) are ordered as smaller than any regular value with `missing` smaller than `NaN`. So `isless` defines an ascending total order with `NaN` and `missing` as the @@ -1306,7 +1306,7 @@ Some collections follow a slightly different definition. For example, use [`haskey`](@ref) or `k in keys(dict)`. For these collections, the result is always a `Bool` and never `missing`. -To determine whether an item is not in a given collection, see [`:∉`](@ref). +To determine whether an item is not in a given collection, see [`∉`](@ref). You may also negate the `in` by doing `!(a in b)` which is logically similar to "not in". When broadcasting with `in.(items, collection)` or `items .∈ collection`, both diff --git a/base/ordering.jl b/base/ordering.jl index e49102159c962..d0c9cb99f9c72 100644 --- a/base/ordering.jl +++ b/base/ordering.jl @@ -122,7 +122,7 @@ lt(o::Lt, a, b) = o.lt(a,b) @propagate_inbounds function lt(p::Perm, a::Integer, b::Integer) da = p.data[a] db = p.data[b] - lt(p.order, da, db) | (!lt(p.order, db, da) & (a < b)) + (lt(p.order, da, db)::Bool) | (!(lt(p.order, db, da)::Bool) & (a < b)) end _ord(lt::typeof(isless), by::typeof(identity), order::Ordering) = order diff --git a/base/pair.jl b/base/pair.jl index b5dffbb4e7e86..579555739ab71 100644 --- a/base/pair.jl +++ b/base/pair.jl @@ -55,7 +55,7 @@ last(p::Pair) = p.second convert(::Type{Pair{A,B}}, x::Pair{A,B}) where {A,B} = x function convert(::Type{Pair{A,B}}, x::Pair) where {A,B} - Pair{A,B}(convert(A, x[1]), convert(B, x[2])) + Pair{A,B}(convert(A, x[1]), convert(B, x[2]))::Pair{A,B} end promote_rule(::Type{Pair{A1,B1}}, ::Type{Pair{A2,B2}}) where {A1,B1,A2,B2} = diff --git a/base/permuteddimsarray.jl b/base/permuteddimsarray.jl index ea1863de8b708..a8523013434b3 100644 --- a/base/permuteddimsarray.jl +++ b/base/permuteddimsarray.jl @@ -275,11 +275,21 @@ end P end -function Base._mapreduce_dim(f, op, init::Base._InitialValue, A::PermutedDimsArray, dims::Colon) +const CommutativeOps = Union{typeof(+),typeof(Base.add_sum),typeof(min),typeof(max),typeof(Base._extrema_rf),typeof(|),typeof(&)} + +function Base._mapreduce_dim(f, op::CommutativeOps, init::Base._InitialValue, A::PermutedDimsArray, dims::Colon) + Base._mapreduce_dim(f, op, init, parent(A), dims) +end +function Base._mapreduce_dim(f::typeof(identity), op::Union{typeof(Base.mul_prod),typeof(*)}, init::Base._InitialValue, A::PermutedDimsArray{<:Union{Real,Complex}}, dims::Colon) Base._mapreduce_dim(f, op, init, parent(A), dims) end -function Base.mapreducedim!(f, op, B::AbstractArray{T,N}, A::PermutedDimsArray{T,N,perm,iperm}) where {T,N,perm,iperm} +function Base.mapreducedim!(f, op::CommutativeOps, B::AbstractArray{T,N}, A::PermutedDimsArray{S,N,perm,iperm}) where {T,S,N,perm,iperm} + C = PermutedDimsArray{T,N,iperm,perm,typeof(B)}(B) # make the inverse permutation for the output + Base.mapreducedim!(f, op, C, parent(A)) + B +end +function Base.mapreducedim!(f::typeof(identity), op::Union{typeof(Base.mul_prod),typeof(*)}, B::AbstractArray{T,N}, A::PermutedDimsArray{<:Union{Real,Complex},N,perm,iperm}) where {T,N,perm,iperm} C = PermutedDimsArray{T,N,iperm,perm,typeof(B)}(B) # make the inverse permutation for the output Base.mapreducedim!(f, op, C, parent(A)) B diff --git a/base/pointer.jl b/base/pointer.jl index 60db18f2ca855..62b34dd06d368 100644 --- a/base/pointer.jl +++ b/base/pointer.jl @@ -20,14 +20,14 @@ const C_NULL = bitcast(Ptr{Cvoid}, 0) # TODO: deprecate these conversions. C doesn't even allow them. # pointer to integer -convert(::Type{T}, x::Ptr) where {T<:Integer} = T(UInt(x)) +convert(::Type{T}, x::Ptr) where {T<:Integer} = T(UInt(x))::T # integer to pointer convert(::Type{Ptr{T}}, x::Union{Int,UInt}) where {T} = Ptr{T}(x) # pointer to pointer convert(::Type{Ptr{T}}, p::Ptr{T}) where {T} = p -convert(::Type{Ptr{T}}, p::Ptr) where {T} = bitcast(Ptr{T}, p) +convert(::Type{Ptr{T}}, p::Ptr) where {T} = bitcast(Ptr{T}, p)::Ptr{T} # object to pointer (when used with ccall) @@ -92,7 +92,8 @@ function unsafe_wrap(::Union{Type{Array},Type{Array{T}},Type{Array{T,1}}}, ccall(:jl_ptr_to_array_1d, Array{T,1}, (Any, Ptr{Cvoid}, Csize_t, Cint), Array{T,1}, p, d, own) end -unsafe_wrap(Atype::Type, p::Ptr, dims::NTuple{N,<:Integer}; own::Bool = false) where {N} = +unsafe_wrap(Atype::Union{Type{Array},Type{Array{T}},Type{Array{T,N}}}, + p::Ptr{T}, dims::NTuple{N,<:Integer}; own::Bool = false) where {T,N} = unsafe_wrap(Atype, p, convert(Tuple{Vararg{Int}}, dims), own = own) """ diff --git a/base/process.jl b/base/process.jl index 42bf6335b071c..65d06d73dff0b 100644 --- a/base/process.jl +++ b/base/process.jl @@ -430,7 +430,7 @@ function open(f::Function, cmds::AbstractCmd, args...; kwargs...) rethrow() end close(P.in) - if !eof(P.out) + if !(eof(P.out)::Bool) waitkill(P) throw(_UVError("open(do)", UV_EPIPE)) end diff --git a/base/range.jl b/base/range.jl index 4b2bf18e9f634..4765503668dd4 100644 --- a/base/range.jl +++ b/base/range.jl @@ -252,7 +252,7 @@ abstract type AbstractRange{T} <: AbstractArray{T,1} end RangeStepStyle(::Type{<:AbstractRange}) = RangeStepIrregular() RangeStepStyle(::Type{<:AbstractRange{<:Integer}}) = RangeStepRegular() -convert(::Type{T}, r::AbstractRange) where {T<:AbstractRange} = r isa T ? r : T(r) +convert(::Type{T}, r::AbstractRange) where {T<:AbstractRange} = r isa T ? r : T(r)::T ## ordinal ranges diff --git a/base/rational.jl b/base/rational.jl index 782b05e587e1b..26746ad0b4bc2 100644 --- a/base/rational.jl +++ b/base/rational.jl @@ -551,7 +551,7 @@ function hash(x::Rational{<:BitInteger64}, h::UInt) end # These methods are only needed for performance. Since `first(r)` and `last(r)` have the -# same denominator (because their difference is an integer), `length(r)` can be calulated +# same denominator (because their difference is an integer), `length(r)` can be calculated # without calling `gcd`. function length(r::AbstractUnitRange{T}) where T<:Rational @inline diff --git a/base/reduce.jl b/base/reduce.jl index 64ea4293c9893..a7f821a73be92 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -989,7 +989,7 @@ _findmin(a, ::Colon) = findmin(identity, a) """ argmax(f, domain) -Return a value `x` in the domain of `f` for which `f(x)` is maximised. +Return a value `x` from `domain` for which `f(x)` is maximised. If there are multiple maximal values for `f(x)` then the first one will be found. `domain` must be a non-empty iterable. @@ -1041,7 +1041,7 @@ argmax(itr) = findmax(itr)[2] """ argmin(f, domain) -Return a value `x` in the domain of `f` for which `f(x)` is minimised. +Return a value `x` from `domain` for which `f(x)` is minimised. If there are multiple minimal values for `f(x)` then the first one will be found. `domain` must be a non-empty iterable. diff --git a/base/reflection.jl b/base/reflection.jl index f377e7b16b571..0ed8cfdb0caf4 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -265,6 +265,11 @@ Determine whether a global is declared `const` in a given module `m`. isconst(m::Module, s::Symbol) = ccall(:jl_is_const, Cint, (Any, Any), m, s) != 0 +function isconst(g::GlobalRef) + g.binding != C_NULL && return ccall(:jl_binding_is_const, Cint, (Ptr{Cvoid},), g.binding) != 0 + return isconst(g.mod, g.name) +end + """ isconst(t::DataType, s::Union{Int,Symbol}) -> Bool @@ -547,7 +552,7 @@ end isprimitivetype(T) -> Bool Determine whether type `T` was declared as a primitive type -(i.e. using the `primitive` keyword). +(i.e. using the `primitive type` syntax). """ function isprimitivetype(@nospecialize t) @_total_meta @@ -648,7 +653,7 @@ isconcretetype(@nospecialize(t)) = (@_total_meta; isa(t, DataType) && (t.flags & isabstracttype(T) Determine whether type `T` was declared as an abstract type -(i.e. using the `abstract` keyword). +(i.e. using the `abstract type` syntax). # Examples ```jldoctest @@ -871,13 +876,13 @@ function to_tuple_type(@nospecialize(t)) t end -function signature_type(@nospecialize(f), @nospecialize(args)) - f_type = isa(f, Type) ? Type{f} : typeof(f) - if isa(args, Type) - u = unwrap_unionall(args) - return rewrap_unionall(Tuple{f_type, u.parameters...}, args) +function signature_type(@nospecialize(f), @nospecialize(argtypes)) + ft = Core.Typeof(f) + if isa(argtypes, Type) + u = unwrap_unionall(argtypes) + return rewrap_unionall(Tuple{ft, u.parameters...}, argtypes) else - return Tuple{f_type, args...} + return Tuple{ft, argtypes...} end end @@ -1221,13 +1226,7 @@ function code_typed(@nospecialize(f), @nospecialize(types=default_tt(f)); if isa(f, Core.OpaqueClosure) return code_typed_opaque_closure(f; optimize, debuginfo, interp) end - ft = Core.Typeof(f) - if isa(types, Type) - u = unwrap_unionall(types) - tt = rewrap_unionall(Tuple{ft, u.parameters...}, types) - else - tt = Tuple{ft, types...} - end + tt = signature_type(f, types) return code_typed_by_type(tt; optimize, debuginfo, world, interp) end @@ -1347,13 +1346,7 @@ function code_ircode( if isa(f, Core.OpaqueClosure) error("OpaqueClosure not supported") end - ft = Core.Typeof(f) - if isa(types, Type) - u = unwrap_unionall(types) - tt = rewrap_unionall(Tuple{ft,u.parameters...}, types) - else - tt = Tuple{ft,types...} - end + tt = signature_type(f, types) return code_ircode_by_type(tt; world, interp, optimize_until) end @@ -1402,14 +1395,19 @@ function return_types(@nospecialize(f), @nospecialize(types=default_tt(f)); return Any[rt] end types = to_tuple_type(types) - rt = [] + if isa(f, Core.Builtin) + argtypes = Any[types.parameters...] + rt = Core.Compiler.builtin_tfunction(interp, f, argtypes, nothing) + return Any[rt] + end + rts = [] for match in _methods(f, types, -1, world)::Vector match = match::Core.MethodMatch meth = func_for_method_checked(match.method, types, match.sparams) ty = Core.Compiler.typeinf_type(interp, meth, match.spec_types, match.sparams) - push!(rt, something(ty, Any)) + push!(rts, something(ty, Any)) end - return rt + return rts end function infer_effects(@nospecialize(f), @nospecialize(types=default_tt(f)); @@ -1420,23 +1418,28 @@ function infer_effects(@nospecialize(f), @nospecialize(types=default_tt(f)); if isa(f, Core.Builtin) argtypes = Any[types.parameters...] rt = Core.Compiler.builtin_tfunction(interp, f, argtypes, nothing) - return Core.Compiler.builtin_effects(f, argtypes, rt) - else - effects = Core.Compiler.EFFECTS_TOTAL - matches = _methods(f, types, -1, world)::Vector - if isempty(matches) - # this call is known to throw MethodError - return Core.Compiler.Effects(effects; nothrow=false) - end - for match in matches - match = match::Core.MethodMatch - frame = Core.Compiler.typeinf_frame(interp, - match.method, match.spec_types, match.sparams, #=run_optimizer=#false) - frame === nothing && return Core.Compiler.Effects() - effects = Core.Compiler.merge_effects(effects, frame.ipo_effects) - end - return effects + return Core.Compiler.builtin_effects(Core.Compiler.typeinf_lattice(interp), f, argtypes, rt) + end + tt = signature_type(f, types) + result = Core.Compiler.findall(tt, Core.Compiler.method_table(interp)) + if result === missing + # unanalyzable call, return the unknown effects + return Core.Compiler.Effects() + end + (; matches) = result + effects = Core.Compiler.EFFECTS_TOTAL + if matches.ambig || !any(match::Core.MethodMatch->match.fully_covers, matches.matches) + # account for the fact that we may encounter a MethodError with a non-covered or ambiguous signature. + effects = Core.Compiler.Effects(effects; nothrow=false) + end + for match in matches.matches + match = match::Core.MethodMatch + frame = Core.Compiler.typeinf_frame(interp, + match.method, match.spec_types, match.sparams, #=run_optimizer=#false) + frame === nothing && return Core.Compiler.Effects() + effects = Core.Compiler.merge_effects(effects, frame.ipo_effects) end + return effects end """ diff --git a/base/refpointer.jl b/base/refpointer.jl index cd179c87b30d5..290ffc51cbf2a 100644 --- a/base/refpointer.jl +++ b/base/refpointer.jl @@ -101,7 +101,7 @@ IteratorSize(::Type{<:Ref}) = HasShape{0}() unsafe_convert(::Type{Ref{T}}, x::Ref{T}) where {T} = unsafe_convert(Ptr{T}, x) unsafe_convert(::Type{Ref{T}}, x) where {T} = unsafe_convert(Ptr{T}, x) -convert(::Type{Ref{T}}, x) where {T} = RefValue{T}(x) +convert(::Type{Ref{T}}, x) where {T} = RefValue{T}(x)::RefValue{T} ### Methods for a Ref object that is backed by an array at index i struct RefArray{T,A<:AbstractArray{T},R} <: Ref{T} diff --git a/base/set.jl b/base/set.jl index 3b5635ccb5a33..c1c9cc91d29c1 100644 --- a/base/set.jl +++ b/base/set.jl @@ -548,7 +548,7 @@ function hash(s::AbstractSet, h::UInt) end convert(::Type{T}, s::T) where {T<:AbstractSet} = s -convert(::Type{T}, s::AbstractSet) where {T<:AbstractSet} = T(s) +convert(::Type{T}, s::AbstractSet) where {T<:AbstractSet} = T(s)::T ## replace/replace! ## diff --git a/base/show.jl b/base/show.jl index 6f17fe6ee2ef6..1e281fbd6d6d1 100644 --- a/base/show.jl +++ b/base/show.jl @@ -1,8 +1,10 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +using Core.Compiler: has_typevar + function show(io::IO, ::MIME"text/plain", u::UndefInitializer) show(io, u) - get(io, :compact, false) && return + get(io, :compact, false)::Bool && return print(io, ": array initializer with undefined values") end @@ -22,7 +24,7 @@ function show(io::IO, ::MIME"text/plain", r::LinRange) end function show(io::IO, ::MIME"text/plain", f::Function) - get(io, :compact, false) && return show(io, f) + get(io, :compact, false)::Bool && return show(io, f) ft = typeof(f) mt = ft.name.mt if isa(f, Core.IntrinsicFunction) @@ -48,59 +50,66 @@ show(io::IO, ::MIME"text/plain", c::ComposedFunction) = show(io, c) show(io::IO, ::MIME"text/plain", c::Returns) = show(io, c) show(io::IO, ::MIME"text/plain", s::Splat) = show(io, s) -const ansi_regex = r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])" -# An iterator similar to `pairs` but skips over "tokens" corresponding to -# ansi sequences -struct IgnoreAnsiIterator - captures::Base.RegexMatchIterator +const ansi_regex = r"(?s)(?:\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~]))|." + +# Pseudo-character representing an ANSI delimiter +struct ANSIDelimiter + del::SubString{String} end -IgnoreAnsiIterator(s::AbstractString) = - IgnoreAnsiIterator(eachmatch(ansi_regex, s)) +ncodeunits(c::ANSIDelimiter) = ncodeunits(c.del) +textwidth(::ANSIDelimiter) = 0 -Base.IteratorSize(::Type{IgnoreAnsiIterator}) = Base.SizeUnknown() -function iterate(I::IgnoreAnsiIterator, (i, m_st)=(1, iterate(I.captures))) - # Advance until the next non ansi sequence - if m_st !== nothing - m, j = m_st - if m.offset == i - i += sizeof(m.match) - return iterate(I, (i, iterate(I.captures, j))) - end - end - ci = iterate(I.captures.string, i) - ci === nothing && return nothing - i_prev = i - (c, i) = ci - return (i_prev => c), (i, m_st) +# An iterator similar to `pairs(::String)` but whose values are Char or ANSIDelimiter +struct ANSIIterator + captures::RegexMatchIterator end +ANSIIterator(s::AbstractString) = ANSIIterator(eachmatch(ansi_regex, s)) -function _truncate_at_width_or_chars(ignore_ansi::Bool, str, width, chars="", truncmark="…") +IteratorSize(::Type{ANSIIterator}) = SizeUnknown() +eltype(::Type{ANSIIterator}) = Pair{Int, Union{Char,ANSIDelimiter}} +function iterate(I::ANSIIterator, (i, m_st)=(1, iterate(I.captures))) + m_st === nothing && return nothing + m, (j, new_m_st) = m_st + c = lastindex(m.match) == 1 ? only(m.match) : ANSIDelimiter(m.match) + return (i => c, (j, iterate(I.captures, (j, new_m_st)))) +end +textwidth(I::ANSIIterator) = mapreduce(textwidth∘last, +, I; init=0) + +function _truncate_at_width_or_chars(ignore_ANSI::Bool, str, width, rpad=false, chars="\r\n", truncmark="…") truncwidth = textwidth(truncmark) (width <= 0 || width < truncwidth) && return "" wid = truncidx = lastidx = 0 - ignore_ansi &= match(ansi_regex, str) !== nothing - I = ignore_ansi ? IgnoreAnsiIterator(str) : pairs(str) - for (_lastidx, c) in I - lastidx = _lastidx - wid += textwidth(c) - if wid >= (width - truncwidth) && truncidx == 0 - truncidx = lastidx - end - (wid >= width || c in chars) && break - end - if lastidx != 0 && str[lastidx] in chars - lastidx = prevind(str, lastidx) - end + # if str needs to be truncated, truncidx is the index of truncation. + stop = false # once set, only ANSI delimiters will be kept as new characters. + needANSIend = false # set if the last ANSI delimiter before truncidx is not "\033[0m". + I = ignore_ANSI ? ANSIIterator(str) : pairs(str) + for (i, c) in I + if c isa ANSIDelimiter + truncidx == 0 && (needANSIend = c != "\033[0m") + lastidx = i + ncodeunits(c) - 1 + else + stop && break + wid += textwidth(c) + truncidx == 0 && wid > (width - truncwidth) && (truncidx = lastidx) + lastidx = i + c in chars && break + stop = wid >= width + end + end + lastidx == 0 && return rpad ? ' '^width : "" + str[lastidx] in chars && (lastidx = prevind(str, lastidx)) + ANSIend = needANSIend ? "\033[0m" : "" + pad = rpad ? repeat(' ', max(0, width-wid)) : "" truncidx == 0 && (truncidx = lastidx) if lastidx < lastindex(str) - return String(SubString(str, 1, truncidx) * truncmark) + return string(SubString(str, 1, truncidx), ANSIend, truncmark, pad) else - return String(str) + return string(str, ANSIend, pad) end end function show(io::IO, ::MIME"text/plain", iter::Union{KeySet,ValueIterator}) - isempty(iter) && get(io, :compact, false) && return show(io, iter) + isempty(iter) && get(io, :compact, false)::Bool && return show(io, iter) summary(io, iter) isempty(iter) && return print(io, ". ", isa(iter,KeySet) ? "Keys" : "Values", ":") @@ -122,7 +131,7 @@ function show(io::IO, ::MIME"text/plain", iter::Union{KeySet,ValueIterator}) if limit str = sprint(show, v, context=io, sizehint=0) - str = _truncate_at_width_or_chars(get(io, :color, false), str, cols, "\r\n") + str = _truncate_at_width_or_chars(get(io, :color, false)::Bool, str, cols) print(io, str) else show(io, v) @@ -154,19 +163,20 @@ function show(io::IO, ::MIME"text/plain", t::AbstractDict{K,V}) where {K,V} rows -= 1 # Subtract the summary # determine max key width to align the output, caching the strings + hascolor = get(recur_io, :color, false) ks = Vector{String}(undef, min(rows, length(t))) vs = Vector{String}(undef, min(rows, length(t))) - keylen = 0 - vallen = 0 + keywidth = 0 + valwidth = 0 for (i, (k, v)) in enumerate(t) i > rows && break ks[i] = sprint(show, k, context=recur_io_k, sizehint=0) vs[i] = sprint(show, v, context=recur_io_v, sizehint=0) - keylen = clamp(length(ks[i]), keylen, cols) - vallen = clamp(length(vs[i]), vallen, cols) + keywidth = clamp(hascolor ? textwidth(ANSIIterator(ks[i])) : textwidth(ks[i]), keywidth, cols) + valwidth = clamp(hascolor ? textwidth(ANSIIterator(vs[i])) : textwidth(vs[i]), valwidth, cols) end - if keylen > max(div(cols, 2), cols - vallen) - keylen = max(cld(cols, 3), cols - vallen) + if keywidth > max(div(cols, 2), cols - valwidth) + keywidth = max(cld(cols, 3), cols - valwidth) end else rows = cols = typemax(Int) @@ -175,12 +185,12 @@ function show(io::IO, ::MIME"text/plain", t::AbstractDict{K,V}) where {K,V} for (i, (k, v)) in enumerate(t) print(io, "\n ") if i == rows < length(t) - print(io, rpad("⋮", keylen), " => ⋮") + print(io, rpad("⋮", keywidth), " => ⋮") break end if limit - key = rpad(_truncate_at_width_or_chars(get(recur_io, :color, false), ks[i], keylen, "\r\n"), keylen) + key = _truncate_at_width_or_chars(hascolor, ks[i], keywidth, true) else key = sprint(show, k, context=recur_io_k, sizehint=0) end @@ -188,7 +198,7 @@ function show(io::IO, ::MIME"text/plain", t::AbstractDict{K,V}) where {K,V} print(io, " => ") if limit - val = _truncate_at_width_or_chars(get(recur_io, :color, false), vs[i], cols - keylen, "\r\n") + val = _truncate_at_width_or_chars(hascolor, vs[i], cols - keywidth) print(io, val) else show(recur_io_v, v) @@ -232,7 +242,7 @@ function show(io::IO, ::MIME"text/plain", t::AbstractSet{T}) where T if limit str = sprint(show, v, context=recur_io, sizehint=0) - print(io, _truncate_at_width_or_chars(get(io, :color, false), str, cols, "\r\n")) + print(io, _truncate_at_width_or_chars(get(io, :color, false)::Bool, str, cols)) else show(recur_io, v) end @@ -293,7 +303,7 @@ function IOContext(io::IO, dict::ImmutableDict) IOContext{typeof(io0)}(io0, dict) end -convert(::Type{IOContext}, io::IO) = IOContext(unwrapcontext(io)...) +convert(::Type{IOContext}, io::IO) = IOContext(unwrapcontext(io)...)::IOContext IOContext(io::IO) = convert(IOContext, io) @@ -424,9 +434,10 @@ Julia code when possible. [`repr`](@ref) returns the output of `show` as a string. -To customize human-readable text output for objects of type `T`, define -`show(io::IO, ::MIME"text/plain", ::T)` instead. Checking the `:compact` -[`IOContext`](@ref) property of `io` in such methods is recommended, +For a more verbose human-readable text output for objects of type `T`, define +`show(io::IO, ::MIME"text/plain", ::T)` in addition. Checking the `:compact` +[`IOContext`](@ref) key (often checked as `get(io, :compact, false)::Bool`) +of `io` in such methods is recommended, since some containers show their elements by calling this method with `:compact => true`. @@ -485,7 +496,7 @@ end function active_module() isassigned(REPL_MODULE_REF) || return Main REPL = REPL_MODULE_REF[] - return REPL.active_module()::Module + return invokelatest(REPL.active_module)::Module end # Check if a particular symbol is exported from a standard library module @@ -545,8 +556,6 @@ function print_without_params(@nospecialize(x)) return isa(b, DataType) && b.name.wrapper === x end -has_typevar(@nospecialize(t), v::TypeVar) = ccall(:jl_has_typevar, Cint, (Any, Any), t, v)!=0 - function io_has_tvar_name(io::IOContext, name::Symbol, @nospecialize(x)) for (key, val) in io.dict if key === :unionall_env && val isa TypeVar && val.name === name && has_typevar(x, val) @@ -607,7 +616,7 @@ function make_typealias(@nospecialize(x::Type)) env = env::SimpleVector # TODO: In some cases (such as the following), the `env` is over-approximated. # We'd like to disable `fix_inferred_var_bound` since we'll already do that fix-up here. - # (or detect and reverse the compution of it here). + # (or detect and reverse the computation of it here). # T = Array{Array{T,1}, 1} where T # (ti, env) = ccall(:jl_type_intersection_with_env, Any, (Any, Any), T, Vector) # env[1].ub.var == T.var @@ -943,13 +952,13 @@ function _show_type(io::IO, @nospecialize(x::Type)) if print_without_params(x) show_type_name(io, (unwrap_unionall(x)::DataType).name) return - elseif get(io, :compact, true) && show_typealias(io, x) + elseif get(io, :compact, true)::Bool && show_typealias(io, x) return elseif x isa DataType show_datatype(io, x) return elseif x isa Union - if get(io, :compact, true) && show_unionaliases(io, x) + if get(io, :compact, true)::Bool && show_unionaliases(io, x) return end print(io, "Union") @@ -1162,7 +1171,7 @@ function show(io::IO, p::Pair) isdelimited(io_i, p[i]) || print(io, "(") show(io_i, p[i]) isdelimited(io_i, p[i]) || print(io, ")") - i == 1 && print(io, get(io, :compact, false) ? "=>" : " => ") + i == 1 && print(io, get(io, :compact, false)::Bool ? "=>" : " => ") end end @@ -1562,7 +1571,7 @@ unquoted(ex::Expr) = ex.args[1] function printstyled end function with_output_color end -emphasize(io, str::AbstractString, col = Base.error_color()) = get(io, :color, false) ? +emphasize(io, str::AbstractString, col = Base.error_color()) = get(io, :color, false)::Bool ? printstyled(io, str; color=col, bold=true) : print(io, uppercase(str)) @@ -1686,7 +1695,14 @@ end ## AST printing ## -show_unquoted(io::IO, val::SSAValue, ::Int, ::Int) = print(io, "%", val.id) +function show_unquoted(io::IO, val::SSAValue, ::Int, ::Int) + if get(io, :maxssaid, typemax(Int))::Int < val.id + # invalid SSAValue, print this in red for better recognition + printstyled(io, "%", val.id; color=:red) + else + print(io, "%", val.id) + end +end show_unquoted(io::IO, sym::Symbol, ::Int, ::Int) = show_sym(io, sym, allow_macroname=false) show_unquoted(io::IO, ex::LineNumberNode, ::Int, ::Int) = show_linenumber(io, ex.line, ex.file) show_unquoted(io::IO, ex::GotoNode, ::Int, ::Int) = print(io, "goto %", ex.label) @@ -1823,9 +1839,10 @@ function allow_macroname(ex) end end -function is_core_macro(arg, macro_name::AbstractString) - arg === GlobalRef(Core, Symbol(macro_name)) +function is_core_macro(arg::GlobalRef, macro_name::AbstractString) + arg == GlobalRef(Core, Symbol(macro_name)) end +is_core_macro(@nospecialize(arg), macro_name::AbstractString) = false # symbol for IOContext flag signaling whether "begin" is treated # as an ordinary symbol, which is true in indexing expressions. @@ -2705,7 +2722,7 @@ function dump(io::IOContext, x::Array, n::Int, indent) println(io) recur_io = IOContext(io, :SHOWN_SET => x) lx = length(x) - if get(io, :limit, false) + if get(io, :limit, false)::Bool dump_elts(recur_io, x, n, indent, 1, (lx <= 10 ? lx : 5)) if lx > 10 println(io) diff --git a/base/some.jl b/base/some.jl index 8dc726e5c0022..e09a926ab931b 100644 --- a/base/some.jl +++ b/base/some.jl @@ -35,7 +35,7 @@ end convert(::Type{T}, x::T) where {T>:Nothing} = x convert(::Type{T}, x) where {T>:Nothing} = convert(nonnothingtype_checked(T), x) convert(::Type{Some{T}}, x::Some{T}) where {T} = x -convert(::Type{Some{T}}, x::Some) where {T} = Some{T}(convert(T, x.value)) +convert(::Type{Some{T}}, x::Some) where {T} = Some{T}(convert(T, x.value))::Some{T} function show(io::IO, x::Some) if get(io, :typeinfo, Any) == typeof(x) diff --git a/base/sort.jl b/base/sort.jl index 8a3d2e2871cfe..d668424a641b0 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -333,6 +333,8 @@ Return the index of the first value in `a` greater than or equal to `x`, accordi specified order. Return `lastindex(a) + 1` if `x` is greater than all values in `a`. `a` is assumed to be sorted. +`insert!`ing `x` at this index will maintain sorted order. + See also: [`searchsortedlast`](@ref), [`searchsorted`](@ref), [`findfirst`](@ref). # Examples @@ -514,12 +516,13 @@ const SMALL_ALGORITHM = InsertionSort const SMALL_THRESHOLD = 20 function sort!(v::AbstractVector, lo::Integer, hi::Integer, ::InsertionSortAlg, o::Ordering) - @inbounds for i = lo+1:hi + lo_plus_1 = (lo + 1)::Integer + @inbounds for i = lo_plus_1:hi j = i x = v[i] while j > lo y = v[j-1] - if !lt(o, x, y) + if !(lt(o, x, y)::Bool) break end v[j] = y diff --git a/base/special/log.jl b/base/special/log.jl index d868071818a18..5e20cdbaa06a6 100644 --- a/base/special/log.jl +++ b/base/special/log.jl @@ -556,7 +556,7 @@ const t_log_table_compact = ( end # Log implementation that returns 2 numbers which sum to give true value with about 68 bits of precision -# Since `log` only makes sense for positive exponents, we speed up the implimentation by stealing the sign bit +# Since `log` only makes sense for positive exponents, we speed up the implementation by stealing the sign bit # of the input for an extra bit of the exponent which is used to normalize subnormal inputs. # Does not normalize results. # Adapted and modified from https://github.com/ARM-software/optimized-routines/blob/master/math/pow.c @@ -575,7 +575,7 @@ function _log_ext(xu) t, logctail = getfield(t_log_table_compact, Int(i+1)) invc, logc = log_tab_unpack(t) # Note: invc is j/N or j/N/2 where j is an integer in [N,2N) and - # |z/c - 1| < 1/N, so r = z/c - 1 is exactly representible. + # |z/c - 1| < 1/N, so r = z/c - 1 is exactly representable. r = fma(z, invc, -1.0) # k*Ln2 + log(c) + r. t1 = muladd(k, 0.6931471805598903, logc) #ln(2) hi part diff --git a/base/special/trig.jl b/base/special/trig.jl index e3033aab6c272..817d073d0cc48 100644 --- a/base/special/trig.jl +++ b/base/special/trig.jl @@ -255,7 +255,7 @@ end # # Note: tan(y+z) = tan(y) + tan'(y)*z # ~ tan(y) + (1+y*y)*z - # Therefore, for better accuracz in computing tan(y+z), let + # Therefore, for better accuracy in computing tan(y+z), let # 3 2 2 2 2 # r = y *(T2+y *(T3+y *(...+y *(T12+y *T13)))) # then diff --git a/base/stream.jl b/base/stream.jl index 6c81f5f44ea6a..0d8676885fa0c 100644 --- a/base/stream.jl +++ b/base/stream.jl @@ -1361,7 +1361,7 @@ julia> io1 = open("same/path", "w") julia> io2 = open("same/path", "w") -julia> redirect_stdio(f, stdout=io1, stderr=io2) # not suppored +julia> redirect_stdio(f, stdout=io1, stderr=io2) # not supported ``` Also the `stdin` argument may not be the same descriptor as `stdout` or `stderr`. ```julia-repl diff --git a/base/strings/basic.jl b/base/strings/basic.jl index 306ecc5cc214a..db4409cc3a5dd 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -229,7 +229,7 @@ Symbol(s::AbstractString) = Symbol(String(s)) Symbol(x...) = Symbol(string(x...)) convert(::Type{T}, s::T) where {T<:AbstractString} = s -convert(::Type{T}, s::AbstractString) where {T<:AbstractString} = T(s) +convert(::Type{T}, s::AbstractString) where {T<:AbstractString} = T(s)::T ## summary ## diff --git a/base/strings/io.jl b/base/strings/io.jl index d1bf7a763e93c..e800002076d54 100644 --- a/base/strings/io.jl +++ b/base/strings/io.jl @@ -201,7 +201,7 @@ function show( ) # compute limit in default case if limit === nothing - get(io, :limit, false) || return show(io, str) + get(io, :limit, false)::Bool || return show(io, str) limit = max(20, displaysize(io)[2]) # one line in collection, seven otherwise get(io, :typeinfo, nothing) === nothing && (limit *= 7) diff --git a/base/strings/string.jl b/base/strings/string.jl index e44746f9834d9..3d8db74d7b795 100644 --- a/base/strings/string.jl +++ b/base/strings/string.jl @@ -17,10 +17,12 @@ function Base.showerror(io::IO, exc::StringIndexError) if firstindex(s) <= exc.index <= ncodeunits(s) iprev = thisind(s, exc.index) inext = nextind(s, iprev) + escprev = escape_string(s[iprev:iprev]) if inext <= ncodeunits(s) - print(io, ", valid nearby indices [$iprev]=>'$(s[iprev])', [$inext]=>'$(s[inext])'") + escnext = escape_string(s[inext:inext]) + print(io, ", valid nearby indices [$iprev]=>'$escprev', [$inext]=>'$escnext'") else - print(io, ", valid nearby index [$iprev]=>'$(s[iprev])'") + print(io, ", valid nearby index [$iprev]=>'$escprev'") end end end diff --git a/base/strings/strings.jl b/base/strings/strings.jl index 07e43674fed97..d995d8535e24b 100644 --- a/base/strings/strings.jl +++ b/base/strings/strings.jl @@ -6,5 +6,7 @@ include("strings/unicode.jl") import .Unicode: textwidth, islowercase, isuppercase, isletter, isdigit, isnumeric, iscntrl, ispunct, isspace, isprint, isxdigit, lowercase, uppercase, titlecase, lowercasefirst, uppercasefirst +import .Iterators: PartitionIterator + include("strings/util.jl") include("strings/io.jl") diff --git a/base/strings/substring.jl b/base/strings/substring.jl index b8a0de1948326..baaea038b2cfe 100644 --- a/base/strings/substring.jl +++ b/base/strings/substring.jl @@ -55,13 +55,13 @@ SubString{T}(s::T) where {T<:AbstractString} = SubString{T}(s, 1, lastindex(s):: @propagate_inbounds maybeview(s::AbstractString, args...) = getindex(s, args...) convert(::Type{SubString{S}}, s::AbstractString) where {S<:AbstractString} = - SubString(convert(S, s)) + SubString(convert(S, s))::SubString{S} convert(::Type{T}, s::T) where {T<:SubString} = s # Regex match allows only Union{String, SubString{String}} so define conversion to this type convert(::Type{Union{String, SubString{String}}}, s::String) = s convert(::Type{Union{String, SubString{String}}}, s::SubString{String}) = s -convert(::Type{Union{String, SubString{String}}}, s::AbstractString) = convert(String, s) +convert(::Type{Union{String, SubString{String}}}, s::AbstractString) = convert(String, s)::String function String(s::SubString{String}) parent = s.string diff --git a/base/strings/unicode.jl b/base/strings/unicode.jl index 36af24bda857b..821e186501d1d 100644 --- a/base/strings/unicode.jl +++ b/base/strings/unicode.jl @@ -468,7 +468,7 @@ A character is classified as numeric if it belongs to the Unicode general catego i.e. a character whose category code begins with 'N'. Note that this broad category includes characters such as ¾ and ௰. -Use [`isdigit`](@ref) to check whether a character a decimal digit between 0 and 9. +Use [`isdigit`](@ref) to check whether a character is a decimal digit between 0 and 9. # Examples ```jldoctest diff --git a/base/strings/util.jl b/base/strings/util.jl index bfc361e92d16f..3cb98054d8ede 100644 --- a/base/strings/util.jl +++ b/base/strings/util.jl @@ -530,7 +530,7 @@ function iterate(iter::SplitIterator, (i, k, n)=(firstindex(iter.str), firstinde r = findnext(iter.splitter, iter.str, k)::Union{Nothing,Int,UnitRange{Int}} while r !== nothing && n != iter.limit - 1 && first(r) <= ncodeunits(iter.str) j, k = first(r), nextind(iter.str, last(r))::Int - k_ = k <= j ? nextind(iter.str, j) : k + k_ = k <= j ? nextind(iter.str, j)::Int : k if i < k substr = @inbounds SubString(iter.str, i, prevind(iter.str, j)::Int) (iter.keepempty || i < j) && return (substr, (k, k_, n + 1)) @@ -543,6 +543,15 @@ function iterate(iter::SplitIterator, (i, k, n)=(firstindex(iter.str), firstinde @inbounds SubString(iter.str, i), (ncodeunits(iter.str) + 2, k, n + 1) end +# Specialization for partition(s,n) to return a SubString +eltype(::Type{PartitionIterator{T}}) where {T<:AbstractString} = SubString{T} + +function iterate(itr::PartitionIterator{<:AbstractString}, state = firstindex(itr.c)) + state > ncodeunits(itr.c) && return nothing + r = min(nextind(itr.c, state, itr.n - 1), lastindex(itr.c)) + return SubString(itr.c, state, r), nextind(itr.c, r) +end + eachsplit(str::T, splitter; limit::Integer=0, keepempty::Bool=true) where {T<:AbstractString} = SplitIterator(str, splitter, limit, keepempty) diff --git a/base/sysinfo.jl b/base/sysinfo.jl index f0852f32fc17d..62241457f8954 100644 --- a/base/sysinfo.jl +++ b/base/sysinfo.jl @@ -20,6 +20,8 @@ export BINDIR, loadavg, free_memory, total_memory, + physical_free_memory, + physical_total_memory, isapple, isbsd, isdragonfly, @@ -246,19 +248,44 @@ function loadavg() return loadavg_ end +""" + Sys.free_physical_memory() + +Get the free memory of the system in bytes. The entire amount may not be available to the +current process; use `Sys.free_memory()` for the actually available amount. +""" +free_physical_memory() = ccall(:uv_get_free_memory, UInt64, ()) + +""" + Sys.total_physical_memory() + +Get the total memory in RAM (including that which is currently used) in bytes. The entire +amount may not be available to the current process; see `Sys.total_memory()`. +""" +total_physical_memory() = ccall(:uv_get_total_memory, UInt64, ()) + """ Sys.free_memory() Get the total free memory in RAM in bytes. """ -free_memory() = ccall(:uv_get_free_memory, UInt64, ()) +free_memory() = ccall(:uv_get_available_memory, UInt64, ()) """ Sys.total_memory() Get the total memory in RAM (including that which is currently used) in bytes. +This amount may be constrained, e.g., by Linux control groups. For the unconstrained +amount, see `Sys.physical_memory()`. """ -total_memory() = ccall(:uv_get_total_memory, UInt64, ()) +function total_memory() + memory = ccall(:uv_get_constrained_memory, UInt64, ()) + if memory == 0 + return total_physical_memory() + else + return memory + end +end """ Sys.get_process_title() diff --git a/base/task.jl b/base/task.jl index 5601fea70a112..1a9bff051d7c7 100644 --- a/base/task.jl +++ b/base/task.jl @@ -452,9 +452,22 @@ const sync_varname = gensym(:sync) """ @sync -Wait until all lexically-enclosed uses of `@async`, `@spawn`, `@spawnat` and `@distributed` +Wait until all lexically-enclosed uses of [`@async`](@ref), [`@spawn`](@ref Threads.@spawn), `@spawnat` and `@distributed` are complete. All exceptions thrown by enclosed async operations are collected and thrown as -a `CompositeException`. +a [`CompositeException`](@ref). + +# Examples +```julia-repl +julia> Threads.nthreads() +4 + +julia> @sync begin + Threads.@spawn println("Thread-id \$(Threads.threadid()), task 1") + Threads.@spawn println("Thread-id \$(Threads.threadid()), task 2") + end; +Thread-id 3, task 1 +Thread-id 1, task 2 +``` """ macro sync(block) var = esc(sync_varname) @@ -545,6 +558,14 @@ end errormonitor(t::Task) Print an error log to `stderr` if task `t` fails. + +# Examples +```julia-repl +julia> Base._wait(errormonitor(Threads.@spawn error("task failed"))) +Unhandled Task ERROR: task failed +Stacktrace: +[...] +``` """ function errormonitor(t::Task) t2 = Task() do diff --git a/base/threadingconstructs.jl b/base/threadingconstructs.jl index 0852fafe192ec..6c8ea35cfa373 100644 --- a/base/threadingconstructs.jl +++ b/base/threadingconstructs.jl @@ -199,7 +199,7 @@ microseconds). `:static` scheduler creates one task per thread and divides the iterations equally among them, assigning each task specifically to each thread. In particular, the value of -[`threadid()`](@ref Threads.threadid) is guranteed to be constant within one iteration. +[`threadid()`](@ref Threads.threadid) is guaranteed to be constant within one iteration. Specifying `:static` is an error if used from inside another `@threads` loop or from a thread other than 1. diff --git a/base/toml_parser.jl b/base/toml_parser.jl index 323f954cf8b11..d9579e17ce990 100644 --- a/base/toml_parser.jl +++ b/base/toml_parser.jl @@ -326,7 +326,7 @@ function Base.showerror(io::IO, err::ParserError) str1, err1 = point_to_line(err.str::String, pos, pos, io) @static if VERSION <= v"1.6.0-DEV.121" # See https://github.com/JuliaLang/julia/issues/36015 - format_fixer = get(io, :color, false) == true ? "\e[0m" : "" + format_fixer = get(io, :color, false)::Bool == true ? "\e[0m" : "" println(io, "$format_fixer ", str1) print(io, "$format_fixer ", err1) else diff --git a/base/twiceprecision.jl b/base/twiceprecision.jl index a8611b21052b5..edbce928f527c 100644 --- a/base/twiceprecision.jl +++ b/base/twiceprecision.jl @@ -164,7 +164,7 @@ div12(x, y) = div12(promote(x, y)...) A number with twice the precision of `T`, e.g., quad-precision if `T = Float64`. -!!! warn +!!! warning `TwicePrecision` is an internal type used to increase the precision of floating-point ranges, and not intended for external use. If you encounter them in real code, the most likely explanation is @@ -268,10 +268,10 @@ TwicePrecision{T}(x::Number) where {T} = TwicePrecision{T}(T(x), zero(T)) convert(::Type{TwicePrecision{T}}, x::TwicePrecision{T}) where {T} = x convert(::Type{TwicePrecision{T}}, x::TwicePrecision) where {T} = - TwicePrecision{T}(convert(T, x.hi), convert(T, x.lo)) + TwicePrecision{T}(convert(T, x.hi), convert(T, x.lo))::TwicePrecision{T} -convert(::Type{T}, x::TwicePrecision) where {T<:Number} = T(x) -convert(::Type{TwicePrecision{T}}, x::Number) where {T} = TwicePrecision{T}(x) +convert(::Type{T}, x::TwicePrecision) where {T<:Number} = T(x)::T +convert(::Type{TwicePrecision{T}}, x::Number) where {T} = TwicePrecision{T}(x)::TwicePrecision{T} float(x::TwicePrecision{<:AbstractFloat}) = x float(x::TwicePrecision) = TwicePrecision(float(x.hi), float(x.lo)) diff --git a/base/util.jl b/base/util.jl index b824fe1c351dc..f26ed0717a1fd 100644 --- a/base/util.jl +++ b/base/util.jl @@ -119,7 +119,7 @@ or an integer between 0 and 255 inclusive. Note that not all terminals support 2 Keywords `bold=true`, `underline=true`, `blink=true` are self-explanatory. Keyword `reverse=true` prints with foreground and background colors exchanged, -and `hidden=true` should be invisibe in the terminal but can still be copied. +and `hidden=true` should be invisible in the terminal but can still be copied. These properties can be used in any combination. See also [`print`](@ref), [`println`](@ref), [`show`](@ref). @@ -251,9 +251,10 @@ unsafe_securezero!(p::Ptr{Cvoid}, len::Integer=1) = Ptr{Cvoid}(unsafe_securezero Display a message and wait for the user to input a secret, returning an `IO` object containing the secret. -Note that on Windows, the secret might be displayed as it is typed; see -`Base.winprompt` for securely retrieving username/password pairs from a -graphical interface. +!!! info "Windows" + Note that on Windows, the secret might be displayed as it is typed; see + `Base.winprompt` for securely retrieving username/password pairs from a + graphical interface. """ function getpass end @@ -347,7 +348,7 @@ Displays the `message` then waits for user input. Input is terminated when a new is encountered or EOF (^D) character is entered on a blank line. If a `default` is provided then the user can enter just a newline character to select the `default`. -See also `Base.getpass` and `Base.winprompt` for secure entry of passwords. +See also `Base.winprompt` (for Windows) and `Base.getpass` for secure entry of passwords. # Example @@ -506,9 +507,12 @@ order to function correctly with the keyword outer constructor. `Base.@kwdef` for parametric structs, and structs with supertypes requires at least Julia 1.1. +!!! compat "Julia 1.9" + This macro is exported as of Julia 1.9. + # Examples ```jldoctest -julia> Base.@kwdef struct Foo +julia> @kwdef struct Foo a::Int = 1 # specified default b::String # required keyword end diff --git a/base/version.jl b/base/version.jl index 978abbba1a8aa..67377c86a8493 100644 --- a/base/version.jl +++ b/base/version.jl @@ -289,7 +289,7 @@ function banner(io::IO = stdout) commit_date = isempty(Base.GIT_VERSION_INFO.date_string) ? "" : " ($(split(Base.GIT_VERSION_INFO.date_string)[1]))" - if get(io, :color, false) + if get(io, :color, false)::Bool c = text_colors tx = c[:normal] # text jl = c[:normal] # julia diff --git a/cli/Makefile b/cli/Makefile index e5298a8da7619..274877ecaf12a 100644 --- a/cli/Makefile +++ b/cli/Makefile @@ -28,6 +28,14 @@ endif # Build list of dependent libraries that must be opened SHIPFLAGS += -DDEP_LIBS="\"$(LOADER_BUILD_DEP_LIBS)\"" DEBUGFLAGS += -DDEP_LIBS="\"$(LOADER_DEBUG_BUILD_DEP_LIBS)\"" +ifneq (,$(findstring MINGW,$(shell uname))) +# In MSYS2, do not perform path conversion for `DEP_LIBS`. +# https://www.msys2.org/wiki/Porting/#filesystem-namespaces +# We define this environment variable for only these two object files, +# as they're the only ones that require it at the time of writing. +$(BUILDDIR)/loader_lib.o: export MSYS2_ARG_CONV_EXCL = -DDEP_LIBS= +$(BUILDDIR)/loader_lib.dbg.obj: export MSYS2_ARG_CONV_EXCL = -DDEP_LIBS= +endif # MSYS2 EXE_OBJS := $(BUILDDIR)/loader_exe.o EXE_DOBJS := $(BUILDDIR)/loader_exe.dbg.obj diff --git a/cli/loader.h b/cli/loader.h index 2d0b977f7142f..0620113048efe 100644 --- a/cli/loader.h +++ b/cli/loader.h @@ -22,8 +22,6 @@ #define realloc loader_realloc #endif -#include - #ifdef _OS_WINDOWS_ #define WIN32_LEAN_AND_MEAN @@ -49,6 +47,8 @@ #endif +#include + // Borrow definition from `support/dtypes.h` #ifdef _OS_WINDOWS_ # ifdef LIBRARY_EXPORTS diff --git a/deps/blastrampoline.mk b/deps/blastrampoline.mk index 2e9a14cd6b7be..bd1cb65c6ae2d 100644 --- a/deps/blastrampoline.mk +++ b/deps/blastrampoline.mk @@ -6,16 +6,25 @@ BLASTRAMPOLINE_GIT_URL := https://github.com/JuliaLinearAlgebra/libblastrampolin BLASTRAMPOLINE_TAR_URL = https://api.github.com/repos/JuliaLinearAlgebra/libblastrampoline/tarball/$1 $(eval $(call git-external,blastrampoline,BLASTRAMPOLINE,,,$(BUILDDIR))) +BLASTRAMPOLINE_BUILD_OPTS := $(MAKE_COMMON) CC="$(CC) $(SANITIZE_OPTS)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" +BLASTRAMPOLINE_BUILD_OPTS += ARCH="$(ARCH)" OS="$(OS)" + $(BUILDDIR)/$(BLASTRAMPOLINE_SRC_DIR)/build-configured: $(BUILDDIR)/$(BLASTRAMPOLINE_SRC_DIR)/source-extracted mkdir -p $(dir $@) echo 1 > $@ +BLASTRAMPOLINE_BUILD_ROOT := $(BUILDDIR)/$(BLASTRAMPOLINE_SRC_DIR)/src $(BUILDDIR)/$(BLASTRAMPOLINE_SRC_DIR)/build-compiled: $(BUILDDIR)/$(BLASTRAMPOLINE_SRC_DIR)/build-configured - cd $(dir $@)/src && $(MAKE) $(MAKE_COMMON) CC="$(CC) $(SANITIZE_OPTS)" + cd $(dir $@)/src && $(MAKE) $(BLASTRAMPOLINE_BUILD_OPTS) +ifeq ($(OS), WINNT) + # Windows doesn't like soft link, use hard link + cd $(BLASTRAMPOLINE_BUILD_ROOT)/build/ && \ + cp -f --dereference --link libblastrampoline.dll libblastrampoline.dll +endif echo 1 > $@ define BLASTRAMPOLINE_INSTALL - $(MAKE) -C $(BUILDDIR)/$(BLASTRAMPOLINE_SRC_DIR)/src $(MAKE_COMMON) install DESTDIR="$2" + $(MAKE) -C $(BLASTRAMPOLINE_BUILD_ROOT) install $(BLASTRAMPOLINE_BUILD_OPTS) DESTDIR="$2" endef $(eval $(call staged-install, \ blastrampoline,$(BLASTRAMPOLINE_SRC_DIR), \ @@ -23,6 +32,11 @@ $(eval $(call staged-install, \ $$(BLASTRAMPOLINE_OBJ_TARGET), \ $$(INSTALL_NAME_CMD)libblastrampoline.$$(SHLIB_EXT) $$(build_shlibdir)/libblastrampoline.$$(SHLIB_EXT))) +clean-blastrampoline: + -$(MAKE) -C $(BLASTRAMPOLINE_BUILD_ROOT) clean + -$(RM) $(BUILDDIR)/$(BLASTRAMPOLINE_SRC_DIR)/build-compiled \ + $(BUILDDIR)/$(BLASTRAMPOLINE_SRC_DIR)/build-configured + get-blastrampoline: $(BLASTRAMPOLINE_SRC_FILE) extract-blastrampoline: $(BUILDDIR)/$(BLASTRAMPOLINE_SRC_DIR)/source-extracted configure-blastrampoline: extract-blastrampoline diff --git a/deps/checksums/NetworkOptions-4d3df6445bbca0556a7a9f2abb0e48ba7d774f5a.tar.gz/md5 b/deps/checksums/NetworkOptions-4d3df6445bbca0556a7a9f2abb0e48ba7d774f5a.tar.gz/md5 deleted file mode 100644 index f1a62f3d38760..0000000000000 --- a/deps/checksums/NetworkOptions-4d3df6445bbca0556a7a9f2abb0e48ba7d774f5a.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -47be3a2c46e5279714bcb7837127c08a diff --git a/deps/checksums/NetworkOptions-4d3df6445bbca0556a7a9f2abb0e48ba7d774f5a.tar.gz/sha512 b/deps/checksums/NetworkOptions-4d3df6445bbca0556a7a9f2abb0e48ba7d774f5a.tar.gz/sha512 deleted file mode 100644 index 27b5e2397013c..0000000000000 --- a/deps/checksums/NetworkOptions-4d3df6445bbca0556a7a9f2abb0e48ba7d774f5a.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -df45c5fa22619da686481b78de76b60573c798c14a9bbf3a9dd449f52ffca1f2b8dd3b247e2a7679d3dd55ba115787f3734cf03d29a10eba8fecdd78890891b5 diff --git a/deps/checksums/NetworkOptions-8ce1e104eeddcf9c7ccb387dc4811ddb1c750cc2.tar.gz/md5 b/deps/checksums/NetworkOptions-8ce1e104eeddcf9c7ccb387dc4811ddb1c750cc2.tar.gz/md5 new file mode 100644 index 0000000000000..4f4a11a34cbb5 --- /dev/null +++ b/deps/checksums/NetworkOptions-8ce1e104eeddcf9c7ccb387dc4811ddb1c750cc2.tar.gz/md5 @@ -0,0 +1 @@ +a86ceac14b0ddc0dace2a5b30c3c0e2a diff --git a/deps/checksums/NetworkOptions-8ce1e104eeddcf9c7ccb387dc4811ddb1c750cc2.tar.gz/sha512 b/deps/checksums/NetworkOptions-8ce1e104eeddcf9c7ccb387dc4811ddb1c750cc2.tar.gz/sha512 new file mode 100644 index 0000000000000..3fb8797a10eb8 --- /dev/null +++ b/deps/checksums/NetworkOptions-8ce1e104eeddcf9c7ccb387dc4811ddb1c750cc2.tar.gz/sha512 @@ -0,0 +1 @@ +0554193fbad941b0b9f88a3fced366c4b066207023736f628f6623266de113a546aa883b9fe1c46cd1d7cf64ad2e7992471c1b76e3894aa401c27227828dcaa3 diff --git a/deps/checksums/Pkg-3cbbd860afd4c2a50a80a04fa229fe5cd5bddc76.tar.gz/md5 b/deps/checksums/Pkg-3cbbd860afd4c2a50a80a04fa229fe5cd5bddc76.tar.gz/md5 new file mode 100644 index 0000000000000..8480935cba812 --- /dev/null +++ b/deps/checksums/Pkg-3cbbd860afd4c2a50a80a04fa229fe5cd5bddc76.tar.gz/md5 @@ -0,0 +1 @@ +f164cc7c322b2bd3f9a1ed49882d9a8c diff --git a/deps/checksums/Pkg-3cbbd860afd4c2a50a80a04fa229fe5cd5bddc76.tar.gz/sha512 b/deps/checksums/Pkg-3cbbd860afd4c2a50a80a04fa229fe5cd5bddc76.tar.gz/sha512 new file mode 100644 index 0000000000000..2f3164077b8a9 --- /dev/null +++ b/deps/checksums/Pkg-3cbbd860afd4c2a50a80a04fa229fe5cd5bddc76.tar.gz/sha512 @@ -0,0 +1 @@ +5d1d8acfed6e432033473f083860cdbefafcc0f0b8d8aa99fa445288a3064ca72da8fc4dfa1a3459347e1d512adba252bc5d468305fa4a74e4e8f25ae0628c87 diff --git a/deps/checksums/Pkg-8d77a6cac48113d143e028209aa28f10d5473032.tar.gz/md5 b/deps/checksums/Pkg-8d77a6cac48113d143e028209aa28f10d5473032.tar.gz/md5 deleted file mode 100644 index ea7ad31ce7035..0000000000000 --- a/deps/checksums/Pkg-8d77a6cac48113d143e028209aa28f10d5473032.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -9e337aa579ec47017d7b5ef2df3bcd02 diff --git a/deps/checksums/Pkg-8d77a6cac48113d143e028209aa28f10d5473032.tar.gz/sha512 b/deps/checksums/Pkg-8d77a6cac48113d143e028209aa28f10d5473032.tar.gz/sha512 deleted file mode 100644 index 3ef1b9730fa60..0000000000000 --- a/deps/checksums/Pkg-8d77a6cac48113d143e028209aa28f10d5473032.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -99e67b045691f8d9c16680e77014a33a507250377c037a7cf23e5dc2f0294c771a834e6d14f6a3a19a8def0ebb61a6fde17a4f3c1284cab0f4d7b5ea8c128d5d diff --git a/deps/checksums/SparseArrays-78e48c331d18212b01dd23f7be18cae13425a16f.tar.gz/md5 b/deps/checksums/SparseArrays-78e48c331d18212b01dd23f7be18cae13425a16f.tar.gz/md5 deleted file mode 100644 index 30e0cd2db7a80..0000000000000 --- a/deps/checksums/SparseArrays-78e48c331d18212b01dd23f7be18cae13425a16f.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -2ff42077f542a76b66b0de44ed4377df diff --git a/deps/checksums/SparseArrays-78e48c331d18212b01dd23f7be18cae13425a16f.tar.gz/sha512 b/deps/checksums/SparseArrays-78e48c331d18212b01dd23f7be18cae13425a16f.tar.gz/sha512 deleted file mode 100644 index 01985555d4916..0000000000000 --- a/deps/checksums/SparseArrays-78e48c331d18212b01dd23f7be18cae13425a16f.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -2d1ca7bfbd8949279a795ff0ff5444d80425d5850961c5937f9c90f9ed94fd15ff76b1f727d9bd0a6f32379ddba2341e9d7433a85aab6c31638fd4ece41c6e58 diff --git a/deps/checksums/SparseArrays-91814c1e84421a9c43b2776fc9dc96ec25104ac8.tar.gz/md5 b/deps/checksums/SparseArrays-91814c1e84421a9c43b2776fc9dc96ec25104ac8.tar.gz/md5 new file mode 100644 index 0000000000000..470e121636cd1 --- /dev/null +++ b/deps/checksums/SparseArrays-91814c1e84421a9c43b2776fc9dc96ec25104ac8.tar.gz/md5 @@ -0,0 +1 @@ +da78690de5f015cad4419b2c68e8b242 diff --git a/deps/checksums/SparseArrays-91814c1e84421a9c43b2776fc9dc96ec25104ac8.tar.gz/sha512 b/deps/checksums/SparseArrays-91814c1e84421a9c43b2776fc9dc96ec25104ac8.tar.gz/sha512 new file mode 100644 index 0000000000000..72a6bf1ce9731 --- /dev/null +++ b/deps/checksums/SparseArrays-91814c1e84421a9c43b2776fc9dc96ec25104ac8.tar.gz/sha512 @@ -0,0 +1 @@ +c4045aeaef8094644a36b6d1f80fa62de33146f90bf18e23369a7234752d39fbdf5822c556cf81242109031b08ab6f5354facc5ede3f45215e68cc10421abf42 diff --git a/deps/checksums/Tar-56062695b92920c8b75e997fb0c8c3b015d04b78.tar.gz/md5 b/deps/checksums/Tar-56062695b92920c8b75e997fb0c8c3b015d04b78.tar.gz/md5 deleted file mode 100644 index 3be44f2d90718..0000000000000 --- a/deps/checksums/Tar-56062695b92920c8b75e997fb0c8c3b015d04b78.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -2e6f1656df70500842c4de4d0f941f89 diff --git a/deps/checksums/Tar-56062695b92920c8b75e997fb0c8c3b015d04b78.tar.gz/sha512 b/deps/checksums/Tar-56062695b92920c8b75e997fb0c8c3b015d04b78.tar.gz/sha512 deleted file mode 100644 index 7c1626b841ee0..0000000000000 --- a/deps/checksums/Tar-56062695b92920c8b75e997fb0c8c3b015d04b78.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -2d2ed113bb9e9469b29a680172d1ab06b2ad8e0574788c3eb16467e621b9127c6159afbddd1014694d46bf9945cfcecbe8cbc315448e0a06fe14b45a4b10ae83 diff --git a/deps/checksums/Tar-5914ef9b542b3689287d4bc322320ad9e8d40feb.tar.gz/md5 b/deps/checksums/Tar-5914ef9b542b3689287d4bc322320ad9e8d40feb.tar.gz/md5 new file mode 100644 index 0000000000000..432d96f5d7a6b --- /dev/null +++ b/deps/checksums/Tar-5914ef9b542b3689287d4bc322320ad9e8d40feb.tar.gz/md5 @@ -0,0 +1 @@ +18a90ef71dcf89846ed536c044352ccc diff --git a/deps/checksums/Tar-5914ef9b542b3689287d4bc322320ad9e8d40feb.tar.gz/sha512 b/deps/checksums/Tar-5914ef9b542b3689287d4bc322320ad9e8d40feb.tar.gz/sha512 new file mode 100644 index 0000000000000..5b1577d1b3275 --- /dev/null +++ b/deps/checksums/Tar-5914ef9b542b3689287d4bc322320ad9e8d40feb.tar.gz/sha512 @@ -0,0 +1 @@ +a3d6773b32aa492d5c0f160d70983b27dc99b354fa54044702c203d1f0c0e96751f9aadf9e1c32c6f5af55cf07fa8e1df26b4a7ad1f744b673dad8c137db7e2d diff --git a/deps/checksums/clang b/deps/checksums/clang index 3b9c1210d73f1..3cb8e59b6791a 100644 --- a/deps/checksums/clang +++ b/deps/checksums/clang @@ -1,116 +1,116 @@ -Clang.v14.0.5+3.aarch64-apple-darwin-llvm_version+14.asserts.tar.gz/md5/6b348a17486a0341ce5d29b46676ffe9 -Clang.v14.0.5+3.aarch64-apple-darwin-llvm_version+14.asserts.tar.gz/sha512/0a136ee170831c5c8f94b817560e62cb6e74cc45bdff25628249adce6e9c92554348fbfad5a015b0bccd7d455d6cfa96205529c5557d9a9918b5937246f91c80 -Clang.v14.0.5+3.aarch64-apple-darwin-llvm_version+14.tar.gz/md5/6cb40666812420e480be0e852d0afcd1 -Clang.v14.0.5+3.aarch64-apple-darwin-llvm_version+14.tar.gz/sha512/e9371fe5d4b74301d56f90910d996571ad40f9fd4c516a1153d171b0b7195ea4483700f37a0ed5dce8e4a134ead82017b19caf7f0283dbb832667ea465e70a60 -Clang.v14.0.5+3.aarch64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/c39b5813f31efde2643a2f1fcfff0712 -Clang.v14.0.5+3.aarch64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/921a18a32b2d816b0a7fa64df603a2d6ac4dd7eef38be1a6251e521869cce44637a8df79f2f20064a60135e7b648cc9be72f49e1ed09a7b104149e97adebf398 -Clang.v14.0.5+3.aarch64-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/ff04b2f629fbfe52c0bfcf1c01c1e899 -Clang.v14.0.5+3.aarch64-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/9038dadfbc21973c12ecbb2ae87598bf7c288b2c663f2d46395a481e66d76f2b892ac0b322d2b303e779d0350732aa62782401b340b95ff5581af578af1bd938 -Clang.v14.0.5+3.aarch64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/efd9661ceffd24d140ce673e273541db -Clang.v14.0.5+3.aarch64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/df0d28e126d4a9a635ca036ffd4379f6d6025a5e59e684f7889510655436ec66b335bb6bb5b57a62eef418443a27404ea2a904e366b591bcd155128b743ff958 -Clang.v14.0.5+3.aarch64-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/30ac4ddab7485ef3d4e9a16972273c00 -Clang.v14.0.5+3.aarch64-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/f24d6d8c9af0b383004170f831c14ca3e3c2b10d5622d195723c058254cae6711b24b849cda001887ec9e984a66cc72facac032456c3302f6dc681f79607e2e9 -Clang.v14.0.5+3.aarch64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/dd663eebde360c4f9ce38b5379549582 -Clang.v14.0.5+3.aarch64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/3ab857dfac603bddaa430a8210dc16f05d8a3e4a9cdd72ebd007c995fa3380eec0b5e9421372b1fd17dcd438ef283ad7583e006a28b99f693d2028e5f7701c90 -Clang.v14.0.5+3.aarch64-linux-musl-cxx03-llvm_version+14.tar.gz/md5/0b5d792aa94c2a33688a5c5ed71f790d -Clang.v14.0.5+3.aarch64-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/e450a439c065322c3320a1a11eadf9e607139ae813e75e6b3f775016b8f24eb61d6beeef4f6d0ec55aa5b5ec5eb217ca38b2c18c0ca274030c7834024de82b14 -Clang.v14.0.5+3.aarch64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/c81da32893f11dc7ff9e955fa7631bcc -Clang.v14.0.5+3.aarch64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/c016f7c29206f3faeabb2d3e18433f8b994e3040c41ab221628e5c26dc64d5068ef7100ecc035bae821718ded60ac628dd92d968d67e957ae01cc7129ff8e47b -Clang.v14.0.5+3.aarch64-linux-musl-cxx11-llvm_version+14.tar.gz/md5/51b94d2d6ae77d7bc09e9660f469e61f -Clang.v14.0.5+3.aarch64-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/fcf9b4dfac45999ad342100e76a9da4eb25e7cdddff1bba8871522300679d74fc033421cac3e2d86347cd78252fc03f7fecff86f1d9d9e673ee88e58b9ef53e2 -Clang.v14.0.5+3.armv6l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/65d16924c1ac4f5a4193b4c4df19015a -Clang.v14.0.5+3.armv6l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/fae2b3f4268f167124d359c3eb18c5686859e50e9b438b583ce89c3e9d3db43143479c6d39bd1e66789d06d964d91d11d4970ee7f28655e644b2cecbf40722c4 -Clang.v14.0.5+3.armv6l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/md5/81816305c782f9af31bab7119af32950 -Clang.v14.0.5+3.armv6l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/sha512/4c0fe2d65d0943e9cc5402a386665037c5c0feb6152389c9910d96ebe64fa14f8d5d92a96066783ef782210ffa8c411dcf62b521067c33a3a34ad49a22c75ddb -Clang.v14.0.5+3.armv6l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/23a56e77348f0ae60149ffdc8a983d85 -Clang.v14.0.5+3.armv6l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/b0cc6d1acbf202cec1ce09b00d45894020f735e655740511af8c19eca78e2121130c9026192b2b54bf4c68f01db9548fd9f6905a62196d09668513776dd074ff -Clang.v14.0.5+3.armv6l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/md5/3a5ffdc6c2e6dd0d9d88af425993acea -Clang.v14.0.5+3.armv6l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/sha512/f031b1d65472d388280a58dd7ecc75e65de73b1d324dc03c3521a3ada64f87f53d9c54816132468c996139b7043c762eb38999e6adb84d880be479065adab1d4 -Clang.v14.0.5+3.armv6l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/12525f36fbc291df84db549e4daf385f -Clang.v14.0.5+3.armv6l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/bd693fd7cd61df4c3af3ae37e3765cf1fca2e1bcc7c7e3e72497baed8a671d77c7d0bf9d9279d336ed7321b80b16a2a2bf976078aa023d4abba2a46c1d2cec37 -Clang.v14.0.5+3.armv6l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/md5/96307b773837849115b6cc399a832767 -Clang.v14.0.5+3.armv6l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/sha512/684e45564f8fa7539249607b9b8ec63adc21e06678933e0aacf891729ccf449face0abb9c897c6076d1f262ba5f9b784048258342336ef93c89bdf0fa480a656 -Clang.v14.0.5+3.armv6l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/c2824237dd39ad3163fbdc58250a42e7 -Clang.v14.0.5+3.armv6l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/eacb660fdfe4127607f6fc867bbb09b30182ac6d0d0ef7258b0ceccdfc3199a0ae5c1b61192346adbf9956f751a6f0181ecc42cf0945d366c03c625c957b5f99 -Clang.v14.0.5+3.armv6l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/md5/24f878973b45178ebbeb09ceca56e96f -Clang.v14.0.5+3.armv6l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/sha512/d1daeddccc5ffcbb869778171d5ac87e30793e04bbae0bc25c3ce41ca16e1b2161f1cc98e15b81a6cdee4fbf5433f02c698628e8a7401b3ce36982e798b62f36 -Clang.v14.0.5+3.armv7l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/9945e9b6104a402df030f3412bc642e0 -Clang.v14.0.5+3.armv7l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/c1b9764908bc61fd6ea9a17db70388d1cc0c0f75797ce1be8d07a24784cfedde8553b5dc5606d5c395e3385da5afa0abb607cca0a7deeed8eb6ff5818e8edfe2 -Clang.v14.0.5+3.armv7l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/md5/1a6f00390e04a56cb89f7f1afb9abba6 -Clang.v14.0.5+3.armv7l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/sha512/e9e4bec30cd77cfba29b9258ddfa5994d312750b901a91fca0fbfc6bc66f3c4df19cb609149755306c650dc4f3c815cd44dbb83db5ef61fb0d2fc31c6fcf27e8 -Clang.v14.0.5+3.armv7l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/a2ac0220a521ab80718b2cfbc2d35d4c -Clang.v14.0.5+3.armv7l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/f618c040d5fd18efff280e4da6a8fcb343732cb6beff93f868a7735c4b88fb38ed6b6f09aac598db876aacd1f1e5379d134d30e604e0af1c37aaac29f8b725a3 -Clang.v14.0.5+3.armv7l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/md5/25dfb136ef52be7f1147dcedfb622b96 -Clang.v14.0.5+3.armv7l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/sha512/2d291b8100a17b992bd88963bf211d61948f13130af868ce63da08f6c224e9f2f4b5aca69ed212f4b8795d830d1e03562997f57bb1dfa13e23e8c606e63a5b05 -Clang.v14.0.5+3.armv7l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/fbd4ddda6f632de4af29d765b2ee91f0 -Clang.v14.0.5+3.armv7l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/83a6038e248b3639a5f9b5621d269103f2baeef86ba32c47787e9c8125e04af9e573653f3ff870856c7bc71afc30ec7598b6d6e503d0994b8a2d6597802a4a72 -Clang.v14.0.5+3.armv7l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/md5/6b94bc6e9dab2a70dcd7282cc39ad191 -Clang.v14.0.5+3.armv7l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/sha512/14fdccdc50bab738cae3b62084726e49124616c16b8281103ee50c362270ef63014bf8d3254c9baa555397425fd26ff567013104c3adfa6e2448c7de5ee0b2e3 -Clang.v14.0.5+3.armv7l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/1fe19241bd62b9ecfdf4334b9ed4e2fc -Clang.v14.0.5+3.armv7l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/cfe7e01f1eabdc978107ba72b5624321d64e73a5464591db22926cc277d0c1834ac1720e9aee14c262c2e9627fb7c34541d62fef6ec9af68f094fce603f1b394 -Clang.v14.0.5+3.armv7l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/md5/5389b937980be57c27437a3f2f900d56 -Clang.v14.0.5+3.armv7l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/sha512/d30ff5ed29a74a2253910c103819784bccfed0e0b49d0ab5aef77dabf71e4a217500619980d875b9160bdab82d90163000107b4757add76fa662c97badf9f966 -Clang.v14.0.5+3.i686-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/8419b95dc44b7ad5f751eda96952e5e9 -Clang.v14.0.5+3.i686-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/1807c96d89d680cb311149085623e8469454ac56a2610e97f47dd1429dadb06de19ea02918796a1c35ffbeb921b23d2d4465dc6deaa5f7e26e763d4afdd55581 -Clang.v14.0.5+3.i686-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/8860012f4b975b3848df84e08a5500e3 -Clang.v14.0.5+3.i686-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/f1f4cdad2b72494d8bf4223a4aa7da8f4e2942f0796f31cbe2676e58066c645a4ba8fb23f89929712866c899f438d803a6b92c523f4de992512de33b344e0646 -Clang.v14.0.5+3.i686-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/051bfaa5ceae32ea086bd2c72e09719c -Clang.v14.0.5+3.i686-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/3f8b92120cc14aac086da4bd8c2a77efa20884180a2864243144498173ea8076b3104588586dc5d7b563863e7a7390c0ac8ef57978a6c7a823ecff40d9da95db -Clang.v14.0.5+3.i686-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/9f16f0dae9e3dc41db7a46e20ed3f79a -Clang.v14.0.5+3.i686-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/e8378d2c55920479599c13ce7620a16b48c46d81c94dfd343d046aabd0e704a8c8a1945ad796127964b975591168bbbeb01dd32a261835f6eb085d902031fb03 -Clang.v14.0.5+3.i686-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/f8f86030559207fcf8c90d163e62fa18 -Clang.v14.0.5+3.i686-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/451beee73d75f768a85df3de916c919354bf2d014351fa29b1e59cadec847db73db98b1d37c6ba3e3066df0774b00dfde260702b2cb3ecc27dec32dda4e93783 -Clang.v14.0.5+3.i686-linux-musl-cxx03-llvm_version+14.tar.gz/md5/2bb39ac53b8391ab94cc9c868333d29f -Clang.v14.0.5+3.i686-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/888237c27ae9279186241797f100a3cfc240f3b38259f6d289fa1e991516d8633c81c16147788668a9cc2eac6135e4a7b4f2159a7ff7387bb871e7f8217f0404 -Clang.v14.0.5+3.i686-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/a4b047860c7a1fb8a257dd91b2c87656 -Clang.v14.0.5+3.i686-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/05685415eb7a2b862a5124935315c91b438a4ae0bd73b9d06cbf2f03b72a98f25008fff1cc2fa36c89c367993ea222354331b1dd347f0e4d272f5d0f2af83677 -Clang.v14.0.5+3.i686-linux-musl-cxx11-llvm_version+14.tar.gz/md5/8a98cb86849be3f2ad297f869dc53561 -Clang.v14.0.5+3.i686-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/5357f852a417ea6ecb2427fb337c37d721720e00e07e22ad1f7fc7fec2e62688165dc70220f031ec642758ccd27942527388ff5141ee245dcae895870b34d420 -Clang.v14.0.5+3.i686-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/md5/eb10067716599b5917923f90f7a888eb -Clang.v14.0.5+3.i686-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/sha512/83ca40047b329208c93ee274a7c3c0db73642b8a09004f085393a613651f3503028fdd036163c68b572dec47031e7a1b28d9fefae5d37cc5561fba1941acb303 -Clang.v14.0.5+3.i686-w64-mingw32-cxx03-llvm_version+14.tar.gz/md5/545673dc4cfb337e56329117821e3717 -Clang.v14.0.5+3.i686-w64-mingw32-cxx03-llvm_version+14.tar.gz/sha512/55121566bd6ab6b83f4c3313b220e7d9ce56a63107fff8165070a7e41f41527f0ad536c53a114a88139d356de4f2b52cfbfe57b9995b90da3fd9edfd1c264ade -Clang.v14.0.5+3.i686-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/md5/3d11d3939a04a0a0c7b90ae2822ceabe -Clang.v14.0.5+3.i686-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/sha512/9a88fc418fadb960b3de4401685a1650a56f1b2e46e227b43a193d2b9679abe2f7bd5278f8975e62f48e9aa9d6d042843b78c97bef75d7960d8098d55eb53653 -Clang.v14.0.5+3.i686-w64-mingw32-cxx11-llvm_version+14.tar.gz/md5/058442685a6b3c429ebd0b6b9a2742e0 -Clang.v14.0.5+3.i686-w64-mingw32-cxx11-llvm_version+14.tar.gz/sha512/df8ae6cfae9d4cdb6a9e0abf173c2b8e568e10d37dd909fbb810a39dfa5ac44df22c1951f93f0a850dbc68ca83a9fbff0ec2589dcabf76ab71ab9623b12ef818 -Clang.v14.0.5+3.powerpc64le-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/cff98d9d2260a25237c92ad577457bbe -Clang.v14.0.5+3.powerpc64le-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/2d31b8636d21f0f000961d9c34d41ff175054786b4641819c058c3d221816be8256750fa3191a4e6e1533b76d5e11fc491e43f3dc974228ae1cfceb3fb08123c -Clang.v14.0.5+3.powerpc64le-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/3eb63cb369d56d5c8d280f30c841c892 -Clang.v14.0.5+3.powerpc64le-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/902194f729e17ac8dae4c5d57d39e58d7e59730b3ba98bf6724875b032a63731f657440268a5dff94c5c7384ef15dc2e39e0778d7b84d8dbbea51a2920050a15 -Clang.v14.0.5+3.powerpc64le-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/aa66e3089b7d0647039645c12beaced5 -Clang.v14.0.5+3.powerpc64le-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/f2d4b6f7fc7b58dbb7684139650ead99fe46e1e5034fba3323e96f12f5dff1956fc195a47120317b641bc04c02e9649a56fcf43d45e456bc1404c4274fd96631 -Clang.v14.0.5+3.powerpc64le-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/7bc16298c40c0a9b114972c6610480de -Clang.v14.0.5+3.powerpc64le-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/6901d2d397890e2519c3cc56f937b221341e3eec6c9ecfecac975ac7d06222fd6a2574e301eca8fb863ec956f77f8b0c0e95e389fd1c1c6d07056023cbe22fca -Clang.v14.0.5+3.x86_64-apple-darwin-llvm_version+14.asserts.tar.gz/md5/be6bcea66978ace05e009bfe1d590ee6 -Clang.v14.0.5+3.x86_64-apple-darwin-llvm_version+14.asserts.tar.gz/sha512/1cba06ceb02d20d8e19b388ae5c90bf136bb5095cdcae1b27c0c960d2b549aa05b64e59f3d004e380d1891d874eb4dc9d6a425a43ef50a6b57f0839234b79bbb -Clang.v14.0.5+3.x86_64-apple-darwin-llvm_version+14.tar.gz/md5/99b330190daa88537ed35958ec8c4f99 -Clang.v14.0.5+3.x86_64-apple-darwin-llvm_version+14.tar.gz/sha512/1f7d9c49f5478e7a3aec8286b7aa1f6077d5629b5370d4277cdd6f80b7ea577236ff43fe24f293a72e14641a84dad5a9ad63192169b7c28ade2adcd7a765664d -Clang.v14.0.5+3.x86_64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/350edd25403a292f2b6eca1f91f5b52b -Clang.v14.0.5+3.x86_64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/bbd8f8624b59e673b676a1fd102975a1aec91043ef6ec6ccedf28aee871463eca4d83e806734cbbab2b447f85e17c9b86e15ca6c8bd55bafa50f36d4bbc69a6a -Clang.v14.0.5+3.x86_64-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/f22125e4a1ba212fe08562a29b3cbb7d -Clang.v14.0.5+3.x86_64-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/90241eed7c38360ab408e6a78be99816d388994ffb066544647e0f457295d5ac2031513cce0dc1ec69f95a5779c3850184e0d7e15cf8ba38ec9252d4164aabad -Clang.v14.0.5+3.x86_64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/067ad4d5aefdf1e9e89df440b1fbb051 -Clang.v14.0.5+3.x86_64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/ae06851a5228ed4fec4cf5dc66f5cebb230e2c7c8fb3fa81d543f2a08c52d506349fad51d79ae66182f0aab68278cb7cb3109a267ffdf7e110dce51aced4a0ef -Clang.v14.0.5+3.x86_64-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/971aaea160fce64d68d32c37ae6fd863 -Clang.v14.0.5+3.x86_64-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/01e19e7308e6a50bf35fda31c04dc1fb4a8934ebbb6a269931b5ace4880ec1b6aaa4cc5bf122b0cb18ce30e6fc8581cabfa287a3d3e9eb528cb36aa12fb6ce08 -Clang.v14.0.5+3.x86_64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/320b165946061b8564d6aa31b40715ad -Clang.v14.0.5+3.x86_64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/603889c6dd5ffc5deec75c0f9c48f495453f48e27e9e2c7ad8c434c36c4ed2f8b0a831735dc1c99ec0617386b066c79309c4166e56c65d1ce9408c0b6987fc36 -Clang.v14.0.5+3.x86_64-linux-musl-cxx03-llvm_version+14.tar.gz/md5/5cc0f317469cd86392702d57f1768ae3 -Clang.v14.0.5+3.x86_64-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/1abe71a898caf744aaffd1c4562f650af7aae3d91b3c0f337de73e921fa63ba5d03b2910bf135752dca63e11bfcefcee32526d359b9e4e9dcda968e6fe3c8efd -Clang.v14.0.5+3.x86_64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/5b7f51888a61c29747e89b2622f26818 -Clang.v14.0.5+3.x86_64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/074b97f2905f055b6aab61e545417efc42fd1be925693c777b2368c7b7ccc0ad618fb5388c719c7c70c9ffacd94f299874c4b394323d1a40dc2177cef4037f81 -Clang.v14.0.5+3.x86_64-linux-musl-cxx11-llvm_version+14.tar.gz/md5/6db48866b5edce638a863724b4b15eef -Clang.v14.0.5+3.x86_64-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/472f90471616add503bb5ebd51090e5f0c590b1b32e5d2131fd2335793a85211ca17cc4b43f765348e64effc81c346abebb9e495b0486651a56e490acf0dd82a -Clang.v14.0.5+3.x86_64-unknown-freebsd-llvm_version+14.asserts.tar.gz/md5/22b547e88104604c404dfd81c619bbd9 -Clang.v14.0.5+3.x86_64-unknown-freebsd-llvm_version+14.asserts.tar.gz/sha512/48fbc5fdefbb1c8810f5ef990ea469e87f8393b30bbc88063a8c8d54d4203d1b121617d96aab03080d978ca02537ce0585941cbc72d4e7dd24ecedf455588c1b -Clang.v14.0.5+3.x86_64-unknown-freebsd-llvm_version+14.tar.gz/md5/863aa1416d79961eda02bb3dfd104651 -Clang.v14.0.5+3.x86_64-unknown-freebsd-llvm_version+14.tar.gz/sha512/052863f2ce7a994d32b6cec7dcbe2c0f0d22293a2d423cfd254686ec056fa0c25095777a6c572443fcece8b664808da5f545e3c9426f7a39ab9c62f3b63b943e -Clang.v14.0.5+3.x86_64-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/md5/6bfb96ff317c27ef402d3148adcd6d61 -Clang.v14.0.5+3.x86_64-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/sha512/84d7ed38825e5d758d0220ba1ef24c57489415dbee0ad4f8474ce2dcea1cce28b621ad87890558fc620bbf60ef56e513cf682f2776a590ed48511ac9af9e01ba -Clang.v14.0.5+3.x86_64-w64-mingw32-cxx03-llvm_version+14.tar.gz/md5/6b9a1896ccc89f0d5cfd53f6585bc685 -Clang.v14.0.5+3.x86_64-w64-mingw32-cxx03-llvm_version+14.tar.gz/sha512/882f3aa3635498890c3722b57127530d731e93ea488861f2aaabd32c00ed99a68ce8b113a6e671d9b0f54dbcfacfb291dd6c862ff2cac4208b25e855db2a15af -Clang.v14.0.5+3.x86_64-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/md5/cd5c163a984f82c91e8563da7dc2433f -Clang.v14.0.5+3.x86_64-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/sha512/9e14e95a3e7442362b4e71c8d9c04408cf05f0b6ea2f7cb10ca0f006d8f4bea432f1e398205ea59fc18db7a7fd7af588e45a9c6a49f48d982b0cd5d3fb80fcfd -Clang.v14.0.5+3.x86_64-w64-mingw32-cxx11-llvm_version+14.tar.gz/md5/a9e07a08622f6a515a015ca80299646d -Clang.v14.0.5+3.x86_64-w64-mingw32-cxx11-llvm_version+14.tar.gz/sha512/cb2be324c2da4f75dae7431520455e1dfd1ca3c0d63470131e2bd569d646302615be2bebb6326022d9edbc77c282f605886f9429802c9671cce6bc45f4e25c91 +Clang.v14.0.6+0.aarch64-apple-darwin-llvm_version+14.asserts.tar.gz/md5/298e05bc189e33877b76a7a6c9ed9478 +Clang.v14.0.6+0.aarch64-apple-darwin-llvm_version+14.asserts.tar.gz/sha512/c460899d649982b6cc6c79ccfdebdc98257f7077e2f2f04597f86f3be98f2643400258035614ff7d434639c5861671ca1410945662d00ba1be8f3a887e2e0f59 +Clang.v14.0.6+0.aarch64-apple-darwin-llvm_version+14.tar.gz/md5/7189c71fa493fa40253a7b0644869c55 +Clang.v14.0.6+0.aarch64-apple-darwin-llvm_version+14.tar.gz/sha512/5bca9174562f8f1388321e501c9ae36389a7b07a112bddac3c25184b535dc5324b8c7c56f40c5b6a31772dcc87c411054d6817d9348e2d38375887c339426bdd +Clang.v14.0.6+0.aarch64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/a170c242afd649b37bfe17196baa1455 +Clang.v14.0.6+0.aarch64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/e77f0a8a268297d9bc7c164f7c89e351c1c839fc7ab52265552171d7d73b0c974b8a1c2ee200d7773a331293127b869d635b7cd6273e2db58bc4d60bc163296a +Clang.v14.0.6+0.aarch64-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/8234f867f72c39bd04cd47a4659a22a1 +Clang.v14.0.6+0.aarch64-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/accae8bef10e8499b86073d0d50b5dbc2accca7a5a0acccc214d55049da882d705ffa936627a339713fe1aab29e9078888fd474ee41c820316efedca1f35463e +Clang.v14.0.6+0.aarch64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/42423636e6a7a726477cf86399227c88 +Clang.v14.0.6+0.aarch64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/8cee8754ac597861ffd54b7a0f261efbe44ed3d3ed56711355b3c9f14a21fa0883b5665e4f55f82eabb2eea20a03ab738eaf32589322dce06f3788fbd943ee39 +Clang.v14.0.6+0.aarch64-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/0151cd8dcc8784154a51a333aa1dc4bd +Clang.v14.0.6+0.aarch64-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/b2cc6fbeb2ff4079596c09ced2b856ec7be2db64420b09f3b52b80cac1ba900967af611709834940ae3118adf82bdbcb2d5a90d8b9d5b5a1c1aded8e1b604dca +Clang.v14.0.6+0.aarch64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/8ed62616ef3e1a583e9095130ebf2ce8 +Clang.v14.0.6+0.aarch64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/0ffdae3ec39068e56749da47636dffc21a601df9c2bfc7421c97c6924c6107fe10d2eb641b660fde50ba5fc0a4ceb922041a0adf32cc8aa553d0ab9aa374f11f +Clang.v14.0.6+0.aarch64-linux-musl-cxx03-llvm_version+14.tar.gz/md5/a3518f44e475e1ac8b9fcd6fdf470bf3 +Clang.v14.0.6+0.aarch64-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/2fd3a8524f627a4d7967b6646a9ad9d973301d060883e2b488a67c2b4bb3242c44e46f78a63257cabbca000690e3659e7420173a40af6439106dc1806ce9cfa4 +Clang.v14.0.6+0.aarch64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/598475afb9320f81dffd8c2af89564b8 +Clang.v14.0.6+0.aarch64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/6a360ea886eca3c7a60bda7a41b305afdcef00593f7084c50a44456b1ccd079c2d6990e90c081c716eafb2c5226d880a9f1bb855e61941fa4acd0590b63dd2fd +Clang.v14.0.6+0.aarch64-linux-musl-cxx11-llvm_version+14.tar.gz/md5/22bdaa9b14a7ab40cc0de4c5fb174f20 +Clang.v14.0.6+0.aarch64-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/96f45265f947357cd3f79d42bc05c891570f62cfa4a84fef6c99a8db14a845a444d857d4e84985a2b741377798861e714252b61f7676269b98caa5e304e63ff6 +Clang.v14.0.6+0.armv6l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/70f47a6695b81d157c87668ce3b1e453 +Clang.v14.0.6+0.armv6l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/e1ef1e288aa7fad7dccc2bc4bdd0cbef0d134e97b41f85e5e85fc56e6a276beb358aecfe0d0791d745d2e3834ffba269b7bb289716d39ad3260568cc10e9b3da +Clang.v14.0.6+0.armv6l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/md5/3141a42822b55f86d0f075ded553be8a +Clang.v14.0.6+0.armv6l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/sha512/cfae9ff35702119c0cc5de6cdde4640629d020512b086280c26c974b71c024f0555b910a29c95f00a9ffb602f12512f21dbaae10278dc15e6ff6546f66ad1a97 +Clang.v14.0.6+0.armv6l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/8b1f2da8ec4768c9426b15cfeed00dbe +Clang.v14.0.6+0.armv6l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/ca4efad2aea4339fda792e8ad3cff7ad891ff2ed4a2647d466a6aeab67d61054da79fb39c1f3bd0456226dac5eb8ef1306ff70f795e21725d3611846bdd124d3 +Clang.v14.0.6+0.armv6l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/md5/468e0f231d30f64f40866a719d281e5e +Clang.v14.0.6+0.armv6l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/sha512/91e205aa53337a150d6c3c84edfb06e408aba0c39843db5c3defa18c6684055139c4c40c7714355cb6d7530d40c720a13d59e9a7f99ffbf2ee389ef090687845 +Clang.v14.0.6+0.armv6l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/a4006665b5c955df38a251281429dd94 +Clang.v14.0.6+0.armv6l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/f67892698dfee1861c0837b6439ad897502e3441f534b4027eb5fda6a73eda616343a8d8d8273f08b7cda0ecebf88eadeea1c2b9df96bc807767dbb455144e17 +Clang.v14.0.6+0.armv6l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/md5/6662732339b55dd2aac965b12db07969 +Clang.v14.0.6+0.armv6l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/sha512/b66ca56ce67b653f903bf85a274b11077f4967946719b71a306ae249867cf22d2f22e8fe7adf67be29b4cff87ca54a8dc910aebcc8325f9188854da5907b3b2b +Clang.v14.0.6+0.armv6l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/392e4b35796cd085840345d1078b6c43 +Clang.v14.0.6+0.armv6l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/78aa79f0ede37280acd504ff32cad3ea862ee20118e00b65c53d6eb2c0a99d307be7961abc3e53b01a4e44a4a26541c62bc3ba6c1213f17335beee71e905f6bb +Clang.v14.0.6+0.armv6l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/md5/679b0cffef21e3e8a3ac41f9c0d1758b +Clang.v14.0.6+0.armv6l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/sha512/3df8edf277753d5a27826d0614a7e359d44a48f5b086641998d9b0b1f4bf575c03cff03ff59b7dc3ca773af3b91a487755561a5964c7884896a885b40d5c40f3 +Clang.v14.0.6+0.armv7l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/5a7526421f59c8626b84fbe3c7adb686 +Clang.v14.0.6+0.armv7l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/ea8230025f212b081696dcdd094c7f44f86413c5b6547a31e166b05e119a82fc4afa811fb6907037c07de309f21e1b36c266a65d6f4fed49d815036ff578bcf1 +Clang.v14.0.6+0.armv7l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/md5/a385cf886ebf1036e465c54575ee45a8 +Clang.v14.0.6+0.armv7l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/sha512/2c53f5c1bb19f33764c0c65d7e337fa0f96213fd98527db1680ab2f036ccdef0a51c008667892300413f7ede68b7220da9f36420c1188fb58164497aad41e22e +Clang.v14.0.6+0.armv7l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/7c19b127843bfad76f981534395e9b2b +Clang.v14.0.6+0.armv7l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/d5ebc8f781f1147a5e459856a2888dc0525f1f63f6f3e53599faaba20c5b6ef75ca01261c8cf8c6917178658e2f38a70720299c5bbbb316b4ef631a8129ed7d0 +Clang.v14.0.6+0.armv7l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/md5/5877d43223bb2629934394bcc803c580 +Clang.v14.0.6+0.armv7l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/sha512/1ebeeb1f491463acaf12d2f1ba10220ed215df80ad79e392f99989466f34d395fdce87fa3502bfdaaca1e4feae7998d861bacd4fcfc12b5e23467d1608cc27cb +Clang.v14.0.6+0.armv7l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/b277b57e63f1025bef77786400c30909 +Clang.v14.0.6+0.armv7l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/fbf0eb469dd91f9d480417e86ce341215758c48adba98b4eb3b53d9321e2ed81cb551549614da722bdf62eefb8145b55d160a2563cd4523c43ff71276fd45f45 +Clang.v14.0.6+0.armv7l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/md5/d973a878a00a38fd892c9e697e4aefac +Clang.v14.0.6+0.armv7l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/sha512/6557bc7ea57a09ae6dca45cf90f925983f30afabe4af597aa2a397a9a3182b61d0408bf16c4cee5ccab3907a644d6ad5542d30fa28cf3fb5b790f66f43031b91 +Clang.v14.0.6+0.armv7l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/79284554223c4866f204bb7704e99bfe +Clang.v14.0.6+0.armv7l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/b78b1c7234096d88f061253866300a8db94928ddb8867d9d5a03f263c32fb3ade36f77c351b04ef3ebfd07131e9dfef7afa0d81cf5cb88e87848cbea354f15ce +Clang.v14.0.6+0.armv7l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/md5/e9235c729a76570ad2a919f2c4cb2415 +Clang.v14.0.6+0.armv7l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/sha512/651b512a8cae627cb30575f0907ad1488e3838fa106fe583962e8399883b5b02138e29bcfdb30456ec3e30360efce7283018005ac6352fae4e2564db3b50aac1 +Clang.v14.0.6+0.i686-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/7a7e56421b13e36ddda5119def5cf104 +Clang.v14.0.6+0.i686-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/fd45e46f44bfe2e6346e4795cd1e08bb775c243ba015394e5b9acda2fa0db704cf96191a79cd48c5bbecfc87118c6165ddc3b74f91ef1fa651e71df6f610042e +Clang.v14.0.6+0.i686-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/f59a37a860a38dbdd6f422d9eaf24642 +Clang.v14.0.6+0.i686-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/4e1eca8784e42ff1ac1fcb810579746f49bd54559ca9cb20776fb84e7e42f5fc924a975d4941c1e061b31901f3f9522fca3e8bbeac45fd8717556e5e70fb4b05 +Clang.v14.0.6+0.i686-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/e3c0338c9b592c67562afecaee5eee8e +Clang.v14.0.6+0.i686-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/0dda3627cfec247825103ce25d51457893eb699a6176151dbc0874ef1e087dcbad98790ba6400e2a8c5187b742d2e7a2671b15f3c63b9c17b9eaa8777795eb01 +Clang.v14.0.6+0.i686-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/2359790c7f6de7fbfe8208c3f3cddf34 +Clang.v14.0.6+0.i686-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/c4032bb8322f9daeb7d838ca66868bd5487242ac2e3854d47a789f17211a9255efe79e3893511099ea77f61e85550b56b8c2c3b206fb632c95527ad391584e51 +Clang.v14.0.6+0.i686-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/e8321015b108eace4abceedc289bd6fe +Clang.v14.0.6+0.i686-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/a760c2e1a6ff33225a42ee4beb566d38c78ccc333d58129635e96009ef92d8c96740e164e0305215542bdc3ae0339e698a899c7cc53c260411f1ff22b60d3dde +Clang.v14.0.6+0.i686-linux-musl-cxx03-llvm_version+14.tar.gz/md5/985f7225c38a5e7f68d759b2929d3fa1 +Clang.v14.0.6+0.i686-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/f74921af797ef0d3d1ec394ce1b672b72d4b25225207f2c7f7f227f0f033647afce139f710e6d4d23d474528d9f1e223f286d0c2b1b1bdf82c38b273bacc838e +Clang.v14.0.6+0.i686-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/9ab44ae551b230e83232de13e2a63203 +Clang.v14.0.6+0.i686-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/f017dfec0f088c7e0fb714164ca4e4f73cc290e8bfc4fa1838bfb5bc8f13d2cbddc1294863febefbf83dfdabf72b6b6493cf8b816b6a7c25d6a29b658d757e80 +Clang.v14.0.6+0.i686-linux-musl-cxx11-llvm_version+14.tar.gz/md5/d772e714293d4f4a49652413783ad4e4 +Clang.v14.0.6+0.i686-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/b45610cdb1907d9b1aabe6dabf2a6e7ee1e2e796caf5c62f504f17f098a61d2913b02f30570bd7ca62005276c2a2861f6eb347bc93c78e4878e433f13eb187b8 +Clang.v14.0.6+0.i686-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/md5/a91febe6ea0dc6e45a1972084cfd9b55 +Clang.v14.0.6+0.i686-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/sha512/cbd826d9843db662e5ab74172380a7d1000822c9c5a821fcc54746909dca2fcdccc7190f723e6aca60d73fb204422c95edd01bbcbe0b355d998f84f40d899ccb +Clang.v14.0.6+0.i686-w64-mingw32-cxx03-llvm_version+14.tar.gz/md5/15dfb79ac059279303528fb9bd60417f +Clang.v14.0.6+0.i686-w64-mingw32-cxx03-llvm_version+14.tar.gz/sha512/15236f71d74448a81f08e9cd9ac503e17e6e8ef679b11219f6d42b8b4a74a8fcb0093f3d3bdc36b8041ec67f1ab30754dc73bb54d498ee3ad52c519cd260cf09 +Clang.v14.0.6+0.i686-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/md5/035734a134fd46a5fe558f264f838299 +Clang.v14.0.6+0.i686-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/sha512/2cb35b0907129d1d8d6468d8f9a981839afd829cd16fe5fb539fe50f79560e852e5f0873b577ef0827211a51b07e26bd6090c98cde24fadda58ed28735095fbc +Clang.v14.0.6+0.i686-w64-mingw32-cxx11-llvm_version+14.tar.gz/md5/262c482c5af85f15cacd7d63f645589a +Clang.v14.0.6+0.i686-w64-mingw32-cxx11-llvm_version+14.tar.gz/sha512/ba70b123c105edd4ea1906f988582c8daaf0e625d645ad881976b68b98cd57717143f4b4bf35c3ca90f582ebfdc07c1ca208aa7c7aec330347f1baec74a79262 +Clang.v14.0.6+0.powerpc64le-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/935168f2b01f3fc9ab11396ed2d4a0bb +Clang.v14.0.6+0.powerpc64le-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/e602720c37e841f67ce2810908943a1bb68d59a2f17ca0ecf772de4a94880459a467fff263c15e310189c12bc573d1d3d2a0264274965d4c5f2957fd36daefee +Clang.v14.0.6+0.powerpc64le-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/76275a214835cf423b53bdb2d5d483ba +Clang.v14.0.6+0.powerpc64le-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/e231f87d73f32b9f08c1dfc5a7f6407b6a214b28c77d4604c1358ac0ffccb7391e005e4f4e88c03dc5fbe7decac6df77e5d9ec60cdfa18f47bf51c70b0ce3d32 +Clang.v14.0.6+0.powerpc64le-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/dd6eb853ba155972322f4f92cd019146 +Clang.v14.0.6+0.powerpc64le-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/c48026d655f5a8f896866299e8cbd4841bf3a1a2d00957309cbcdcf137bfd6e41bbbd8bfaae51265127e7922c3384512f6c086060e03e9bb1bcd22586969c9db +Clang.v14.0.6+0.powerpc64le-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/a8d6871f004cdca531abcd14a783f418 +Clang.v14.0.6+0.powerpc64le-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/e9e33eaa5af1485715fabf281cdf4c45f985904012db4f31a4d6ef70611a2ddecc13cc0dc4deb1ed75a6dd4da4b29b1cfae761c108f661e9df46f04ad9e011ed +Clang.v14.0.6+0.x86_64-apple-darwin-llvm_version+14.asserts.tar.gz/md5/12d3c0d8d84a41630198eb69a06651f5 +Clang.v14.0.6+0.x86_64-apple-darwin-llvm_version+14.asserts.tar.gz/sha512/1ed2de110db980e6daaad2e821fba6653cf1e72ed3b69d41a423cd597eac5ac18f88cd83c2afcc000c41effd268bf8b545c292096449630ab2c091474be42261 +Clang.v14.0.6+0.x86_64-apple-darwin-llvm_version+14.tar.gz/md5/a5b6ba0d493b4542e3c5374e982b60ab +Clang.v14.0.6+0.x86_64-apple-darwin-llvm_version+14.tar.gz/sha512/d65a6a6adc6a47be6dbc53b1b74e8ee0065cdc5e593a99f9fe40fdb8d23741146720c89de4dad9388dab801f4797e1524a39d778400e622bb9c03f23622d0708 +Clang.v14.0.6+0.x86_64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/c7f5a6766b5f9aeeeff2a10748b35627 +Clang.v14.0.6+0.x86_64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/1717d54c6328fd27a87aab0f120d85c066e74cc19f6e77f57f138d75d5da02ca9fc9956e620173385b89badfad12dbb6d5b90d676d000323024060b14a4a2212 +Clang.v14.0.6+0.x86_64-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/3e415c55a918b9fb20e7a9159f2a302f +Clang.v14.0.6+0.x86_64-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/be58bacc8fcd1f0cff745d8c7e555feba3e059274925b9361005603f93348d8c2d88c7f9249bc7d422e2bce52cdb280a2f1c5dab93044235cf8959ccfb193f95 +Clang.v14.0.6+0.x86_64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/65b32b4dc28112dc57a1d62f5cd8740e +Clang.v14.0.6+0.x86_64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/497eb5cfc826424468b3e53af7be3c0ee9c1d7a9ee85f30660dffbc728319301373617f9f7d9d09a300132fc93df8038fe2f099846d6b55ad07263afa2334b96 +Clang.v14.0.6+0.x86_64-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/066451584d69234c5096edf29421a713 +Clang.v14.0.6+0.x86_64-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/1e3c7dd8387cc5e5e0b1bc248c6d4dd7ca67bba2c681708593f395158546a305f9f7ea9a12be35376f020c768db834a3458625abe7c7ff3edfecb3b1425506a1 +Clang.v14.0.6+0.x86_64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/51d8ed30230760dc228e3f4350cf8527 +Clang.v14.0.6+0.x86_64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/37b0a003eaa618782f3ecf660829a1da8ec5d06bff9bdefdc6371a99156f0ab9778cc841c03b6ed1cb6e97e66123ce9f6d91b8c260a27f55e1d5d3371869d45c +Clang.v14.0.6+0.x86_64-linux-musl-cxx03-llvm_version+14.tar.gz/md5/4cac304533ee927f818f6f2e8804c6b4 +Clang.v14.0.6+0.x86_64-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/7f642a1da1074683ac8023d1f2bffeb7ae06d09bbdf31d6cfaa089ba44c459f71326585fce3587f0b1c98df122f635de46b3a2dcc9cd245449e453d47dd3f0f5 +Clang.v14.0.6+0.x86_64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/33daf6fbfc468f3e0b013cc43b1482ba +Clang.v14.0.6+0.x86_64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/1aae2a79622e821e6a8743786a0191ccafa7fe11c71741cb8cc41029890def518d41973f74568c6d8d4a6c8e3ddb37cbb29413c79517e4cc0458c2b636f92171 +Clang.v14.0.6+0.x86_64-linux-musl-cxx11-llvm_version+14.tar.gz/md5/debb98a67dfbac8e7f57ef6ab242816e +Clang.v14.0.6+0.x86_64-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/ed85d0a7d880193421f132082f46facfb9750da60c7860c611c37947212b7c7bd5393899906b0e21f58d98056f8d0611dbf25e06c6d6021acb4f79a7b6956100 +Clang.v14.0.6+0.x86_64-unknown-freebsd-llvm_version+14.asserts.tar.gz/md5/1456cf6c22c78537bd3feb556319a05a +Clang.v14.0.6+0.x86_64-unknown-freebsd-llvm_version+14.asserts.tar.gz/sha512/0cd46d6e0e135db0f2961d614faa59b8442e56f7507f07a27675dd400078d6556060ac13ad40b55f41393ab5be6d1db027038e97d3fd32c833ca1ec64ea3dd4d +Clang.v14.0.6+0.x86_64-unknown-freebsd-llvm_version+14.tar.gz/md5/8b3ae4d75b49ce372f64011af803c32d +Clang.v14.0.6+0.x86_64-unknown-freebsd-llvm_version+14.tar.gz/sha512/2de4e4521887d6dc951ab29bd25cbaf5d8dbd55630b63682acfb0929ea8a378e051f61f3d1b4cad127b8f67f65848dfd5aaa2ad38dcdee39a0c3f0d0a2962dbe +Clang.v14.0.6+0.x86_64-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/md5/89f575a07f9b42b659af895d66d36dc0 +Clang.v14.0.6+0.x86_64-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/sha512/cd3a201eedc0c685d6f11537b050bbc8aa29583391790a4d54ba8662a4ddb27574bc588bba52cac899a45733807a879d57f1caac380c0cb6401a7012602aa345 +Clang.v14.0.6+0.x86_64-w64-mingw32-cxx03-llvm_version+14.tar.gz/md5/5f3acbfc31fc032a18799b9738643f44 +Clang.v14.0.6+0.x86_64-w64-mingw32-cxx03-llvm_version+14.tar.gz/sha512/ee631163849ac5b8755477c0b485b3bc9a24ca07270e68b374beb5c2ae10aab1a44586ac4f40fcab80a08a3fdccee66584688e98859bf9a07d23c1e14e4a4ca6 +Clang.v14.0.6+0.x86_64-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/md5/450e2f2c49f97fbc0e18ab3e0daa183d +Clang.v14.0.6+0.x86_64-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/sha512/4ef4adbef50c5bb77699c8aec3f29a8faffbf5114c3b45e6530b4180e97443133d19f02358de99feed58cee37c88830c76600d2bc81fdd0318c3f41540f3190c +Clang.v14.0.6+0.x86_64-w64-mingw32-cxx11-llvm_version+14.tar.gz/md5/ef9b53f0fbf0a71c45277a49104a3939 +Clang.v14.0.6+0.x86_64-w64-mingw32-cxx11-llvm_version+14.tar.gz/sha512/326db9bdc978940e36580e3478bd64473bcf157840c9d6eff67ebc1f2452e00d41acc1fa6489c7ac536b000c3c6fa2e86198077d3f95bab32d71cfde6fc1a368 diff --git a/deps/checksums/libuv b/deps/checksums/libuv index 99b328f0dc9b5..844b063287c6d 100644 --- a/deps/checksums/libuv +++ b/deps/checksums/libuv @@ -1,34 +1,34 @@ -LibUV.v2.0.1+8.aarch64-apple-darwin.tar.gz/md5/c6123b5807b457a7b171b9060bcafa19 -LibUV.v2.0.1+8.aarch64-apple-darwin.tar.gz/sha512/bfbf31fde87e8a4bbb9cde72fba98c562a66a5c64cb2a9998dce4f94cc955fd6afa0b54757682499da483baee9c78c30bd685a60ef6419d2b7383fd313f7eee3 -LibUV.v2.0.1+8.aarch64-linux-gnu.tar.gz/md5/97274d22abb4c3674508732907d74b47 -LibUV.v2.0.1+8.aarch64-linux-gnu.tar.gz/sha512/2adbfaaf690d928b7d32b2e4d48a53c4ffdd94cb699db8e46d93dde496a33b29feb3f0d1c62df42b2dfaace9941a79829d54fd68900632f9cec5da71015de28f -LibUV.v2.0.1+8.aarch64-linux-musl.tar.gz/md5/0eaec69cc9b40d99c23182b7a20c4b81 -LibUV.v2.0.1+8.aarch64-linux-musl.tar.gz/sha512/224156e8fb287d45060445dbbc2dedafebee0cd44923b541c13d6688c8e8f7a86fe608fe6235c9459a2f07eac9e4b0d38577164674238f89033c3ab8c76e6e05 -LibUV.v2.0.1+8.armv6l-linux-gnueabihf.tar.gz/md5/2ddd26fac1ec25faa44be79a95ea52e0 -LibUV.v2.0.1+8.armv6l-linux-gnueabihf.tar.gz/sha512/123a1faf182e4e757b96faf2f4981f4985246780796e0be9239872dbcc76631f2d028171a6e40150b532b4840de83c36e274e9630c2474ed50e9c150efaf2dd7 -LibUV.v2.0.1+8.armv6l-linux-musleabihf.tar.gz/md5/bf474e3faa0a8dafdc3c37eef1f22133 -LibUV.v2.0.1+8.armv6l-linux-musleabihf.tar.gz/sha512/9a4e4b0af14e5e16e654033f2b77910a5004dbbd52eaad844429af7f521233a8a352d3f12e96a5d6dc6b709b578146d9bb34e12ba959b0cc111b8a6667fc88d9 -LibUV.v2.0.1+8.armv7l-linux-gnueabihf.tar.gz/md5/a10c8d87b4cc631e85d93c3e0ea0e882 -LibUV.v2.0.1+8.armv7l-linux-gnueabihf.tar.gz/sha512/65ebe30c7e14a4d72e0489cfcc299a45a6313102b540b2c245df0d098ec9c79c1037517c9a341b095912fe81c36fd6d5c308dfb090169dea76c04105c871e790 -LibUV.v2.0.1+8.armv7l-linux-musleabihf.tar.gz/md5/d77772d6330ae6692fd1295f3dfea8a8 -LibUV.v2.0.1+8.armv7l-linux-musleabihf.tar.gz/sha512/c21ab143bb5262fb09a8d457ef53f639e3040802abd128bb49b300015bba857fe3adaa0181e277b7a79ca20e02aaafc644f1297cfc18a1e1ca8af8cf1af711be -LibUV.v2.0.1+8.i686-linux-gnu.tar.gz/md5/54bb6813c26a7e0ea2518de5faa243a5 -LibUV.v2.0.1+8.i686-linux-gnu.tar.gz/sha512/cef37e6b164a66135bb5eb3742827575a41e0723fa66e037b030833461bec681054c70684d0ab3b30e52a5b0a16eb003cc9a67003652f0865b7e0d504af2e7a8 -LibUV.v2.0.1+8.i686-linux-musl.tar.gz/md5/515fbd2e524ae8bff39520fa50ebe792 -LibUV.v2.0.1+8.i686-linux-musl.tar.gz/sha512/5b5679937c4aef39fc22bb8681440a33bd53eb6115315f8b169f65a9f59d632f3d774b0cd3fe14d9a2f74db64a459f0e81ceb94648c6c464e0d275567c87dadb -LibUV.v2.0.1+8.i686-w64-mingw32.tar.gz/md5/7f0fedba47d432c48b26757348b1eb5d -LibUV.v2.0.1+8.i686-w64-mingw32.tar.gz/sha512/3d3fe9bbd210896d68d3de2748a013a59e11fa42360c186fe7a461e2aa4b8c26fa7bacd1a04cd22e86c8600b2d764cb5c66a0cacbf956df8df04aa6cf26503f7 -LibUV.v2.0.1+8.powerpc64le-linux-gnu.tar.gz/md5/feac1f65834f86b0f1aedf002431fbd4 -LibUV.v2.0.1+8.powerpc64le-linux-gnu.tar.gz/sha512/f78b55da9ee0c9cd13c4824e07d4b96f7b47dfbc2d7abc5d09210cfff3c659f46ebb3dc733f8eeb9c6464c8252927e89f76540b48cdb370dd89e8ea1eabc6cb8 -LibUV.v2.0.1+8.x86_64-apple-darwin.tar.gz/md5/930a03b3cb44a2a42ff20be4c5bb388d -LibUV.v2.0.1+8.x86_64-apple-darwin.tar.gz/sha512/5398264f42707c35cacb68ba5dab84e49efcb5571e01b16055030dd11f5b8ea4371972b419e2087a1daf9565b4b578633fce13d1e050adb23f91b7ac16ad1937 -LibUV.v2.0.1+8.x86_64-linux-gnu.tar.gz/md5/3a3346f4e91123d49bf41a124303a670 -LibUV.v2.0.1+8.x86_64-linux-gnu.tar.gz/sha512/d81951bb396e5116d80127a69546844ec99f9b19b229a0344d3f9051e2f08c13f3abb0650bc314ca5be0fc556f0a655dba960e2513de590db0bfaae4575d6f54 -LibUV.v2.0.1+8.x86_64-linux-musl.tar.gz/md5/603fec3ba7efb51be040c22803784ded -LibUV.v2.0.1+8.x86_64-linux-musl.tar.gz/sha512/345fe3f0cedf7404345d49e9eca7032787d758b3d5e2e0af2b59836a1fc2e5b71738c8389eb31738c161527a717c7f6f30af123e3a9056785bcdbcb9a1b18057 -LibUV.v2.0.1+8.x86_64-unknown-freebsd.tar.gz/md5/ec6df758c4b27a495adb97820b5a8b22 -LibUV.v2.0.1+8.x86_64-unknown-freebsd.tar.gz/sha512/16d3c39d8fd2e4c9035cff99433c5f5a9150da18fac3ed9639e22a38715ef51f30d28f83674c68be69d1305f4b53b785f3a8f89d28253fe254bd2515fc49d5ea -LibUV.v2.0.1+8.x86_64-w64-mingw32.tar.gz/md5/0dff06ff0a42ac3404f78f7eccf08f1b -LibUV.v2.0.1+8.x86_64-w64-mingw32.tar.gz/sha512/4884c6cd7c29eee725b0d9f6eab091086665b3070f3cd33854f482c9b2ec55924ab560bd5d27b46c5e0ed6a7af08bffb5beb0e75fef6aa82b4f90bd7599ee691 -libuv-3f7038d62e43c3682394a6ea7b4ccc46be0fa0bf.tar.gz/md5/fe6957e2603df688a40605134505052b -libuv-3f7038d62e43c3682394a6ea7b4ccc46be0fa0bf.tar.gz/sha512/28f13b8d927e0663bff26e9ab829538947754046088a42fc85d772d62c28fb47f8f3075d1a884bbbae6ce0ba294eb8f3b5f9cb95be14d7ae1f467b713b4a14a7 +LibUV.v2.0.1+11.aarch64-apple-darwin.tar.gz/md5/60c0a26acbd9c6d35743c19ac917f9b9 +LibUV.v2.0.1+11.aarch64-apple-darwin.tar.gz/sha512/4f62658c10486040ffe04e8e694fbcdb2a07340d8f1d18b703598141f5b377c421e06b7896dc0be8472c6c9f748ff44be109db99304b0442f10eb878bf2af1df +LibUV.v2.0.1+11.aarch64-linux-gnu.tar.gz/md5/215a204f1fb13a8d1fc9b26106814bee +LibUV.v2.0.1+11.aarch64-linux-gnu.tar.gz/sha512/3f20dc865a1ebae98ac75581585c5057b6c27bbfe084580274089f3103b4ad5fceee7dd5822b6f1cee4dfdfe027a379ea5116e37ca331845108380d6c2ecf63f +LibUV.v2.0.1+11.aarch64-linux-musl.tar.gz/md5/b618837c1c2ff1e64578ae043c0a00c3 +LibUV.v2.0.1+11.aarch64-linux-musl.tar.gz/sha512/7a82709a183977237f76cc0048034522466843d583519cec95fc7dd39cab1891b397052c6deb69b8d6fab6d0f57c91b642431b579bfb6c790881509b8daaa24c +LibUV.v2.0.1+11.armv6l-linux-gnueabihf.tar.gz/md5/f09464b716b779b6cccc8e8103313acb +LibUV.v2.0.1+11.armv6l-linux-gnueabihf.tar.gz/sha512/7c39685bbb9beb39670c94a3dea0cfac8685c9ff1116026784e68610d9314c281690f87bba918dfcc60f39e3f5c54ce432ab7365f785510be4108fa2454905dc +LibUV.v2.0.1+11.armv6l-linux-musleabihf.tar.gz/md5/6a483f49e053a1d796c2280a165e5cdd +LibUV.v2.0.1+11.armv6l-linux-musleabihf.tar.gz/sha512/16d6ade651018b20e2b465ee9beab6d6442a8d3942249a90def2797ac2b2c0376173eb9411f26cdd3f82ae9798640f819e139dd3cd70ce7e4684f6154f68fbfa +LibUV.v2.0.1+11.armv7l-linux-gnueabihf.tar.gz/md5/d3c6110ba03be6136d0c0a3740b2bc21 +LibUV.v2.0.1+11.armv7l-linux-gnueabihf.tar.gz/sha512/a41c26cd52c82804bf14d783965ebf4893db0cae7319d9840777485a328237e9f7c54aa3c2dc9a0ee39f98db430b8616de6f60906fbd00771f9a50e989e68fde +LibUV.v2.0.1+11.armv7l-linux-musleabihf.tar.gz/md5/a302e22ac3bc6d0909cd1b2a90c712ac +LibUV.v2.0.1+11.armv7l-linux-musleabihf.tar.gz/sha512/dd0291b86e11dbf7a8cf5b22f862bb0a93dcfd0d5ae009fe0c53f569d012bc2ea4895976c699aabd79ce05f4ae6161ce56263859c1994ea696e50f918fc2f51b +LibUV.v2.0.1+11.i686-linux-gnu.tar.gz/md5/d3b8cfaee74da3f4ba58c6845345ebfe +LibUV.v2.0.1+11.i686-linux-gnu.tar.gz/sha512/9623b84f6411f9b7c5a67f5e346d6661f00103a8417e22018b513efa3b8904268c57c7de21cc2f66a55727060436159f70727beed49b7efc882befd4d399332d +LibUV.v2.0.1+11.i686-linux-musl.tar.gz/md5/0e04697b85d2798c19f56e437eb55e56 +LibUV.v2.0.1+11.i686-linux-musl.tar.gz/sha512/75373bb5a5e3dd8f3fa4a85664bcfa0c651a793d8b104264eafa9626520cfb936025d4b1540c8e6d16a73468b7a1068a5ab4fb3b37762404d1ef7225a85e1664 +LibUV.v2.0.1+11.i686-w64-mingw32.tar.gz/md5/617dfd4290517837ad4c709dc4301733 +LibUV.v2.0.1+11.i686-w64-mingw32.tar.gz/sha512/7069f8bbb876ab5e2a7f0d79f4a297cd7984e1a83eadb1f91f5de86afc951b38e5bf2641883a4b7f327eabbc2f25434453b855ff7d537d30cc5ae6c8a00341d4 +LibUV.v2.0.1+11.powerpc64le-linux-gnu.tar.gz/md5/70f16a63097a353fa45971d3e4313da4 +LibUV.v2.0.1+11.powerpc64le-linux-gnu.tar.gz/sha512/ecc9f39fef7e9917dbadf4a7fd7966d06fb240f73cc2df021d9b8fa1951655d078782f17948abbfb5a21f2b7fcd9c7390af0a05610a9b952d55d53b6826ec312 +LibUV.v2.0.1+11.x86_64-apple-darwin.tar.gz/md5/17fee1aaeb6947614705120a62a21fa4 +LibUV.v2.0.1+11.x86_64-apple-darwin.tar.gz/sha512/cf4c80e797e3d68f54916bae6163d948f0a300f201f2b8209310970751d68eef6c29da571721aa98794c9ae30f7dc655385a5091c716e0402d3241342a1d9544 +LibUV.v2.0.1+11.x86_64-linux-gnu.tar.gz/md5/7e2cfbd1d4cdf2afec2ab18f0f75e812 +LibUV.v2.0.1+11.x86_64-linux-gnu.tar.gz/sha512/8551dbaf242c859010481e12864d75e8df01c69a90b94293402881b50e32105add7f7fdae455144076a2169f37e5796eb528d8ef6fc02226fbbb9d0f1bc6f6d3 +LibUV.v2.0.1+11.x86_64-linux-musl.tar.gz/md5/3879f86977865ceac0ea36e3f563be73 +LibUV.v2.0.1+11.x86_64-linux-musl.tar.gz/sha512/0831c0606e9bed4f819cb8f2abba464c9e0034533abdb5bf6e6e92b9f37644103c39adc4498db5128395dc65da28c93d7cd01bfc474985fa5dd660b04ca14cc1 +LibUV.v2.0.1+11.x86_64-unknown-freebsd.tar.gz/md5/288d9ab3dd95028568880838462c1f35 +LibUV.v2.0.1+11.x86_64-unknown-freebsd.tar.gz/sha512/ac0366d8eb4d0908d5ea55105dc608418455bc601fc22058512e228225cbd1ad2c778f7838b9d2374a6f1661e386f4121bae0f4cecaa18a4ba70a3a743318e24 +LibUV.v2.0.1+11.x86_64-w64-mingw32.tar.gz/md5/2b390151d13474968444b0f07adc92c0 +LibUV.v2.0.1+11.x86_64-w64-mingw32.tar.gz/sha512/6c56a7ab3e28ebcc7e55917b5ba051b4725ca77752b5206f865b306e905d119170cd0bb4e117c7352a95aa13b814ec5e15547ec3904615b561775a17e6993741 +libuv-e6f0e4900e195c8352f821abe2b3cffc3089547b.tar.gz/md5/c4465d7bff6610761cf37a1e8e3da08c +libuv-e6f0e4900e195c8352f821abe2b3cffc3089547b.tar.gz/sha512/3347668b2b377704f3188e8901b130e891d19ac944ab3b7c1f4939d7afa119afff7dc10feaa2a518ec4122968147e31eb8932c6dfc1142a58a4828488f343191 diff --git a/deps/checksums/lld b/deps/checksums/lld index 230f499a9e0e2..588522e1cdb62 100644 --- a/deps/checksums/lld +++ b/deps/checksums/lld @@ -1,116 +1,116 @@ -LLD.v14.0.5+3.aarch64-apple-darwin-llvm_version+14.asserts.tar.gz/md5/8c0016fc3456a734169bf24aa11bdfc5 -LLD.v14.0.5+3.aarch64-apple-darwin-llvm_version+14.asserts.tar.gz/sha512/9e8497beb3b472e458e00608ca5d40bb366a0f6c4fbb5a063d4b284ef4707faac1587014a373990b10f759f3162a62f5b237ceef57d2c1700bd28f547d95965e -LLD.v14.0.5+3.aarch64-apple-darwin-llvm_version+14.tar.gz/md5/3da8ca68c84ac618660ab8668c63582c -LLD.v14.0.5+3.aarch64-apple-darwin-llvm_version+14.tar.gz/sha512/4fc102cb31475b10d9bff8d9896d5cff117ad60c657c8e5bf0c66fd2bdf8e67604d044a183c77d6d53fe9ca8b6d1ec7e5fd1aff837f0ca2377d27c62648eddae -LLD.v14.0.5+3.aarch64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/633d14891f40cb9b58ee7bde0f5b9f1d -LLD.v14.0.5+3.aarch64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/338a63a3b31f5a04aafbd57405045ff464ddc3f71360df13b6e6910a344f68159f6e59ff7df27b740bd936e9b2ea49cf6ca21b06bb69d720a1d27d88d44987ba -LLD.v14.0.5+3.aarch64-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/055b955d19b96fbca731017cfa7eb73e -LLD.v14.0.5+3.aarch64-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/cbabf2ba59b157e7527bb6482211d1870237b2b557fa187a160397061810b2729d2e990ec01245be6c2272cfbf8ba60c36d2ef4a752a94486ddb393134b6a5b2 -LLD.v14.0.5+3.aarch64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/65edbd6af9e0417922d4007851face45 -LLD.v14.0.5+3.aarch64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/35c19a995f77b8afede866254aee5d8cc19bb037a7bfaeefd0700428b85b3134fd523206167180afcc6894b96c34eea449c0c84201ebea261e1c2773a6e584e6 -LLD.v14.0.5+3.aarch64-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/5c2785601c943e7cdf3dbc76c7d9eb48 -LLD.v14.0.5+3.aarch64-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/788cac1ed36b3ddb657e4627ee9fcd10a59bfe839d8e8b3ef8d49bc2cd9b44f0a71988ddb8d96b64686f4ca4d7979f2e48c17a7d785125da6a1e47ee80c13d91 -LLD.v14.0.5+3.aarch64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/8bdcdc8960edb1ed08b0493073deef29 -LLD.v14.0.5+3.aarch64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/54ef85a02de3b4f9272587504ff9f3a6e1780b3d57a51bfbcdb8bf24df74b92891aba18aafda1a98e911304e9d8e3b3c0140dc22cafe3cf6d37ae9fa23ffea9e -LLD.v14.0.5+3.aarch64-linux-musl-cxx03-llvm_version+14.tar.gz/md5/07c152bb41599901c48735b5c2da6a56 -LLD.v14.0.5+3.aarch64-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/d30a6e6b1579be50b37ecf26c04db1885f838fb68f8036cddc2ad840a98b0ad1a62a965db43f4dbc5de63d00c6ad5e1bd92144e7e4d83ca0efaab995f4ac92dc -LLD.v14.0.5+3.aarch64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/8787b8326cb0ae92afc01322565d219a -LLD.v14.0.5+3.aarch64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/a84d70118718f433933ef4dcfdb0bd215b108bc9f038db92d4e16985557b668c1b0d70accaaa64b1a7f843c46f75eab4e98795ac1e34ee48a1b1e2b2d1c968a2 -LLD.v14.0.5+3.aarch64-linux-musl-cxx11-llvm_version+14.tar.gz/md5/8f2bbf8e2dbc0d90d027a76e6a961f7d -LLD.v14.0.5+3.aarch64-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/0b0405417bff2bdefde9de5309cc84b72b9d4d2a2b8244855ec995b7b6c3d493427b9564aa662b1122686064bf5eb1950cd3998173d3722d6b16b9e9eb9832a4 -LLD.v14.0.5+3.armv6l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/b26e0155aad5cecf1fde8ac911306c48 -LLD.v14.0.5+3.armv6l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/8dc10f854f51f889869537747e4ea41323eb321bd1ff2b8337d66a24e05534b215d90bf59881edb20bf8f6b186902f30b2119f67caeedaa6b8e98b95a263004b -LLD.v14.0.5+3.armv6l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/md5/0648cfef90754fc542c590cd077c5e6f -LLD.v14.0.5+3.armv6l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/sha512/e8153e56e5a6e39cfd1f8a72148d3fd4a1c40db439a84072e614553a87a2275c66e61099583b8ab633829a40509fe52f761d7f6077baf9ddff86651bf42b8a8c -LLD.v14.0.5+3.armv6l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/ddc750ef2d97f46e4e45c8b4e671543a -LLD.v14.0.5+3.armv6l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/e0bbbe411fa89eb6c8bda39d9037888839795cf9e6b3a8372e86cf1076c7d5dcbb93a8e471680800b86605359f5c6a5972529cd99b41d008c50e00cd263d5e3c -LLD.v14.0.5+3.armv6l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/md5/e38753a9b2e8f4c19672c6573e8e7920 -LLD.v14.0.5+3.armv6l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/sha512/f1ebcee236bdc22101e64e6adb71c44aad060968419f2e0849c4994db3f2d011b5e405a3086148e5d8c3c1158f506df27beff9fbdf2b487369dc6ba973a03134 -LLD.v14.0.5+3.armv6l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/3435af737a9fbfb244331bca84c9d11d -LLD.v14.0.5+3.armv6l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/9cfa3e9e86af94f1159cc3a3899ff41e8a2eb454a7218ae271e513140e08f17b3e9f8fb5a30819f3120f10b2abca624c69b01dfaa5d0e7c0395a80567978beb3 -LLD.v14.0.5+3.armv6l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/md5/cb404fa26289e4bccc0720e76c8fb078 -LLD.v14.0.5+3.armv6l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/sha512/c92a9b1e217568725b479a81ad9ef0b35a74fad5a6a79ccaf19e7b4b074aea12fbc34e088fcf0b231f15ee1e1169e5f9b4e8bed94ab5fb5f7e93438702eca247 -LLD.v14.0.5+3.armv6l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/9a523734040f9fba7ccdf5260e60049f -LLD.v14.0.5+3.armv6l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/556cc3d916acbb137936509b25c05ccf0f1e60dc7777008a3c1b716de3c30318b0a7d3b185e201f4def73d1054ac51876a7a5f3d95b72f0f1a1dddf1e6b5ee16 -LLD.v14.0.5+3.armv6l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/md5/48b87ff6fabf1cb33b7363e0b913cd34 -LLD.v14.0.5+3.armv6l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/sha512/6b3f0e0c206bed61e4ad41cf8a73aca6a810483a71a6db98cae83781aba7d35ac75a55e72c34d6ec4836059a726c713996988f3dfe225c026fc61ec076cac5e2 -LLD.v14.0.5+3.armv7l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/d5fa0da63d7d3dd17e0449299497a1c5 -LLD.v14.0.5+3.armv7l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/41044992cc2c43bfa5765601a40a899d63a4b44bb2c59fe551882a08e3e721856e2a4c68d90c079ddfde8545ae6b5b429942d7fefa5f37858ece94e88385aff0 -LLD.v14.0.5+3.armv7l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/md5/3eb042a2a789832122d9d4991814761f -LLD.v14.0.5+3.armv7l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/sha512/903c09ce9a63ab5c8ffcfa657c640ff09dfec1c5eacafb6f1cdb4264a7ba388a829c1fd5b0c3fc519ca4bbe631cdce57908906688c92f20cc04ef6e14ba744f4 -LLD.v14.0.5+3.armv7l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/7a13e91c5386e2308a84f31cd9295ebb -LLD.v14.0.5+3.armv7l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/712d193701486204e30fa6dff834ffc0f7e826629badbac1fb8ea0ec96f772289d95aa7ea74e0a8e98e571a34adb3624e64da6329b560c165d5af096e989a2fa -LLD.v14.0.5+3.armv7l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/md5/91a525ca556b551e0902580465fd99e7 -LLD.v14.0.5+3.armv7l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/sha512/3e1e266bcae6aca8e8c3369e19efa0d24906485a158e327591dae63ee1237cdbe2974fbd0d8bf4c6148a11c1c25a79861406a35cb94471ca43cd50e870003859 -LLD.v14.0.5+3.armv7l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/75f7d46a7cd00e07cc31984689cd17ab -LLD.v14.0.5+3.armv7l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/558329e1981d2e029a1062ec49bb18b328967145e5e38efee60b8c091e03cea9ea68ab8977b20d08075531e3336df9fd9f8512bcfe91196de9005e0ee14a645f -LLD.v14.0.5+3.armv7l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/md5/f7bdfd3ff9e61b5fd2a8ad06d9af611d -LLD.v14.0.5+3.armv7l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/sha512/155489ebbde4ac0e12aed8e5e8cf9826dce96956d2c909a7da3708140d89357498edec91e313dccc544b671e31b0eb7af231180a069c7480f32a2f72a2f614e4 -LLD.v14.0.5+3.armv7l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/30789fd05c27f647c880f69f2df0f20d -LLD.v14.0.5+3.armv7l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/71c07a66faa5247ce5d390a14f5c201a6b80d47b7412b397f216ba4cd299b35e7227f486f20122e262d8f560ec1d76e64232d367c2e64f47b566c06c19969900 -LLD.v14.0.5+3.armv7l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/md5/1380b42774d9c13b0c5134f62678a8e4 -LLD.v14.0.5+3.armv7l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/sha512/05512c332c53dae65176feb23e33417e40ff2778a3b77d123f58e5883253021d209a5885e45bd69c51cc9bbaf6f42673679632534103ef897610b4664beb6453 -LLD.v14.0.5+3.i686-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/258826be140b444cced264228781e948 -LLD.v14.0.5+3.i686-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/c2a28edfdbce5475837a44615e7fa06a710424d06d770cf8cbf4d10bb4767d25a3df88497b4f57b117da65510a15a4acdc9749d03aa8ec50f0e1e645130298d6 -LLD.v14.0.5+3.i686-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/f40992df694ec2cea6bd783a7b19ccbd -LLD.v14.0.5+3.i686-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/58ce6366150391afac7968509bb66b325f69c7331cded7e9c61f936d22c85c2366d03d61f4ea845d1de76eeb513205604c98ba69bbbe6892073d71bc8f0fbc5e -LLD.v14.0.5+3.i686-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/2f62cba6c73201daf6c43276bcca0744 -LLD.v14.0.5+3.i686-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/ebc66d5a287caf6c2940bce79e43c245a37a37bb3eee7c142481a4857b23d17359ec7115d20c87551bbcc8d82a1ca9d91372bc3a0b037d52938f564922e58718 -LLD.v14.0.5+3.i686-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/882caac603615101ee64b7b670c6a46b -LLD.v14.0.5+3.i686-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/a86e6fb28e6fc936caef4c73e4686f7adb1161ac55a90669663c4674c771830d4c0728c13b9fd22a5601b3bc251d8ad407b2a1cbee6bf1b6af6bf53ee32dd67b -LLD.v14.0.5+3.i686-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/e3c0e1bbbe0774f932d53fe1c4d9573b -LLD.v14.0.5+3.i686-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/9dda268461e0fb2ad84bd40ac780cc9214ebd4237b4cdd3004a73d489a1f6e83384975e93301604209f8e4642828c73c4a71b61c82fe424edb3d5596d6f133d1 -LLD.v14.0.5+3.i686-linux-musl-cxx03-llvm_version+14.tar.gz/md5/90d7ade44ba297e6b3721712240a8955 -LLD.v14.0.5+3.i686-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/206ac75651e0d5d862a79564d7ae5357419c56ba621530d4eaf40fb4e95b30a780066348d53bd879149939dd8b07d8b9abe734f0a9cdae2ed61166a8e084f460 -LLD.v14.0.5+3.i686-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/e94a9a5d81b1c4dc8409dfd4134b03ae -LLD.v14.0.5+3.i686-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/4abf942bf6615aff9168468037a4e1bd22c52c979d3869b6e7bf3049c10ffafbe729159983cc340cf5505060da8c352c517ed429978962f270a1fa6469c98b5f -LLD.v14.0.5+3.i686-linux-musl-cxx11-llvm_version+14.tar.gz/md5/b81db5633a1447d15f7f2985cba01802 -LLD.v14.0.5+3.i686-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/90dd363eccd0c59047b67af8c6bc5496db6cbacc6f91b37fdf3f03814cd8711a3ccc08ac7a1c38d5f1e2397082572b54be55f0900f40d2e026f7c4123547d98b -LLD.v14.0.5+3.i686-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/md5/cc6e74bebe78565d230cfdf5b0196579 -LLD.v14.0.5+3.i686-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/sha512/0a715195926640ce6fae478f1ad3e8f50f1071c0dc5303610c0515da9c66c2604bf07c322a98e7085a8f7b42f6923118b644e11f35ad9da33fd854787e0cd7c4 -LLD.v14.0.5+3.i686-w64-mingw32-cxx03-llvm_version+14.tar.gz/md5/ee62c3e2744fb7a14fd7011adada8cb0 -LLD.v14.0.5+3.i686-w64-mingw32-cxx03-llvm_version+14.tar.gz/sha512/afe03d46d4174ce7f43786f34d6e6842183a72ba04e0658d0bc38c23c0d17761f79f392b80d70a49e6138584ae5aa8d5668420e16f6f38460dd505b763578886 -LLD.v14.0.5+3.i686-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/md5/5763a00670b797e5b0c6ed2548792d6c -LLD.v14.0.5+3.i686-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/sha512/3c84c0e5b6ddf1e34f2a755175df2152d3daa1cbcaa53910081ee9a23d7f998ef1b476d232fcd27ad485c8d687b1adec253323faadb555041d9ef35853204691 -LLD.v14.0.5+3.i686-w64-mingw32-cxx11-llvm_version+14.tar.gz/md5/06c8a03d9c9393498340646f817addc8 -LLD.v14.0.5+3.i686-w64-mingw32-cxx11-llvm_version+14.tar.gz/sha512/1058f00d2571f11a3084c2861ff0822df969c82a7f82a517c0d704568667d67c3f93cac5b17ad48bbcfe62cca15199033f0c9de3d48dffe5df80c6ccef2bf7b2 -LLD.v14.0.5+3.powerpc64le-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/e62195d4962e6a6d502c6856be1d3688 -LLD.v14.0.5+3.powerpc64le-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/72ffab279fe535cd2c0a8ea40afae73abb90ae0e3824812dc1b716ffa6038ad8b26eaef69d06b6b3c29687e901c14ef534ee6c64bb5a4390646b4c704c675d52 -LLD.v14.0.5+3.powerpc64le-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/719ef46fcf4ad428a52d7dcb051d9e41 -LLD.v14.0.5+3.powerpc64le-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/ce89e0cc4a5d841d6d97f6d80bdf5336fef56328e618a38e880f7dace01d0bf9ada73e5eaa821f884a1a505d6353672b86ba90fccdfd095dcdc0ac93f35949fc -LLD.v14.0.5+3.powerpc64le-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/ad2f242f1df03516ebe98e4dd8f90abd -LLD.v14.0.5+3.powerpc64le-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/c2c6a3b8f7dfdb7652b80f95c9eac85d74e6a94e814337a6d6ae9ca2c33b47c90aab63171550a043c523a09d0f6eea9f2341ebc3708cafdb184a04588b0bc5c1 -LLD.v14.0.5+3.powerpc64le-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/a6280227759f48538a6bcf9666502a14 -LLD.v14.0.5+3.powerpc64le-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/2e3d5a541ad42f3558dc0a8f9112f61bb7c06ed2d4a1aa6f8e3611841e7e2874add76cc88fa8b76b3e491a1c1dc9a8ed1939f6931d334731c5d7c4e1a6b083e4 -LLD.v14.0.5+3.x86_64-apple-darwin-llvm_version+14.asserts.tar.gz/md5/8248779068eddc7e43978e71e76977b8 -LLD.v14.0.5+3.x86_64-apple-darwin-llvm_version+14.asserts.tar.gz/sha512/feb45385c8ca2df0bde4d8ff409f70bed3512ffdbbfc07b769a68c324a5296354f35163ac92b980632e7cf17c4169c22ac9e64a5c6f0e6d58ee028ff95e0314e -LLD.v14.0.5+3.x86_64-apple-darwin-llvm_version+14.tar.gz/md5/155546aa504931073f59a8a63b3e7ebd -LLD.v14.0.5+3.x86_64-apple-darwin-llvm_version+14.tar.gz/sha512/9263c32e0761104011be32bd333325da5a8c2bf4f2448fd8a8117fc0ffb7a85cbd93f18849767f2ffee561476d2e249621128bc98dd0c50b0973ab3829cf1c7d -LLD.v14.0.5+3.x86_64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/76cfa361fe1f4719dbb70f0e14780521 -LLD.v14.0.5+3.x86_64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/9461db4f7825701c1aaf0c71ca34f8ccbb5389c5af04651454160bbc2f3051710efe689ee3d09790e12d4a3daaa8ae98e5c12785e31b776037d727b8364c1255 -LLD.v14.0.5+3.x86_64-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/757d098a263dba872eb595b5718a3e63 -LLD.v14.0.5+3.x86_64-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/625bbc787a9efb2bf455eb98ea2e41c9d6479ee0b5b009fe16194451fa95ffee2f9e82e12d1aeb7fa0ec0b314c5d7c0d533fd750e7f6dc51b12a00182b3e7be8 -LLD.v14.0.5+3.x86_64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/1d011209db860a6a37ddd9a7c5a82378 -LLD.v14.0.5+3.x86_64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/85e08dd3067f6cf6620ad20cacbefd474a49465588261975f122dd32fb629dac36c72dc10f632a9988878c0ccdd27af76ac6056e8d14c6beb4cf15ebba1841a4 -LLD.v14.0.5+3.x86_64-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/dd57f567e35654be4bd26ceeb4b0a468 -LLD.v14.0.5+3.x86_64-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/f42e7c4c4bc17eced803643499a89e07107175d5c244dbd998bfc7acba34dc7546bf94fc34c71fc291bff4fe731213306a1a3ecd4e8bad7f5d94fe4d413fb014 -LLD.v14.0.5+3.x86_64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/4a38b8dae3c80ba6154c25273ae08101 -LLD.v14.0.5+3.x86_64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/1fb2f40b209eb903578d7d6b2527ba124baa0219c517c4fb573645fdfaa61b2abd27926a4c0b32da9c40202df68c543dbcf9e53de5948446b8f589c1feed35c1 -LLD.v14.0.5+3.x86_64-linux-musl-cxx03-llvm_version+14.tar.gz/md5/eb668ceb4878a4747ef95337f20c7e6c -LLD.v14.0.5+3.x86_64-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/10eb872f0cdf72b1a206c8a08a6f9289a2205bd468cae802a7606f406cd20011b6149db2dafa944582b3a4a6746030d43d9e3cf1cf9a25a42db7de56f21831d6 -LLD.v14.0.5+3.x86_64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/4ed84dc932b5e6e65d22c5e8e5c83ab9 -LLD.v14.0.5+3.x86_64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/8c3db5d56afffb136b206ed5e1f9ee60814d441013c5d0996783fcce7052fedbd2efccbacd7b6bafbe4536020e52a1e5bf2b026ff52bd380203760e2a6f03b7c -LLD.v14.0.5+3.x86_64-linux-musl-cxx11-llvm_version+14.tar.gz/md5/91aa6ae667d0e1f3f44587619b3762ff -LLD.v14.0.5+3.x86_64-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/9c45d4a295f6a1a7ec7e855673977773f1617e6d880708eb7f6c5fdb505d8849538f59e1c92f383530bb8c5c1ed438be442f50df9f157242cb493614d423d6eb -LLD.v14.0.5+3.x86_64-unknown-freebsd-llvm_version+14.asserts.tar.gz/md5/9344e0cae0899f671173bf2c5121ba62 -LLD.v14.0.5+3.x86_64-unknown-freebsd-llvm_version+14.asserts.tar.gz/sha512/879858cce846728465c96f3edfd00bc0d0646236d08ee7ec0d2f7566ccd1ffab73d4cb820d2724374c39556122ca0c3defb4ff1c5be9b1ff85a9cdd8d1f2bfdf -LLD.v14.0.5+3.x86_64-unknown-freebsd-llvm_version+14.tar.gz/md5/378f8b32cca5d88eb029598ebaf3076f -LLD.v14.0.5+3.x86_64-unknown-freebsd-llvm_version+14.tar.gz/sha512/2fb6c177a1009d0e09119888f7785e041ba3fb023a55d66eeec643bab01db60c4ddf6f026637ada6cbc69544ef3ab30922cc978ef4c60077dc813f6fe951cbb5 -LLD.v14.0.5+3.x86_64-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/md5/a107c199ef47fa47d4e0fd4c86f057ea -LLD.v14.0.5+3.x86_64-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/sha512/ad212fcc21e421da9b90af5fb8f547127eb7ab477f8ac816543410411ef227421c0aadb49cf944babe5dec22d24468953fe5e52e797c59669c78dd0630dc72ed -LLD.v14.0.5+3.x86_64-w64-mingw32-cxx03-llvm_version+14.tar.gz/md5/d3360e9403172778432fff5d650b0159 -LLD.v14.0.5+3.x86_64-w64-mingw32-cxx03-llvm_version+14.tar.gz/sha512/503dc5eb26364522a6a49c892c8e470de7985064485a1f04ddf909184e355b679ed8410741123108156f8ea696af3be286119d816f14713cf121ea007546871b -LLD.v14.0.5+3.x86_64-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/md5/2c42b2e72c6507082815457511370450 -LLD.v14.0.5+3.x86_64-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/sha512/99a049e1c2fb3927bf06741f8b54d6a9222d0518668c4c06f90c9d8836d8227c206d81b9c9f6bf8c56489ed4e359abfe463630e83dcd4a6c7f632716987eac74 -LLD.v14.0.5+3.x86_64-w64-mingw32-cxx11-llvm_version+14.tar.gz/md5/da5e8dc90a901cc405bd31a3fcb10793 -LLD.v14.0.5+3.x86_64-w64-mingw32-cxx11-llvm_version+14.tar.gz/sha512/92b66e2f45c368ab736603c06daf520ffda444a09e80368d37d57994183f228854d84ce3efc7a2f03fa5567feb7ed3a28679a4bf42a5dcf3bd37e0b7503f6182 +LLD.v14.0.6+0.aarch64-apple-darwin-llvm_version+14.asserts.tar.gz/md5/fc262d76d2c8b848713b39fda7d55544 +LLD.v14.0.6+0.aarch64-apple-darwin-llvm_version+14.asserts.tar.gz/sha512/86d584699333feeb574e9c00116a9bcfb728ecd905e983ebf02eaeded052c03a148fcaed1b655c07edaebbfb256f376f6451e1167503b235bf557836a9ddf7f1 +LLD.v14.0.6+0.aarch64-apple-darwin-llvm_version+14.tar.gz/md5/cdf439f1bb444adc506fb844230709b7 +LLD.v14.0.6+0.aarch64-apple-darwin-llvm_version+14.tar.gz/sha512/9cefd451e0282d9d787fb79d70430bf811297a81c045af386a0b685f34627a31631d036d1b67dd32360dfffc51450d0498e71a03302e0cbba3e60d45cbd3112b +LLD.v14.0.6+0.aarch64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/0e2d3659de3c546073a52db675b2f00d +LLD.v14.0.6+0.aarch64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/6d52a3b56f3bdbb59addca2c7d4b0776f8f414191579b59938c5715b14b1d1cc1e76b873c098ce98a28bed57a0a97974805f158ec952a83551adb61dbac3891b +LLD.v14.0.6+0.aarch64-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/c319caffaf1ae4271e86354661eac133 +LLD.v14.0.6+0.aarch64-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/f908988258050f06e4022b44dc9e49fd66221abe0c205a92e0fd270705b9b78ad7892ffc9adfc69b9c2a70f955e98678ca65dbcc3ebdd748d08ec1c414e90892 +LLD.v14.0.6+0.aarch64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/69fd74156fd9d4c32596f8ec8743f24f +LLD.v14.0.6+0.aarch64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/04220b61f3a9a93be147a8e73f044233bda56dce7500c2225089c1fd1e64092f8af7d91b9fd41b4f347950d787194e9ecda0fa3f09e9f0dd3f1f0836d39bcc95 +LLD.v14.0.6+0.aarch64-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/0848225be33d9f436d6cab9fe0b1a6ca +LLD.v14.0.6+0.aarch64-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/d1bf4cdb1f47c28f0ceb86606cdf073141e2e5a249756bbc4fb862aa4e3476b9b6c436e994c5702019b82b773c2c3d2f0e78d22a3cdd905e159c9ff753d2619c +LLD.v14.0.6+0.aarch64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/8abd66714f15f7db949da104a1ad0fa5 +LLD.v14.0.6+0.aarch64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/9edb1dcb32e5133634db932dbd04d29256a4ee636e44933f63c1585113b06dfa6b38eaf87b72a4b3efd044a25f0f173083360cdd15bb964d4f8ff3b4d5125d32 +LLD.v14.0.6+0.aarch64-linux-musl-cxx03-llvm_version+14.tar.gz/md5/4c8249e6976e75c7790b8a120a57d8f8 +LLD.v14.0.6+0.aarch64-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/405552d7d102a393c44d3386cef9a2a85916cdcab88b52bf3918f131b860bead5f6aadefb6794a879e9ae553a6b3a6d6444bb900c33acc77c1f79d60c024e772 +LLD.v14.0.6+0.aarch64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/e86955bfda5ae339a22b959d1c97b7f0 +LLD.v14.0.6+0.aarch64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/0cfb78274857b1f5f34ec0407dc52a5ec6083a00d9e9b959099839d7467f5ba304dda8a974ba4f3281b66ec3aee5d7ecf0cc774f26a6d059aeca39d850cdd17e +LLD.v14.0.6+0.aarch64-linux-musl-cxx11-llvm_version+14.tar.gz/md5/b17725f5c189699eb325506325ad7cc9 +LLD.v14.0.6+0.aarch64-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/cf7393cb10d023c7d1a04eee85e706c383ed8fe03b66b2e6a46f5a7cd0e76ef5cf065b94e612f6b46f4e2dade6782f8f2ea2b0885fa7dad2d2c83b049b376ce4 +LLD.v14.0.6+0.armv6l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/73e8e847ec3126fadec0a6ba79974ec1 +LLD.v14.0.6+0.armv6l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/7daface02ef1b12bf738ecc026c33b7568b415b91c452c64125d74db24f97f640a888c313156363de30b78d2c6a2593e3b4d683783b0a63d057b58ebd2a29047 +LLD.v14.0.6+0.armv6l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/md5/d141277d0d02d820c17634331bf0a40e +LLD.v14.0.6+0.armv6l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/sha512/d0e0f145852fbd971ffbab7a92c24e435c581e6945d49588701f9e930d2d16bd6bd598b638b23f473f764bc57248ee9fa5bd725c35249a298ae30063d26ab0b3 +LLD.v14.0.6+0.armv6l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/bfb86c885380c9bf0430ae21c5202057 +LLD.v14.0.6+0.armv6l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/f5d7fc12102e8c728adf271b2ddddc67d766d1ef7477b57f8788c218f568bf93947137c0607008e9b8e8e7ec5c4ba9cc92688b0b8a15af96b3a54574b6d9f3a3 +LLD.v14.0.6+0.armv6l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/md5/054302b380b9b91d0ddfb09426ce44d3 +LLD.v14.0.6+0.armv6l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/sha512/354c10a4705fad5c32a16140eba579603c077e725c35b1085e8d99a7b766b4a732b5b26f44bf4877f7bae477543f38c2222c3e4b610e901bcf70fa54828ea4e9 +LLD.v14.0.6+0.armv6l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/50f02bd884e32ec088f279f99c4536ed +LLD.v14.0.6+0.armv6l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/d0094821adc5254ca279f664199c76fc4754c5b1c4d676053acbd490ce1d84808817218b5e20c0e5a07243eb62e3876ab0b5cbfd1c3e80e0b0343153f0d85bd9 +LLD.v14.0.6+0.armv6l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/md5/ceb31cf8a3315a2d1c9ec314848ae5d7 +LLD.v14.0.6+0.armv6l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/sha512/c83f85f36d61076c366ced1b03009e5695b7fbf77dedafbb5efa42e8a167a7841ad6e5c946d5d614e38f259bbc564bb24edf6a041b85ac52e12a4025d9cebc0a +LLD.v14.0.6+0.armv6l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/2f51541d7a59b166d5c875c14ed9b5be +LLD.v14.0.6+0.armv6l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/a092db3050dbae96a8e85dc5078c13fc415bfaf68800ed8c27871a04da19ac96ed5263366bdcf3f75b42d2c329ba473f1df6a38af3d3968bd1b165f9bdb50e13 +LLD.v14.0.6+0.armv6l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/md5/f2e13021c00a2ce98de6a153a3661944 +LLD.v14.0.6+0.armv6l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/sha512/b1273890b740d9a9fe194d5351b74db261b7c1077e02c02bc6be47b4e61f5b069df248c140e46f5e4a8c735503ffb84dc7ea23f673f3b0943af1667cab836381 +LLD.v14.0.6+0.armv7l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/4ded55f6eae1fa6a54e5765af6b99df9 +LLD.v14.0.6+0.armv7l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/772c087814ba18418357799737ebf650ea5944e9c1a8f6b4c10770cf14f3ed8ea152854532b7975f6326b81d640021a63f8e0334e64ece776e41c5741591ae52 +LLD.v14.0.6+0.armv7l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/md5/bff02de59314ad554f2fd01924a80693 +LLD.v14.0.6+0.armv7l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/sha512/114519b9ee153a495bedd174b42df227e1f41375511c8a4010a06013c73a3aa5db0938d764e0e639ceb86f9f13513c6416b3291f53eadfe0e1ef5b4a93b4ca03 +LLD.v14.0.6+0.armv7l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/70e16637af23ce7f6c33b061e073dafe +LLD.v14.0.6+0.armv7l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/2f3afd0cf1ae8a0c0f331a9dcca0e1e69d7b49397c226f1260ed38b2b5a2d400673578be0371cbb2a028827d9e22e6a8890e34110967250ef0f0f907f63d59f2 +LLD.v14.0.6+0.armv7l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/md5/b00c58a756363edfa9bcc6e26991ec74 +LLD.v14.0.6+0.armv7l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/sha512/6e5d9448272aa69ec72a201f5d4b90b0a4804f654b510c4a6d98393cad3c1b352d6bb9f47b909ecf46a8afb4fc582176f0c26c028203cfc72ed6635255a1da4a +LLD.v14.0.6+0.armv7l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/955be6224e721378e90a5c78c7c0557f +LLD.v14.0.6+0.armv7l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/74c4bb8419a75782721c97d4af893ae4f976ddc7b159937bd6b3a1e00aa63708a227bd02b95685d681afe2955c7bec080873b1fc1fa4507bca24a09edf7adfb1 +LLD.v14.0.6+0.armv7l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/md5/5e3394ef7debe390219a4ce95df29741 +LLD.v14.0.6+0.armv7l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/sha512/17b8f0a257f857093fc70c16821797107b5b1ac62239f28998d4c355e1d0e5541628e917464ad30ffd07f4c8ec3ce262125bcbabb0d39044fad73acdf96ef1e8 +LLD.v14.0.6+0.armv7l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/9de7aad1857b8fffe7bd6476b0ce881f +LLD.v14.0.6+0.armv7l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/876963d34b883ddfa13e59286d08ae7a6aecdf6a35f77b0d12867435e48468b65008d8c8b1f5bd931196076fffde615971efdb3774b5c7aa68ec08b1d6f0ebf2 +LLD.v14.0.6+0.armv7l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/md5/b9ac0071ec9b36819c77529559635998 +LLD.v14.0.6+0.armv7l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/sha512/c6f7112b680c80d35feb633bfba3910405b0fc0914e05fbf5cf8fad001c5868973b7269b467aa1724d6c2b15278ff54a14aa09808b26104f54eb5452e3f78c43 +LLD.v14.0.6+0.i686-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/e387441aeaecb5f587f2e1edef3717c9 +LLD.v14.0.6+0.i686-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/e9b6e42dd132eff9f539108f9329ce29821d8101879d880e7cff587d3c7982c57eecd6e33d1af18edeb18664e77e6b5bca8f62d69fad57a176f7edcd43a51adc +LLD.v14.0.6+0.i686-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/70aea168615be9cf0868e9a504b2e572 +LLD.v14.0.6+0.i686-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/1a555b1c354ee690718ce08b1f736140925b06cee1b9533962ce7eb7f6332bbdb9e25e1281423772e0fdec8d34b5b690eccb6835cf6b764ada492ab20ad5088a +LLD.v14.0.6+0.i686-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/ca1e12e88613e2fa5f70a9b932306a5a +LLD.v14.0.6+0.i686-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/e2b669f1d5f24673f85f95dc53a041c3b5a34b05f3113803f53fddc9f8637cb92867a79fc02b19ce5e6cd99f0c0a7b6d351fd68994b244c1c35a1ed7058cb0d9 +LLD.v14.0.6+0.i686-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/b6833e7ca5dbf8c46ef536ec834b8f23 +LLD.v14.0.6+0.i686-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/995915b3cf655618176a98c41b54a3345797fb5ace72771ce963644dec67060ca84ba20779b94fc4bc48e8688d1f911b20abfeb459832b279ddcfc5afc998776 +LLD.v14.0.6+0.i686-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/ca9848c652737d4119d6f2f1b83bc807 +LLD.v14.0.6+0.i686-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/465c88336259a472fa49c6ce88d7965e44aaf34d0260e38a832f27ed5b99d77d9653c2390dc12f15db549325170c59be108eb9f41f99ef88d5fae47edd538abf +LLD.v14.0.6+0.i686-linux-musl-cxx03-llvm_version+14.tar.gz/md5/07c8437e8af4e120268242fe1ceee853 +LLD.v14.0.6+0.i686-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/ead33174285f85e4d8f40baf2f18c88ea51894dfac528be47db16a4885ad658ac5b92431693ef24690d9a8f7a9de7d3fdc348ea1f505e29f8e8455f1a4e57ca8 +LLD.v14.0.6+0.i686-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/13395b2c3c4077899229e5b7dec5e535 +LLD.v14.0.6+0.i686-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/a3f95af4b499f0b4426a109cafc1c9bb4fcf2a600d6aaedc8472d26aa61b04b1aaa3a801d39e165a9e7253eddca6009006e2b8030dded6e592cae7a477015d64 +LLD.v14.0.6+0.i686-linux-musl-cxx11-llvm_version+14.tar.gz/md5/02f86c3d3e21b8e4de49ee5632d42c1c +LLD.v14.0.6+0.i686-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/ec796d467089ebbb0e5a6085c0f5b15e5f43247335661b22fc95d7656b860ad34bf5dcbc3d3c14898bec871347eee565c18100a872f1150d25120e25702d5613 +LLD.v14.0.6+0.i686-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/md5/055a29a5b3e7bfc69cc4455150d2a765 +LLD.v14.0.6+0.i686-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/sha512/0a51cf1f1b1c825cf397279916a0bdda789dc9f8917a9cca70e10050bd253f286fc296725ccc17651d72c304458356c9e0c7744e85ea0961fd5a895a2300eb26 +LLD.v14.0.6+0.i686-w64-mingw32-cxx03-llvm_version+14.tar.gz/md5/357377a9b28dbe542141528ff21df505 +LLD.v14.0.6+0.i686-w64-mingw32-cxx03-llvm_version+14.tar.gz/sha512/199182506961dbb552cdb7a40bd53dd613f9a15bf824d96813bfcd26e0cce1081651314211f99dbeb7145d250ee90eaad760bdfee27ce8e14cc40561ff8e3028 +LLD.v14.0.6+0.i686-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/md5/50e1465dfdd73cb4892dbc84dc2bd407 +LLD.v14.0.6+0.i686-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/sha512/bac02215501595510bd92f59bc5d6f707a79faa360823afc82893e7eb64b42ddf035ac3083dbe37f87b3dded5c5f06269b3fdedd2ea1eca0a41738178492fa46 +LLD.v14.0.6+0.i686-w64-mingw32-cxx11-llvm_version+14.tar.gz/md5/c86e047af65383a802f9f40f0366486d +LLD.v14.0.6+0.i686-w64-mingw32-cxx11-llvm_version+14.tar.gz/sha512/24dc600035ac9fc7fc94dd47e3bcb197ea64557565a962bffe683ee040a089a4f0a6618e6ff06c9225ec0961adbfc810706d016a0dab659d77d2fcc73c1e302a +LLD.v14.0.6+0.powerpc64le-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/463c8a2b34c01c1964f9090d476ee1b5 +LLD.v14.0.6+0.powerpc64le-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/a2d8da10ad2b81b9fb5563ac98e992a7500d35c4999ff51e30dabf662199b4bf47c3b8191a87c6dcbd6fd3fb7917f680ca9d9dfcab92fc66afda42d93bfe7a1c +LLD.v14.0.6+0.powerpc64le-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/02871a4b77f564a1562fd1b8766341ec +LLD.v14.0.6+0.powerpc64le-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/acf16625e34e0f686bbd02da34515ab9ad1cebbc03fc2cc4793728d153c3d30d5e684179293e0df333bec54c35c02f63b4e8b39373c4a78b4dc496cb84168953 +LLD.v14.0.6+0.powerpc64le-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/6ccd870609a949083245a0a469a256c6 +LLD.v14.0.6+0.powerpc64le-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/e79381809dfbbb457f6ab542aef7bd20e758f92c6306d8efa900f3d951cc37857170fb41d6e264d8fac903aab6b1b3c2cb6cd7b29b12db05df23a3f0136d3149 +LLD.v14.0.6+0.powerpc64le-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/a26d060376eec9f52ca65cc9117de48d +LLD.v14.0.6+0.powerpc64le-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/b7ec3789ae9afa900a332e7d545576995de14ebb31b00ef9f8d16d6f8eabdb8d35a508c283b9dc49cbd2cbf0aa99c0c081750ac9d4d80a1fbff71e044361cf72 +LLD.v14.0.6+0.x86_64-apple-darwin-llvm_version+14.asserts.tar.gz/md5/c4063d74231b368d5e4dec1f8a110187 +LLD.v14.0.6+0.x86_64-apple-darwin-llvm_version+14.asserts.tar.gz/sha512/0cedd30610c042e58a91e1f4a46fc973a781a0f432292d40fd87b4907dde868574dfe7cd372d8a05f7e56e73d507b20df8c89d49b1bcb5edea161365aaed04e5 +LLD.v14.0.6+0.x86_64-apple-darwin-llvm_version+14.tar.gz/md5/09f1070e327911a6eb38e4d7481be776 +LLD.v14.0.6+0.x86_64-apple-darwin-llvm_version+14.tar.gz/sha512/47236e8449a479599dc03d198c28da352139cb62d08b7def13328a32b5209a29985d7f0044c74d716a3458adbeb8ce2845a760bfe3923a50a4d4eab1f832dbcf +LLD.v14.0.6+0.x86_64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/214314e0359316fa00e5a770b55daacb +LLD.v14.0.6+0.x86_64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/b25ef3505996442b5e4d4c20e3cd9b9fdf385b8e86a8f5598616943fc8aef8b96307206d6aa836f3f8d65818806eec6901b1d26fb339320f538e3ef7568b6859 +LLD.v14.0.6+0.x86_64-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/32760e37872e2353c33c175cf42fab39 +LLD.v14.0.6+0.x86_64-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/6b38c31a34cf4b1384f3b24cbf7e4ebb20a112465293bbb37e33bcf06d998f2ccc0393c94a95a1b39147c8e6eba84b107ae934f207aa56512f16e992a642714d +LLD.v14.0.6+0.x86_64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/1e935c8f2b36fb537574c2c14baf51c6 +LLD.v14.0.6+0.x86_64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/ffaeb5160830e5859b2f650d818422b80ca187f0cc43422915bdf1dc0b4ccc4b6d0cc8caaf570105ee531169fc494a6fbc9656ea4ba9f9cade8e38b7ee339fc9 +LLD.v14.0.6+0.x86_64-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/ceeefef634d597e201047041ac330f43 +LLD.v14.0.6+0.x86_64-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/f4b4ba04f2a72744f59dc26d894956f8af267e7b26a34a658fbf6ebf681b5d414775aa7137e2641ef0e9a0600269926c1a45d98d9ea2087677901c62b94cb414 +LLD.v14.0.6+0.x86_64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/a9dbcac1935a74f3bb3ad3a879098ca6 +LLD.v14.0.6+0.x86_64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/7975edea6954b6168de5d05f7fdd5d95bcdd3c826b5b098baff86c93928eb3d9b169b3948fd94f9194f01f859cef1f1bd3db7fb470c7296b0194c37adca1de71 +LLD.v14.0.6+0.x86_64-linux-musl-cxx03-llvm_version+14.tar.gz/md5/b9690d75d244393b4990c68ff9e4196f +LLD.v14.0.6+0.x86_64-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/d062cf3d89bbee1597871e2d7921cd4fef31e955434005f300a87fdb6d1245e399e417da7a1093f99ccf816f22873c517937bf7a139efce350e66a01368c0c7a +LLD.v14.0.6+0.x86_64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/9c5651ed5d643dd3db02a7183453d3f6 +LLD.v14.0.6+0.x86_64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/a6e99cb649cf7d6c81958ba1f2bc8460e3164e0cee4fd5a62bf62bd3040b8641b5665f0eb47933a4f13e1b1034ff6a167938088bac4b9b2eb75dc1060d53fe40 +LLD.v14.0.6+0.x86_64-linux-musl-cxx11-llvm_version+14.tar.gz/md5/6fa5219c6a38dffb193ff53d5b3a3d1d +LLD.v14.0.6+0.x86_64-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/f7191d625f35d8e8a147426c004b1c7bb327e3394b047478c8d003bdbcb1b2da492cfed0c71ca123fea68c500c17d10cb6f157080228ef1517d88a6a2c8103a8 +LLD.v14.0.6+0.x86_64-unknown-freebsd-llvm_version+14.asserts.tar.gz/md5/de8e66dcda15ce77c82350a0c708358f +LLD.v14.0.6+0.x86_64-unknown-freebsd-llvm_version+14.asserts.tar.gz/sha512/ead4dd1b926ad903c99a3ca5280397f1f866356a3c2e0c92143165593288af8e29796cc0909e72123b64c58cc522bc49703f5039f731e8805944f8bc8f318104 +LLD.v14.0.6+0.x86_64-unknown-freebsd-llvm_version+14.tar.gz/md5/fb78f5da88875c423fe9c4e897db7547 +LLD.v14.0.6+0.x86_64-unknown-freebsd-llvm_version+14.tar.gz/sha512/9a667f0d6d1436dcd61e6d83dbd749b5d156cea5b7286667f723d835a93db6409f5c3df3b77e8816707c8d779d9571a7ed1ad764409204a45cd4ff01df252e79 +LLD.v14.0.6+0.x86_64-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/md5/ac4c0898727e017239bce35420ad80b1 +LLD.v14.0.6+0.x86_64-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/sha512/7e80a8b7583c28b3e92c7f0d1c8b8d5b3ffbe00d5df87e3a2c4a4877421f28e4a9b658672684d0f37164209a9e74191be687571db6c498edc902bd104bc2dc4c +LLD.v14.0.6+0.x86_64-w64-mingw32-cxx03-llvm_version+14.tar.gz/md5/b70020b2b3065478ae37e309cf4e9e8d +LLD.v14.0.6+0.x86_64-w64-mingw32-cxx03-llvm_version+14.tar.gz/sha512/56b99742fc2ae442d3d3e3a80339fa016c4b6f53699798aed0351b1e6bf75c8300b18ce2e67416443f7eb8f110f98d3aefadc140d2c9f906e77b69ca349f954a +LLD.v14.0.6+0.x86_64-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/md5/6ec819571dc37ca63d590bc0a3cb4e54 +LLD.v14.0.6+0.x86_64-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/sha512/e0acd7b407f8dd88572dab34e30d385fe23a8c98dcc4550811db5667e182f2ddbe773b992e4f83015033b0ab6c38071ffe0b6f68e0a01e8f9b9d627a233c46fe +LLD.v14.0.6+0.x86_64-w64-mingw32-cxx11-llvm_version+14.tar.gz/md5/0668a79e8d23e48aa5380fff43436d82 +LLD.v14.0.6+0.x86_64-w64-mingw32-cxx11-llvm_version+14.tar.gz/sha512/bd78a518126c715861d7f27993ae26e8082452d4ad18a9d3a0fa39ef46fca8b6e98ca14ec715470161a1c9d64ee71c7ed4c815be1b3c480f1d003ed3377895d1 diff --git a/deps/checksums/llvm b/deps/checksums/llvm index 1dd4bf8d25b2a..905a88f80a2e3 100644 --- a/deps/checksums/llvm +++ b/deps/checksums/llvm @@ -1,119 +1,119 @@ -LLVM.v14.0.5+3.aarch64-apple-darwin-llvm_version+14.asserts.tar.gz/md5/0c76e71a19a34674d60b16d6e4ee05e8 -LLVM.v14.0.5+3.aarch64-apple-darwin-llvm_version+14.asserts.tar.gz/sha512/a2ff10102f3d815fac59cf9deadc7fac4d80119448faa586c8b4b18065395d6c01afdb033cf4df0ee9b6a1b47cfca64a7abf3e516ba53c1b511bd3163e849b72 -LLVM.v14.0.5+3.aarch64-apple-darwin-llvm_version+14.tar.gz/md5/d1a4470e03d01d334fef19961207f904 -LLVM.v14.0.5+3.aarch64-apple-darwin-llvm_version+14.tar.gz/sha512/27cb2bc0ffa2c2a900d82b2a022ab08fadd51049a41e7c4384124f3206dce8ae21dd166ada134097cb62eed1cc6b126a5f1fdb05a7a6618090c1fd4f057057ed -LLVM.v14.0.5+3.aarch64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/b0c4e4f118661a8067c54d942a3b5484 -LLVM.v14.0.5+3.aarch64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/4c03b578fce13debcb9c41279b3e0368f7e8050e4e5706df5981990f5f7cb23a127318c832c45951ddfbdc75b30505312fe0ffa18eb78d8071b6c11ee5715001 -LLVM.v14.0.5+3.aarch64-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/ef2ef9ce8f464714105b110849ddaa05 -LLVM.v14.0.5+3.aarch64-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/ab9f5be73cafa7b25873ddd00554c954e6614ba3a89e8bab5524715a4263994ff9f2294d94bff6967649b21873d46fea39fefc05ae861df05885bb0515103dd0 -LLVM.v14.0.5+3.aarch64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/1e8d31bae456e9f09bd5cc4a31dd2222 -LLVM.v14.0.5+3.aarch64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/1d767fa39a244e84697b96d7f2a8b74838e42f34dc920c49dfa0b90653973dbcc3550d73e49c42da58ececf3e24081257eb3e5a3ddd03218285bada6e226c756 -LLVM.v14.0.5+3.aarch64-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/10256df67e8b054c3eb9265fc0bc6e4f -LLVM.v14.0.5+3.aarch64-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/88bdd4fef3168ed59f3d7c8863ccd7a83d8e22e885cfc0a8dc69900743b30dd3d4d1f20e1d73a1d010cb4fa8fe08e5ec0a226dfcbe4f60f67c9ee26e7778f40c -LLVM.v14.0.5+3.aarch64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/c59f8d15b7b0aee8f05b948d55ec8669 -LLVM.v14.0.5+3.aarch64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/f1d2cf8b039036fd55eb5b8d01d2cd18729b4a8fdbb76c76b8ec4ba7f761ec9b6b350c3dc8dcf9acc1a51419bf401fab16fe8debbab795fc170b01234b85cde3 -LLVM.v14.0.5+3.aarch64-linux-musl-cxx03-llvm_version+14.tar.gz/md5/ef5c22089fbea6a2b3c90aec0b9dde71 -LLVM.v14.0.5+3.aarch64-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/092de108c28788ebb49e757dcc4aa1bb049af91c37bd5b705382fb93c52e0ad8f4d068d1e344ef559c05e8f12333067c423dd175e101145754e68ec730887a4d -LLVM.v14.0.5+3.aarch64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/8f273421d7315363170c4848004110cc -LLVM.v14.0.5+3.aarch64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/6fd617a95efcdc9f8236e1c978a80f560ea5f079bacaee8a9f16938ee13e7d3bab3dbd6d9cbde985c9f0ace866cb2130e7196ce5c2aa29a45561fd32175f4f43 -LLVM.v14.0.5+3.aarch64-linux-musl-cxx11-llvm_version+14.tar.gz/md5/b77f7e2ebdf97535e6c51ecbef5fd15e -LLVM.v14.0.5+3.aarch64-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/27b351d494e2b13aad7bc32555beadf4445740a438b1965a01947dbf616249cf4b91a094b787617660f8d1e4391cd4b8d00770c0127b1c483441be6367d1151c -LLVM.v14.0.5+3.armv6l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/88cab2df0359568e5b0a1c94cd4bc232 -LLVM.v14.0.5+3.armv6l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/849e8bf2faeb6e8d9b1fc49991cdcddcdcd708b0c264134daf6793019eefff2c0f8d8fc9bcc81aa3a0af7c5e3f2879da4dfaf9b6735b4992f0b1d7b63cbe713c -LLVM.v14.0.5+3.armv6l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/md5/2127bde6c442ecd8eb0d4803e15f2350 -LLVM.v14.0.5+3.armv6l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/sha512/dcdd9ae023bba72fc65f01eae537e34b3927e6486a4b2817a26a2ada393645747e4472dcc9df1c9d7b647d463efa2eada9338f3f996caaca26ae835f6a89006c -LLVM.v14.0.5+3.armv6l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/3dc3024b888b8950f2e4515f58932724 -LLVM.v14.0.5+3.armv6l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/35be20253565312b6536c520c003586d6437ad8001da112788a9ba521d7df58d7ebb03385fd11df7af87a77523795f84b37728433f9fa0eb9851e1634662bc73 -LLVM.v14.0.5+3.armv6l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/md5/a75cb433050232df0121a6eee4a8f181 -LLVM.v14.0.5+3.armv6l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/sha512/f55b4d87b6297e3cc6aba4475b2faea80afb924cbbcc0a3006a85d1e1381e1fe9222c3216734692546db8ab66ed77129e963a633d9eec0b07cafc4d63ee07622 -LLVM.v14.0.5+3.armv6l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/292972ee70f04cd9d924dbf978fa2e8a -LLVM.v14.0.5+3.armv6l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/e9e8a38109d7a7e3591ea62c86cdeda0a35bd7e1bb66ea751e120025477144b335b14cebbaa7bbebfde4a6272d77fb0d7725c4affd46f50e042a01e98c95bf20 -LLVM.v14.0.5+3.armv6l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/md5/3e858809fb4e06ef103f5168855552f1 -LLVM.v14.0.5+3.armv6l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/sha512/eeeaa836ca57af5fbf3426d2670dc1828d34f47102ac0a7e360a56649570d98d8a6d062392c69fb25c67a99001c389e5f81536e272cbe64d3645244ca60b1ec3 -LLVM.v14.0.5+3.armv6l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/1dc5de23222aa4ba4d1f47bbf95dbe9d -LLVM.v14.0.5+3.armv6l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/e7fbfda31bab79ebfba178218f7bee4adedd5876d9bd8a9a1f90e6ada5fdcf6256f91fa7bb78682f6ce21ddc690f7fa1e13a7e23d95b3c23260b724da3a31060 -LLVM.v14.0.5+3.armv6l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/md5/dfeb1654bc02f28565d1161a944c0769 -LLVM.v14.0.5+3.armv6l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/sha512/dea0d20a138df2e6a846bb57008b7304b370c22cad62ebb8e2a35c184a7797f6e33e1b05ae9178e9220827c15d6539ea289581462d96f59379ab87aa361d48be -LLVM.v14.0.5+3.armv7l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/c5e72e611913355c3ef38a930d4303aa -LLVM.v14.0.5+3.armv7l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/44fbd792f6923c03000d5b37f9f5a64fa1dda34f0648ca4814fc5a9ba8afd44cb9d20712837a4d6913968a44a277828d0a46c3da78985f659dab55297ee3d449 -LLVM.v14.0.5+3.armv7l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/md5/b63f687a5c91f961a3f4fcab9c0fd672 -LLVM.v14.0.5+3.armv7l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/sha512/a6c0b58d9b1d30fd447397148b2c413d2dd0e203ef9b3a7c018c0456b5558f0b45cc2a9c01ef87bb07335b23ed03add7f2fa557e1b36a38d6792a74521896965 -LLVM.v14.0.5+3.armv7l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/905c8b326ed7953e9acd9472d492d97a -LLVM.v14.0.5+3.armv7l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/39a143eb2f9a5066a756026bef2bf91de43179a3ed255d8420ef202ac4a330baa6637d6dee755bd07a1b30c0f486d1b30a9b1e9e04c4315413b581459390508a -LLVM.v14.0.5+3.armv7l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/md5/e9d641263761ec8470bc5b0eede79f7a -LLVM.v14.0.5+3.armv7l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/sha512/480f31a162cdbd74c2ace36632b5a430549823d37250609480ae871bfbb90fa7f229606266dd30f2d12546472689e83f2ee1d2cb48e3590c101526b79a14c750 -LLVM.v14.0.5+3.armv7l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/edc201b7e4f6d4c450fbfe489a5fe11c -LLVM.v14.0.5+3.armv7l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/a8420dab1d8ad2a4a91c9bcf3563e862bbf9830fc86fda54b79840f54fcb1f76bd89267a708302539480b2e5d070028e27297d2a39a8507e8059116b918f67d3 -LLVM.v14.0.5+3.armv7l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/md5/783e3fed63e7281f8a18e732a5c93b6b -LLVM.v14.0.5+3.armv7l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/sha512/354588e793d5a2127178a4477d01a09200a83e4d4687c6d696ecccd61df9181f42767fb997bdee44be8bb68200a4addeaf6d2ea1b63e4aadf2f43c70bfbe2fb1 -LLVM.v14.0.5+3.armv7l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/529bebf43cd44d1b7106c2aeaa18cb86 -LLVM.v14.0.5+3.armv7l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/c5b92133becc3195e60d8bff69df3aa2e63815a59af847a742cafe862caf7a76bdb615e10c20682962110fa93528d3d4019ea7281356d203e362b2a8c334ea79 -LLVM.v14.0.5+3.armv7l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/md5/60e7e6513b72f8cce04461e1048dc005 -LLVM.v14.0.5+3.armv7l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/sha512/e3ba84c9caf7589497ac8f2ea7a9a0036895a64d0a558acf001d6741cdd3e37f9a94478b7af0f3e71c445d1e7bc006f66bcc7d0e4a1ecceac5114f9517ea63b4 -LLVM.v14.0.5+3.i686-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/bf95645be89d8399fe4897d265130207 -LLVM.v14.0.5+3.i686-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/939ef321b24fa8161c79591eb94de0b3a4b7979456eab9822f5f15772133b8676fbe845705adf51a62d294ab1966e96a377f73911b27aac4f8ad40f1b33d2ed6 -LLVM.v14.0.5+3.i686-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/e36e10322d8157829ba56b8aa5b99a69 -LLVM.v14.0.5+3.i686-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/6a9487ebd384ceba767e52c257a783fd9251f9ce549690dac36f225a4a2d0f4e429077fb68a8e04629ff8e7d9c2134933e73ca4590d9c617b0768f69eb044efa -LLVM.v14.0.5+3.i686-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/347157000cca1eef2f7d56401f0be7a4 -LLVM.v14.0.5+3.i686-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/c664e665c1955efe90a8bd56bd56674886b68e989a166e8c7b2c5bb193e72eea09722eb0a349c2be3e6df288de69ab913a3461bd5be518e75e58d243817bae53 -LLVM.v14.0.5+3.i686-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/6704e2a7d209e5b145be3d9ea0c74ec1 -LLVM.v14.0.5+3.i686-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/534617d76e709e61f97e0f4ca513cd41675eda967b917fd54fa04a9a078b23f056a4283ce22cedce774eb1130944074e630b03797a2f80510b3a84e6b02ae5b4 -LLVM.v14.0.5+3.i686-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/667e01bafb504c62c221bd4fa25c78aa -LLVM.v14.0.5+3.i686-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/f2dc5ced205f20b4cd1ce071139c3ae920a4de42908b2fe76fd260f53cdfd792d77fe34208fa8748f35429a568e3b029b887281738f8d0ec461fe66ede7703de -LLVM.v14.0.5+3.i686-linux-musl-cxx03-llvm_version+14.tar.gz/md5/be3b05de2011f7c2580fb374288cf1e6 -LLVM.v14.0.5+3.i686-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/1da5e45e5ccf42e6367dd087615fafc32d8140605afd237fad6f290afc461cc1bfe2d518cd9d158c3dfa7aac16585d291d598f4c76ff33ec55317fca4b7933dd -LLVM.v14.0.5+3.i686-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/a66b362d166d7f7b8f0d6cfd80849caf -LLVM.v14.0.5+3.i686-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/057ab8545e642c99c2bd9b3a83d2a186afd274187beea0e7fa4f4d09dd52aa742eafc43ee3d1a3ee47714a5cfd52b81e84244a4dd9024c8fc0d312bc29440ab1 -LLVM.v14.0.5+3.i686-linux-musl-cxx11-llvm_version+14.tar.gz/md5/645da8a4129e8e46ea6068553ed5c55f -LLVM.v14.0.5+3.i686-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/4fe7a3e2a64759eddc58d12dee35e3ec338f005d1e228194a7cf80498c3f668fc947b0a759b3c36a245beccb1d050dad6e0775749d1c815752113f7b8459179a -LLVM.v14.0.5+3.i686-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/md5/803b19a812efb8345edb98ec4f86edc5 -LLVM.v14.0.5+3.i686-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/sha512/2075907c0e7a58420e9086639fd07eb8c3197c13a0fcbc6d2306c4f19825601f76634c286e3aef144864749de50b9851a5f7e272fc4ca52a736d58f5c066532b -LLVM.v14.0.5+3.i686-w64-mingw32-cxx03-llvm_version+14.tar.gz/md5/435649f806f37134ac1e6e7ea70fd0d0 -LLVM.v14.0.5+3.i686-w64-mingw32-cxx03-llvm_version+14.tar.gz/sha512/dddcce930128f9ef274c9e395b9993a8930498ca97ef3154ff9545afea4bc694b17fa195e80b2b12580adc759ff37d6d9532c4a76e83e61f95b2601a63068de2 -LLVM.v14.0.5+3.i686-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/md5/0ffb561e2bf17abce26ba75995b0cb27 -LLVM.v14.0.5+3.i686-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/sha512/8a7c127756f9e7af5372a85002399d9ed13712a35ce229b1c2e652a96e2364b83d531bf5c9b5074515b669a72a72a0aecc3ed3be4c5eeda6af440f2d334467b3 -LLVM.v14.0.5+3.i686-w64-mingw32-cxx11-llvm_version+14.tar.gz/md5/08e59f959b5c470695b532d1ee4af51b -LLVM.v14.0.5+3.i686-w64-mingw32-cxx11-llvm_version+14.tar.gz/sha512/dce6729c536dc6ddb0e370eb52f21d99b5b4bb3c2003992ae6d9bb680a9a15eddf6fcca3cf03f47e624e50a4dd4256a6eb51a6aa59773cca78282553b10c8387 -LLVM.v14.0.5+3.powerpc64le-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/13a027a2025374f75d35c88b6c2bac5c -LLVM.v14.0.5+3.powerpc64le-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/2ad96dbcb650edbe61068632822a431c840989b38b2c3d679589f10dc3a51db79b769417f2f3a6cbb940a944151e71750c743304c82e448adf7638ab54bce0f6 -LLVM.v14.0.5+3.powerpc64le-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/30b3a22c2838a716ec4effdf39b5afdd -LLVM.v14.0.5+3.powerpc64le-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/6e365b80dbfc405bf6959ee95097a2bd387f348891722dc9ed1a3f9643576e80cdd0847fc201b964dce91ef7da707a64fc43c9ab2649da83a6c289b570ab57fe -LLVM.v14.0.5+3.powerpc64le-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/6cf789c4993e19f4e718e30e01e9cbe0 -LLVM.v14.0.5+3.powerpc64le-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/021363778e23cad4257bf298ee8cd986e0d2476f7d4ee13262b5227178736df576a69d70aafa5f9c784a0276dd76135d16ac7801eda74b8c908a2e14252f5861 -LLVM.v14.0.5+3.powerpc64le-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/ca941c607ecf5441b8572649270f7a76 -LLVM.v14.0.5+3.powerpc64le-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/d6ef6940b758a53ab5d3982f30454cc6ecc71e57125de951b31cd42399a11bb612a7d7911a3512783bb511805f4a37d14a25f8263e503f720bf1926ef1cf1694 -LLVM.v14.0.5+3.x86_64-apple-darwin-llvm_version+14.asserts.tar.gz/md5/671d4de96672fc9488ecca751efaf318 -LLVM.v14.0.5+3.x86_64-apple-darwin-llvm_version+14.asserts.tar.gz/sha512/160f9e7fb22ded234b2c6256571f25b21d99569baad48aea0723bfcef1481a561f2ba61368502c2b7e716d9d0fbcd3592528fa3e14b83184eea6c8c2d15131ed -LLVM.v14.0.5+3.x86_64-apple-darwin-llvm_version+14.tar.gz/md5/d544e7712b13260c8bc9e6937b6a3d37 -LLVM.v14.0.5+3.x86_64-apple-darwin-llvm_version+14.tar.gz/sha512/cb87e0d4c7bf1802e67d2c27824a45955c69bca02ccd200a3b54f940e5a99a59775a141137374df1afa37a0699de21c8d82268229c16afc7e2da162aca30dc86 -LLVM.v14.0.5+3.x86_64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/7f7301f4de89c4c58fb3a842541594ff -LLVM.v14.0.5+3.x86_64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/9c4087a21960ea392340e0ee8be33fc550459c5890df8d2c4badee4be8b77a88a4830979aacc20d589d1ef030732c7731440331a45c1fbdea247fe18bafcad9b -LLVM.v14.0.5+3.x86_64-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/7fb4d43c3609f96e92eb99a86224cce6 -LLVM.v14.0.5+3.x86_64-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/508238cf0d109d7650f5b16dce1fda03b682ef12de1ada4f691fd72b3da8d82fd594af40c779698cbcc6f3dd8d462ec8eed8c267f850b3ee388a48e8b0772d32 -LLVM.v14.0.5+3.x86_64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/6bf1d3ca75d1301448741628ec0fbcd5 -LLVM.v14.0.5+3.x86_64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/a1dca79ca42dc42b3beb953ae314921646c37f2c0e151d50e4ffadc2ee8145afe8ae3f1a110ce1b73779f649cf4db1e46f03724eaee5e5915cc724997de6a09b -LLVM.v14.0.5+3.x86_64-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/88d2dbb17a5993969cb17cfd72249ae9 -LLVM.v14.0.5+3.x86_64-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/3eb5002bed0f844cf154a6503ee7076bd94aa7989341a0087924d8a211cd73b2c7ab6dab9e9bf09c4b5105a32d8ab8bc39b29f51ed44d7bb0c031242bde00b88 -LLVM.v14.0.5+3.x86_64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/608113f3d254e13acdd4bdbd26e582a3 -LLVM.v14.0.5+3.x86_64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/1b50f6b33915b5661140bc954d619f9e570f54e15d642d66e88fcd06c77a393d246d6556bf1c153612a05b82ac9d335a0d2ce096f77f04f48b60457ea849abf8 -LLVM.v14.0.5+3.x86_64-linux-musl-cxx03-llvm_version+14.tar.gz/md5/1798a3087f3a047f40f3a27bc0628315 -LLVM.v14.0.5+3.x86_64-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/252d35e5cf75b884d5cd274c7f27620e00592f038f87b3ffba83f5e98d28a306f39835be4a108f47418f5707f1f0ef80bb32264cd94cb1ed570beecc622d1513 -LLVM.v14.0.5+3.x86_64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/0f39f76b4885151193d7493a52c42229 -LLVM.v14.0.5+3.x86_64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/817f583ebc4bff25bdeb62e7a12c8536474f84cd77829031b8775f98927beaeacebfc8a38b505b8d0d77127a189dc417624904b85270d1185b0b56c527a97537 -LLVM.v14.0.5+3.x86_64-linux-musl-cxx11-llvm_version+14.tar.gz/md5/89ee73f869ccdf82ebba65d4bc73205d -LLVM.v14.0.5+3.x86_64-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/1fe90e766bc2a024f30bfe59998ec7c4b5424896dabf779e66bbf6e1b1ba624e127625943dddba30657d6c2869d8f5b2ba10fef84f59e3f7bb9c50c683d8a963 -LLVM.v14.0.5+3.x86_64-unknown-freebsd-llvm_version+14.asserts.tar.gz/md5/72b0dfd9e3365203d2bdfbaa43f30d87 -LLVM.v14.0.5+3.x86_64-unknown-freebsd-llvm_version+14.asserts.tar.gz/sha512/054559d7837a05389fe072d5180809da033ba20b06e493aad3c53485a78006f1e7a1d97e764243d6e98d35f15158f4593f64634c79457c56048b70b8a8cd62aa -LLVM.v14.0.5+3.x86_64-unknown-freebsd-llvm_version+14.tar.gz/md5/67656fa6c09567f970d75bcdea7688e3 -LLVM.v14.0.5+3.x86_64-unknown-freebsd-llvm_version+14.tar.gz/sha512/339ccf2096e4284dec118c5c894761b19c38b28c804a65ef279af74269ff7679edc4beb73bb030f52a540bc244697f5e70f5886d72b7c0eae55f756b23e274f6 -LLVM.v14.0.5+3.x86_64-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/md5/3bf399051f7988c3ef75bb8f9fdfb6a0 -LLVM.v14.0.5+3.x86_64-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/sha512/0ec48eca8e98db4abea62d5f44da2a7a2975e6c750533a977ab83eb364cbd190a8708b5eb92305fad4962ddd908bd03d9dd78e3370f1ffa3e52b1a0a7c54b44d -LLVM.v14.0.5+3.x86_64-w64-mingw32-cxx03-llvm_version+14.tar.gz/md5/5de65422f1d56f8db6f57163479f78df -LLVM.v14.0.5+3.x86_64-w64-mingw32-cxx03-llvm_version+14.tar.gz/sha512/0cbbc58ad1261779f0d6d2a81279cb6b9782c0c4100d82b32f83a296c0a009f003097c623e380bfd8f930ef02d032357a627208a9896c177724f754cced4e987 -LLVM.v14.0.5+3.x86_64-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/md5/144d30f32962338e9a7f83d155dd4fcf -LLVM.v14.0.5+3.x86_64-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/sha512/0a6d4e7b0caf941c44b41f5ec32d128e89e8dc77aed09fbe62933683e3757d345ca96df7a0c31bd7efee925150663c4869f183238ce83a64efa22f77f6e6726c -LLVM.v14.0.5+3.x86_64-w64-mingw32-cxx11-llvm_version+14.tar.gz/md5/908b83a1cc9c08796716516b2921be73 -LLVM.v14.0.5+3.x86_64-w64-mingw32-cxx11-llvm_version+14.tar.gz/sha512/07e61338e5d4a0707b6d620a661676aa6ade753fb54ddb913669990a7fff32fa380e6697d04fcddbb7f0c19b437178ee80f63b28b0ab3e58e0e8c5d9a23aee68 +LLVM.v14.0.6+0.aarch64-apple-darwin-llvm_version+14.asserts.tar.gz/md5/533cdc265cf2625457f3655b8589b43f +LLVM.v14.0.6+0.aarch64-apple-darwin-llvm_version+14.asserts.tar.gz/sha512/3a0c96b2fc7c16fc33741933654a564574a5059d806a3999f0c0c0af31f99acc5948ef09edb21eae9f6d4362a7968af55781048029a875ea92a981669c6e8cda +LLVM.v14.0.6+0.aarch64-apple-darwin-llvm_version+14.tar.gz/md5/4fbb96de11f9f64d5bc3f467a36b5584 +LLVM.v14.0.6+0.aarch64-apple-darwin-llvm_version+14.tar.gz/sha512/bf08ae144e7fdc7f5055f98ff2a4e8d5b46670db00ed498cd3323e10df86506172ff41aa6f0815259018168bdee40a73775b962c5f0ba8639c28b18d65cbf927 +LLVM.v14.0.6+0.aarch64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/73e92eaf551cc50ba8b1072ea5a177d8 +LLVM.v14.0.6+0.aarch64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/691090c34cb5fe5217c44f1f7f0a411b733bd8197baab7c5cf2eadedb4a6838bd39935795a7715521c8edcf0e611c6555068b49e17c4b2465201aa1772010bab +LLVM.v14.0.6+0.aarch64-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/3f0783b752b25d2d47b557c3504f35fb +LLVM.v14.0.6+0.aarch64-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/ffce30b3286ddf0c09328b66876bf3c2f2330ec0adf5bccb4039be3f09cd55acead7c34feb6f9473892338768da4fbc3ee8589197f420d89fcfb2039ff15d889 +LLVM.v14.0.6+0.aarch64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/3ec4084b5dcad58981a701fbeaab02e3 +LLVM.v14.0.6+0.aarch64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/cf95a368f5a6b9ddcc368ca91631546a92ab374d9da74aa6e2036d61ac788f8348b50465c241853c37f64608bc2d067b96d17990c03ad71ce69032cc012ec433 +LLVM.v14.0.6+0.aarch64-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/cb4072b14022490456636e0fda20e569 +LLVM.v14.0.6+0.aarch64-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/1750a2be132a0db76db43b91592c5144ede76c5b205693d5eccc2fd340534fd5d90ab358a8c1af08deab8138e6c82d382e3e95c13ba027b1b92b6f955da1ced5 +LLVM.v14.0.6+0.aarch64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/f2f7f1b86007e297c8827d5ab58f5c7d +LLVM.v14.0.6+0.aarch64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/49a9efe8cb1352ae38169a3545ce1cb719d0f7fefc29a24b40fd3d59f99c98483ff33e869e283463f17fb63b883cca792f618296a840eeae82a5855a9dc67e86 +LLVM.v14.0.6+0.aarch64-linux-musl-cxx03-llvm_version+14.tar.gz/md5/24c659a871de64c3f8d54e7bea029e84 +LLVM.v14.0.6+0.aarch64-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/3e4487be7762672a4dfd5f7675945d2b640e81660153036ec2b5cf44fd278266233a94a0cfa337ec11c5b4ad6fd46f80406806bdd3a1f1eb9e3da43184af83d6 +LLVM.v14.0.6+0.aarch64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/39412690e1c3da7fcf4416184feea3be +LLVM.v14.0.6+0.aarch64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/142eaaf10bc19b5e786bd2f8edbab31cd5dfd6045e86c6244239fd7288b7556347adbede12cb40fff02da52295edd85c172fe17ea27126246ff4c8fec05b29d2 +LLVM.v14.0.6+0.aarch64-linux-musl-cxx11-llvm_version+14.tar.gz/md5/0fa28f8c44961f43899886a6b6b0c0dc +LLVM.v14.0.6+0.aarch64-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/9dae70462e8fab0fdb0cd589470bb058569c5640e60bf74e600821344561afbcbf1191e47df9d2117ff5934bf707e57e67fcb9d889e470531505bc18d996b2fa +LLVM.v14.0.6+0.armv6l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/1de340a831cbfcb7d026a77d6f91070e +LLVM.v14.0.6+0.armv6l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/a36758040ca5d84a514b4764dc60c97e4cb8ff7737d1ffeace3b9f0b0c73716ee7202672291d7bf24da03e193b52292b0c2cb74e200b2eb15b3b982c8f67c3ee +LLVM.v14.0.6+0.armv6l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/md5/03042210289cd06ead94a0d84234d99e +LLVM.v14.0.6+0.armv6l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/sha512/7b16eff41381880a42c6c13f6241aae4184ebd9a5fd696afad4c030f815a210ef54eb877a4e375d9eaa31e53ba71594174edb4c17e60854034e190a6a6ad084f +LLVM.v14.0.6+0.armv6l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/c2de107822fb76243378e9de06278775 +LLVM.v14.0.6+0.armv6l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/e04a608ba0c7ea6bf827aef2f060241c0891908dd495dbdc675db81114f07c7ecaa27c0df630aa1118f56c71b59ec3f81e96e84336cfcf4cfc16464da0871675 +LLVM.v14.0.6+0.armv6l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/md5/58766a44a4f74bba6204c20a6a00a10d +LLVM.v14.0.6+0.armv6l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/sha512/5776b898b4b988d1fc44a7961fd759646aad17d0f4b5a3544857183ae5e863a1f42e632cbbb7712b95fd418a2c680497ba2c23dc8fc5d6080e25ff94ae289646 +LLVM.v14.0.6+0.armv6l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/4a78da7a5b639353e61e47559072e190 +LLVM.v14.0.6+0.armv6l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/82dde74099a64b35e94f53765f2748eb65e815a7ccd51a8d288c37ecc306eded95cc4b424812e9e59f247f3f9183c3a1bc7f244ea51f2d1912445db4611c030f +LLVM.v14.0.6+0.armv6l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/md5/c49efd85a0273ad684d13101f4dcfff3 +LLVM.v14.0.6+0.armv6l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/sha512/af25f90527744970458792697027250f543d8ab1ea068767cd1c240a251492ce33b2211e6850a7cf36f16f6b65ba11ccb799f6bbaa777fc92c51785d0188e101 +LLVM.v14.0.6+0.armv6l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/167f874b6eae226e02f32c7ac5859b2d +LLVM.v14.0.6+0.armv6l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/1a3b0b128b5b8fa26509d3b814f03ed1f1a6cfbc0017e5751761d0aa3b3821dfd4165e7687b09ba03d11c29ea533d866bc435e7187c1816405df37f897ae6d2d +LLVM.v14.0.6+0.armv6l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/md5/29f396d657b0e5340443c71d59faf366 +LLVM.v14.0.6+0.armv6l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/sha512/d43fcdded977428b5938aaa6b6443326cee9b522ceaf5d871c0ef783773e20cd955baf95d0639db7273a8fcccaf17259b05d77a347aa6ac481c446969b436f24 +LLVM.v14.0.6+0.armv7l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/c17e06330348f30d3f74f26db2499612 +LLVM.v14.0.6+0.armv7l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/ce308261d0be8f4cdf3c639085a38779a214abfe6bfa38626810f9e99c696b133af20a592ccf9a301edd2a05a99195154a76910d8a120178764c8692ec9dc4fa +LLVM.v14.0.6+0.armv7l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/md5/203772b8f6063cf6d8d4a7c249fba457 +LLVM.v14.0.6+0.armv7l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/sha512/ed7574ab6915db25c0b9675be8ab8db04f71cfd775626cf67142d82a2b32f73ba5e3689108bc10872863bcb6672b2cce3502e1bd941ef602559d7fe2c9d8d4e1 +LLVM.v14.0.6+0.armv7l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/6a08b5cec8c3147ba678db787fc4d2e1 +LLVM.v14.0.6+0.armv7l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/9e8c77bddb64c0bac8326750e81cecc38d54168e1d7760f69d17a1bab4b4b69305c2a75e03f5f10e40a2b2bdc0f07eb2cd5e48e3f8630722e7a30940091c7a69 +LLVM.v14.0.6+0.armv7l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/md5/b018658105b8ff058a1c8aa04654e895 +LLVM.v14.0.6+0.armv7l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/sha512/a182645261fba4d41e89473fa18510778c236c27ac8bc5db1cebdfc1da2617e9b4b940f08045b057c271d44b9a61caee24f4204e1a98cac2c2f40284f14c3e05 +LLVM.v14.0.6+0.armv7l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/7100005784dc8202c966c4d9b0f8b4ff +LLVM.v14.0.6+0.armv7l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/f38e939bb1cdbb4d895cd8300022094e16b1940eaa450b4098c6822126e83389f52235dbbb22fa776930ef508770db074f5f378848057c693ad1690337ae43ca +LLVM.v14.0.6+0.armv7l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/md5/4c8003cb2fac076627ec325340792f5e +LLVM.v14.0.6+0.armv7l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/sha512/cdb25936c38077b0b486821158a06a0d182e756cb7567cc9e0b0e696fcb10bc2597c41e7ae6316f4945771ddb18a03864ea2ee6ca93cd1eb737eb365933e3a4a +LLVM.v14.0.6+0.armv7l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/f6e0156ce3a0dd264668aeea0b6acfef +LLVM.v14.0.6+0.armv7l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/01c31900e79786b719d535bb1f57a36e54d56f0690361771ede98f2806fa30f825dcf6d4c176b33d73940c838d8e69440dd49180d3d29954ae02e1525ad05708 +LLVM.v14.0.6+0.armv7l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/md5/5ed27717d90e862b22226a11bad4696c +LLVM.v14.0.6+0.armv7l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/sha512/47a8e6aadc5e736f4b78ff059c628488a685ad3d97a0ac2b8c5d048b116dd0116514399d66983f3f519e8701ea4a851986b94b17405ab31480f09acbd0edf9c0 +LLVM.v14.0.6+0.i686-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/7d154fd2adb1cba4312fa2ee20d2147c +LLVM.v14.0.6+0.i686-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/4a26b459baf5ba801ced522b4575c81328c9212cce9dbd1af233931c95c9b6d869e81964778dffb5d376dc4a258adb8f2986c868d9c90f480d6fdc021f252187 +LLVM.v14.0.6+0.i686-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/0deb9f1cb47d683fc4250071bd9490fe +LLVM.v14.0.6+0.i686-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/2717b2c15b715de323d4a7d914f191e017aaf38224e41554f60c68885b1aad625fa8fa8b3e305e8703e8772407284d03d229cb2d2f9ff219d7dbe5f91366ee9b +LLVM.v14.0.6+0.i686-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/4d9a0d826ea67ab20769999783641abc +LLVM.v14.0.6+0.i686-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/7cf33e40f6672703d88e8a0ce656e955c4a7d010b857cef89f7dc56291b1af1003c0dbb5ab32e0285260216b58e30a38cb78da28d1bf08ee66cd7a8218a835c9 +LLVM.v14.0.6+0.i686-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/54736c04b06b3e1f27673c5b552fd8de +LLVM.v14.0.6+0.i686-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/942f8f4c4191b9ab75e2a03174c0c1241c4c6af06b6f5833fd0c56d57ad195b45374af80089fdb1e2e431f9cbf256a7856ede7e8f76712e0d3189009cae5995b +LLVM.v14.0.6+0.i686-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/9738446d7d909cfaed0658cb104526b8 +LLVM.v14.0.6+0.i686-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/8c8db654a9d2da00195ec1e1beb89f10447a0a73e8d3e055b456f0f7d8e1dd90d7873ef9da2e2b27528b316b334166f2286755abb33acfc0a9eca06b23a26b0e +LLVM.v14.0.6+0.i686-linux-musl-cxx03-llvm_version+14.tar.gz/md5/16134c865661a0f29d9cc693ed3d5510 +LLVM.v14.0.6+0.i686-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/173407929822c567e7841f24040b82d9981c6bf176717df6942d14ad00757871c1d2a81ccc4467abcad59a1d874d611b7cb5f0cff83898a74fed637781ae0a5e +LLVM.v14.0.6+0.i686-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/d9a7eda0ebfd108c6a1cf435674be3ba +LLVM.v14.0.6+0.i686-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/381bae57c71c387c4608de3cc8a3477b826461a8df1b98fe06259c4a595066a816e96c6731565ea1c3166377a0d9aff722a483e47c76ba01293d408f2eb3b577 +LLVM.v14.0.6+0.i686-linux-musl-cxx11-llvm_version+14.tar.gz/md5/0d312cbea5545a03a49dabcf7519191b +LLVM.v14.0.6+0.i686-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/39c86e52d6298408fee6ab3de6416b710b782ec0810602ec76eb76a87facab57abdc9d8a60be9522c0665766a24ef0af8c83437493b778f028012577188572a5 +LLVM.v14.0.6+0.i686-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/md5/bf5eb915b604825b04ca84b1ec3e9f1d +LLVM.v14.0.6+0.i686-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/sha512/0907a5bfb790c34a8acdd28aeb28ac36a6bec25210b85e2f617f7145ebd80a3d6d4718c633d45411218a5d49545c0adf69c922c19c4674b2db527ce7e7a0d084 +LLVM.v14.0.6+0.i686-w64-mingw32-cxx03-llvm_version+14.tar.gz/md5/0972a1aa6efa0accbdb1be9b799aaa6c +LLVM.v14.0.6+0.i686-w64-mingw32-cxx03-llvm_version+14.tar.gz/sha512/4bcfd7cabdd5ce119cd848d8838644c8f4ff189e2998b4d3ae69193cc9c64ccffb31d08d66b2f81f86876b19266c6d2c362314f539f0612efb69b6b6df981469 +LLVM.v14.0.6+0.i686-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/md5/df4f0d07cdf26759104686d4f36e2818 +LLVM.v14.0.6+0.i686-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/sha512/5983d1e9c1a072045c773dc438da13715faad6e0999fa9a3405821a4922ed8fab666186bf1a8dcc45743e27e5065825df8bc92a06cf3321354aaf022191f35c8 +LLVM.v14.0.6+0.i686-w64-mingw32-cxx11-llvm_version+14.tar.gz/md5/216857bad881f6a50678e2079d93f9bc +LLVM.v14.0.6+0.i686-w64-mingw32-cxx11-llvm_version+14.tar.gz/sha512/17cec3034d17551eca798b6e6fc355f746ef71ce2337439b55c2f55b63f0f89168cdadfea578d7971bb1f6eb096bee47e94e34f85ae99d88e39d2052d2a51a6a +LLVM.v14.0.6+0.powerpc64le-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/a2b9db6135bafc8f80d275d676859d13 +LLVM.v14.0.6+0.powerpc64le-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/bb98b51aa3a3e2f4f58ab6ff0ad36536e4455a602045f811cf30e04e87efc4be4be27b905fc1716b4ed3e2971a5d9b4bd41c438541288ed4240e608adbbbddec +LLVM.v14.0.6+0.powerpc64le-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/a3a189210c2b6e2bd32ad7ee6d353a82 +LLVM.v14.0.6+0.powerpc64le-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/3304170ea4c369f24a99e6249401a2ed078693c9e6444a03c65dd033bd539326f0444e0ea71e4d8e84dda9cecefb46b7fba87a302365497115e4359370b5fd76 +LLVM.v14.0.6+0.powerpc64le-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/dc0be3ad6e188d471bc1b0f7a07aba35 +LLVM.v14.0.6+0.powerpc64le-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/0d9eef5b33ce0bd2bd6d7467d198e2f00f6c31ea0cf116491e368c78882f8437442cc18663d96f72e99fe201041d08e79d61c13b3998fdecffb1a7d6f2843a35 +LLVM.v14.0.6+0.powerpc64le-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/2563d77bfb2317192f5cd0a00148b6cc +LLVM.v14.0.6+0.powerpc64le-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/d0572501e91cce51d662a1a6c780adf148f34e0f4a151c1fb7bb55bc064f7f6f29a6423715f9e2332205e50f076a561ca4b0992e834b234a77f7709ab4c92786 +LLVM.v14.0.6+0.x86_64-apple-darwin-llvm_version+14.asserts.tar.gz/md5/a096186819d3f06c70d40498aafc5879 +LLVM.v14.0.6+0.x86_64-apple-darwin-llvm_version+14.asserts.tar.gz/sha512/67c83539c0272d090e1a2221748eacb4fad15350bfc84f7839227d623ed234878752c38f412f0396b1dacae1543dfa9323e184b98cdec3fb9b436aa8a907bce3 +LLVM.v14.0.6+0.x86_64-apple-darwin-llvm_version+14.tar.gz/md5/c5402ce51e61f4aa46dc56942c374746 +LLVM.v14.0.6+0.x86_64-apple-darwin-llvm_version+14.tar.gz/sha512/f9072dab2ee52b5d8116cefbc32b023745860af644de867eef658d0fb9308d5868a5a871489c399cd95efcef9075c7a20b877933e9a243454f0819b4b0cf5213 +LLVM.v14.0.6+0.x86_64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/ec70c50570a56b50df05b140f320c475 +LLVM.v14.0.6+0.x86_64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/df598d58bb083634b298edc0e4e9006ebfe76029206fda10a58481be1872ea42ee441ebd3c36dd59490c66e89d9db0f610799be4b5d4c96dc315099e2f19728c +LLVM.v14.0.6+0.x86_64-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/4688e7cb1c73e5957e0ecd0cc14ed53e +LLVM.v14.0.6+0.x86_64-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/b825067f87d3bebf6e50a472ca6629cce7272579d473e36231bb2b765e509d4fd23cb899ad14489ace12f5ba8531089392d5fb9f3541351b162664eb63ab1390 +LLVM.v14.0.6+0.x86_64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/d9762bedfee132f62012b31c3cc4719b +LLVM.v14.0.6+0.x86_64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/29a2f8b5e4084d1c10aa15ab7d25812508233cc53c1dedac89d5951bf6488641461507fd769be6e4449fe435c17e933c6a295b00093f158dac97b92b448cb149 +LLVM.v14.0.6+0.x86_64-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/c68eaa7c015201a8292e1f1d8cc65fd6 +LLVM.v14.0.6+0.x86_64-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/ccda3083ec0246969824d8c5cfdcb965585fcd1d38306ea160024259e54a433e421d058b6ac2a924f091e0042010ee0512e51af928a6b0762bda0cdb7f99f120 +LLVM.v14.0.6+0.x86_64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/853391923e6372c3ec18ff5a44c338aa +LLVM.v14.0.6+0.x86_64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/166189bc0b81ca270bb017e68cdb05d4c9d1d1664bd9fd24b9bc49e14dc1d811fc6565958628a062b509f8784d42632603de31df1d4bf1b1e9ef9ab9c5656122 +LLVM.v14.0.6+0.x86_64-linux-musl-cxx03-llvm_version+14.tar.gz/md5/2907097b73dcc8d8999b1df921c4b75b +LLVM.v14.0.6+0.x86_64-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/6574d330914a1535b6e1be83f889c6a2cdb474e83ddf00315662a146f1e29657bddcbbf261315446f749c9859d8fc496be084f3dc56572367b0ad8d25f09f06c +LLVM.v14.0.6+0.x86_64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/33e00eb48fba5be418d76f1c1d0ace78 +LLVM.v14.0.6+0.x86_64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/10908824a5dda3e69aedd03d0c7695379f465b284b78681d6f8419e7304702ede9c721ae0b54169716abbed429db199450e3fba5b0e5d56e21867defd9573cc1 +LLVM.v14.0.6+0.x86_64-linux-musl-cxx11-llvm_version+14.tar.gz/md5/6f8bc1a92fe8f3e85991739fdefaf1a8 +LLVM.v14.0.6+0.x86_64-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/4ff992b094a6d03256b4eaeebbcbd023a22b54b49976471c16ded0542e1a79e46da43cf0346d54760cd5d18e9b3f108f42f3caa37593a6c1037bcdb4d4461923 +LLVM.v14.0.6+0.x86_64-unknown-freebsd-llvm_version+14.asserts.tar.gz/md5/a3b82c7e8e9af0e7431d7b3a6b3e62a2 +LLVM.v14.0.6+0.x86_64-unknown-freebsd-llvm_version+14.asserts.tar.gz/sha512/8fc9c0d2ae985d4da89734aa4b49fb368d245819c1fd4a345baf354d58a4a0b85d6390e1d6979b5ae757e29fdff58579cb7ab6388c596d9923e80d34fac4766d +LLVM.v14.0.6+0.x86_64-unknown-freebsd-llvm_version+14.tar.gz/md5/9bc7eb74f530e71a3d2dca02a200363d +LLVM.v14.0.6+0.x86_64-unknown-freebsd-llvm_version+14.tar.gz/sha512/3beb680621d3862f18441471cb9318d38da108bb7114423475ca67d3e8998652e4046bf7ffa40692dbb63f377c506e41d3f6c621bc3b1f88366ff0fc6cefe59a +LLVM.v14.0.6+0.x86_64-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/md5/ba22b4e204e585ff18c3cb57b8e2c87d +LLVM.v14.0.6+0.x86_64-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/sha512/037bcf1c9e0fe5faf40c4c5f8a06b9f90fd8ea36d3649f4faa6927df8615819a2231b4393963a8f29070b0dcef6e755106b12f9cdb2a9a61610dab35fa5aa4bb +LLVM.v14.0.6+0.x86_64-w64-mingw32-cxx03-llvm_version+14.tar.gz/md5/e33235975b1a6ec8f69d40ae91d0e4ef +LLVM.v14.0.6+0.x86_64-w64-mingw32-cxx03-llvm_version+14.tar.gz/sha512/1ccbddc51c6d9df883ddb75257fc42ed95c8b3d3fc99d6bbe9aba508e142865bf96678272719f60cb28a3b6f49adf68d390ec50abce47b139e6f7db653537ef0 +LLVM.v14.0.6+0.x86_64-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/md5/a620552217c5b3b5318be75a3ebe31fe +LLVM.v14.0.6+0.x86_64-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/sha512/5703664ffe0587035cc12de3bace722e7c93cb920810a36beab49d456ddc6d285abab70172f95a83e952f5c5254dbe4825e465d2efc905c6798d7c4cb258ebea +LLVM.v14.0.6+0.x86_64-w64-mingw32-cxx11-llvm_version+14.tar.gz/md5/4d90ccd98213c482f202034d16442be3 +LLVM.v14.0.6+0.x86_64-w64-mingw32-cxx11-llvm_version+14.tar.gz/sha512/ba41bc5f229e61a87f517f552fce604ef4fce17523b6b1b856ae7aeba4827f114a0eea73bf05262fd58604fad3e746c8aa54e9fb87cd97aafa50cd9d3396126b LLVMLibUnwind.v12.0.1+0.aarch64-apple-darwin.tar.gz/md5/b95ad4844e649bf46db43683b55b9f4f LLVMLibUnwind.v12.0.1+0.aarch64-apple-darwin.tar.gz/sha512/15e0996aebe6db91fe58121001aa7ea4b23685ead3c26b5d89afae34b535e34b4e801a971f4854d8e1a1fbc805cece06272470622eef863e225358113a127913 LLVMLibUnwind.v12.0.1+0.aarch64-linux-gnu.tar.gz/md5/6d8783dc9b86c9884e0877f0d8ac4167 @@ -146,123 +146,123 @@ LLVMLibUnwind.v12.0.1+0.x86_64-unknown-freebsd.tar.gz/md5/54ac594b4c8e7f261034a8 LLVMLibUnwind.v12.0.1+0.x86_64-unknown-freebsd.tar.gz/sha512/a43756afd92081e6dd7244d162862fc318b41ca110a5e8be6e4ee2d8fdfd8fb0f79961ae55e48913e055779791bd1c0ecd34fd59281fb66b3c4f24a1f44128f0 LLVMLibUnwind.v12.0.1+0.x86_64-w64-mingw32.tar.gz/md5/83cf8fc2a085a73b8af4245a82b7d32f LLVMLibUnwind.v12.0.1+0.x86_64-w64-mingw32.tar.gz/sha512/297a5c7b33bd3f57878871eccb3b9879ea5549639523a1b9db356b710cafb232906a74d668315340d60ba0c5087d3400f14ab92c3704e32e062e6b546abf7df6 -libLLVM.v14.0.5+3.aarch64-apple-darwin-llvm_version+14.asserts.tar.gz/md5/98edfd392bd87c1e4389635dcf6c9b03 -libLLVM.v14.0.5+3.aarch64-apple-darwin-llvm_version+14.asserts.tar.gz/sha512/abc559339a504bb32018ab7204afb4ef20e7b95bc6124dffb45566204242b4b1300131f4ad64f51b03cfd13576c5203785209e26c64d3c82b79fcd1ce2469ae1 -libLLVM.v14.0.5+3.aarch64-apple-darwin-llvm_version+14.tar.gz/md5/c3435bf375e6f9cf8a07264fe17a4fcb -libLLVM.v14.0.5+3.aarch64-apple-darwin-llvm_version+14.tar.gz/sha512/b5facd69b211d021333690b17832dc7812309981c3b0f09219dcecff17dce73df9a4046ace64136ea1900b518fbb87e072cf966ab1dd6be397607461281994d9 -libLLVM.v14.0.5+3.aarch64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/55176f53121207d7aaf5faf15cc73498 -libLLVM.v14.0.5+3.aarch64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/108fe4218d70acb25048401b5f1d3edec28822ec977d11320f0d3efdbb9227552ff13edccccd8049f31939c889c09209d0dd7f4938fc90c3c93eddd686af498c -libLLVM.v14.0.5+3.aarch64-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/c054098b8593c603ca8138ddd1ed7acb -libLLVM.v14.0.5+3.aarch64-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/39fde9044e69af75fff847e22eac3724ecfd88f72af5cb3c98bfd2d89af5c908db128f0f459381cffed1389b596a6e125e83e9fa3597bea364ee2462b0ec3b1e -libLLVM.v14.0.5+3.aarch64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/74c000d9a6bc3d532ed221d193ca8a86 -libLLVM.v14.0.5+3.aarch64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/d2ded5aff1a4ab6fe7274dc75f64cb1d75ffa25bfe18488d73db442628febca2ef518aeb8aed8486a6f5ae3f8fb4ecc401391f47976eeead371cd927fd771def -libLLVM.v14.0.5+3.aarch64-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/29e86e90b883e46cde67f1c402155ebf -libLLVM.v14.0.5+3.aarch64-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/c5cd3b1db10bedaa4f945b6f734dab54cfb6cfee49609a755aa1daab4ca952a29f7306d2c323547462c9fe400b920ba574e8d15e67fab1855bf4933151f84b56 -libLLVM.v14.0.5+3.aarch64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/4ef8699f83cee4f3d6e842d6ba36f9d4 -libLLVM.v14.0.5+3.aarch64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/92b3d20b643e5e9c478bdbd1d1ca8e472385b70b812ad8289d8c5cf605ec213a1c06a7f323aa04ac869be0f5e397979f1981254a58a672c890f8bf45426ca4ab -libLLVM.v14.0.5+3.aarch64-linux-musl-cxx03-llvm_version+14.tar.gz/md5/afbd401226eed8618834863cfa05d04b -libLLVM.v14.0.5+3.aarch64-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/0cdcc194bf01f2e89e759b1074203a9d9a944c263818c7edf4be5ec72bb9864eaca1418f1056144a77f23fe578d368184cf840f0a6f2672713d5260e9d4a198b -libLLVM.v14.0.5+3.aarch64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/a88f7b74c5d3d7a67cf9a2d4b45a0e10 -libLLVM.v14.0.5+3.aarch64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/092fbe034a12494d18bc0c21b3b9d8a43034d1899d216d97a530d3f42c27706599ac3e5fd657ed46d1e8a6dde78e32c5647085b18a046578b17c00f8bca2b7bf -libLLVM.v14.0.5+3.aarch64-linux-musl-cxx11-llvm_version+14.tar.gz/md5/952a6d4749f12b1f8a14362bef24b8e2 -libLLVM.v14.0.5+3.aarch64-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/d292ea3b49ee5ed7cd43ab4ddad2d326e8ff17b7ed231aa2c3b653fb49178729ad4f54693e9d54295fc27020627fe3d098083c95dff71f03b0d8682ccbcfc8d3 -libLLVM.v14.0.5+3.armv6l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/7a0b6016f18d3b50b37ff71d95400fad -libLLVM.v14.0.5+3.armv6l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/943df3aa4b25e62e90aae0a2cbca9ae85060af7407d2aab5d303878070b27636d99eeda39abedb49d3ecd69a032b4ef27da73bf829b4bafb318f2ce27357b6a4 -libLLVM.v14.0.5+3.armv6l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/md5/5cb1f95a46295e7d7456a715ef6eac50 -libLLVM.v14.0.5+3.armv6l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/sha512/c5c2e62a53a8c0adfb1d836dde2c504379f92f091e0ebd763850ef7c0fa4ff90aed9609a2f494fd8b6480552d948a700bf8b53997fa175d78647bea59bd51505 -libLLVM.v14.0.5+3.armv6l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/411025a357d1f8bdacda85dd40984c48 -libLLVM.v14.0.5+3.armv6l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/405242c828bf90b82e34b997e5dde1131c361d640f2c3e1a9b0b6870b5120821e096eca546acfdddb0b03233e6f28fd8b09182e124d8b4556e8ef3046d721c0a -libLLVM.v14.0.5+3.armv6l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/md5/4546ed395724295649ce9b82f5eb3101 -libLLVM.v14.0.5+3.armv6l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/sha512/8335a08f1a84d468b8c3b127b75a2863b39c1623ece869d449f41da79d2c8a24538b97233acc09fee1a6c0d03270ecc7dd6476ef3603709df0b1ba0243269a68 -libLLVM.v14.0.5+3.armv6l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/8880495fa4d6494e38953c754743d563 -libLLVM.v14.0.5+3.armv6l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/d6dcf72ff6d1321edd2675c198a62956de450a9860bce113549abd47855532bb2b7bd7975a0f7acc78c6a965189d6a056ad1d5522f6ac52a4a82cd2eb2db2b22 -libLLVM.v14.0.5+3.armv6l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/md5/5464991f7e0ea0503bace24ca2a64e31 -libLLVM.v14.0.5+3.armv6l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/sha512/3dcf8ee623a5ace0e16b9e6ec37bdd5808639aa740ce9aaee9bd51f2d80855b33bdbfb52d38f4fe0e0eb42a749f814353a23c1e61756863706ae3afee0611d52 -libLLVM.v14.0.5+3.armv6l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/98b6d4a58baeef735e0a6faa3ad69848 -libLLVM.v14.0.5+3.armv6l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/5b17e63010b274ebac1b48804bd81bdd2f229096d164a6d2d3ddce6eef8dbab6e51e598d054d5bf70eb2109d654fa4b1558b4b700837f7d7a5d434f5a752bbe0 -libLLVM.v14.0.5+3.armv6l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/md5/23ff52793b4c9397919735929479bcbd -libLLVM.v14.0.5+3.armv6l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/sha512/16e0d0c3cdc0581b5d80504ed358375bd527027bb9d3ee1d795eea2b4ab2467ef6eb4d960f148d5e26297eb42ab6f5e73300899a9d855c019cf932c7482e02f9 -libLLVM.v14.0.5+3.armv7l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/946cc89e0fa89c19bcfd15adfdbb7970 -libLLVM.v14.0.5+3.armv7l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/4bc0ac1d02f59611683c499371ab1c18f41a1c97ee36653ebd35f7bdb3af8e7701f2c7f5b0975d6584727e9a9e0fce8df5d2d6e1bf0fee8612a950fe47e1c060 -libLLVM.v14.0.5+3.armv7l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/md5/0d46f869321786989a6118a82c3ea66e -libLLVM.v14.0.5+3.armv7l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/sha512/943655c29786deb0c0a19118fd2d26a8213fb030723a5ec099b841630ecf9b28e3ab2de041361f7c38cab8daa81a7e4b594aa6002fd45a38d47345cb4cd0ba5f -libLLVM.v14.0.5+3.armv7l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/9e48541f09174d8b0bf061304afa54cf -libLLVM.v14.0.5+3.armv7l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/d6696877af61426f9c76b717490839762ff3efee2a315c5a0da8a36c3110bb38140bd1e82f09612c33a2682d4d7a056ea2945e2d53a68a1937bb1497f4a60d0e -libLLVM.v14.0.5+3.armv7l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/md5/8a44877e943b6584cc0f4e4aac6d21a4 -libLLVM.v14.0.5+3.armv7l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/sha512/f40f5210a9ecf848a13567933417f92060a1b6c6f42decbfdcd721b38cc24989deea0a2e8276ad1e5611a6e68574aa60b20344ac3f9da862a4c155468d7628c6 -libLLVM.v14.0.5+3.armv7l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/3590738ad44189751814531aa0336050 -libLLVM.v14.0.5+3.armv7l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/f7eb97571370ce5aa5949825cef3139901d7388413d33e654ac8dcfed06fb760cfbcb3d26c87cb2cd8e463bf690db0fedece6c77f270d569a5e549cf326ba84b -libLLVM.v14.0.5+3.armv7l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/md5/0328c1d212e57289448324e5279672d4 -libLLVM.v14.0.5+3.armv7l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/sha512/8d6ecc77db25b437464930d04c6b700702fa245ca32986ecb356551ec9d27c3711195be7e688b5f76c777c08447e931364a2a0f5c652b8e74ef2e589d9dad77c -libLLVM.v14.0.5+3.armv7l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/fc6ef6cffb62cccc308f0af543d23807 -libLLVM.v14.0.5+3.armv7l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/20605f1fdfb4013f79519d03c43b6670cbdb695cf20a886f6c887711acc24f1a3d809ecb71138c9627018fb9bcff32de61a5047e02ed9d87938c002980eeeeaa -libLLVM.v14.0.5+3.armv7l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/md5/6c12380bb7550b57cb5588d0d0f8c9ec -libLLVM.v14.0.5+3.armv7l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/sha512/96a2cbede4243f9805b7aa5140f59a87ed79ceb51870ad6ac2688fa8b99dee1994dcd36e3b4a4187b090ff89e53a4918ee142eea2585b551e1c5868fb1684141 -libLLVM.v14.0.5+3.i686-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/a059315d68524fd58c0dcf5a9769c9f9 -libLLVM.v14.0.5+3.i686-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/94aaf46334f66258f8d0b0f26d7f64d42b14902f85b734b4e5b4c89a3b2ecb0d28a7401f2631be6feb9a7dd5ed84cf0ae6772c80d4e7d2f02824fa5cdaea0b5f -libLLVM.v14.0.5+3.i686-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/8f41556d6404a2056a83731f061ba0df -libLLVM.v14.0.5+3.i686-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/dfac5dbac822f99281d504eaf9cd16859b86640e273a50e309fcdbdd8937169485e6d80cc0cd65d1d6cb33f921147cff3a797ddecfdbdcb41355f07d30652741 -libLLVM.v14.0.5+3.i686-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/82453196fe362154bde0293929c209d3 -libLLVM.v14.0.5+3.i686-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/284621f221c14903a23d495d3df5d930c0b8669b53b5ce728f2eb6f5450ea3aef0c2f31bddaf4dee99eef664dea8e5a212d8febdaccfc87841e525acbd0d18c7 -libLLVM.v14.0.5+3.i686-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/1a34fb25985d6c2121d0b2830fb0ec21 -libLLVM.v14.0.5+3.i686-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/f1a3f93d4c72f9d91f59d6bb34952d803d36386b3deb7909e04151a50d69eb79b3a8cb143ded8c80d02af2defc06cf2b7f317c066ceb56e0a0d36c6d4504909e -libLLVM.v14.0.5+3.i686-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/b6586ebd74d597b00fc8f8c3befc5115 -libLLVM.v14.0.5+3.i686-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/92e18e7f99e31c20aed2034bac9a7a4326d49301e84364d27f6bdba6c10e21e2b232f698d1e3c2eb4763dfb22c243deaec27f94859e37467405054062c0181eb -libLLVM.v14.0.5+3.i686-linux-musl-cxx03-llvm_version+14.tar.gz/md5/8017dc361866f3dcd6e23493196063de -libLLVM.v14.0.5+3.i686-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/ee911d814735ecf1d7d0263dc065b9ab4906cda9ce798def8cf2488b623f28b86b4be44aaddac3d5303277e12ecd5009846c28a918bd466015c7a03649d20b32 -libLLVM.v14.0.5+3.i686-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/06688205d76cb96b2271376b9b12a318 -libLLVM.v14.0.5+3.i686-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/7b81cea8e2ff8532ce205bfbcf01785df82e526373daecb33af13a42cfbea5cf13905f898828b59066231d8985b4e31f49e6cb58342b3c29017e77de360b6f3f -libLLVM.v14.0.5+3.i686-linux-musl-cxx11-llvm_version+14.tar.gz/md5/e9d98d4193600f5fbf41cd473d29422d -libLLVM.v14.0.5+3.i686-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/88237005968960213c7df83dcdc1fc3c383176b04edf352fc5bdbe1a1163e6024290243e2611d3bbb803749a1b74016092510d7b77e8bb7c3fb42ba9cf34a0ad -libLLVM.v14.0.5+3.i686-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/md5/33b3d78789bfc1ee47a9bfc336b63822 -libLLVM.v14.0.5+3.i686-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/sha512/1247c576b4c974ce51f123bab6637e9315a27ae3e0ed0778b18842207a0a9be1a7c321227e8605c88abf4f87b4bd9b5a46c5fcb6b220356f2a4d1044001e99d6 -libLLVM.v14.0.5+3.i686-w64-mingw32-cxx03-llvm_version+14.tar.gz/md5/31048ebd14145c38d3c52954813eb91d -libLLVM.v14.0.5+3.i686-w64-mingw32-cxx03-llvm_version+14.tar.gz/sha512/7057154a2e81ecce0cf32de3db3868d665c6fb07ab42a3aa1070cdd8991e56ffa26b84f44fd94ebf400175d477960e11e6f9ddda3d11529f7ea973d3045a08c2 -libLLVM.v14.0.5+3.i686-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/md5/6e6f02827a77f469306f66187cf5e347 -libLLVM.v14.0.5+3.i686-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/sha512/f3b0e42b72d2fc7ae4ddf413ed00d8cabc62bda54f0159b47735262e8474d95db78da0a0b15ae54566b4b293f744e91060a83187f6b19c41529ed4ee6fe67054 -libLLVM.v14.0.5+3.i686-w64-mingw32-cxx11-llvm_version+14.tar.gz/md5/549c582ceee2ca5a99fd51b947a99c92 -libLLVM.v14.0.5+3.i686-w64-mingw32-cxx11-llvm_version+14.tar.gz/sha512/a159f59a308c67d4d06f74d51696c2301a174a45415f0e6e2426e4df6d5f638b245e95a0038e6c9192c5e2ff59e4e24899ffbc1d2437e4ef226c9a2ace840d12 -libLLVM.v14.0.5+3.powerpc64le-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/c40b3e7c3d61136a622c9fdeb1b91c46 -libLLVM.v14.0.5+3.powerpc64le-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/33720015a37d455e95c9529f0c2f4d8c404e173007072a7ffe8b76e1384e923183f2c8d4347f599478c3d02041e95ba79da87ace2a35ec273b413aefe656a340 -libLLVM.v14.0.5+3.powerpc64le-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/a14b32952d56547d845645d10c8a87fd -libLLVM.v14.0.5+3.powerpc64le-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/c533195eba3b03007985dca7b250a8d283e7948bbde7bad352bfff701e318e383e719d773666d7857a88d90291246889ebb9fde7f3b89de5a5fabe7d640dd8f5 -libLLVM.v14.0.5+3.powerpc64le-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/cdff86b8390e64f6060b629f96c1ce78 -libLLVM.v14.0.5+3.powerpc64le-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/8d964e32c9a4b819aac4ca9ceae4965891c0fa26a8761794e30292a4125ea9cb0d198222509179a9aeaf44ced89b4a3d9ab30a733605b344cd5ed288463000aa -libLLVM.v14.0.5+3.powerpc64le-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/28f3c8d502ca7a0ce0da3bf9e150dba0 -libLLVM.v14.0.5+3.powerpc64le-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/b5ef97031e963b1fc2263a8f0f416b4e8f1dcfb05b908ffd685c9d7f0900dc02feb660c1a59f3c33fc262f373593b13502a55726dfbd5f73b4317132bebb81e0 -libLLVM.v14.0.5+3.x86_64-apple-darwin-llvm_version+14.asserts.tar.gz/md5/70ec5ce09b401585fc01c27746abb524 -libLLVM.v14.0.5+3.x86_64-apple-darwin-llvm_version+14.asserts.tar.gz/sha512/3807a85d3f3ce7a6c8a12765c4e96fdcfb9cbf131e3259c654a34406c06ad81e3cd0ba4230860f0bc070247f6b8ba6318ef1c63c52ddbf83b6a7dca0fe80605e -libLLVM.v14.0.5+3.x86_64-apple-darwin-llvm_version+14.tar.gz/md5/de4258e6b353f38871dbc4a544570b55 -libLLVM.v14.0.5+3.x86_64-apple-darwin-llvm_version+14.tar.gz/sha512/0fcd9052b4fb0e31cdf73972858d9d604dcd30b17e964b4b44e6f99d24e55f46d9539cee45ac390dba2276cd4193fe78d092a620d37f51ff6ce383b0ff098e6f -libLLVM.v14.0.5+3.x86_64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/dd4f9f8c134d7ac1841302de76afb56a -libLLVM.v14.0.5+3.x86_64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/3216ba16930bbf666ad184010eee5f09246066bb5395fe88a0d56c36b309c652321a1b30a50a8c5fee3ec91dd70182f79feeaeb31bd35559325dd2a430225164 -libLLVM.v14.0.5+3.x86_64-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/c9820b7d75a5708227c5431651dfd9ea -libLLVM.v14.0.5+3.x86_64-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/2c78534892429dc064799657d77337d8b253946a955ef3213f052c1422a6f581adf63e6851a51327081bc0172418cbe8d1ce5972451ed062387de495789b176b -libLLVM.v14.0.5+3.x86_64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/fdc36b08e9527c8cc95b042a7ac5879a -libLLVM.v14.0.5+3.x86_64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/3ca6902e487545adc5aa94d64015552f4f899e6fc32ff7387fcad652c32e4c05ed57ed1a51e209066b06692f1f7b3301abf29cea67bda4b06c7488ab1bc3d18f -libLLVM.v14.0.5+3.x86_64-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/8d69f636a36247461dda2bbbdf0435f9 -libLLVM.v14.0.5+3.x86_64-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/f3b110b5beec01208adc3397ec84e2ef867559e4d3d70d2eb2427a26fcc40f42639eabb342d50924093bedde511f27cc51922c47aee3ed42d4bf05bd39ce3129 -libLLVM.v14.0.5+3.x86_64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/ddbeaf2b2a56983d1563fcdc484a75e2 -libLLVM.v14.0.5+3.x86_64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/55136c26c3a8c4c12d328bb2457073138ed747d711ccf46f3c102979bf9b98c9fef28b2c71755972ee4eb70544f3a6ba848643d97b9a01710a03aee56d9fa4bf -libLLVM.v14.0.5+3.x86_64-linux-musl-cxx03-llvm_version+14.tar.gz/md5/c1125ccfc89f68a66c943b06a74c5272 -libLLVM.v14.0.5+3.x86_64-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/42c11d63632d16987ba0d092d255e141ce99a3e2015a371cb886dc5f2e4e376fc6b3cfb9aede106f00c88555a675abd343d1cc737a00cd145d1d19f00d4ae368 -libLLVM.v14.0.5+3.x86_64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/4e7b0cd8d695ee65c984f4c61ad0957c -libLLVM.v14.0.5+3.x86_64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/654b46a1f4c5e0cae0fdd5e4a2da361d72af761a95a33f077f1f9b3216c8a509c2ece0726a4c6954a315d2b85e177e03d8ae7af20bbddb236b02f3b3bd67b836 -libLLVM.v14.0.5+3.x86_64-linux-musl-cxx11-llvm_version+14.tar.gz/md5/b1638db0af4915b809fc68f378ee7faa -libLLVM.v14.0.5+3.x86_64-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/375992b170781b0fee3ecdf06b6b260a6ac93b31bb273fecc44605cc1b1be717f78e494b7b391db239d5ec28b04908ee7fb0de9bf8d2c2d9880588cb15b59e6e -libLLVM.v14.0.5+3.x86_64-unknown-freebsd-llvm_version+14.asserts.tar.gz/md5/d1fd699c1b8c86eb9de58bc7db1fba19 -libLLVM.v14.0.5+3.x86_64-unknown-freebsd-llvm_version+14.asserts.tar.gz/sha512/b06a651189a69395505246eacc64e47fec13b772aedd7773cc5ad27a66babc610396cca108535b00a35c689b59d68450272cca6e63de0121c84ede48280423f6 -libLLVM.v14.0.5+3.x86_64-unknown-freebsd-llvm_version+14.tar.gz/md5/37538a4f484a8732c2a14517aebf6b15 -libLLVM.v14.0.5+3.x86_64-unknown-freebsd-llvm_version+14.tar.gz/sha512/0942865d8a1af33a414b1e6c8f920c629ffaf1de64c030be231404945319d5eeff4df9803d4026af9ee3cc7a141d6c960818880ac21308d8b49d4814b2922eb6 -libLLVM.v14.0.5+3.x86_64-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/md5/90ffc0702fd94f58ae48d2f83221b314 -libLLVM.v14.0.5+3.x86_64-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/sha512/c662b80994a2a9564b625d795a30227864c54f61e3e800b7f3d80711f873fed18eac51dc1a4ee471669694a036d66b2366aba3eced81bcfb8868386485a680a3 -libLLVM.v14.0.5+3.x86_64-w64-mingw32-cxx03-llvm_version+14.tar.gz/md5/a8ef0684805b4e284758db4c68dd12de -libLLVM.v14.0.5+3.x86_64-w64-mingw32-cxx03-llvm_version+14.tar.gz/sha512/ee324ad0db2a1c7e068cfa3d2172cb0e1231005f92a0cec188c5b339e63b28d15053f6703d7230235e4e03853a9b37b5628ddd8dc202e2ffd8243e98f08f794e -libLLVM.v14.0.5+3.x86_64-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/md5/fb4303d8ade17ea5780979e805668ea7 -libLLVM.v14.0.5+3.x86_64-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/sha512/18adc37903181e75af95c6e72d66958e575a0e131e23fae1868b976291a1d340555593292a45e2adb254814125467fe95cd1aebb3ead116afc21f1b468c62a35 -libLLVM.v14.0.5+3.x86_64-w64-mingw32-cxx11-llvm_version+14.tar.gz/md5/ac44022f0b2679433121d745bc76b283 -libLLVM.v14.0.5+3.x86_64-w64-mingw32-cxx11-llvm_version+14.tar.gz/sha512/37fd4f54b6b63dd48664f0b7c3d11de9b14011d66e358d4ad5875bc24ebd707e2bec468814bc40feb174e83846b5e3795f80b6235c57cce9d46afcefb0af5b13 -llvm-julia-14.0.5-3.tar.gz/md5/e774d56d136b7aaadfeca00d9e5ae780 -llvm-julia-14.0.5-3.tar.gz/sha512/1e9d859417838f2705c8a800556f3e4f51355b9e5d954331cd1efda8f5906060d55a28ed20d56d88f0927f86e3137168c244f7ee20c2ddcb0e119d6a69f1d60b +libLLVM.v14.0.6+0.aarch64-apple-darwin-llvm_version+14.asserts.tar.gz/md5/6c5ee2a38d4ea9eedb10ddb182f99e1b +libLLVM.v14.0.6+0.aarch64-apple-darwin-llvm_version+14.asserts.tar.gz/sha512/471559396c160f7c69e39aa027955eeaa585382feccec79efe63e89d63ca2af0008d20fcd73b67444fca8ae17d48f9324f0d5d207eb1b3661f9562f7aeb4534a +libLLVM.v14.0.6+0.aarch64-apple-darwin-llvm_version+14.tar.gz/md5/12d98767b737c33206b8f06923932f7f +libLLVM.v14.0.6+0.aarch64-apple-darwin-llvm_version+14.tar.gz/sha512/08babffaa18e40c0df47d852bc063f6a1bd77ba0a3a73e77e4717c71ddd255ca6ed29924fb78fd61bfed64f29b343818d27da44f43400eb83da391d863473533 +libLLVM.v14.0.6+0.aarch64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/c879bdb130e8a068a8474969ca7f23d7 +libLLVM.v14.0.6+0.aarch64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/2fa94870a8e72222a72491efa584014d06185ee5c9ff7aef75ae02be246cc438f124020cbe6820023ba5cc823fa60188e054c171cfb80d240db7e0414c63c3f5 +libLLVM.v14.0.6+0.aarch64-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/bd13bcfb024f72a2df65afc61a305862 +libLLVM.v14.0.6+0.aarch64-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/999f6199577362a9e607265cab518d8b0b0a9455e6bd7ef4fc80d77f57d81e6cca8ff3f6651eb3b8541d451297c9d85e38a09cb1bfb2960f1d2ffdeda4f657f7 +libLLVM.v14.0.6+0.aarch64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/717afe277d8447cc8c9c354d31541ea0 +libLLVM.v14.0.6+0.aarch64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/5ce37884f45f128fcf814b54b5b7d8cfc0ef2f4ab5dd38cf6bb8acad3d9accd568cdbcfe32f445890a11ddad4614c57e88a9d6c39787f4ee0738c781637811d8 +libLLVM.v14.0.6+0.aarch64-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/dbbd454cc983cfee2fbfd7861117ed4f +libLLVM.v14.0.6+0.aarch64-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/81ea01a7f4d4da96e10abf027e8a2baa2ff8086bf923a9bac82af02416deb543c3528692bd8f470e137669ca58ad05c2224243afca8213cdcf794bb65ed0b452 +libLLVM.v14.0.6+0.aarch64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/0b9e93cfc2e6a72aa3e7f1dee03c831e +libLLVM.v14.0.6+0.aarch64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/f796a029452a6af689b06d0a7b2b746d49d4a95a0edb6b064baa41614c2f16f843cd613f29ced45f1e42d4c600b5ebc435f564adb2ac52632abb397b97517189 +libLLVM.v14.0.6+0.aarch64-linux-musl-cxx03-llvm_version+14.tar.gz/md5/2b259c04529102c161910fcc38ac79ea +libLLVM.v14.0.6+0.aarch64-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/26f97b72b63bd93f71fc1b4dc56cbd66e05f6633bb35f4f033b10a150773e6550127a13bf49a67cc0492b6140ebf01c02254678eb4af9e2832f2c757ba89b7c2 +libLLVM.v14.0.6+0.aarch64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/89e0c9030216fc05b932326ca1d065ec +libLLVM.v14.0.6+0.aarch64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/b35b869afff05ecad66e102b1374b9e51a05284684d01a80259a08496bcd1b0d208b4015e64bb55c24f105bcbae0eaeadf188d76daac9bf0800e446782230ff4 +libLLVM.v14.0.6+0.aarch64-linux-musl-cxx11-llvm_version+14.tar.gz/md5/f61852a29c7f30562b6b9cb660fbb968 +libLLVM.v14.0.6+0.aarch64-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/dd7adb9b8b7a7c8a667a3e021032ef601b459f6afff198853dead00879008d24cc67f6785d6ce1ff284ad9c7279e77e817613af40aef86fa1bb4a57c20006a36 +libLLVM.v14.0.6+0.armv6l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/91c9fc7bfec64c0309c1f3b7126bba76 +libLLVM.v14.0.6+0.armv6l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/d3b03c50a3d6b56b333efca03f7ba0f4633d2a12acf4685fc30cfcedf3d0483e34784aa1715973ace6ed12e0c2bf1a35645b931afa34adfd75f04959509d9218 +libLLVM.v14.0.6+0.armv6l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/md5/8a4893e1a088c02f1af8171dbf1e8be9 +libLLVM.v14.0.6+0.armv6l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/sha512/606861d316759450060eaf81e924b8805494e0303cc8ce8e5b03e09e5c09294ceec274edaacb628eec1ac614ed68f64983b574841f56878b9e308d231ef363c5 +libLLVM.v14.0.6+0.armv6l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/1ed600f5af67def3fadac97fb008ad83 +libLLVM.v14.0.6+0.armv6l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/12b17d567f426260b6d9dc5c352a609d93a2c81c94287163d67628b3b227410920836a01292718052929f22028cc737cbe7885e430164e5b9bad7aa5fe048d46 +libLLVM.v14.0.6+0.armv6l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/md5/7ef417149337a8ef1819dbbaf9ce0d67 +libLLVM.v14.0.6+0.armv6l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/sha512/031ceb1b9928429674f9c28899c6a0b66eb6f517af0760227587101ba0645e31a772619d8145301a10402784763c07a20046a7e455c4b912e3788e192017cf3b +libLLVM.v14.0.6+0.armv6l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/abc563cdf8e7cd16000b0ee872b8aaab +libLLVM.v14.0.6+0.armv6l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/45159941d6c9c7fd4e392e500f96dd7ee74fbda9dd29026463bae7d542bb3eb71ea8c4fca49c1738effc1439e54c166fb72962f3d96e351e811efa7aa1770a7f +libLLVM.v14.0.6+0.armv6l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/md5/24f6b603f9a4ceb4939a662d212249fd +libLLVM.v14.0.6+0.armv6l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/sha512/3ebb6c078939191acd90560d1cdc3ba35d7c1d5b77ea699acb9a739b99fe8a2b832af3f9c98337ce435fca31dc7f267cb287a48ef12ca793fec4ffd1ff98e5f2 +libLLVM.v14.0.6+0.armv6l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/2cbdd592ab2d5a9ee5ccc68f730ef783 +libLLVM.v14.0.6+0.armv6l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/f976047b12cc6f0c09d6996f1986dd03014ae2848ef8287a9889bbc69fbb1e16118af682f83d1f33548ffbaddb6edf557f8b49639d4e63b8d0782dcfebde4420 +libLLVM.v14.0.6+0.armv6l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/md5/f627500b3b0340b3510c105e5c26bdd1 +libLLVM.v14.0.6+0.armv6l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/sha512/3e60bd5d43996ddba4a8bab4e03f3a29370e3bfe147edd61bc26f82b5019e464e8131c20d336be104dfd067e80955f7fbf610e79550394011803b4a941628edb +libLLVM.v14.0.6+0.armv7l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/0eed22f302a580a21105b6111ece2760 +libLLVM.v14.0.6+0.armv7l-linux-gnueabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/e14ac2bf1b5087b904e453ab18bc5750f6a8b17a0e247b4e791bea967b288cd5890af748608ef4dfe74a6fbc588841c4c8c7b58587ba6088cff737f19b15af0b +libLLVM.v14.0.6+0.armv7l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/md5/4f6f3bded0d4fde726cd2e8e90efcb31 +libLLVM.v14.0.6+0.armv7l-linux-gnueabihf-cxx03-llvm_version+14.tar.gz/sha512/a112057ae5b44373101a744ac6d65b4561f76435d7990961f0df692f4b44b792811a96df6d6307dd0abc3c35856ae456ca8f1fabfcc564d8f3c0e812f2793940 +libLLVM.v14.0.6+0.armv7l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/e922fe5db388a4493ea2c19bfb468931 +libLLVM.v14.0.6+0.armv7l-linux-gnueabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/9fa3b3956ac18d1735fc6b78c874415405d808754e96da3bd1a4e43cee7c0f7e6a65fc982f4868c47caf155d4f0f9df5dfee46bdddc6769b641c046d9fdd88af +libLLVM.v14.0.6+0.armv7l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/md5/3f1d64de6acd05aaa93efb2c36fa0d6e +libLLVM.v14.0.6+0.armv7l-linux-gnueabihf-cxx11-llvm_version+14.tar.gz/sha512/fbf7e4d53bd052eee794de903cf17bd3abd570a0a4a98d14a5fcbe4fd2bc121a7ebcf04110a9c1c7907c61ef13b0d972ef085b7c5a294cd9613c23ac14079b1f +libLLVM.v14.0.6+0.armv7l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/md5/9ef224e893cfef52494dc43787963aaa +libLLVM.v14.0.6+0.armv7l-linux-musleabihf-cxx03-llvm_version+14.asserts.tar.gz/sha512/8b8678c14cafe937f3cd4619486c96fee651503571f552d77da9be49f77530d9df98db1863b3970ab3f400b5ca76df538887c2488ba4f6876b0f9853f3edb5ff +libLLVM.v14.0.6+0.armv7l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/md5/307a2e7c5689ed7fa05aac413e932aaa +libLLVM.v14.0.6+0.armv7l-linux-musleabihf-cxx03-llvm_version+14.tar.gz/sha512/8ef7ff87f11c3e6f0daabeab8e4b15e47bbfe3296b7d99aa15a4f2debca7527c5f8dec193bde4d96e0b979bf7438a75c4a6e8faed23acf08debac0ede679f493 +libLLVM.v14.0.6+0.armv7l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/md5/881fd88344cf429e78519c48794e2118 +libLLVM.v14.0.6+0.armv7l-linux-musleabihf-cxx11-llvm_version+14.asserts.tar.gz/sha512/2dae579a7c90d3528aaa30892c0f6f0d7c82c16eaf011bb460602cd80f7b806d114c3417664635919b28ee9c15ef4035cdefed047348472fe8d2190db4af41a1 +libLLVM.v14.0.6+0.armv7l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/md5/ab01cffaabf4c788355e7cb25b51af45 +libLLVM.v14.0.6+0.armv7l-linux-musleabihf-cxx11-llvm_version+14.tar.gz/sha512/c2cd6a426728a5b0dbdcdf7f67e4621aab0f89da1187bc9447d4e5a7cc6c716b649fc1dc957ab3fcc82d2287712ce9d1c1116dea85e0a9324909a68c12484e0c +libLLVM.v14.0.6+0.i686-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/ded7afb1e8c5be1189adcbf84a169475 +libLLVM.v14.0.6+0.i686-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/7013d0d414917cd38144afd7ea90d1718a9084d1b8702bb911060a24a106e3fb9e584094f541aff71dea4961b25698d15c1f9515cb44b137ce855defa5e47197 +libLLVM.v14.0.6+0.i686-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/abb91475af33c6a97948d4af2693d2e7 +libLLVM.v14.0.6+0.i686-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/64b8ae8f399bac84ac092e20597767c79e3427e09b8a8ed8d3292c4d1a233bdef00d2b27b578d1192850b72480e8e9e9fe025cca8aae54208122b492cce1cf48 +libLLVM.v14.0.6+0.i686-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/df2c50462c36e9e3647cd6ac98f4f395 +libLLVM.v14.0.6+0.i686-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/bbd20df4071e221417724091527a54dede73490af03357b79db7a63c2d925a7b2126dd967eff4bec14b27ebe263f9d88d212eed82d7260f693c67ddf0839cfb2 +libLLVM.v14.0.6+0.i686-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/3844c7dd6f9d2e033bb5b98744a23213 +libLLVM.v14.0.6+0.i686-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/380d56a1b872070a79c37c4d02948a008312a6ce262a38a94206d5b4209d9ee07cddc2536adb8c6dd109e4554ba16c490c96dae8307a1f7699d562b0d686d333 +libLLVM.v14.0.6+0.i686-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/294cae70e45a6a28d31dd524ca950976 +libLLVM.v14.0.6+0.i686-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/79cadf16603e388d9d0f9f925403ff7c34a04acdbd02f33dd4e823249f3dd02b6e37edfc247088220b8b333e3a8fd64c4ee267cff9d073c231109ea51514407e +libLLVM.v14.0.6+0.i686-linux-musl-cxx03-llvm_version+14.tar.gz/md5/fff69236c97a34f0fe9d50ed93b82fc3 +libLLVM.v14.0.6+0.i686-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/4f7b03836bae2767ff910c5c7c79dccaae1c8478de597fb81e2b686f6e7dd195acf2140e3be72cae77509be9f25092fe8c19bd64af041469e45cf948a0baeff7 +libLLVM.v14.0.6+0.i686-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/527c35f304ab42a39df7e1fcecec26f3 +libLLVM.v14.0.6+0.i686-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/7ed37d57cf4f61bc29d7eec25579b17f449c734e658ce779fea923ccf997732b4d07c9d8bc68962fa42c0f66d739b8a9abafe0c5efb940e36c4bcf2bf6a1f0da +libLLVM.v14.0.6+0.i686-linux-musl-cxx11-llvm_version+14.tar.gz/md5/504a55204bb0f8b57debd377788aab7d +libLLVM.v14.0.6+0.i686-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/03c3bd280c77356d168fcf5837dbe984f1be225a3576032de76dde1d9bb151e3b63efbd35542dff315999b1113c74ae466cc8d7e52ce12cb5d195b4bd24fca2a +libLLVM.v14.0.6+0.i686-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/md5/3a6e6fa8ad2ea6665b184ecfb8e3f8d9 +libLLVM.v14.0.6+0.i686-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/sha512/21131866e0c4355e9de01c32415b337babf113386c293e55191070bf5b08d64c7cf00d15407e78a01f3a25d557c208774df99d46c9a858e35ce27c5609bf30c8 +libLLVM.v14.0.6+0.i686-w64-mingw32-cxx03-llvm_version+14.tar.gz/md5/ab3b323eee3d22829a74d966ec464196 +libLLVM.v14.0.6+0.i686-w64-mingw32-cxx03-llvm_version+14.tar.gz/sha512/cc297c791c7367756da76b2f0aa4b272a48d4bbd563f50b6e9d9f6c741b1a060bd3d1637838233a67dd12976d27b1d2e9a041cbdbcc42a23f7ca5da73e38db3d +libLLVM.v14.0.6+0.i686-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/md5/0e8c5a7d07c21fa9070e3c9fdeade6ad +libLLVM.v14.0.6+0.i686-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/sha512/3306216a8edb2c91f7bec2fa65737e264fecbb5fa9b6431b493e5e42c9637f52d43018c3126e53d9963c88fc095de26b258e50e3f0a9ca5dd68d1530368e3776 +libLLVM.v14.0.6+0.i686-w64-mingw32-cxx11-llvm_version+14.tar.gz/md5/81922f4a88c94409b117e6fe1f8e9832 +libLLVM.v14.0.6+0.i686-w64-mingw32-cxx11-llvm_version+14.tar.gz/sha512/265aa30a53a68432bc254164598fba8fcd4909b07cfb2a8e80a6d3a71434d1851728329354c8c6b1a5da91559ca0da9718d49b711fb94ec9b974ea5efd97cc3d +libLLVM.v14.0.6+0.powerpc64le-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/cd1ce9719cbcaca2ddf6bec9cb34c2eb +libLLVM.v14.0.6+0.powerpc64le-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/849bce21013282edd2e32e4b6ab98f8586c2d986656498d6efd0092d4db9358a05f2a33c2200c17b1fb6cff2714318f7f322a5cf1ecf9a16c6bac5cac3517627 +libLLVM.v14.0.6+0.powerpc64le-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/0d44242a7516c2808eca52cb54b5d01b +libLLVM.v14.0.6+0.powerpc64le-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/3cea355f8d754cc712f16ad87f24f637381313f18963c8382cc79b3cf0237c4829f9c7d498d57d28c7aef5106ae7dafdfafabe90351ffb307adeb01e43bcf722 +libLLVM.v14.0.6+0.powerpc64le-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/7b93f9f33beee190dbaa71508ef4d562 +libLLVM.v14.0.6+0.powerpc64le-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/55eeba37a5b0724cbe813d5d9ec8e3b61f988c953896cc767866059c8d01e77163526935f16a8e30c6dde17999b2d6ea4088980ac118f6720f4bad8183debfcc +libLLVM.v14.0.6+0.powerpc64le-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/24b8b6e559ea15a6bf90c39e2040f852 +libLLVM.v14.0.6+0.powerpc64le-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/180307a7e17edd2ce4758595afa784cccdfc2b09d9a1c601a69ca3a0ac1be420bc1990b8773209410e8da5c5fc81bc3a2e54687898a6d3ef0d496a27a8b27222 +libLLVM.v14.0.6+0.x86_64-apple-darwin-llvm_version+14.asserts.tar.gz/md5/a74e1d380cde9950179a4b6a8e28ca61 +libLLVM.v14.0.6+0.x86_64-apple-darwin-llvm_version+14.asserts.tar.gz/sha512/8f8ff44ed42b5315949d076b73abe91fdf958fd82a337dd15dd71182038e1643337159652e5fd911323af21a4668e46d3a401d85774f6d33fac982945d77022f +libLLVM.v14.0.6+0.x86_64-apple-darwin-llvm_version+14.tar.gz/md5/85b65eef488ec075920048bfa6d9a7a1 +libLLVM.v14.0.6+0.x86_64-apple-darwin-llvm_version+14.tar.gz/sha512/cf865396678dc95b9d514c286fdbe85ea2a74715f5888e4392250770eb9556e354ecd9e52fc28864df88f87e06b8b39c6b403eda2bf9efd46d205f4c982e1551 +libLLVM.v14.0.6+0.x86_64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/md5/411a28efef112b63a7e2cc5a7fa79432 +libLLVM.v14.0.6+0.x86_64-linux-gnu-cxx03-llvm_version+14.asserts.tar.gz/sha512/7d5eb694dd50f9f02d2cf0b2787c66f6b824c3928616759509326c7d85578f984d29ca888d3366cec9584466fcee063f236dcf0a353df280f7abb79352930f96 +libLLVM.v14.0.6+0.x86_64-linux-gnu-cxx03-llvm_version+14.tar.gz/md5/1fa0b4eefa8a57c858dbd9788d222741 +libLLVM.v14.0.6+0.x86_64-linux-gnu-cxx03-llvm_version+14.tar.gz/sha512/8c1b075ea01b661da518e309d521636c8e0dbeeaad688e9220db8b22965172050b9a0edb3b1098c3191873a516d03ab86b495550933ac680300ec0b42d3f31b3 +libLLVM.v14.0.6+0.x86_64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/md5/b4f68d0b04db7c8021a180fe1df14768 +libLLVM.v14.0.6+0.x86_64-linux-gnu-cxx11-llvm_version+14.asserts.tar.gz/sha512/5c43368be28fc7cfa14ba03cb76b3a30f854e2c34d6b2ba3b9d7887dd2f0e4944f16b6380617bf080fc7bd760629b87f1292b49c07c684bfaf33ff9a48ba22ce +libLLVM.v14.0.6+0.x86_64-linux-gnu-cxx11-llvm_version+14.tar.gz/md5/e3b764196550adc33db2c15a74402dc4 +libLLVM.v14.0.6+0.x86_64-linux-gnu-cxx11-llvm_version+14.tar.gz/sha512/1822f35862887d00c162a8fc39e70d9fbf73ff6f2fd5bed44b678a1f983bf20f7a11d524e7bdbd3774d919392b061d1f980dcc12b306fc95cd456e984e81d2ca +libLLVM.v14.0.6+0.x86_64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/md5/2d7837e11d7e65ca30878c25b38ff171 +libLLVM.v14.0.6+0.x86_64-linux-musl-cxx03-llvm_version+14.asserts.tar.gz/sha512/62be4f20d35aa6efa2d52858d66150205f2b5fc1fc5faa2a49a48b27e78fd1587ed4b62123cdb25486d6a6f87951e628a45356df4263b7bdee820c850b727fe2 +libLLVM.v14.0.6+0.x86_64-linux-musl-cxx03-llvm_version+14.tar.gz/md5/65d72c92bbbedb202c5e26fb4bfab6be +libLLVM.v14.0.6+0.x86_64-linux-musl-cxx03-llvm_version+14.tar.gz/sha512/2ec91bc32d89d390d104ff248440435df9cc73d7df79892f93b800feede8bb8d43f2a3e6d4682d72850b038ca75a256d24c7e9e34a751288f89cf5a8d69dcba9 +libLLVM.v14.0.6+0.x86_64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/md5/f2eb226ef29f4ab2fa303f65253dac66 +libLLVM.v14.0.6+0.x86_64-linux-musl-cxx11-llvm_version+14.asserts.tar.gz/sha512/61e2a4d02d113ea9df863a268268d3bdea5a9c9f481b9d4ae6c96a553e7516fdfb23896d4c17bbcfef931689d67daca61ef53f307713f3a583988420dc839af5 +libLLVM.v14.0.6+0.x86_64-linux-musl-cxx11-llvm_version+14.tar.gz/md5/d8cd2760cb5a2a332488a6d8170ce82b +libLLVM.v14.0.6+0.x86_64-linux-musl-cxx11-llvm_version+14.tar.gz/sha512/a11764fb22d64831ce97315877d10c760697b0aa8fd667c6f3763038037fbe220285db20c981aa63f028b4dd13a8b0b57b32be6c792c1afa93dc531aff297621 +libLLVM.v14.0.6+0.x86_64-unknown-freebsd-llvm_version+14.asserts.tar.gz/md5/33343f2e7fa1169eef570305a4d8837f +libLLVM.v14.0.6+0.x86_64-unknown-freebsd-llvm_version+14.asserts.tar.gz/sha512/49b8189e8cac264f0d7cae54d78e65913f4dc047cc51f074a557073662203a96d15ef64452afb8069018f523bafd724951531d6b03c9034cdf16d359eeb9a850 +libLLVM.v14.0.6+0.x86_64-unknown-freebsd-llvm_version+14.tar.gz/md5/3d211319807cdbfb6e405f47ec2a1d42 +libLLVM.v14.0.6+0.x86_64-unknown-freebsd-llvm_version+14.tar.gz/sha512/0173f80d5d6912543b2c3932a47d667449a579aed7f2b291f49bba6dcd0b680705a8f10be6175517fa4e8aecf2cfd027ef15d526bae76c99893f7203b7cf620a +libLLVM.v14.0.6+0.x86_64-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/md5/9018ceb966b33afecd3f9440e75393f9 +libLLVM.v14.0.6+0.x86_64-w64-mingw32-cxx03-llvm_version+14.asserts.tar.gz/sha512/4bdc0e93f7d6be18c3522acbb016dc2e770d96be60a665f118866263366f1d6bc7702046d65e962d063b41b0d24f5a4fd0d4cfa5c4a9758052538e1404801708 +libLLVM.v14.0.6+0.x86_64-w64-mingw32-cxx03-llvm_version+14.tar.gz/md5/f15cfe02c92f22187b71d5f8508a1bca +libLLVM.v14.0.6+0.x86_64-w64-mingw32-cxx03-llvm_version+14.tar.gz/sha512/b73f4932df6c36b0e943d6c6048f7a238aa1d28347ee97b2a7daab622d173c23fbf452a026bdbb26eda102f99cd96a3d09a751a462f201d207dcffdafc4be429 +libLLVM.v14.0.6+0.x86_64-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/md5/dfb780878726fc582a56ff433c27818e +libLLVM.v14.0.6+0.x86_64-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/sha512/59b7a0ecb36288149d19d72e79ab4cb27eba5e873617ca4ae020f281a764345aa9a9226c51ad6dbf8e5de3735ef73cbdd6a0447f7d7c58850fafba3c675695af +libLLVM.v14.0.6+0.x86_64-w64-mingw32-cxx11-llvm_version+14.tar.gz/md5/49fb02433cb908da55ab0413eb91b0ab +libLLVM.v14.0.6+0.x86_64-w64-mingw32-cxx11-llvm_version+14.tar.gz/sha512/f411737f06e3927b199a855802bb840d33471f7d9a011d49fb299916e313ddba10f635ce58080787345f387a9dddd18b368e9f45a233e5ff84426d101434e298 +llvm-julia-14.0.6-0.tar.gz/md5/b262d8da6940024a9f0f717d26023f31 +llvm-julia-14.0.6-0.tar.gz/sha512/19af997a93dee55fd7d53c73d85c29f479ec81343266a81a81fef5321c88455eb3a315c03664f1d9763f2cb3f286f202d77629cf528b3f7ae77d369dc3d2c8a4 llvmunwind-12.0.1.tar.xz/md5/4ec327cee517fdb1f6a20e83748e2c7b llvmunwind-12.0.1.tar.xz/sha512/847b6ba03010a43f4fdbfdc49bf16d18fd18474d01584712e651b11191814bf7c1cf53475021d9ee447ed78413202b4ed97973d7bdd851d3e49f8d06f55a7af4 diff --git a/deps/checksums/openblas b/deps/checksums/openblas index 1523372d709fa..5c9194f5dd404 100644 --- a/deps/checksums/openblas +++ b/deps/checksums/openblas @@ -1,94 +1,94 @@ -OpenBLAS.v0.3.20+0.aarch64-apple-darwin-libgfortran5.tar.gz/md5/036acd7c7b68432f01f2a980bc4958be -OpenBLAS.v0.3.20+0.aarch64-apple-darwin-libgfortran5.tar.gz/sha512/db2c995b09b5ab046491257b44a8806fd5e254bbf4b4df6e9281ffc8d199745a3d6fea912da2fdd657447e194c73db52cf7acb348b49fd37758b6fbbbdfd3a93 -OpenBLAS.v0.3.20+0.aarch64-linux-gnu-libgfortran3.tar.gz/md5/7c5de800082f39fea05d1fdf9cdf2e79 -OpenBLAS.v0.3.20+0.aarch64-linux-gnu-libgfortran3.tar.gz/sha512/78775b01c1f24848da6111d9f4746f0b44f5966aa202af00182c4da649e4b4cf630cd1bb90e8ed32f54dfdbee0f6d03b87c171f03fee9b37886634a20546d627 -OpenBLAS.v0.3.20+0.aarch64-linux-gnu-libgfortran4.tar.gz/md5/eefc198718aa837a04e0f8e6dbdc8b0f -OpenBLAS.v0.3.20+0.aarch64-linux-gnu-libgfortran4.tar.gz/sha512/cdc351d992b795732e02698df8f5f31c301dbcd6d995d2a35790461b08f3c942d70e8f7c031a943873eead4fcbd1e73649aafdfdb7450b955f4848be2e9a43de -OpenBLAS.v0.3.20+0.aarch64-linux-gnu-libgfortran5.tar.gz/md5/8d9ced4a8e441713ceb0d79b72b43ca5 -OpenBLAS.v0.3.20+0.aarch64-linux-gnu-libgfortran5.tar.gz/sha512/b1dfc3f4a539d01266e3e5d400864cd445c4bc561de464e2f6c9eb5704541aa436944f6bfc89be1948e9675f1a83098d77fe52f70886dc90d54206c81f350277 -OpenBLAS.v0.3.20+0.aarch64-linux-musl-libgfortran3.tar.gz/md5/fa63d8009ac2605208ceea9f6183acdd -OpenBLAS.v0.3.20+0.aarch64-linux-musl-libgfortran3.tar.gz/sha512/92b8e2fd2bc45c60aaf8d79c59f96b721d969cd3320c0b04989a5a48099cae213fd4a6aa9dca45910d881e495d87863513b23ee7c433c894655cf72c7b009323 -OpenBLAS.v0.3.20+0.aarch64-linux-musl-libgfortran4.tar.gz/md5/68672f9cbcd9bee92c89b19599897034 -OpenBLAS.v0.3.20+0.aarch64-linux-musl-libgfortran4.tar.gz/sha512/4c19f3cb7afb52cd54c3852fef3815a23e57b5c2ebd9b647ad43ee62191b74474c787b22d6213555f38b8233b96d479631881d522c7bdd544954a9f04b51c509 -OpenBLAS.v0.3.20+0.aarch64-linux-musl-libgfortran5.tar.gz/md5/7fd9458e1482d46f761d6a519999a648 -OpenBLAS.v0.3.20+0.aarch64-linux-musl-libgfortran5.tar.gz/sha512/2e20c845deb5c87c6e02a3512728a27204193a764f8ead1a66ce053b66d03bb853bbf40289727b1b635b17423416a7a69c633242c12f98d3ec1eae5e82a88613 -OpenBLAS.v0.3.20+0.armv6l-linux-gnueabihf-libgfortran3.tar.gz/md5/0868668b73c84e14edb634482d59eddc -OpenBLAS.v0.3.20+0.armv6l-linux-gnueabihf-libgfortran3.tar.gz/sha512/c87f91120db8d3b32cc12077b1e36110f89253fde22aae9de88945fc731ee74271acf31cabac9971635725f586b65cf6b1b9badebcbba5408b0ff4c68b580ccf -OpenBLAS.v0.3.20+0.armv6l-linux-gnueabihf-libgfortran4.tar.gz/md5/9e84b7585acf2bb71781002b2238d888 -OpenBLAS.v0.3.20+0.armv6l-linux-gnueabihf-libgfortran4.tar.gz/sha512/14b57f9d5691997cf01bc6187a1a1d58d07d162ab8eb2a480e7c42f0cff1583161c8b1a059c9eeb83e7ed276c8ffe2e193db001a3b51724e5af24c72f5e33572 -OpenBLAS.v0.3.20+0.armv6l-linux-gnueabihf-libgfortran5.tar.gz/md5/a4768ea555e68fc755da169f1c7eb21c -OpenBLAS.v0.3.20+0.armv6l-linux-gnueabihf-libgfortran5.tar.gz/sha512/490ce2b60cda0b5ed40df103e79b83ab75dd03779ea88b0ae5d3b76acadcf4810b35f69566e396b438d881130e43fd0dbff1672d0383dc7fe275f44574d8830b -OpenBLAS.v0.3.20+0.armv6l-linux-musleabihf-libgfortran3.tar.gz/md5/1a4e7e7cfdefcd878c18bab39b9c80cc -OpenBLAS.v0.3.20+0.armv6l-linux-musleabihf-libgfortran3.tar.gz/sha512/15b512728b49782717770f044958ed3afcd54d6cc70b362a7c96dbadf7599bdcdd157ee021287a70e45957d0a856417540e64e2399cc392b9de55036d607fa29 -OpenBLAS.v0.3.20+0.armv6l-linux-musleabihf-libgfortran4.tar.gz/md5/63ce4aa67d1d56f2cf456285546d3eeb -OpenBLAS.v0.3.20+0.armv6l-linux-musleabihf-libgfortran4.tar.gz/sha512/ac0bd761ef574d3533fa7f6110b9ecf992edf7a68c20fff4faf4b7372d3de4c5ed558119dcdb669296aab5c0da5ce0f51f54abfe998958e1924cfa0eb958305e -OpenBLAS.v0.3.20+0.armv6l-linux-musleabihf-libgfortran5.tar.gz/md5/581bcbd14328d82258511f8b91d8bf84 -OpenBLAS.v0.3.20+0.armv6l-linux-musleabihf-libgfortran5.tar.gz/sha512/be66567c762f70885b187dc8912f83003c69dd5000387b5b82162ba9f47acb17d855f8f5bda2f31d3fc7e01d2aae3cd6b2392632d70ec34f2d648010a8b11f38 -OpenBLAS.v0.3.20+0.armv7l-linux-gnueabihf-libgfortran3.tar.gz/md5/30dfd96f7f3d35df95e70d506f35c9f2 -OpenBLAS.v0.3.20+0.armv7l-linux-gnueabihf-libgfortran3.tar.gz/sha512/84213bbff84899882ab43599f3aeab1c6e3ee8f7158a3873ec2d6a3166e69036c16d742d25c476468f64b6644a2f798485e50427139880f1ae933ad507a2952c -OpenBLAS.v0.3.20+0.armv7l-linux-gnueabihf-libgfortran4.tar.gz/md5/4b82a4e68a43d29538a318763004aa94 -OpenBLAS.v0.3.20+0.armv7l-linux-gnueabihf-libgfortran4.tar.gz/sha512/94d35902c34e6fa68a0648cab65db49650c73ed21d69ee667350cbbb81028413b92fc30e16504648a6b42039f483d327264a3ff39d546cd30241f4672f9300a2 -OpenBLAS.v0.3.20+0.armv7l-linux-gnueabihf-libgfortran5.tar.gz/md5/7e290717c23a468383bd66b46eb58fac -OpenBLAS.v0.3.20+0.armv7l-linux-gnueabihf-libgfortran5.tar.gz/sha512/432cf42a320a265b9259d743eaca75b884663877858149b0feb83948436a941940955c0c89c6de9ca114f0bbf153127a046813195f4669a81cab1ce244cc5a6b -OpenBLAS.v0.3.20+0.armv7l-linux-musleabihf-libgfortran3.tar.gz/md5/f72bf36862607c57fc9cee5dc3f94dac -OpenBLAS.v0.3.20+0.armv7l-linux-musleabihf-libgfortran3.tar.gz/sha512/caecc044e25d2939eec45924d69e64d3854fc54626a56126454fb3855ae2dabf36fc248d7ef9d240f15e8883787a43539e2a0d8dc68fc5c93a094ded94f3b976 -OpenBLAS.v0.3.20+0.armv7l-linux-musleabihf-libgfortran4.tar.gz/md5/66bfd606fc80e02999ad44243d3b686a -OpenBLAS.v0.3.20+0.armv7l-linux-musleabihf-libgfortran4.tar.gz/sha512/b3d76ccf40af1de018e829f5dd696c6d18ad1fd96657a06d190a9d4e939cad5062a3a2ffaeca2ce7f75e822694ae0b817568dd8f115e089a59590bb34af264f8 -OpenBLAS.v0.3.20+0.armv7l-linux-musleabihf-libgfortran5.tar.gz/md5/ef7aca842a623246b4e2876ff28c53ef -OpenBLAS.v0.3.20+0.armv7l-linux-musleabihf-libgfortran5.tar.gz/sha512/a59feb34806d651a2a3614bcc5203407db626e96dabeb6bb12b8d73915cfd87dc02b0e54704c5d0f1b8ab984d85ee64509a934884640d2522fc4a9835989aed8 -OpenBLAS.v0.3.20+0.i686-linux-gnu-libgfortran3.tar.gz/md5/f2ba9ed0f68447aeddfcf3ac883cf83b -OpenBLAS.v0.3.20+0.i686-linux-gnu-libgfortran3.tar.gz/sha512/1b6f300febf5ceeb0045c46cc3d6e9f2481cba2ceb97dcafff1667f06b8b96a2ad4975853e6bc2e3e6715ade28be5fb569fdae005f4fca2140a5557d4a0845ca -OpenBLAS.v0.3.20+0.i686-linux-gnu-libgfortran4.tar.gz/md5/b39347f487b46996de98d9a453ae804e -OpenBLAS.v0.3.20+0.i686-linux-gnu-libgfortran4.tar.gz/sha512/a923a92467b4582f69ec9d96556c8f2ef55a3f99dacecf0491da9740912d14d09a9ba86bdb5fcfbaab87250c57a0c077c2f6ccc08bf3236ba5c7d98822e9c32a -OpenBLAS.v0.3.20+0.i686-linux-gnu-libgfortran5.tar.gz/md5/6d9b4adf3fa54151c45b832b5869409e -OpenBLAS.v0.3.20+0.i686-linux-gnu-libgfortran5.tar.gz/sha512/f15583c15fb4e4b6a38353fbbce2aa57c8f46d58e6c5464a685e5fb0afd76f1bf9b3986c1d34af643a8c9b3a8a24ef63389982c2e8ffbf91a63e8f1ccca2cce5 -OpenBLAS.v0.3.20+0.i686-linux-musl-libgfortran3.tar.gz/md5/fa46f28f624e8c0752bb76abc04a41d5 -OpenBLAS.v0.3.20+0.i686-linux-musl-libgfortran3.tar.gz/sha512/76018ed804f25212760f1128f7d3823a1c8ba72b8cf5d83aa5be5c5f6e3de8076b04be9d5b659af75e3c2fd5cb9a0654dba59651f010534faf174a6c7d836cd3 -OpenBLAS.v0.3.20+0.i686-linux-musl-libgfortran4.tar.gz/md5/48411109935a2ada9d2e336515f36b6f -OpenBLAS.v0.3.20+0.i686-linux-musl-libgfortran4.tar.gz/sha512/9be06c11fb248d6da47dab21f60d1eec6b486a137048f79f2138b5fe6818846ac198da7d73ab93ec161e8861d7e670b587b6eeb846c571497e96023934127903 -OpenBLAS.v0.3.20+0.i686-linux-musl-libgfortran5.tar.gz/md5/b0a81e44dd4a216c60b6ff139512d7b5 -OpenBLAS.v0.3.20+0.i686-linux-musl-libgfortran5.tar.gz/sha512/1b1c3cc5e62af6af8e106c60c59d7ff685d567e93dce19643ba8c0547200000bae96a3473573619ab235c34ff8e65745266001cdc868e948ff3ecaa9ba93389f -OpenBLAS.v0.3.20+0.i686-w64-mingw32-libgfortran3.tar.gz/md5/18988c19ea5bdb81d97f8ce4456319f6 -OpenBLAS.v0.3.20+0.i686-w64-mingw32-libgfortran3.tar.gz/sha512/466d6b05dcf00b6f09c1a8b8fda97a0035838d73d77954f6cd499358e8160af6cf3e8aac97d0f7ba7ced144db1362a9ba126fb113a4469c232a6b9706dc3dc32 -OpenBLAS.v0.3.20+0.i686-w64-mingw32-libgfortran4.tar.gz/md5/d0aa399c07712e9a520a6cb8067bda63 -OpenBLAS.v0.3.20+0.i686-w64-mingw32-libgfortran4.tar.gz/sha512/7c3e0b1c18812719be4d86a641d25d927c9c8cbc6e1571c7a46ca27672ada00cbe3879faf0b5aeaaa0454907551953a20a56be0bc24b651df117532ace2f9067 -OpenBLAS.v0.3.20+0.i686-w64-mingw32-libgfortran5.tar.gz/md5/90d51a2f41c11fc8d1896597dd106cd6 -OpenBLAS.v0.3.20+0.i686-w64-mingw32-libgfortran5.tar.gz/sha512/683c40193ec7a4612c4a36e9d9f6d9443bfb72dbfed7fa10b200305c94589fd75362670d9b4d7646f24b4f7933cfc55a2496030907e2d3fd30b0eed8b6a2d10b -OpenBLAS.v0.3.20+0.powerpc64le-linux-gnu-libgfortran3.tar.gz/md5/30d5022d6f52adccfaf6b3dd837b6151 -OpenBLAS.v0.3.20+0.powerpc64le-linux-gnu-libgfortran3.tar.gz/sha512/433a520458d6804eccf69c74fe357e6d819223b0398007f17420a6aa77a466177d9dcd4f467821b4d99f4397f5e0c1dc0864512a7f69c43f23bc40b6414449b6 -OpenBLAS.v0.3.20+0.powerpc64le-linux-gnu-libgfortran4.tar.gz/md5/2848232be1646333d6d413a588519d99 -OpenBLAS.v0.3.20+0.powerpc64le-linux-gnu-libgfortran4.tar.gz/sha512/edb51d55f602d2a271109dbc12e59e23c232e58833bcc34dd857858d10d318eac99ba300fe4c6480b995e152ff036ff175218a2f4b29910a27f1861543d1e978 -OpenBLAS.v0.3.20+0.powerpc64le-linux-gnu-libgfortran5.tar.gz/md5/8bd4f4d571dc382eaf0084000596276e -OpenBLAS.v0.3.20+0.powerpc64le-linux-gnu-libgfortran5.tar.gz/sha512/f9507f6dc53c632e0f26de074bcd312956b2fb492e9f1d32e3cdf1a6099d6f2b17eea09ae825b2414a28dfbd6958813cffa289fde0a15cf7cba4e6b3653d2a28 -OpenBLAS.v0.3.20+0.x86_64-apple-darwin-libgfortran3.tar.gz/md5/c644f00642c69946d12b8f1f96a8e766 -OpenBLAS.v0.3.20+0.x86_64-apple-darwin-libgfortran3.tar.gz/sha512/2bd51e9adda3e0955ab26c5c178e9a75a8d9c1b4cd2fd221bbb7b9eb72337cd5034f42b53aaddcf97a807e01f2b9836f9be95a5c6517c831374a3b5148b6e380 -OpenBLAS.v0.3.20+0.x86_64-apple-darwin-libgfortran4.tar.gz/md5/cea0d5ad3528298e4512c900a13f21ec -OpenBLAS.v0.3.20+0.x86_64-apple-darwin-libgfortran4.tar.gz/sha512/379ad13b723acde1d2239335c2611a9ebd2abe1432931d4c2395fce9f50bbd5d830a23fd5ea5afc1fc251704e4ed880468abde42bb0ea75b6bb0abb9a7753c5b -OpenBLAS.v0.3.20+0.x86_64-apple-darwin-libgfortran5.tar.gz/md5/bc726288a19a8bdcef3205de12b5f172 -OpenBLAS.v0.3.20+0.x86_64-apple-darwin-libgfortran5.tar.gz/sha512/3e26b8a2075f997ded8750d84e3257b895e7e05adac77d836e66fa7478b43368b7d4b7a458c6991cb642ce0d135b1b507dade7302c4f5a44aabe637849bc1acb -OpenBLAS.v0.3.20+0.x86_64-linux-gnu-libgfortran3.tar.gz/md5/d162add49c7ee74dfc23b820bbd363b6 -OpenBLAS.v0.3.20+0.x86_64-linux-gnu-libgfortran3.tar.gz/sha512/70bcc15f37e4cd822c2f95d8fd23e912829450825399d31c29c00a4ea219ca37f8831d3132ae4b5972fe9ec95c304bd1274a12ec8a8b289b1830cfb7ca0392d7 -OpenBLAS.v0.3.20+0.x86_64-linux-gnu-libgfortran4.tar.gz/md5/f036c51e0954b8b76e3023280144b5ff -OpenBLAS.v0.3.20+0.x86_64-linux-gnu-libgfortran4.tar.gz/sha512/2101747ec254f51fe5c2cfc49ce9599aeacf0d3e7bcb14c9ccaa59d8b0f7e9dcda98ab3ff38973817b736a33ddf654e17748d8a9c3b40e5352a198278484a2f0 -OpenBLAS.v0.3.20+0.x86_64-linux-gnu-libgfortran5.tar.gz/md5/143d8e7cf2fb615ccab6617bffa4acf7 -OpenBLAS.v0.3.20+0.x86_64-linux-gnu-libgfortran5.tar.gz/sha512/6e72144f83cb329301feedea02581a100d137f3b209af4983500c432b6d23cc7473c85a7b1ba90e24965508e74a191b49cea8820b5899793440c3ce067acbe06 -OpenBLAS.v0.3.20+0.x86_64-linux-musl-libgfortran3.tar.gz/md5/871863002d0053784a81409b4581c8cd -OpenBLAS.v0.3.20+0.x86_64-linux-musl-libgfortran3.tar.gz/sha512/908936494c981e14bcd7818043efe979d9522ae1c9ebcd69feb853c46a2249da1cb5292844d0de7276762a21ad8680a1117229f3ad53332b536233d8722c4d85 -OpenBLAS.v0.3.20+0.x86_64-linux-musl-libgfortran4.tar.gz/md5/ce4897980b12374801095fadfad11196 -OpenBLAS.v0.3.20+0.x86_64-linux-musl-libgfortran4.tar.gz/sha512/ba551942563a58fd22d182a29cee83ce5f51db10e52bc8cb27d979dc71632484e1acb713d4304d773c3111d5dba532bd65651374e91a364f8125295acacfffd4 -OpenBLAS.v0.3.20+0.x86_64-linux-musl-libgfortran5.tar.gz/md5/301ae23724b44c1d10e4febdc6738df3 -OpenBLAS.v0.3.20+0.x86_64-linux-musl-libgfortran5.tar.gz/sha512/2f1479b1f1d10682751b025493bc38cd5eb9854620024b1f0ac45ba0f7a7621b4795c4c2f89eece5c80b671387d095b118d58d8ba201214f45bcea1ac64fca91 -OpenBLAS.v0.3.20+0.x86_64-unknown-freebsd-libgfortran3.tar.gz/md5/51088d57d2a9e9e50259128a0ac48727 -OpenBLAS.v0.3.20+0.x86_64-unknown-freebsd-libgfortran3.tar.gz/sha512/c88b1eb662c16b75c46a25959f6fff22de2cfb2a97ff1c0cd482528e83d54a4d8bbf33c3e7d6a79ad75998d0c6d46ef6f245e8ad406d1a072907138d7ca4a34c -OpenBLAS.v0.3.20+0.x86_64-unknown-freebsd-libgfortran4.tar.gz/md5/06167501fc4cc7b6587ead3696ef72af -OpenBLAS.v0.3.20+0.x86_64-unknown-freebsd-libgfortran4.tar.gz/sha512/a853a4c5163e0bc0266e75df0b208794e8439a008b625b520b51e7891825a355960f62fe2275e4f849c345862fabf0339d0d22d4bdcd87acfb17ffd65627f74d -OpenBLAS.v0.3.20+0.x86_64-unknown-freebsd-libgfortran5.tar.gz/md5/73a43356c9bf374765a2bc8910e2eb49 -OpenBLAS.v0.3.20+0.x86_64-unknown-freebsd-libgfortran5.tar.gz/sha512/0c2092789f4eeab1725cdfd7d308a2ede054b993d6d1a83f671c5c8e9f651565c282af7371c958c61a57679a233d3f62a287afb44225498dc31249f6821ddf98 -OpenBLAS.v0.3.20+0.x86_64-w64-mingw32-libgfortran3.tar.gz/md5/46bd5ef0708671aeb2a533476a04591b -OpenBLAS.v0.3.20+0.x86_64-w64-mingw32-libgfortran3.tar.gz/sha512/1b0a3f9e61101cbf455da70056dea75637f3008df727072a22150072e7bfc773294378fc42a492b2351f9af2d6b7866503c0039f8addeab07d4f4b5d0f42b5fb -OpenBLAS.v0.3.20+0.x86_64-w64-mingw32-libgfortran4.tar.gz/md5/7e412c9961e4762c40cca9c27e5c9aa2 -OpenBLAS.v0.3.20+0.x86_64-w64-mingw32-libgfortran4.tar.gz/sha512/6a275bd153bb0ba227f39ffbfe95ee1f84f42f79361f7d3a7b1a5c29ca253b8d8b2427ce389f10cf2b95fb87d91dcdf1144f24c82d11320a0aad7dfb8d3c0498 -OpenBLAS.v0.3.20+0.x86_64-w64-mingw32-libgfortran5.tar.gz/md5/2a24ea7c7a9bdf8069d7f62c55d09bb5 -OpenBLAS.v0.3.20+0.x86_64-w64-mingw32-libgfortran5.tar.gz/sha512/7f9134df42be432199119b2a5ef5df2552247cca8647546fb755901d5903030fd5cb565c711248f173c71409cd3b30609a2adadf0213c9a096a9b70298b29a87 -openblas-0b678b19dc03f2a999d6e038814c4c50b9640a4e.tar.gz/md5/4586a405791fb16775eb9aecdd7daa59 -openblas-0b678b19dc03f2a999d6e038814c4c50b9640a4e.tar.gz/sha512/c34a498f2f1ecf65c5174a198022558bf6626eb6da0c4191762a35fd9d335c67dd17246cee3ef503301738a202650aaefe5e0073d8abefd3d1b8ba19cc953304 +OpenBLAS.v0.3.21+0.aarch64-apple-darwin-libgfortran5.tar.gz/md5/a89e1eeae1d9539c21598c98da5ac91c +OpenBLAS.v0.3.21+0.aarch64-apple-darwin-libgfortran5.tar.gz/sha512/181334363669482ac78b17ed9797ecc62ead35c07348eddd674c06252a7b36a356db48c62da77e73072df4cc21d0c25e0fb568c4dc7fe98e5db8e0f76eed7183 +OpenBLAS.v0.3.21+0.aarch64-linux-gnu-libgfortran3.tar.gz/md5/7ed3100359f9ed7da4959ecee3b4fd1e +OpenBLAS.v0.3.21+0.aarch64-linux-gnu-libgfortran3.tar.gz/sha512/329e26dae7f2e5ba81ba2271257c03426a349b89831147458a71d91da062bd11fab1b846f77922f3bc65a9f7d3b1914f15aaa0c14f696ba7bf43b55628a5464d +OpenBLAS.v0.3.21+0.aarch64-linux-gnu-libgfortran4.tar.gz/md5/ae71b44c62d42c246a21385d0691dcfa +OpenBLAS.v0.3.21+0.aarch64-linux-gnu-libgfortran4.tar.gz/sha512/0598da4b6410f59a69690e6908c80724df4a8c4761194993c1b127f84418f046d8fa0d367fda8a7faed5cec2d6c57bd8872ba216e38b5418bc9ff20af27528c6 +OpenBLAS.v0.3.21+0.aarch64-linux-gnu-libgfortran5.tar.gz/md5/fff9e118d250bebd55723e77c492280c +OpenBLAS.v0.3.21+0.aarch64-linux-gnu-libgfortran5.tar.gz/sha512/29d831f773cb6a75119c7cc2363fd72d38e32eaef6124505f8b5a1b64fa3ae7a6ffe199aae851de0893259d3bdc480aa377294688ee55d20f0da7dfc49fce747 +OpenBLAS.v0.3.21+0.aarch64-linux-musl-libgfortran3.tar.gz/md5/e93af05f98be926b3000dac3accf5f56 +OpenBLAS.v0.3.21+0.aarch64-linux-musl-libgfortran3.tar.gz/sha512/de3e9cee786d1a37dd5807aca81728d67d60fdace68aa17c69efcc7ebfe36dd3a240dea16f7cd3c5021f0f967f15f1154a3d32350f91165a9fcdd08285917196 +OpenBLAS.v0.3.21+0.aarch64-linux-musl-libgfortran4.tar.gz/md5/5a0226c6781c748a8f4d144b0ae4609b +OpenBLAS.v0.3.21+0.aarch64-linux-musl-libgfortran4.tar.gz/sha512/83d9ff97a5651b682ee1839cf0e1aa8dcd7c2e2d32b6cadb184b8d71123649a31519516b1c7d98c329ab9902538a01ffc14ec28f95ada35ba8da77241d74c2d2 +OpenBLAS.v0.3.21+0.aarch64-linux-musl-libgfortran5.tar.gz/md5/f09c8409b0f4e5e3ee9d471538289e45 +OpenBLAS.v0.3.21+0.aarch64-linux-musl-libgfortran5.tar.gz/sha512/b41234be953779db6601d5bffe43ab9ea23bb542583b16af48fe3a3400b1e50b45d3c91152895c92f6a1f4844ac018c8003f0fd10e9473c503e70e9fc4ad11b0 +OpenBLAS.v0.3.21+0.armv6l-linux-gnueabihf-libgfortran3.tar.gz/md5/78ea013e0ba52d289c919df3d5b79946 +OpenBLAS.v0.3.21+0.armv6l-linux-gnueabihf-libgfortran3.tar.gz/sha512/50ffb9d99d283db2880e767a3ebedbdc7ca67b18782717f5085e0cfc9f6cc55bdeb112e8dca0011e31954a22272936043ca538204fc9be81cb7a0f22d6726f12 +OpenBLAS.v0.3.21+0.armv6l-linux-gnueabihf-libgfortran4.tar.gz/md5/47d016b3a50c0c9b2ed1eb5e49904169 +OpenBLAS.v0.3.21+0.armv6l-linux-gnueabihf-libgfortran4.tar.gz/sha512/d38fe6df24d658a0f54ab007ac6f9b30c0a02fbf86c0592f2e5cf5a8375b654a7428b75f74c20d97d6c953ae9998664c82800813dfa806a5f16dfc20c798c419 +OpenBLAS.v0.3.21+0.armv6l-linux-gnueabihf-libgfortran5.tar.gz/md5/17f22b32a0715f82fd48cc5d82f6512c +OpenBLAS.v0.3.21+0.armv6l-linux-gnueabihf-libgfortran5.tar.gz/sha512/d9318a4cd232abc58907522c20ac666e6db2a92e6a25c9ddd1db0f0169be6f94aadc808014545e92e6168eaa7fa20de4235072186c48ade2e7fc672a700485ad +OpenBLAS.v0.3.21+0.armv6l-linux-musleabihf-libgfortran3.tar.gz/md5/d5a83c8835ad8553d304bf5260b53985 +OpenBLAS.v0.3.21+0.armv6l-linux-musleabihf-libgfortran3.tar.gz/sha512/3b506824730c7269eb49e90dc11bfde2b17338ef1504da63e84562433c68586a71b022ad37de3096e06ac24e98828b48638c672789320f76cb33eda4c8e8c9eb +OpenBLAS.v0.3.21+0.armv6l-linux-musleabihf-libgfortran4.tar.gz/md5/59cc4a5aeb63dd84c0dc12cbef7d37af +OpenBLAS.v0.3.21+0.armv6l-linux-musleabihf-libgfortran4.tar.gz/sha512/1e9cadcf65232d4a4fba9cda0226e5a5450227e16bf2c27a3268452d5c4e4d5d1321601fd6e1a5c5d92fbc3fc4de21c92e231b5ad3b25dd71eb49d5940fcf243 +OpenBLAS.v0.3.21+0.armv6l-linux-musleabihf-libgfortran5.tar.gz/md5/c04f400d9aca82aac956e94d9fc6fc51 +OpenBLAS.v0.3.21+0.armv6l-linux-musleabihf-libgfortran5.tar.gz/sha512/8751300546ccb059fb7755e3f745e7e195cfaf90daf28b151ea2a3d540edf8910c97351d428dda196707599361a200f1a647098fdf5d7163380b4ad2b4a4f733 +OpenBLAS.v0.3.21+0.armv7l-linux-gnueabihf-libgfortran3.tar.gz/md5/f251abd323b6bc463ae4a1989670aefb +OpenBLAS.v0.3.21+0.armv7l-linux-gnueabihf-libgfortran3.tar.gz/sha512/4f179ed09a5f5b71033d09db3894ad78d58a4429d65203225ab7a2a8c887222924910756a5fc4e3974a7cc6f9d994af287490f53cd05fe90f86c4bd4c4023b6d +OpenBLAS.v0.3.21+0.armv7l-linux-gnueabihf-libgfortran4.tar.gz/md5/f8ffa30a958448028d1294da9d15f3b2 +OpenBLAS.v0.3.21+0.armv7l-linux-gnueabihf-libgfortran4.tar.gz/sha512/0a2d9a73be439d78b4af7c70345bdffd531d5687adeea28049adba3c8c9ab7b6ed221703f2a8aff9e7391305355a596dc9a846c84d36d1b4cdfda521f7c05e8c +OpenBLAS.v0.3.21+0.armv7l-linux-gnueabihf-libgfortran5.tar.gz/md5/56a4aa4f3eafff290d38dc251a5966cb +OpenBLAS.v0.3.21+0.armv7l-linux-gnueabihf-libgfortran5.tar.gz/sha512/fce03b1c1becdac66208de20e66949aba113ce2695217d34703a9ba4fd79d364cdf05424282b9d1f25ad9c315baffca3a8bd0af239f6284bd37cbdb2ec3463c6 +OpenBLAS.v0.3.21+0.armv7l-linux-musleabihf-libgfortran3.tar.gz/md5/aca7ef7f854cfe45bedbf1f6b5a97aaf +OpenBLAS.v0.3.21+0.armv7l-linux-musleabihf-libgfortran3.tar.gz/sha512/16821728c7a0e56589b60176a06543240f2a061b437dc1cf38723dc56910c6add114a4a5e65eda051e5e88ff7b82b8613ffaf5dad7864f1208eb381159bacc8c +OpenBLAS.v0.3.21+0.armv7l-linux-musleabihf-libgfortran4.tar.gz/md5/9f2c39eef42e5c80f56d36aee156e2b0 +OpenBLAS.v0.3.21+0.armv7l-linux-musleabihf-libgfortran4.tar.gz/sha512/441a7833e4e2d1334aeda58d87560e613244138005bc54c74af00d81c26e1e508ce874fccdcd3b3114a74f5e2a102eb520a2e4165b461861ba79fbaff81e4ae3 +OpenBLAS.v0.3.21+0.armv7l-linux-musleabihf-libgfortran5.tar.gz/md5/bf1a9f3e553d6855133b4de3ffc841ee +OpenBLAS.v0.3.21+0.armv7l-linux-musleabihf-libgfortran5.tar.gz/sha512/2002b305ef3f3721287ed839d6d08f34127058e6295233f8280cc3ebd06d91cb326ea83f13c0158820c381fa8a2cc74ec1360a65c99bc525f492be561b15cc09 +OpenBLAS.v0.3.21+0.i686-linux-gnu-libgfortran3.tar.gz/md5/6051a0545d272bf19988e2a889531acd +OpenBLAS.v0.3.21+0.i686-linux-gnu-libgfortran3.tar.gz/sha512/21706d2fd8dde6e1e938b0c7a53c6073d52d830d7672702d828d5606582e2c98bdb39fc7ff1fa67188942713e9d718fdf5f014812115d0d0853066c2df21f297 +OpenBLAS.v0.3.21+0.i686-linux-gnu-libgfortran4.tar.gz/md5/4fc17cff9c7a4512245ffead4d75c678 +OpenBLAS.v0.3.21+0.i686-linux-gnu-libgfortran4.tar.gz/sha512/5a28c5a587be439cd2bdf4880caf967cdec14945d26c978fa5c59ce251d5811d460bebc038808e0e8dd2eb4b6a0fdfcaacca4718e2aeb7855f466bd13d1974a7 +OpenBLAS.v0.3.21+0.i686-linux-gnu-libgfortran5.tar.gz/md5/06fa8dff91cff8ba91e2b4bc896e776c +OpenBLAS.v0.3.21+0.i686-linux-gnu-libgfortran5.tar.gz/sha512/493110d06c4361df13ba8e0839b9410551b0bba4fe6e3cdcb53c0dff41a03b3e34ec1c2e73cd4671516631492a16b8dd140a59fa3ac71c348e670858654f2d8a +OpenBLAS.v0.3.21+0.i686-linux-musl-libgfortran3.tar.gz/md5/1b16814a10900c96537b5bfed19e71c2 +OpenBLAS.v0.3.21+0.i686-linux-musl-libgfortran3.tar.gz/sha512/603b2a2fd92286143cb0cb573e3c085db485cf3c4f54987d255efedaea2a8a3d84b83e28f6b2db9dbf05cd31f061845a749b8402d145cc5e8cc2eb369b38e3f5 +OpenBLAS.v0.3.21+0.i686-linux-musl-libgfortran4.tar.gz/md5/20ec87e486f1154d253bc251c1ec0bce +OpenBLAS.v0.3.21+0.i686-linux-musl-libgfortran4.tar.gz/sha512/a2d1736e0f632bddc5140ea88840113b80fedcad51bf5ea93445053eb07c1ae304a1510a85cf964d3a0e087390b8526a0df2bcd24e356b4693a41e5dfc8a671c +OpenBLAS.v0.3.21+0.i686-linux-musl-libgfortran5.tar.gz/md5/df9f4898d550130b0c0c5cede6dd4db3 +OpenBLAS.v0.3.21+0.i686-linux-musl-libgfortran5.tar.gz/sha512/c4c3133904e7b401c5d3013d0ef38b13d7a9804fb4ba38a2c0a062f1badb4d9150214bfc2a1bf55df1299e4151d71a6dbfce7063d9d80a19fe321878c0e59309 +OpenBLAS.v0.3.21+0.i686-w64-mingw32-libgfortran3.tar.gz/md5/3d83d839f80abbd17f84631fbb8f6624 +OpenBLAS.v0.3.21+0.i686-w64-mingw32-libgfortran3.tar.gz/sha512/e51680b4b97f404f244b4d943148f506f84a21f0f59f4d41a3a0cf81d545658d9cc59592a2538c4c077606fc1e6f87eda23063e49828f066e743205c5e6aee8e +OpenBLAS.v0.3.21+0.i686-w64-mingw32-libgfortran4.tar.gz/md5/2ca3ebd61038a5e422a946ede3d17535 +OpenBLAS.v0.3.21+0.i686-w64-mingw32-libgfortran4.tar.gz/sha512/c692b7c00aa0eda4a3fa989f84c797126b1596e13514117ad898166f941f040df67826ba33d0af93673c7a0b478fe4392f9a53d7859b7371878b6608dcb0556b +OpenBLAS.v0.3.21+0.i686-w64-mingw32-libgfortran5.tar.gz/md5/55995848e4bc9ef739e8ba17962787d3 +OpenBLAS.v0.3.21+0.i686-w64-mingw32-libgfortran5.tar.gz/sha512/e274dcfc6593786ac4c32c3f49ec69ab3a0c7278c67bbd04373d4845bff2dfaf17300d4a71e48ebd508e299fa629190ffe70ce074a68e83bac0eafa51f4db2a0 +OpenBLAS.v0.3.21+0.powerpc64le-linux-gnu-libgfortran3.tar.gz/md5/2a3d5f0240a27cf1617d9d4abba6df78 +OpenBLAS.v0.3.21+0.powerpc64le-linux-gnu-libgfortran3.tar.gz/sha512/489128c884a0c2b9eb5145b18c68f9c7de9a9cc4131f4635689dc67765f87bec852b0547ebea4ecfdad4eec38063aabe8f6c3e96e5856e08c0c26130c2f11897 +OpenBLAS.v0.3.21+0.powerpc64le-linux-gnu-libgfortran4.tar.gz/md5/bb3501965c26519ecf30830465b12672 +OpenBLAS.v0.3.21+0.powerpc64le-linux-gnu-libgfortran4.tar.gz/sha512/bcc78c10f7aba973f1159443e8d408465833ef43530c1c2514715db5a1bb84c0f48510c12b2ac1211b2777328ec682e01ab668818025651f00db7ca747f5674e +OpenBLAS.v0.3.21+0.powerpc64le-linux-gnu-libgfortran5.tar.gz/md5/dc6192b5130e114b3cb1183690c7e398 +OpenBLAS.v0.3.21+0.powerpc64le-linux-gnu-libgfortran5.tar.gz/sha512/95d69ace7b145c02acbe13c52d1e7835fdb1e8788c0b03f0f967d88575b322988e4f4acef3b6ad3e505c895f8d19566b8eb9add02f0250cf2d4a14c9f1428f3f +OpenBLAS.v0.3.21+0.x86_64-apple-darwin-libgfortran3.tar.gz/md5/27a9117002f96c41c7907be0475a8d86 +OpenBLAS.v0.3.21+0.x86_64-apple-darwin-libgfortran3.tar.gz/sha512/2247f3691cc552f65a353412c46a76c1ac4b4d994a5725044ba300f0944f15b37144ceff438d77022b441c25eaf530709a4d3ed4523b97d292991b6407a72970 +OpenBLAS.v0.3.21+0.x86_64-apple-darwin-libgfortran4.tar.gz/md5/30dea9ca8b658ff6a9db9245d8ad7500 +OpenBLAS.v0.3.21+0.x86_64-apple-darwin-libgfortran4.tar.gz/sha512/3289e766bfad456b35efae6d341a77698d4d36908ac8d802f47777feed5eef224fde1cb4799b5bd4e8e216c28c78ab4407b92906ddac0bdd1cfb674136c69aaa +OpenBLAS.v0.3.21+0.x86_64-apple-darwin-libgfortran5.tar.gz/md5/ed820c420a67b32df0a9f34760ce605c +OpenBLAS.v0.3.21+0.x86_64-apple-darwin-libgfortran5.tar.gz/sha512/63f43eb0b1c037849fd5addda66d818c0b8188f9758391cd9929e78593c69ec61729be0efce6a9f943ebac178c634cdddffe172ad681ad1c4717949b075a1de7 +OpenBLAS.v0.3.21+0.x86_64-linux-gnu-libgfortran3.tar.gz/md5/a5393eb8e1799b6c089a82d8dde39fb0 +OpenBLAS.v0.3.21+0.x86_64-linux-gnu-libgfortran3.tar.gz/sha512/8ce9ad2f55f131592a87789ec6a824cbe1d23c3be32fb2ba59e107045f75c34684b85d3bab2913923f5a19414a072b5e855c86fddd44a4319a9b5e7b28d5c169 +OpenBLAS.v0.3.21+0.x86_64-linux-gnu-libgfortran4.tar.gz/md5/652aa333440219a4ec17d94dd4e6d358 +OpenBLAS.v0.3.21+0.x86_64-linux-gnu-libgfortran4.tar.gz/sha512/89d7740b462d4216e920dcd5c7867520b2f49c3cb74bd8424efd287927c92a08492c9fa413506248207f9532c7bb9ea2af587a4f70d7db8ea42ac1bc144e8a12 +OpenBLAS.v0.3.21+0.x86_64-linux-gnu-libgfortran5.tar.gz/md5/9e0831544d02a39565a2d0714b1e121a +OpenBLAS.v0.3.21+0.x86_64-linux-gnu-libgfortran5.tar.gz/sha512/9e57a08a09d5fc47d881f9f7ed2e52fbdc7301908cf1be384fe767e6b7771a5980827417049dd37df4d71a861b2cf2a05f25df892b15ed03458910b0bc53101a +OpenBLAS.v0.3.21+0.x86_64-linux-musl-libgfortran3.tar.gz/md5/dde15d3a2f26601cd7ac0a803efbe503 +OpenBLAS.v0.3.21+0.x86_64-linux-musl-libgfortran3.tar.gz/sha512/fa48e51a59b6fb213f88ce8b2778ca5eef73f0721a5c71e27cd8952a34a5003d69710571deb5c0c06526fa8016cfdacabdc2b343342ad0d1e523903fa94a8d42 +OpenBLAS.v0.3.21+0.x86_64-linux-musl-libgfortran4.tar.gz/md5/55b80d13104f4ddc9eefa0424d71330b +OpenBLAS.v0.3.21+0.x86_64-linux-musl-libgfortran4.tar.gz/sha512/fcd816e4dcd767963ae555846cee846c19f0b7d666042d59757eb2eebe115d30af60072c134c3025049712520705dbe9d2862a1f07c955780f9a0de69e6e00b5 +OpenBLAS.v0.3.21+0.x86_64-linux-musl-libgfortran5.tar.gz/md5/e22e46b304962a1edb550e19914cc5e6 +OpenBLAS.v0.3.21+0.x86_64-linux-musl-libgfortran5.tar.gz/sha512/38f8ce1baee4082fd2432dbc1905fd03d8efbcc378aefc9312e90b6054341717ea46bc4d33f9f517e67af0fca2da55b5c5b112850e6071ba18753a4936d78da2 +OpenBLAS.v0.3.21+0.x86_64-unknown-freebsd-libgfortran3.tar.gz/md5/b8b7a9f9aff94b154e8479a84d7abe4b +OpenBLAS.v0.3.21+0.x86_64-unknown-freebsd-libgfortran3.tar.gz/sha512/afe4c45d4bf4e38fdbbf00b9e86a65244aadaa2b74e59f9a43f1860c130f721bba2f36186519b2573ff0819bd2b30414cc23800634847db2ecd2107f985495ad +OpenBLAS.v0.3.21+0.x86_64-unknown-freebsd-libgfortran4.tar.gz/md5/8fceea42a8524fef29a54b88ea0a721b +OpenBLAS.v0.3.21+0.x86_64-unknown-freebsd-libgfortran4.tar.gz/sha512/e8195597057ab6de0aa5978b4d13b3248ac6acde3f86fc55d9e1c76ec39d464fc2eefea1096cfb5dffbd623f47b06be163c4c74981d2eb13387bc8499b9053fe +OpenBLAS.v0.3.21+0.x86_64-unknown-freebsd-libgfortran5.tar.gz/md5/6f88d96c05663b4aeb81ba8a63882066 +OpenBLAS.v0.3.21+0.x86_64-unknown-freebsd-libgfortran5.tar.gz/sha512/f1f516d8d16a2f86bfb26129e0530146de3a4bcb62abcd2c7b9bf64cc09c069e5eeb66658b1cc0cdcc665de98246ad8ed20a7d8b132fe0f0e4d0651d3b4516d4 +OpenBLAS.v0.3.21+0.x86_64-w64-mingw32-libgfortran3.tar.gz/md5/4fb99984ec612a090b294c6b349a7cdb +OpenBLAS.v0.3.21+0.x86_64-w64-mingw32-libgfortran3.tar.gz/sha512/81bf55c6398a6cf4a61add084332e7cb79e6d550737641f6c0bc77aa61bd8187603a6100b78c2ef80109c3c5b21f7ba618a4780a5b68e5168a461af521f26c52 +OpenBLAS.v0.3.21+0.x86_64-w64-mingw32-libgfortran4.tar.gz/md5/a1a2c3623d583ab995ac86df07ab73bb +OpenBLAS.v0.3.21+0.x86_64-w64-mingw32-libgfortran4.tar.gz/sha512/ec5fab349607862c9e0badaa1fd433e057ac7d056008af683bbb37bf43fef5322e598cd71a6d9c3dd55ef857b39ca634e64572e9ae6e263022dc7f89083f9bca +OpenBLAS.v0.3.21+0.x86_64-w64-mingw32-libgfortran5.tar.gz/md5/05ef0ede7d565247a936c3110c25c83c +OpenBLAS.v0.3.21+0.x86_64-w64-mingw32-libgfortran5.tar.gz/sha512/34d2812bc0c6605558cbd6244c41d0805fc9a943cd91a74994bcacdd5ff19612eac8751832e3ee761089a853cf16069e67e13507ca75bbe4b7dc4517e41515e0 +openblas-b89fb708caa5a5a32de8f4306c4ff132e0228e9a.tar.gz/md5/716ebe95d4b491253cdde8308b8adb83 +openblas-b89fb708caa5a5a32de8f4306c4ff132e0228e9a.tar.gz/sha512/00e7bde49525c2c28bf07b47290e00b53bff446be63f09e90c51724c6350e5ddc90f5a071ae6de057b3fbb107060e70bf16683fcefcf48ae37ba1d0758be553b diff --git a/deps/clang.version b/deps/clang.version index 182714fbb391e..2fa84f679cb19 100644 --- a/deps/clang.version +++ b/deps/clang.version @@ -1,4 +1,4 @@ ## jll artifact # Clang (paired with LLVM, only here as a JLL download) CLANG_JLL_NAME := Clang -CLANG_JLL_VER := 14.0.5+3 +CLANG_JLL_VER := 14.0.6+0 diff --git a/deps/libssh2.mk b/deps/libssh2.mk index e27a57a4078d1..d0174c0c090e2 100644 --- a/deps/libssh2.mk +++ b/deps/libssh2.mk @@ -36,8 +36,15 @@ $(LIBSSH2_SRC_PATH)/libssh2-userauth-check.patch-applied: $(LIBSSH2_SRC_PATH)/so patch -p1 -f < $(SRCDIR)/patches/libssh2-userauth-check.patch echo 1 > $@ +# issue: https://github.com/JuliaLang/julia/issues/45645#issuecomment-1153214379 +# fix pr: https://github.com/libssh2/libssh2/pull/711 +$(LIBSSH2_SRC_PATH)/libssh2-fix-import-lib-name.patch-applied: $(LIBSSH2_SRC_PATH)/libssh2-userauth-check.patch-applied + cd $(LIBSSH2_SRC_PATH) && \ + patch -p1 -f < $(SRCDIR)/patches/libssh2-fix-import-lib-name.patch + echo 1 > $@ + $(BUILDDIR)/$(LIBSSH2_SRC_DIR)/build-configured: \ - $(LIBSSH2_SRC_PATH)/libssh2-userauth-check.patch-applied + $(LIBSSH2_SRC_PATH)/libssh2-fix-import-lib-name.patch-applied $(BUILDDIR)/$(LIBSSH2_SRC_DIR)/build-configured: $(LIBSSH2_SRC_PATH)/source-extracted mkdir -p $(dir $@) diff --git a/deps/libuv.version b/deps/libuv.version index 5cffc1898842f..e4b277e36b099 100644 --- a/deps/libuv.version +++ b/deps/libuv.version @@ -4,4 +4,4 @@ LIBUV_JLL_NAME := LibUV ## source build LIBUV_VER := 2 LIBUV_BRANCH=julia-uv2-1.44.2 -LIBUV_SHA1=3f7038d62e43c3682394a6ea7b4ccc46be0fa0bf +LIBUV_SHA1=e6f0e4900e195c8352f821abe2b3cffc3089547b diff --git a/deps/lld.version b/deps/lld.version index 89b6829a99df9..2b34a5d3012ad 100644 --- a/deps/lld.version +++ b/deps/lld.version @@ -1,3 +1,3 @@ ## jll artifact LLD_JLL_NAME := LLD -LLD_JLL_VER := 14.0.5+3 +LLD_JLL_VER := 14.0.6+0 diff --git a/deps/llvm-tools.version b/deps/llvm-tools.version index 522bc8a466ed5..5da312d32f0af 100644 --- a/deps/llvm-tools.version +++ b/deps/llvm-tools.version @@ -1,5 +1,5 @@ ## jll artifact # LLVM_tools (downloads LLVM_jll to get things like `lit` and `opt`) LLVM_TOOLS_JLL_NAME := LLVM -LLVM_TOOLS_JLL_VER := 14.0.5+3 -LLVM_TOOLS_ASSERT_JLL_VER := 14.0.5+3 +LLVM_TOOLS_JLL_VER := 14.0.6+0 +LLVM_TOOLS_ASSERT_JLL_VER := 14.0.6+0 diff --git a/deps/llvm.version b/deps/llvm.version index 969134091759c..2dbcd0f510f81 100644 --- a/deps/llvm.version +++ b/deps/llvm.version @@ -4,5 +4,5 @@ LLVM_ASSERT_JLL_VER := 14.0.5+3 ## source build LLVM_VER := 14.0.5 -LLVM_BRANCH=julia-14.0.5-3 -LLVM_SHA1=julia-14.0.5-3 +LLVM_BRANCH=julia-14.0.6-0 +LLVM_SHA1=julia-14.0.6-0 diff --git a/deps/mpfr.mk b/deps/mpfr.mk index 1bb3ff32c302f..36a4f77c6a929 100644 --- a/deps/mpfr.mk +++ b/deps/mpfr.mk @@ -7,28 +7,23 @@ endif ifneq ($(USE_BINARYBUILDER_MPFR),1) -MPFR_OPTS := --enable-thread-safe --enable-shared-cache --disable-float128 --disable-decimal-float -ifeq ($(USE_SYSTEM_GMP), 0) -MPFR_OPTS += --with-gmp-include=$(abspath $(build_includedir)) --with-gmp-lib=$(abspath $(build_shlibdir)) -endif -ifeq ($(BUILD_OS),WINNT) -ifeq ($(OS),WINNT) -MPFR_OPTS += CFLAGS="$(CFLAGS) -DNPRINTF_L -DNPRINTF_T -DNPRINTF_J" -endif -endif +MPFR_CONFIGURE_OPTS := $(CONFIGURE_COMMON) +MPFR_CONFIGURE_OPTS += --enable-thread-safe --enable-shared-cache --disable-float128 --disable-decimal-float +MPFR_CONFIGURE_OPTS += --enable-shared --disable-static - -ifeq ($(OS),Darwin) -MPFR_CHECK_MFLAGS := LDFLAGS="$(LDFLAGS) -Wl,-rpath,'$(build_libdir)'" +ifeq ($(USE_SYSTEM_GMP), 0) +MPFR_CONFIGURE_OPTS += --with-gmp=$(abspath $(build_prefix)) endif ifeq ($(SANITIZE),1) # Force generic C build -MPFR_OPTS += --host=none-unknown-linux +MPFR_CONFIGURE_OPTS += --host=none-unknown-linux endif + $(SRCCACHE)/mpfr-$(MPFR_VER).tar.bz2: | $(SRCCACHE) $(JLDOWNLOAD) $@ https://www.mpfr.org/mpfr-$(MPFR_VER)/$(notdir $@) + $(SRCCACHE)/mpfr-$(MPFR_VER)/source-extracted: $(SRCCACHE)/mpfr-$(MPFR_VER).tar.bz2 $(JLCHECKSUM) $< cd $(dir $<) && $(TAR) -jxf $< @@ -42,23 +37,24 @@ checksum-mpfr: $(SRCCACHE)/mpfr-$(MPFR_VER).tar.bz2 $(BUILDDIR)/mpfr-$(MPFR_VER)/build-configured: $(SRCCACHE)/mpfr-$(MPFR_VER)/source-extracted mkdir -p $(dir $@) cd $(dir $@) && \ - $(dir $<)/configure $(CONFIGURE_COMMON) $(MPFR_OPTS) F77= --enable-shared --disable-static + $(dir $<)/configure $(MPFR_CONFIGURE_OPTS) echo 1 > $@ $(BUILDDIR)/mpfr-$(MPFR_VER)/build-compiled: $(BUILDDIR)/mpfr-$(MPFR_VER)/build-configured - $(MAKE) -C $(dir $<) $(LIBTOOL_CCLD) + $(MAKE) -C $(dir $<) echo 1 > $@ $(BUILDDIR)/mpfr-$(MPFR_VER)/build-checked: $(BUILDDIR)/mpfr-$(MPFR_VER)/build-compiled ifeq ($(OS),$(BUILD_OS)) - $(MAKE) -C $(dir $@) $(LIBTOOL_CCLD) check $(MPFR_CHECK_MFLAGS) + $(MAKE) -C $(dir $@) check endif echo 1 > $@ $(eval $(call staged-install, \ mpfr,mpfr-$(MPFR_VER), \ - MAKE_INSTALL,$$(LIBTOOL_CCLD),, \ - $$(INSTALL_NAME_CMD)libmpfr.$$(SHLIB_EXT) $$(build_shlibdir)/libmpfr.$$(SHLIB_EXT))) + MAKE_INSTALL,,, \ + $$(WIN_MAKE_HARD_LINK) $(build_bindir)/libmpfr-*.dll $(build_bindir)/libmpfr.dll && \ + $$(INSTALL_NAME_CMD)libmpfr.$$(SHLIB_EXT) $$(build_shlibdir)/libmpfr.$$(SHLIB_EXT))) clean-mpfr: -rm -f $(BUILDDIR)/mpfr-$(MPFR_VER)/build-configured $(BUILDDIR)/mpfr-$(MPFR_VER)/build-compiled diff --git a/deps/openblas.version b/deps/openblas.version index 843bb449c92c7..9e433d2629071 100644 --- a/deps/openblas.version +++ b/deps/openblas.version @@ -1,10 +1,11 @@ +# -*- makefile -*- ## jll artifact OPENBLAS_JLL_NAME := OpenBLAS ## source build -OPENBLAS_VER := 0.3.20 -OPENBLAS_BRANCH=v0.3.20 -OPENBLAS_SHA1=0b678b19dc03f2a999d6e038814c4c50b9640a4e +OPENBLAS_VER := 0.3.21 +OPENBLAS_BRANCH=v0.3.21 +OPENBLAS_SHA1=b89fb708caa5a5a32de8f4306c4ff132e0228e9a # LAPACK, source-only LAPACK_VER := 3.9.0 diff --git a/deps/patches/libssh2-fix-import-lib-name.patch b/deps/patches/libssh2-fix-import-lib-name.patch new file mode 100644 index 0000000000000..15aafb58d2736 --- /dev/null +++ b/deps/patches/libssh2-fix-import-lib-name.patch @@ -0,0 +1,26 @@ +From 3732420725efbf410df5863b91a09ca214ee18ba Mon Sep 17 00:00:00 2001 +From: "Y. Yang" +Date: Thu, 16 Jun 2022 19:16:37 +0800 +Subject: [PATCH] Fix DLL import library name + +https://aur.archlinux.org/packages/mingw-w64-libssh2 +https://cmake.org/cmake/help/latest/prop_tgt/IMPORT_PREFIX.html +--- + src/CMakeLists.txt | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt +index cb8fee1..17ecefd 100644 +--- a/src/CMakeLists.txt ++++ b/src/CMakeLists.txt +@@ -220,6 +220,7 @@ endif() + add_library(libssh2 ${SOURCES}) + # we want it to be called libssh2 on all platforms + set_target_properties(libssh2 PROPERTIES PREFIX "") ++set_target_properties(libssh2 PROPERTIES IMPORT_PREFIX "") + + target_compile_definitions(libssh2 PRIVATE ${PRIVATE_COMPILE_DEFINITIONS}) + target_include_directories(libssh2 +-- +2.36.1 + diff --git a/doc/Manifest.toml b/doc/Manifest.toml index 74081475bc96b..cf50a1d41ddbd 100644 --- a/doc/Manifest.toml +++ b/doc/Manifest.toml @@ -18,15 +18,15 @@ uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" [[deps.DocStringExtensions]] deps = ["LibGit2"] -git-tree-sha1 = "b19534d1895d702889b219c382a6e18010797f0b" +git-tree-sha1 = "5158c2b41018c5f7eb1470d558127ac274eca0c9" uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -version = "0.8.6" +version = "0.9.1" [[deps.Documenter]] deps = ["ANSIColoredPrinters", "Base64", "Dates", "DocStringExtensions", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "REPL", "Test", "Unicode"] -git-tree-sha1 = "e4967ebb9dce1328d582200b03bcc44c69372312" +git-tree-sha1 = "6030186b00a38e9d0434518627426570aac2ef95" uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -version = "0.27.20" +version = "0.27.23" [[deps.IOCapture]] deps = ["Logging", "Random"] @@ -64,9 +64,9 @@ version = "1.2.0" [[deps.Parsers]] deps = ["Dates"] -git-tree-sha1 = "0044b23da09b5608b4ecacb4e5e6c6332f833a7e" +git-tree-sha1 = "3d5bf43e3e8b412656404ed9466f1dcbf7c50269" uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.3.2" +version = "2.4.0" [[deps.Printf]] deps = ["Unicode"] diff --git a/doc/make.jl b/doc/make.jl index 5f5986497c922..61adf2ec603fa 100644 --- a/doc/make.jl +++ b/doc/make.jl @@ -343,6 +343,7 @@ function Documenter.deploy_folder(::BuildBotConfig; devurl, repo, branch, kwargs @info "Unable to deploy the documentation: DOCUMENTER_KEY missing" return Documenter.DeployDecision(; all_ok=false) end + release = match(r"^release-([0-9]+\.[0-9]+)$", Base.GIT_VERSION_INFO.branch) if Base.GIT_VERSION_INFO.tagged_commit # Strip extra pre-release info (1.5.0-rc2.0 -> 1.5.0-rc2) ver = VersionNumber(VERSION.major, VERSION.minor, VERSION.patch, @@ -351,6 +352,10 @@ function Documenter.deploy_folder(::BuildBotConfig; devurl, repo, branch, kwargs return Documenter.DeployDecision(; all_ok=true, repo, branch, subfolder) elseif Base.GIT_VERSION_INFO.branch == "master" return Documenter.DeployDecision(; all_ok=true, repo, branch, subfolder=devurl) + elseif !isnothing(release) + # If this is a non-tag build from a release-* branch, we deploy them as dev docs into the + # appropriate vX.Y-dev subdirectory. + return Documenter.DeployDecision(; all_ok=true, repo, branch, subfolder="v$(release[1])-dev") end @info """ Unable to deploy the documentation: invalid GIT_VERSION_INFO diff --git a/doc/src/base/base.md b/doc/src/base/base.md index 2105817475fe6..54ef38f78616f 100644 --- a/doc/src/base/base.md +++ b/doc/src/base/base.md @@ -88,6 +88,7 @@ outer const struct mutable struct +@kwdef abstract type primitive type where @@ -346,6 +347,8 @@ Base.Sys.iswindows Base.Sys.windows_version Base.Sys.free_memory Base.Sys.total_memory +Base.Sys.free_physical_memory +Base.Sys.total_physical_memory Base.Sys.uptime Base.Sys.isjsvm Base.Sys.loadavg diff --git a/doc/src/devdocs/build/build.md b/doc/src/devdocs/build/build.md index 541c402d7519c..4fd5e25731dff 100644 --- a/doc/src/devdocs/build/build.md +++ b/doc/src/devdocs/build/build.md @@ -167,7 +167,7 @@ Julia uses the following external libraries, which are automatically downloaded (or in a few cases, included in the Julia source repository) and then compiled from source the first time you run `make`. The specific version numbers of these libraries that Julia -uses are listed in [`deps/$(LibName).version`](https://github.com/JuliaLang/julia/blob/master/deps/): +uses are listed in [`deps/$(libname).version`](https://github.com/JuliaLang/julia/blob/master/deps/): - **[LLVM]** (14.0 + [patches](https://github.com/JuliaLang/llvm-project)) — compiler infrastructure (see [note below](#llvm)). - **[FemtoLisp]** — packaged with Julia source, and used to implement the compiler front-end. @@ -303,3 +303,50 @@ From this point, you should (Note that `sudo` isn't installed, but neither is it necessary since you are running as `root`, so you can omit `sudo` from all commands.) Then add all the [build dependencies](@ref build-tools), a console-based editor of your choice, `git`, and anything else you'll need (e.g., `gdb`, `rr`, etc). Pick a directory to work in and `git clone` Julia, check out the branch you wish to debug, and build Julia as usual. + + +## Update the version number of a dependency + +There are two types of builds +1. Build everything (`deps/` and `src/`) from source code. + (Add `USE_BINARYBUILDER=0` to `Make.user`, see [Building Julia](#building-julia)) +2. Build from source (`src/`) with pre-compiled dependencies (default) + +When you want to update the version number of a dependency in `deps/`, +you may want to use the following checklist: + +```md +### Check list + +Version numbers: +- [ ] `deps/$(libname).version`: `LIBNAME_VER`, `LIBNAME_BRANCH`, `LIBNAME_SHA1` and `LIBNAME_JLL_VER` +- [ ] `stdlib/$(LIBNAME_JLL_NAME)_jll/Project.toml`: `version` + +Checksum: +- [ ] `deps/checksums/$(libname)` +- [ ] `deps/checksums/$(LIBNAME_JLL_NAME)-*/`: `md5` and `sha512` + +Patches: +- [ ] `deps/$(libname).mk` +- [ ] `deps/patches/$(libname)-*.patch` +``` + +Note: +- For specific dependencies, some items in the checklist may not exist. +- For checksum file, it may be **a single file** without a suffix, or **a folder** containing two files. + + +### Example: `OpenLibm` + +1. Update Version numbers in `deps/openlibm.version` + - `OPENLIBM_VER := 0.X.Y` + - `OPENLIBM_BRANCH = v0.X.Y` + - `OPENLIBM_SHA1 = new-sha1-hash` +2. Update Version number in `stdlib/OpenLibm_jll/Project.toml` + - `version = "0.X.Y+0"` +3. Update checksums in `deps/checksums/openlibm` + - `make -f contrib/refresh_checksums.mk openlibm` +4. Check if the patch files `deps/patches/openlibm-*.patch` exist + - if patches don't exist, skip. + - if patches exist, check if they have been merged into the new version and need to be removed. + When deleting a patch, remember to modify the corresponding Makefile file (`deps/openlibm.mk`). diff --git a/doc/src/devdocs/build/windows.md b/doc/src/devdocs/build/windows.md index 4b1ed0054e18f..4f7f40a030488 100644 --- a/doc/src/devdocs/build/windows.md +++ b/doc/src/devdocs/build/windows.md @@ -115,11 +115,67 @@ MinGW-w64 compilers available through Cygwin's package manager. ### Compiling with MinGW/MSYS2 -Compiling Julia from source using [MSYS2](https://msys2.github.io) has worked in the past -but is not actively supported. Pull requests to restore support would be welcome. See a -[past version of this -file](https://github.com/JuliaLang/julia/blob/v0.6.0/README.windows.md) for the former -instructions for compiling using MSYS2. +> MSYS2 provides a robust MSYS experience. + +Note: MSYS2 requires **64 bit** Windows 7 or newer. + + 1. Install and configure [MSYS2](https://www.msys2.org/), Software Distribution + and Building Platform for Windows. + + 1. Download and run the latest installer for the + [64-bit](https://github.com/msys2/msys2-installer/releases/latest) distribution. + The installer will have a name like `msys2-x86_64-yyyymmdd.exe`. + + 2. Open MSYS2. Update package database and base packages: + ```sh + pacman -Syu + ``` + + 3. Exit and restart MSYS2, Update the rest of the base packages: + ```sh + pacman -Syu + ``` + + 3. Then install tools required to build julia: + ```sh + # tools + pacman -S cmake diffutils git m4 make patch tar p7zip curl python + + # For 64 bit Julia, install x86_64 + pacman -S mingw-w64-x86_64-gcc + # For 32 bit Julia, install i686 + pacman -S mingw-w64-i686-gcc + ``` + + 4. Configuration of MSYS2 is complete. Now `exit` the MSYS2 shell. + + + 2. Build Julia and its dependencies with pre-build dependencies. + + 1. Open a new [**MINGW64/MINGW32 shell**](https://www.msys2.org/docs/environments/#overview). + Currently we can't use both mingw32 and mingw64, + so if you want to build the x86_64 and i686 versions, + you'll need to build them in each environment separately. + + 2. and clone the Julia sources + ```sh + git clone https://github.com/JuliaLang/julia.git + cd julia + ``` + + 3. Start the build + ```sh + make -j$(nproc) + ``` + + > Protip: build in dir + > ```sh + > make O=julia-mingw-w64 configure + > echo 'ifeq ($(BUILDROOT),$(JULIAHOME)) + > $(error "in-tree build disabled") + > endif' >> Make.user + > make -C julia-mingw-w64 + > ``` ### Cross-compiling from Unix (Linux/Mac/WSL) diff --git a/doc/src/devdocs/llvm.md b/doc/src/devdocs/llvm.md index 9a833ca8af516..6c6b33c2281dc 100644 --- a/doc/src/devdocs/llvm.md +++ b/doc/src/devdocs/llvm.md @@ -9,18 +9,36 @@ Julia dynamically links against LLVM by default. Build with `USE_LLVM_SHLIB=0` t The code for lowering Julia AST to LLVM IR or interpreting it directly is in directory `src/`. -| File | Description | -|:------------------- |:---------------------------------------------------------- | -| `builtins.c` | Builtin functions | -| `ccall.cpp` | Lowering [`ccall`](@ref) | -| `cgutils.cpp` | Lowering utilities, notably for array and tuple accesses | -| `codegen.cpp` | Top-level of code generation, pass list, lowering builtins | -| `debuginfo.cpp` | Tracks debug information for JIT code | -| `disasm.cpp` | Handles native object file and JIT code diassembly | -| `gf.c` | Generic functions | -| `intrinsics.cpp` | Lowering intrinsics | -| `llvm-simdloop.cpp` | Custom LLVM pass for [`@simd`](@ref) | -| `sys.c` | I/O and operating system utility functions | +| File | Description | +|:-------------------------------- |:------------------------------------------------------------------ | +| `aotcompile.cpp` | Legacy pass manager pipeline, compiler C-interface entry | +| `builtins.c` | Builtin functions | +| `ccall.cpp` | Lowering [`ccall`](@ref) | +| `cgutils.cpp` | Lowering utilities, notably for array and tuple accesses | +| `codegen.cpp` | Top-level of code generation, pass list, lowering builtins | +| `debuginfo.cpp` | Tracks debug information for JIT code | +| `disasm.cpp` | Handles native object file and JIT code diassembly | +| `gf.c` | Generic functions | +| `intrinsics.cpp` | Lowering intrinsics | +| `jitlayers.cpp` | JIT-specific code, ORC compilation layers/utilities | +| `llvm-alloc-helpers.cpp` | Julia-specific escape analysis | +| `llvm-alloc-opt.cpp` | Custom LLVM pass to demote heap allocations to the stack | +| `llvm-cpufeatures.cpp` | Custom LLVM pass to lower CPU-based functions (e.g. haveFMA) | +| `llvm-demote-float16.cpp` | Custom LLVM pass to lower 16b float ops to 32b float ops | +| `llvm-final-gc-lowering.cpp` | Custom LLVM pass to lower GC calls to their final form | +| `llvm-gc-invariant-verifier.cpp` | Custom LLVM pass to verify Julia GC invariants | +| `llvm-julia-licm.cpp` | Custom LLVM pass to hoist/sink Julia-specific intrinsics | +| `llvm-late-gc-lowering.cpp` | Custom LLVM pass to root GC-tracked values | +| `llvm-lower-handlers.cpp` | Custom LLVM pass to lower try-catch blocks | +| `llvm-muladd.cpp` | Custom LLVM pass for fast-match FMA | +| `llvm-multiversioning.cpp` | Custom LLVM pass to generate sysimg code on multiple architectures | +| `llvm-propagate-addrspaces.cpp` | Custom LLVM pass to canonicalize addrspaces | +| `llvm-ptls.cpp` | Custom LLVM pass to lower TLS operations | +| `llvm-remove-addrspaces.cpp` | Custom LLVM pass to remove Julia addrspaces | +| `llvm-remove-ni.cpp` | Custom LLVM pass to remove Julia non-integral addrspaces | +| `llvm-simdloop.cpp` | Custom LLVM pass for [`@simd`](@ref) | +| `pipeline.cpp` | New pass manager pipeline, pass pipeline parsing | +| `sys.c` | I/O and operating system utility functions | Some of the `.cpp` files form a group that compile to a single object. @@ -77,12 +95,18 @@ LLVM tools as usual. `libjulia` can function as an LLVM pass plugin and can be loaded into LLVM tools, to make julia-specific passes available in this environment. In addition, it exposes the `-julia` meta-pass, which runs the entire Julia pass-pipeline over the IR. As an example, to generate a system -image, one could do: +image with the old pass manager, one could do: ``` opt -enable-new-pm=0 -load libjulia-codegen.so -julia -o opt.bc unopt.bc llc -o sys.o opt.bc cc -shared -o sys.so sys.o ``` +To generate a system image with the new pass manager, one could do: +``` +opt -load-pass-plugin=libjulia-codegen.so --passes='julia' -o opt.bc unopt.bc +llc -o sys.o opt.bc +cc -shared -o sys.so sys.o +``` This system image can then be loaded by `julia` as usual. It is also possible to dump an LLVM IR module for just one Julia function, diff --git a/doc/src/devdocs/locks.md b/doc/src/devdocs/locks.md index 6390277826f7a..6cc0c1270ca85 100644 --- a/doc/src/devdocs/locks.md +++ b/doc/src/devdocs/locks.md @@ -32,6 +32,7 @@ The following are definitely leaf locks (level 1), and must not try to acquire a > * RLST_mutex > * jl_locked_stream::mutex > * debuginfo_asyncsafe +> * inference_timing_mutex > > > flisp itself is already threadsafe, this lock only protects the `jl_ast_context_list_t` pool > > likewise, the ResourcePool::mutexes just protect the associated resource pool diff --git a/doc/src/manual/arrays.md b/doc/src/manual/arrays.md index 1c71a4bd59e35..3126f1c2a3270 100644 --- a/doc/src/manual/arrays.md +++ b/doc/src/manual/arrays.md @@ -879,10 +879,15 @@ slower than multiplication. While some arrays — like [`Array`](@ref) itself are implemented using a linear chunk of memory and directly use a linear index in their implementations, other arrays — like [`Diagonal`](@ref) — need the full set of cartesian indices to do their lookup (see [`IndexStyle`](@ref) to -introspect which is which). As such, when iterating over an entire array, it's -much better to iterate over [`eachindex(A)`](@ref) instead of `1:length(A)`. -Not only will the former be much faster in cases where `A` is `IndexCartesian`, -but it will also support [OffsetArrays](https://github.com/JuliaArrays/OffsetArrays.jl), too. +introspect which is which). + +!!! warnings + + When iterating over all the indices for an array, it is + better to iterate over [`eachindex(A)`](@ref) instead of `1:length(A)`. + Not only will this be faster in cases where `A` is `IndexCartesian`, + but it will also support arrays with custom indexing, such as [OffsetArrays](https://github.com/JuliaArrays/OffsetArrays.jl). + If only the values are needed, then is better to just iterate the array directly, i.e. `for a in A`. #### Omitted and extra indices @@ -974,8 +979,11 @@ i = CartesianIndex(2, 2) i = CartesianIndex(3, 2) ``` -In contrast with `for i = 1:length(A)`, iterating with [`eachindex`](@ref) provides an efficient way to -iterate over any array type. +!!! note + + In contrast with `for i = 1:length(A)`, iterating with [`eachindex`](@ref) provides an efficient way to + iterate over any array type. Besides, this also supports generic arrays with custom indexing such as + [OffsetArrays](https://github.com/JuliaArrays/OffsetArrays.jl). ## Array traits diff --git a/doc/src/manual/conversion-and-promotion.md b/doc/src/manual/conversion-and-promotion.md index 63ae37660cff4..82073c1446bf8 100644 --- a/doc/src/manual/conversion-and-promotion.md +++ b/doc/src/manual/conversion-and-promotion.md @@ -181,7 +181,7 @@ For example, this definition states that it's valid to `convert` any `Number` ty any other by calling a 1-argument constructor: ```julia -convert(::Type{T}, x::Number) where {T<:Number} = T(x) +convert(::Type{T}, x::Number) where {T<:Number} = T(x)::T ``` This means that new `Number` types only need to define constructors, since this diff --git a/doc/src/manual/distributed-computing.md b/doc/src/manual/distributed-computing.md index 2c1af8ecb9c26..544dace1a99ec 100644 --- a/doc/src/manual/distributed-computing.md +++ b/doc/src/manual/distributed-computing.md @@ -251,7 +251,7 @@ The base Julia installation has in-built support for two types of clusters: should use to connect to this worker. !!! note - While Julia generally strives for backward compatability, distribution of code to worker processes relies on + While Julia generally strives for backward compatibility, distribution of code to worker processes relies on [`Serialization.serialize`](@ref). As pointed out in the corresponding documentation, this can not be guaranteed to work across different Julia versions, so it is advised that all workers on all machines use the same version. diff --git a/doc/src/manual/interfaces.md b/doc/src/manual/interfaces.md index af4185a0f1266..5b43933c723d3 100644 --- a/doc/src/manual/interfaces.md +++ b/doc/src/manual/interfaces.md @@ -220,10 +220,10 @@ ourselves, we can officially define it as a subtype of an [`AbstractArray`](@ref | `size(A)` | | Returns a tuple containing the dimensions of `A` | | `getindex(A, i::Int)` | | (if `IndexLinear`) Linear scalar indexing | | `getindex(A, I::Vararg{Int, N})` | | (if `IndexCartesian`, where `N = ndims(A)`) N-dimensional scalar indexing | -| `setindex!(A, v, i::Int)` | | (if `IndexLinear`) Scalar indexed assignment | -| `setindex!(A, v, I::Vararg{Int, N})` | | (if `IndexCartesian`, where `N = ndims(A)`) N-dimensional scalar indexed assignment | | **Optional methods** | **Default definition** | **Brief description** | | `IndexStyle(::Type)` | `IndexCartesian()` | Returns either `IndexLinear()` or `IndexCartesian()`. See the description below. | +| `setindex!(A, v, i::Int)` | | (if `IndexLinear`) Scalar indexed assignment | +| `setindex!(A, v, I::Vararg{Int, N})` | | (if `IndexCartesian`, where `N = ndims(A)`) N-dimensional scalar indexed assignment | | `getindex(A, I...)` | defined in terms of scalar `getindex` | [Multidimensional and nonscalar indexing](@ref man-array-indexing) | | `setindex!(A, X, I...)` | defined in terms of scalar `setindex!` | [Multidimensional and nonscalar indexed assignment](@ref man-array-indexing) | | `iterate` | defined in terms of scalar `getindex` | Iteration | diff --git a/doc/src/manual/metaprogramming.md b/doc/src/manual/metaprogramming.md index 8fddb8868c7d4..8308914f34f79 100644 --- a/doc/src/manual/metaprogramming.md +++ b/doc/src/manual/metaprogramming.md @@ -102,7 +102,7 @@ julia> Meta.show_sexpr(ex3) The `:` character has two syntactic purposes in Julia. The first form creates a [`Symbol`](@ref), an [interned string](https://en.wikipedia.org/wiki/String_interning) used as one building-block -of expressions: +of expressions, from valid identifiers: ```jldoctest julia> s = :foo @@ -119,6 +119,9 @@ their string representations together: julia> :foo === Symbol("foo") true +julia> Symbol("1foo") # `:1foo` would not work, as `1foo` is not a valid identifier +Symbol("1foo") + julia> Symbol("func",10) :func10 @@ -126,9 +129,6 @@ julia> Symbol(:var,'_',"sym") :var_sym ``` -Note that to use `:` syntax, the symbol's name must be a valid identifier. -Otherwise the `Symbol(str)` constructor must be used. - In the context of an expression, symbols are used to indicate access to variables; when an expression is evaluated, a symbol is replaced with the value bound to that symbol in the appropriate [scope](@ref scope-of-variables). diff --git a/doc/src/manual/modules.md b/doc/src/manual/modules.md index c6009594bea2d..9a250fdf716a8 100644 --- a/doc/src/manual/modules.md +++ b/doc/src/manual/modules.md @@ -325,7 +325,17 @@ include(p) = Base.include(Mod, p) end ``` -If even `Core` is not wanted, a module that imports nothing and defines no names at all can be defined with `Module(:YourNameHere, false, false)` and code can be evaluated into it with [`@eval`](@ref) or [`Core.eval`](@ref). +If even `Core` is not wanted, a module that imports nothing and defines no names at all can be defined with `Module(:YourNameHere, false, false)` and code can be evaluated into it with [`@eval`](@ref) or [`Core.eval`](@ref): +```jldoctest +julia> arithmetic = Module(:arithmetic, false, false) +Main.arithmetic + +julia> @eval arithmetic add(x, y) = $(+)(x, y) +add (generic function with 1 method) + +julia> arithmetic.add(12, 13) +25 +``` ### Standard modules diff --git a/doc/src/manual/multi-threading.md b/doc/src/manual/multi-threading.md index ffe8980cff3de..9ebba4fd7f676 100644 --- a/doc/src/manual/multi-threading.md +++ b/doc/src/manual/multi-threading.md @@ -361,9 +361,6 @@ threads in Julia: multiple threads where at least one thread modifies the collection (common examples include `push!` on arrays, or inserting items into a `Dict`). - * `@threads` currently uses a static schedule, using all threads and assigning - equal iteration counts to each. In the future the default schedule is likely - to change to be dynamic. * The schedule used by `@spawn` is nondeterministic and should not be relied on. * Compute-bound, non-memory-allocating tasks can prevent garbage collection from running in other threads that are allocating memory. In these cases it may diff --git a/doc/src/manual/types.md b/doc/src/manual/types.md index 055569d873d50..8a2b5ab1d4a5b 100644 --- a/doc/src/manual/types.md +++ b/doc/src/manual/types.md @@ -108,9 +108,26 @@ local x::Int8 # in a local declaration x::Int8 = 10 # as the left-hand side of an assignment ``` -and applies to the whole current scope, even before the declaration. Currently, type declarations -cannot be used in global scope, e.g. in the REPL, since Julia does not yet have constant-type -globals. +and applies to the whole current scope, even before the declaration. + +As of Julia 1.8, type declarations can now be used in global scope i.e. +type annotations can be added to global variables to make accessing them type stable. +```julia +julia> x::Int = 10 +10 + +julia> x = 3.5 +ERROR: InexactError: Int64(3.5) + +julia> function foo(y) + global x = 15.8 # throws an error when foo is called + return x + y + end +foo (generic function with 1 method) + +julia> foo(10) +ERROR: InexactError: Int64(15.8) +``` Declarations can also be attached to function definitions: @@ -1524,7 +1541,7 @@ when the `:compact` property is set to `true`, falling back to the long representation if the property is `false` or absent: ```jldoctest polartype julia> function Base.show(io::IO, z::Polar) - if get(io, :compact, false) + if get(io, :compact, false)::Bool print(io, z.r, "ℯ", z.Θ, "im") else print(io, z.r, " * exp(", z.Θ, "im)") diff --git a/doc/src/manual/variables.md b/doc/src/manual/variables.md index 608ade7c33312..c6c965985100d 100644 --- a/doc/src/manual/variables.md +++ b/doc/src/manual/variables.md @@ -111,9 +111,8 @@ variable name. For example, if `+ᵃ` is an operator, then `+ᵃx` must be writt it from `+ ᵃx` where `ᵃx` is the variable name. -A particular class of variable names is one that contains only underscores. These identifiers can only be assigned values but cannot be used to assign values to other variables. -More technically, they can only be used as an [L-value](https://en.wikipedia.org/wiki/Value_(computer_science)#lrvalue), but not as an - [R-value](https://en.wikipedia.org/wiki/R-value): +A particular class of variable names is one that contains only underscores. These identifiers can only be assigned values, which are immediately discarded, and cannot therefore be used to assign values to other variables (i.e., they cannot be used as [`rvalues`](https://en.wikipedia.org/wiki/Value_(computer_science)#Assignment:_l-values_and_r-values)) or use the last value +assigned to them in any way. ```julia-repl julia> x, ___ = size([2 2; 1 1]) @@ -121,6 +120,9 @@ julia> x, ___ = size([2 2; 1 1]) julia> y = ___ ERROR: syntax: all-underscore identifier used as rvalue + +julia> println(___) +ERROR: syntax: all-underscore identifier used as rvalue ``` The only explicitly disallowed names for variables are the names of the built-in [Keywords](@ref Keywords): diff --git a/src/abi_aarch64.cpp b/src/abi_aarch64.cpp index 1a3f160329c6c..514c3c5a81a6d 100644 --- a/src/abi_aarch64.cpp +++ b/src/abi_aarch64.cpp @@ -43,9 +43,11 @@ Type *get_llvm_vectype(jl_datatype_t *dt, LLVMContext &ctx) const // the homogeneity check. jl_datatype_t *ft0 = (jl_datatype_t*)jl_field_type(dt, 0); // `ft0` should be a `VecElement` type and the true element type - // should be a primitive type - if (ft0->name != jl_vecelement_typename || - ((jl_datatype_t*)jl_field_type(ft0, 0))->layout->nfields) + // should be a primitive type (nfields == 0) + if (!jl_is_datatype(ft0) || ft0->name != jl_vecelement_typename) + return nullptr; + jl_datatype_t *ft00 = (jl_datatype_t*)jl_field_type(ft0, 0); + if (!jl_is_datatype(ft00) || ft00->layout->nfields) return nullptr; for (size_t i = 1; i < nfields; i++) { if (jl_field_type(dt, i) != (jl_value_t*)ft0) { @@ -120,15 +122,17 @@ bool isHFAorHVA(jl_datatype_t *dt, size_t dsz, size_t &nele, ElementType &ele, L // For composite types, find the first non zero sized member size_t i; size_t fieldsz; - for (i = 0;i < nfields;i++) { + for (i = 0; i < nfields; i++) { if ((fieldsz = jl_field_size(dt, i))) { break; } } assert(i < nfields); - // If there's only one non zero sized member, try again on this member + // If there's only one non-zero sized member, try again on this member if (fieldsz == dsz) { dt = (jl_datatype_t*)jl_field_type(dt, i); + if (!jl_is_datatype(dt)) + return false; continue; } if (Type *vectype = get_llvm_vectype(dt, ctx)) { @@ -140,11 +144,13 @@ bool isHFAorHVA(jl_datatype_t *dt, size_t dsz, size_t &nele, ElementType &ele, L return true; } // Otherwise, process each members - for (;i < nfields;i++) { + for (; i < nfields; i++) { size_t fieldsz = jl_field_size(dt, i); if (fieldsz == 0) continue; jl_datatype_t *fieldtype = (jl_datatype_t*)jl_field_type(dt, i); + if (!jl_is_datatype(dt)) + return false; // Check element count. // This needs to be done after the zero size member check if (nele > 3 || !isHFAorHVA(fieldtype, fieldsz, nele, ele, ctx)) { diff --git a/src/abi_arm.cpp b/src/abi_arm.cpp index 4987d07657ae6..441aa95b1fdf6 100644 --- a/src/abi_arm.cpp +++ b/src/abi_arm.cpp @@ -91,6 +91,8 @@ size_t isLegalHA(jl_datatype_t *dt, Type *&base, LLVMContext &ctx) const size_t parent_members = jl_datatype_nfields(dt); for (size_t i = 0; i < parent_members; ++i) { jl_datatype_t *fdt = (jl_datatype_t*)jl_field_type(dt,i); + if (!jl_is_datatype(fdt)) + return 0; Type *T = isLegalHAType(fdt, ctx); if (T) diff --git a/src/abi_ppc64le.cpp b/src/abi_ppc64le.cpp index 016eebd455525..2e18acdbd4f4b 100644 --- a/src/abi_ppc64le.cpp +++ b/src/abi_ppc64le.cpp @@ -44,6 +44,9 @@ struct ABI_PPC64leLayout : AbiLayout { // count the homogeneous floating aggregate size (saturating at max count of 8) unsigned isHFA(jl_datatype_t *ty, jl_datatype_t **ty0, bool *hva) const { + if (jl_datatype_size(ty) > 128 || ty->layout->npointers || ty->layout->haspadding) + return 9; + size_t i, l = ty->layout->nfields; // handle homogeneous float aggregates if (l == 0) { @@ -52,7 +55,7 @@ unsigned isHFA(jl_datatype_t *ty, jl_datatype_t **ty0, bool *hva) const *hva = false; if (*ty0 == NULL) *ty0 = ty; - else if (*hva || ty->size != (*ty0)->size) + else if (*hva || jl_datatype_size(ty) != jl_datatype_size(*ty0)) return 9; return 1; } @@ -69,7 +72,7 @@ unsigned isHFA(jl_datatype_t *ty, jl_datatype_t **ty0, bool *hva) const *hva = true; if (*ty0 == NULL) *ty0 = ty; - else if (!*hva || ty->size != (*ty0)->size) + else if (!*hva || jl_datatype_size(ty) != jl_datatype_size(*ty0)) return 9; for (i = 1; i < l; i++) { jl_datatype_t *fld = (jl_datatype_t*)jl_field_type(ty, i); diff --git a/src/abi_x86_64.cpp b/src/abi_x86_64.cpp index 43e539b8386ce..c3d12417e6de8 100644 --- a/src/abi_x86_64.cpp +++ b/src/abi_x86_64.cpp @@ -153,6 +153,10 @@ void classifyType(Classification& accum, jl_datatype_t *dt, uint64_t offset) con jl_value_t *ty = jl_field_type(dt, i); if (jl_field_isptr(dt, i)) ty = (jl_value_t*)jl_voidpointer_type; + else if (!jl_is_datatype(ty)) { // inline union + accum.addField(offset, Memory); + continue; + } classifyType(accum, (jl_datatype_t*)ty, offset + jl_field_offset(dt, i)); } } diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 78a259244c74e..98777ddd175a1 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -5,6 +5,7 @@ // target support #include +#include #include #include #include @@ -33,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -58,11 +60,17 @@ using namespace llvm; -#include "julia.h" -#include "julia_internal.h" #include "jitlayers.h" #include "julia_assert.h" +#define DEBUG_TYPE "julia_aotcompile" + +STATISTIC(CICacheLookups, "Number of codeinst cache lookups"); +STATISTIC(CreateNativeCalls, "Number of jl_create_native calls made"); +STATISTIC(CreateNativeMethods, "Number of methods compiled for jl_create_native"); +STATISTIC(CreateNativeMax, "Max number of methods compiled at once for jl_create_native"); +STATISTIC(CreateNativeGlobals, "Number of globals compiled for jl_create_native"); + template // for GlobalObject's static T *addComdat(T *G) { @@ -215,6 +223,7 @@ static void makeSafeName(GlobalObject &G) static void jl_ci_cache_lookup(const jl_cgparams_t &cgparams, jl_method_instance_t *mi, size_t world, jl_code_instance_t **ci_out, jl_code_info_t **src_out) { + ++CICacheLookups; jl_value_t *ci = cgparams.lookup(mi, world, world); JL_GC_PROMISE_ROOTED(ci); jl_code_instance_t *codeinst = NULL; @@ -253,6 +262,8 @@ static void jl_ci_cache_lookup(const jl_cgparams_t &cgparams, jl_method_instance extern "C" JL_DLLEXPORT void *jl_create_native_impl(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvmmod, const jl_cgparams_t *cgparams, int _policy) { + ++CreateNativeCalls; + CreateNativeMax.updateMax(jl_array_len(methods)); if (cgparams == NULL) cgparams = &jl_default_cgparams; jl_native_code_desc_t *data = new jl_native_code_desc_t; @@ -334,6 +345,7 @@ void *jl_create_native_impl(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvm gvars.push_back(std::string(global.second->getName())); data->jl_value_to_llvm[global.first] = gvars.size(); } + CreateNativeMethods += emitted.size(); // clones the contents of the module `m` to the shadow_output collector // while examining and recording what kind of function pointer we have @@ -376,6 +388,7 @@ void *jl_create_native_impl(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvm G->setLinkage(GlobalVariable::InternalLinkage); data->jl_sysimg_gvars.push_back(G); } + CreateNativeGlobals += gvars.size(); //Safe b/c context is locked by params #if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_) @@ -537,17 +550,20 @@ void jl_dump_native_impl(void *native_code, if (TM->addPassesToEmitFile(emitter, asm_OS, nullptr, CGFT_AssemblyFile, false)) jl_safe_printf("ERROR: target does not support generation of object files\n"); - legacy::PassManager optimizer; - if (bc_fname || obj_fname || asm_fname) { - addTargetPasses(&optimizer, TM->getTargetTriple(), TM->getTargetIRAnalysis()); - addOptimizationPasses(&optimizer, jl_options.opt_level, true, true); - addMachinePasses(&optimizer, jl_options.opt_level); - } - // Reset the target triple to make sure it matches the new target machine auto dataM = data->M.getModuleUnlocked(); dataM->setTargetTriple(TM->getTargetTriple().str()); dataM->setDataLayout(jl_create_datalayout(*TM)); + +#ifndef JL_USE_NEW_PM + legacy::PassManager optimizer; + addTargetPasses(&optimizer, TM->getTargetTriple(), TM->getTargetIRAnalysis()); + addOptimizationPasses(&optimizer, jl_options.opt_level, true, true); + addMachinePasses(&optimizer, jl_options.opt_level); +#else + NewPM optimizer{std::move(TM), getOptLevel(jl_options.opt_level), OptimizationOptions::defaults(true, true)}; +#endif + Type *T_size; if (sizeof(size_t) == 8) T_size = Type::getInt64Ty(Context); @@ -574,7 +590,7 @@ void jl_dump_native_impl(void *native_code, // do the actual work auto add_output = [&] (Module &M, StringRef unopt_bc_Name, StringRef bc_Name, StringRef obj_Name, StringRef asm_Name) { preopt.run(M, empty.MAM); - optimizer.run(M); + if (bc_fname || obj_fname || asm_fname) optimizer.run(M); // We would like to emit an alias or an weakref alias to redirect these symbols // but LLVM doesn't let us emit a GlobalAlias to a declaration... @@ -797,7 +813,11 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level, PM->add(createLowerSimdLoopPass()); // Annotate loop marked with "loopinfo" as LLVM parallel loop PM->add(createLICMPass()); PM->add(createJuliaLICMPass()); +#if JL_LLVM_VERSION >= 150000 + PM->add(createSimpleLoopUnswitchLegacyPass()); +#else PM->add(createLoopUnswitchPass()); +#endif PM->add(createLICMPass()); PM->add(createJuliaLICMPass()); PM->add(createInductiveRangeCheckEliminationPass()); // Must come before indvars @@ -944,45 +964,6 @@ void jl_add_optimization_passes_impl(LLVMPassManagerRef PM, int opt_level, int l addOptimizationPasses(unwrap(PM), opt_level, lower_intrinsics); } -// new pass manager plugin - -// NOTE: Instead of exporting all the constructors in passes.h we could -// forward the callbacks to the respective passes. LLVM seems to prefer this, -// and when we add the full pass builder having them directly will be helpful. -static void registerCallbacks(PassBuilder &PB) { - PB.registerPipelineParsingCallback( - [](StringRef Name, FunctionPassManager &PM, - ArrayRef InnerPipeline) { -#define FUNCTION_PASS(NAME, CREATE_PASS) if (Name == NAME) { PM.addPass(CREATE_PASS); return true; } -#include "llvm-julia-passes.inc" -#undef FUNCTION_PASS - return false; - }); - - PB.registerPipelineParsingCallback( - [](StringRef Name, ModulePassManager &PM, - ArrayRef InnerPipeline) { -#define MODULE_PASS(NAME, CREATE_PASS) if (Name == NAME) { PM.addPass(CREATE_PASS); return true; } -#include "llvm-julia-passes.inc" -#undef MODULE_PASS - return false; - }); - - PB.registerPipelineParsingCallback( - [](StringRef Name, LoopPassManager &PM, - ArrayRef InnerPipeline) { -#define LOOP_PASS(NAME, CREATE_PASS) if (Name == NAME) { PM.addPass(CREATE_PASS); return true; } -#include "llvm-julia-passes.inc" -#undef LOOP_PASS - return false; - }); -} - -extern "C" JL_DLLEXPORT ::llvm::PassPluginLibraryInfo -llvmGetPassPluginInfo() { - return {LLVM_PLUGIN_API_VERSION, "Julia", "1", registerCallbacks}; -} - // --- native code info, and dump function to IR and ASM --- // Get pointer to llvm::Function instance, compiling if necessary // for use in reflection from Julia. @@ -1051,10 +1032,14 @@ void jl_get_llvmf_defn_impl(jl_llvmf_dump_t* dump, jl_method_instance_t *mi, siz for (auto &global : output.globals) global.second->setLinkage(GlobalValue::ExternalLinkage); if (optimize) { +#ifndef JL_USE_NEW_PM legacy::PassManager PM; addTargetPasses(&PM, jl_ExecutionEngine->getTargetTriple(), jl_ExecutionEngine->getTargetIRAnalysis()); addOptimizationPasses(&PM, jl_options.opt_level); addMachinePasses(&PM, jl_options.opt_level); +#else + NewPM PM{jl_ExecutionEngine->cloneTargetMachine(), getOptLevel(jl_options.opt_level)}; +#endif //Safe b/c context lock is held by output PM.run(*m.getModuleUnlocked()); } diff --git a/src/builtin_proto.h b/src/builtin_proto.h index d9520bd251b86..f61f76c3966f8 100644 --- a/src/builtin_proto.h +++ b/src/builtin_proto.h @@ -59,6 +59,8 @@ DECLARE_BUILTIN(compilerbarrier); DECLARE_BUILTIN(getglobal); DECLARE_BUILTIN(setglobal); DECLARE_BUILTIN(finalizer); +DECLARE_BUILTIN(_compute_sparams); +DECLARE_BUILTIN(_svec_ref); JL_CALLABLE(jl_f_invoke_kwsorter); #ifdef DEFINE_BUILTIN_GLOBALS @@ -73,7 +75,8 @@ JL_CALLABLE(jl_f__setsuper); JL_CALLABLE(jl_f__equiv_typedef); JL_CALLABLE(jl_f_get_binding_type); JL_CALLABLE(jl_f_set_binding_type); - +JL_CALLABLE(jl_f__compute_sparams); +JL_CALLABLE(jl_f__svec_ref); #ifdef __cplusplus } #endif diff --git a/src/builtins.c b/src/builtins.c index a41a565b45346..954bff7771e3e 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1258,20 +1258,28 @@ JL_CALLABLE(jl_f_set_binding_type) // apply_type ----------------------------------------------------------------- -int jl_valid_type_param(jl_value_t *v) +static int is_nestable_type_param(jl_value_t *t) { - if (jl_is_tuple(v)) { + if (jl_is_namedtuple_type(t)) + t = jl_tparam1(t); + if (jl_is_tuple_type(t)) { // NOTE: tuples of symbols are not currently bits types, but have been // allowed as type parameters. this is a bit ugly. - jl_value_t *tt = jl_typeof(v); - size_t i, l = jl_nparams(tt); - for(i=0; i < l; i++) { - jl_value_t *pi = jl_tparam(tt,i); - if (!(pi == (jl_value_t*)jl_symbol_type || jl_isbits(pi))) + size_t i, l = jl_nparams(t); + for (i = 0; i < l; i++) { + jl_value_t *pi = jl_tparam(t, i); + if (!(pi == (jl_value_t*)jl_symbol_type || jl_isbits(pi) || is_nestable_type_param(pi))) return 0; } return 1; } + return 0; +} + +int jl_valid_type_param(jl_value_t *v) +{ + if (jl_is_tuple(v) || jl_is_namedtuple(v)) + return is_nestable_type_param(jl_typeof(v)); if (jl_is_vararg(v)) return 0; // TODO: maybe more things @@ -1626,6 +1634,36 @@ JL_CALLABLE(jl_f_finalizer) return jl_nothing; } +JL_CALLABLE(jl_f__compute_sparams) +{ + JL_NARGSV(_compute_sparams, 1); + jl_method_t *m = (jl_method_t*)args[0]; + JL_TYPECHK(_compute_sparams, method, (jl_value_t*)m); + jl_datatype_t *tt = jl_inst_arg_tuple_type(args[1], &args[2], nargs-1, 1); + jl_svec_t *env = jl_emptysvec; + JL_GC_PUSH2(&env, &tt); + jl_type_intersection_env((jl_value_t*)tt, m->sig, &env); + JL_GC_POP(); + return (jl_value_t*)env; +} + +JL_CALLABLE(jl_f__svec_ref) +{ + JL_NARGS(_svec_ref, 3, 3); + jl_value_t *b = args[0]; + jl_svec_t *s = (jl_svec_t*)args[1]; + jl_value_t *i = (jl_value_t*)args[2]; + JL_TYPECHK(_svec_ref, bool, b); + JL_TYPECHK(_svec_ref, simplevector, (jl_value_t*)s); + JL_TYPECHK(_svec_ref, long, i); + size_t len = jl_svec_len(s); + ssize_t idx = jl_unbox_long(i); + if (idx < 1 || idx > len) { + jl_bounds_error_int((jl_value_t*)s, idx); + } + return jl_svec_ref(s, idx-1); +} + static int equiv_field_types(jl_value_t *old, jl_value_t *ft) { size_t nf = jl_svec_len(ft); @@ -1998,6 +2036,8 @@ void jl_init_primitives(void) JL_GC_DISABLED jl_builtin_donotdelete = add_builtin_func("donotdelete", jl_f_donotdelete); jl_builtin_compilerbarrier = add_builtin_func("compilerbarrier", jl_f_compilerbarrier); add_builtin_func("finalizer", jl_f_finalizer); + add_builtin_func("_compute_sparams", jl_f__compute_sparams); + add_builtin_func("_svec_ref", jl_f__svec_ref); // builtin types add_builtin("Any", (jl_value_t*)jl_any_type); diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 5b03dbf474f90..c42e6f14473b3 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -431,7 +431,7 @@ static inline void maybe_mark_argument_dereferenceable(AttrBuilder &B, jl_value_ { B.addAttribute(Attribute::NonNull); B.addAttribute(Attribute::NoUndef); - // The `dereferencable` below does not imply `nonnull` for non addrspace(0) pointers. + // The `dereferenceable` below does not imply `nonnull` for non addrspace(0) pointers. size_t size = dereferenceable_size(jt); if (size) { B.addDereferenceableAttr(size); @@ -444,7 +444,7 @@ static inline Instruction *maybe_mark_load_dereferenceable(Instruction *LI, bool { if (isa(LI->getType())) { if (!can_be_null) - // The `dereferencable` below does not imply `nonnull` for non addrspace(0) pointers. + // The `dereferenceable` below does not imply `nonnull` for non addrspace(0) pointers. LI->setMetadata(LLVMContext::MD_nonnull, MDNode::get(LI->getContext(), None)); if (size) { Metadata *OP = ConstantAsMetadata::get(ConstantInt::get(getInt64Ty(LI->getContext()), size)); @@ -1356,6 +1356,8 @@ static bool _can_optimize_isa(jl_value_t *type, int &counter) return (_can_optimize_isa(((jl_uniontype_t*)type)->a, counter) && _can_optimize_isa(((jl_uniontype_t*)type)->b, counter)); } + if (type == (jl_value_t*)jl_type_type) + return true; if (jl_is_type_type(type) && jl_pointer_egal(type)) return true; if (jl_has_intersect_type_not_kind(type)) @@ -1439,6 +1441,22 @@ static std::pair emit_isa(jl_codectx_t &ctx, const jl_cgval_t &x, auto ptr = track_pjlvalue(ctx, literal_pointer_val(ctx, jl_tparam0(intersected_type))); return {ctx.builder.CreateICmpEQ(boxed(ctx, x), ptr), false}; } + if (intersected_type == (jl_value_t*)jl_type_type) { + // Inline jl_is_kind(jl_typeof(x)) + // N.B. We do the comparison with untracked pointers, because that gives + // LLVM more optimization opportunities. That means it is poosible for + // `typ` to get GC'ed, but we don't actually care, because we don't ever + // dereference it. + Value *typ = emit_pointer_from_objref(ctx, emit_typeof_boxed(ctx, x)); + auto val = ctx.builder.CreateOr( + ctx.builder.CreateOr( + ctx.builder.CreateICmpEQ(typ, literal_pointer_val(ctx, (jl_value_t*)jl_uniontype_type)), + ctx.builder.CreateICmpEQ(typ, literal_pointer_val(ctx, (jl_value_t*)jl_datatype_type))), + ctx.builder.CreateOr( + ctx.builder.CreateICmpEQ(typ, literal_pointer_val(ctx, (jl_value_t*)jl_unionall_type)), + ctx.builder.CreateICmpEQ(typ, literal_pointer_val(ctx, (jl_value_t*)jl_typeofbottom_type)))); + return std::make_pair(val, false); + } // intersection with Type needs to be handled specially if (jl_has_intersect_type_not_kind(type) || jl_has_intersect_type_not_kind(intersected_type)) { Value *vx = boxed(ctx, x); @@ -3330,7 +3348,7 @@ static Value *boxed(jl_codectx_t &ctx, const jl_cgval_t &vinfo, bool is_promotab static void emit_unionmove(jl_codectx_t &ctx, Value *dest, MDNode *tbaa_dst, const jl_cgval_t &src, Value *skip, bool isVolatile=false) { if (AllocaInst *ai = dyn_cast(dest)) - // TODO: make this a lifetime_end & dereferencable annotation? + // TODO: make this a lifetime_end & dereferenceable annotation? ctx.builder.CreateAlignedStore(UndefValue::get(ai->getAllocatedType()), ai, ai->getAlign()); if (jl_is_concrete_type(src.typ) || src.constant) { jl_value_t *typ = src.constant ? jl_typeof(src.constant) : src.typ; diff --git a/src/clangsa/GCChecker.cpp b/src/clangsa/GCChecker.cpp index 38bd012ff46fc..34821d6bac9cb 100644 --- a/src/clangsa/GCChecker.cpp +++ b/src/clangsa/GCChecker.cpp @@ -53,8 +53,8 @@ class GCChecker check::Location> { mutable std::unique_ptr BT; template - void report_error(callback f, CheckerContext &C, const char *message) const; - void report_error(CheckerContext &C, const char *message) const { + void report_error(callback f, CheckerContext &C, StringRef message) const; + void report_error(CheckerContext &C, StringRef message) const { return report_error([](PathSensitiveBugReport *) {}, C, message); } void @@ -509,7 +509,7 @@ PDP GCChecker::GCValueBugVisitor::VisitNode(const ExplodedNode *N, template void GCChecker::report_error(callback f, CheckerContext &C, - const char *message) const { + StringRef message) const { // Generate an error node. ExplodedNode *N = C.generateErrorNode(); if (!N) @@ -745,6 +745,7 @@ bool GCChecker::isGCTrackedType(QualType QT) { Name.endswith_lower("jl_method_match_t") || Name.endswith_lower("jl_vararg_t") || Name.endswith_lower("jl_opaque_closure_t") || + Name.endswith_lower("jl_globalref_t") || // Probably not technically true for these, but let's allow it Name.endswith_lower("typemap_intersection_env") || Name.endswith_lower("interpreter_state") || @@ -1229,8 +1230,15 @@ void GCChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { // We could separate out "not safepoint, except for noreturn functions", // but that seems like a lot of effort with little benefit. if (!FD || !FD->isNoReturn()) { - report_error(C, "Calling potential safepoint from function annotated " - "JL_NOTSAFEPOINT"); + report_error( + [&](PathSensitiveBugReport *Report) { + if (FD) + Report->addNote( + "Tried to call method defined here", + PathDiagnosticLocation::create(FD, C.getSourceManager())); + }, + C, ("Calling potential safepoint as " + + Call.getKindAsString() + " from function annotated JL_NOTSAFEPOINT").str()); return; } } diff --git a/src/codegen.cpp b/src/codegen.cpp index fea568c5bd0dd..1298e07525a62 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -155,8 +155,6 @@ typedef Instruction TerminatorInst; #define NOMINMAX #endif -#include "julia.h" -#include "julia_internal.h" #include "jitlayers.h" #include "codegen_shared.h" #include "processor.h" @@ -994,6 +992,18 @@ static const auto jlgetnthfieldchecked_func = new JuliaFunction{ Attributes(C, {Attribute::NonNull}), None); }, }; +static const auto jlfieldisdefinedchecked_func = new JuliaFunction{ + XSTR(jl_field_isdefined_checked), + [](LLVMContext &C) { + auto T_prjlvalue = JuliaType::get_prjlvalue_ty(C); + return FunctionType::get(getInt32Ty(C), + {T_prjlvalue, getSizeTy(C)}, false); + }, + [](LLVMContext &C) { return AttributeList::get(C, + AttributeSet(), + Attributes(C, {}), + None); }, +}; static const auto jlgetcfunctiontrampoline_func = new JuliaFunction{ XSTR(jl_get_cfunction_trampoline), [](LLVMContext &C) { @@ -1176,7 +1186,8 @@ static const auto &builtin_func_map() { { jl_f_apply_type_addr, new JuliaFunction{XSTR(jl_f_apply_type), get_func_sig, get_func_attrs} }, { jl_f_donotdelete_addr, new JuliaFunction{XSTR(jl_f_donotdelete), get_donotdelete_sig, get_donotdelete_func_attrs} }, { jl_f_compilerbarrier_addr, new JuliaFunction{XSTR(jl_f_compilerbarrier), get_func_sig, get_func_attrs} }, - { jl_f_finalizer_addr, new JuliaFunction{XSTR(jl_f_finalizer), get_func_sig, get_func_attrs} } + { jl_f_finalizer_addr, new JuliaFunction{XSTR(jl_f_finalizer), get_func_sig, get_func_attrs} }, + { jl_f__svec_ref_addr, new JuliaFunction{XSTR(jl_f__svec_ref), get_func_sig, get_func_attrs} } }; return builtins; } @@ -3451,6 +3462,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } } } + Value *vidx = emit_unbox(ctx, getSizeTy(ctx.builder.getContext()), fld, (jl_value_t*)jl_long_type); if (jl_is_tuple_type(utt) && is_tupletype_homogeneous(utt->parameters, true)) { // For tuples, we can emit code even if we don't know the exact // type (e.g. because we don't know the length). This is possible @@ -3466,7 +3478,6 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, if (jl_is_vararg(jt)) jt = jl_unwrap_vararg(jt); assert(jl_is_datatype(jt)); - Value *vidx = emit_unbox(ctx, getSizeTy(ctx.builder.getContext()), fld, (jl_value_t*)jl_long_type); // This is not necessary for correctness, but allows to omit // the extra code for getting the length of the tuple if (!bounds_check_enabled(ctx, boundscheck)) { @@ -3484,6 +3495,12 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, return true; } } + + // Unknown object, but field known to be integer + vidx = ctx.builder.CreateSub(vidx, ConstantInt::get(getSizeTy(ctx.builder.getContext()), 1)); + Value *fld_val = ctx.builder.CreateCall(prepare_call(jlgetnthfieldchecked_func), { boxed(ctx, obj), vidx }); + *ret = mark_julia_type(ctx, fld_val, true, jl_any_type); + return true; } } // TODO: generic getfield func with more efficient calling convention @@ -3653,6 +3670,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, const jl_cgval_t &obj = argv[1]; const jl_cgval_t &fld = argv[2]; jl_datatype_t *stt = (jl_datatype_t*)obj.typ; + ssize_t fieldidx = -1; if (jl_is_type_type((jl_value_t*)stt)) { // the representation type of Type{T} is either typeof(T), or unknown // TODO: could use `issingletontype` predicate here, providing better type knowledge @@ -3664,11 +3682,10 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } if (!jl_is_concrete_type((jl_value_t*)stt) || jl_is_array_type(stt) || stt == jl_module_type) { // TODO: use ->layout here instead of concrete_type - return false; + goto isdefined_unknown_idx; } assert(jl_is_datatype(stt)); - ssize_t fieldidx = -1; if (fld.constant && jl_is_symbol(fld.constant)) { jl_sym_t *sym = (jl_sym_t*)fld.constant; fieldidx = jl_field_index(stt, sym, 0); @@ -3677,7 +3694,15 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, fieldidx = jl_unbox_long(fld.constant) - 1; } else { - return false; +isdefined_unknown_idx: + if (nargs == 3 || fld.typ != (jl_value_t*)jl_long_type) + return false; + Value *vidx = emit_unbox(ctx, getSizeTy(ctx.builder.getContext()), fld, (jl_value_t*)jl_long_type); + vidx = ctx.builder.CreateSub(vidx, ConstantInt::get(getSizeTy(ctx.builder.getContext()), 1)); + Value *isd = ctx.builder.CreateCall(prepare_call(jlfieldisdefinedchecked_func), { boxed(ctx, obj), vidx }); + isd = ctx.builder.CreateTrunc(isd, getInt8Ty(ctx.builder.getContext())); + *ret = mark_julia_type(ctx, isd, false, jl_bool_type); + return true; } enum jl_memory_order order = jl_memory_order_unspecified; if (nargs == 3) { @@ -4233,26 +4258,6 @@ static jl_cgval_t emit_sparam(jl_codectx_t &ctx, size_t i) return mark_julia_type(ctx, sp, true, jl_any_type); } -static jl_cgval_t emit_global(jl_codectx_t &ctx, jl_sym_t *sym) -{ - jl_binding_t *jbp = NULL; - Value *bp = global_binding_pointer(ctx, ctx.module, sym, &jbp, false); - if (bp == NULL) - return jl_cgval_t(); - if (jbp && jbp->value != NULL) { - if (jbp->constp) - return mark_julia_const(ctx, jbp->value); - // double-check that a global variable is actually defined. this - // can be a problem in parallel when a definition is missing on - // one machine. - LoadInst *v = ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, bp, Align(sizeof(void*))); - v->setOrdering(AtomicOrdering::Unordered); - tbaa_decorate(ctx.tbaa().tbaa_binding, v); - return mark_julia_type(ctx, v, true, jl_any_type); - } - return emit_checked_var(ctx, bp, sym, false, ctx.tbaa().tbaa_binding); -} - static jl_cgval_t emit_isdefined(jl_codectx_t &ctx, jl_value_t *sym) { Value *isnull = NULL; @@ -4903,7 +4908,7 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_ { if (jl_is_symbol(expr)) { jl_sym_t *sym = (jl_sym_t*)expr; - return emit_global(ctx, sym); + return emit_globalref(ctx, ctx.module, sym, AtomicOrdering::Unordered); } if (jl_is_slot(expr) || jl_is_argument(expr)) { return emit_local(ctx, expr); @@ -6620,6 +6625,7 @@ static jl_llvm_functions_t jl_datatype_t *vatyp = NULL; JL_GC_PUSH2(&ctx.code, &vatyp); ctx.code = src->code; + ctx.source = src; std::map labels; bool toplevel = false; @@ -6642,13 +6648,12 @@ static jl_llvm_functions_t } ctx.nReqArgs = nreq; if (va) { - jl_sym_t *vn = (jl_sym_t*)jl_array_ptr_ref(src->slotnames, ctx.nargs - 1); + jl_sym_t *vn = slot_symbol(ctx, ctx.nargs-1); if (vn != jl_unused_sym) ctx.vaSlot = ctx.nargs - 1; } toplevel = !jl_is_method(lam->def.method); ctx.rettype = jlrettype; - ctx.source = src; ctx.funcName = ctx.name; ctx.spvals_ptr = NULL; jl_array_t *stmts = ctx.code; @@ -6706,7 +6711,7 @@ static jl_llvm_functions_t for (i = 0; i < nreq; i++) { jl_varinfo_t &varinfo = ctx.slots[i]; varinfo.isArgument = true; - jl_sym_t *argname = (jl_sym_t*)jl_array_ptr_ref(src->slotnames, i); + jl_sym_t *argname = slot_symbol(ctx, i); if (argname == jl_unused_sym) continue; jl_value_t *ty = jl_nth_slot_type(lam->specTypes, i); @@ -6923,7 +6928,7 @@ static jl_llvm_functions_t const bool AlwaysPreserve = true; // Go over all arguments and local variables and initialize their debug information for (i = 0; i < nreq; i++) { - jl_sym_t *argname = (jl_sym_t*)jl_array_ptr_ref(src->slotnames, i); + jl_sym_t *argname = slot_symbol(ctx, i); if (argname == jl_unused_sym) continue; jl_varinfo_t &varinfo = ctx.slots[i]; @@ -6950,7 +6955,7 @@ static jl_llvm_functions_t DINode::FlagZero); // Flags (TODO: Do we need any) } for (i = 0; i < vinfoslen; i++) { - jl_sym_t *s = (jl_sym_t*)jl_array_ptr_ref(src->slotnames, i); + jl_sym_t *s = slot_symbol(ctx, i); jl_varinfo_t &varinfo = ctx.slots[i]; if (varinfo.isArgument || s == jl_empty_sym || s == jl_unused_sym) continue; @@ -7175,7 +7180,7 @@ static jl_llvm_functions_t #endif if (returninfo.cc == jl_returninfo_t::Union) { param.addAttribute(Attribute::NonNull); - // The `dereferencable` below does not imply `nonnull` for non addrspace(0) pointers. + // The `dereferenceable` below does not imply `nonnull` for non addrspace(0) pointers. param.addDereferenceableAttr(returninfo.union_bytes); param.addAlignmentAttr(returninfo.union_align); } @@ -7185,7 +7190,7 @@ static jl_llvm_functions_t TypeSize sz = DL.getTypeAllocSize(RT); Align al = DL.getPrefTypeAlign(RT); param.addAttribute(Attribute::NonNull); - // The `dereferencable` below does not imply `nonnull` for non addrspace(0) pointers. + // The `dereferenceable` below does not imply `nonnull` for non addrspace(0) pointers. param.addDereferenceableAttr(sz); param.addAlignmentAttr(al); } @@ -7200,14 +7205,14 @@ static jl_llvm_functions_t AttrBuilder param(f->getAttributes().getParamAttributes(Arg->getArgNo())); #endif param.addAttribute(Attribute::NonNull); - // The `dereferencable` below does not imply `nonnull` for non addrspace(0) pointers. + // The `dereferenceable` below does not imply `nonnull` for non addrspace(0) pointers. size_t size = returninfo.return_roots * sizeof(jl_value_t*); param.addDereferenceableAttr(size); param.addAlignmentAttr(Align(sizeof(jl_value_t*))); attrs.at(Arg->getArgNo()) = AttributeSet::get(Arg->getContext(), param); // function declaration attributes } for (i = 0; i < nreq; i++) { - jl_sym_t *s = (jl_sym_t*)jl_array_ptr_ref(src->slotnames, i); + jl_sym_t *s = slot_symbol(ctx, i); jl_value_t *argType = (i == 0 && ctx.is_opaque_closure) ? (jl_value_t*)jl_any_type : jl_nth_slot_type(lam->specTypes, i); bool isboxed = deserves_argbox(argType); @@ -8516,7 +8521,9 @@ extern "C" void jl_init_llvm(void) // Initialize passes PassRegistry &Registry = *PassRegistry::getPassRegistry(); initializeCore(Registry); +#if JL_LLVM_VERSION < 150000 initializeCoroutines(Registry); +#endif initializeScalarOpts(Registry); initializeVectorization(Registry); initializeAnalysis(Registry); @@ -8551,12 +8558,11 @@ extern "C" void jl_init_llvm(void) // Register GDB event listener #if defined(JL_DEBUG_BUILD) jl_using_gdb_jitevents = true; -# else +#endif const char *jit_gdb = getenv("ENABLE_GDBLISTENER"); - if (jit_gdb && atoi(jit_gdb)) { - jl_using_gdb_jitevents = true; + if (jit_gdb) { + jl_using_gdb_jitevents = !!atoi(jit_gdb); } -#endif if (jl_using_gdb_jitevents) jl_ExecutionEngine->enableJITDebuggingSupport(); diff --git a/src/datatype.c b/src/datatype.c index 822b1d95422cf..a88e283e564de 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -1790,6 +1790,17 @@ JL_DLLEXPORT int jl_field_isdefined(jl_value_t *v, size_t i) JL_NOTSAFEPOINT return fval != NULL ? 1 : 0; } +JL_DLLEXPORT int jl_field_isdefined_checked(jl_value_t *v, size_t i) +{ + if (jl_is_module(v)) { + jl_type_error("isdefined", (jl_value_t*)jl_symbol_type, jl_box_long(i + 1)); + } + if (i >= jl_nfields(v)) + return 0; + return !!jl_field_isdefined(v, i); +} + + JL_DLLEXPORT size_t jl_get_field_offset(jl_datatype_t *ty, int field) { if (!jl_struct_try_layout(ty) || field > jl_datatype_nfields(ty) || field < 1) diff --git a/src/debug-registry.h b/src/debug-registry.h index b98c42f8de1fc..3780bbee33718 100644 --- a/src/debug-registry.h +++ b/src/debug-registry.h @@ -2,6 +2,7 @@ #include #include +#include "julia.h" #include "julia_internal.h" #include "processor.h" diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index eba6ea793b71c..fe5614100f9e3 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -20,10 +20,13 @@ #include #include +#ifdef _OS_DARWIN_ +#include +#endif + using namespace llvm; -#include "julia.h" -#include "julia_internal.h" +#include "jitlayers.h" #include "debuginfo.h" #if defined(_OS_LINUX_) # include @@ -37,11 +40,6 @@ using namespace llvm; #include #include "julia_assert.h" -#ifdef _OS_DARWIN_ -#include -#endif - -#include "jitlayers.h" static JITDebugInfoRegistry &getJITDebugRegistry() JL_NOTSAFEPOINT { return jl_ExecutionEngine->getDebugInfoRegistry(); diff --git a/src/disasm.cpp b/src/disasm.cpp index 69692da4c4b16..cfc030f649fd6 100644 --- a/src/disasm.cpp +++ b/src/disasm.cpp @@ -111,8 +111,6 @@ #include -#include "julia.h" -#include "julia_internal.h" #include "jitlayers.h" #include "processor.h" @@ -796,7 +794,13 @@ static const char *SymbolLookup(void *DisInfo, uint64_t ReferenceValue, uint64_t return NULL; } -static int OpInfoLookup(void *DisInfo, uint64_t PC, uint64_t Offset, uint64_t Size, +static int OpInfoLookup(void *DisInfo, uint64_t PC, + uint64_t Offset, +#if JL_LLVM_VERSION < 150000 + uint64_t Size, +#else + uint64_t OpSize, uint64_t InstSize, +#endif int TagType, void *TagBuf) { SymbolTable *SymTab = (SymbolTable*)DisInfo; @@ -1050,10 +1054,14 @@ static void jl_dump_asm_internal( MCInst Inst; MCDisassembler::DecodeStatus S; FuncMCView view = memoryObject.slice(Index); +#if JL_LLVM_VERSION < 150000 +#define getCommentOS() GetCommentOS() +#endif S = DisAsm->getInstruction(Inst, insSize, view, 0, - /*CStream*/ pass != 0 ? Streamer->GetCommentOS() : nulls()); - if (pass != 0 && Streamer->GetCommentOS().tell() > 0) - Streamer->GetCommentOS() << '\n'; + /*CStream*/ pass != 0 ? Streamer->getCommentOS () : nulls()); + if (pass != 0 && Streamer->getCommentOS ().tell() > 0) + Streamer->getCommentOS () << '\n'; +#undef GetCommentOS switch (S) { case MCDisassembler::Fail: if (insSize == 0) // skip illegible bytes diff --git a/src/dump.c b/src/dump.c index 27c10254eac51..a049730b1e302 100644 --- a/src/dump.c +++ b/src/dump.c @@ -188,11 +188,6 @@ static jl_typename_t *jl_idtable_typename = NULL; static jl_value_t *jl_bigint_type = NULL; static int gmp_limb_size = 0; -static void write_uint64(ios_t *s, uint64_t i) JL_NOTSAFEPOINT -{ - ios_write(s, (char*)&i, 8); -} - static void write_float64(ios_t *s, double x) JL_NOTSAFEPOINT { write_uint64(s, *((uint64_t*)&x)); @@ -314,75 +309,127 @@ static int type_recursively_external(jl_datatype_t *dt) JL_NOTSAFEPOINT return 1; } +static void mark_backedges_in_worklist(jl_method_instance_t *mi, htable_t *visited, int found) +{ + int oldfound = (char*)ptrhash_get(visited, mi) - (char*)HT_NOTFOUND; + if (oldfound < 3) + return; // not in-progress + ptrhash_put(visited, mi, (void*)((char*)HT_NOTFOUND + 1 + found)); +#ifndef NDEBUG + jl_module_t *mod = mi->def.module; + if (jl_is_method(mod)) + mod = ((jl_method_t*)mod)->module; + assert(jl_is_module(mod)); + assert(!mi->precompiled && !module_in_worklist(mod)); + assert(mi->backedges); +#endif + size_t i = 0, n = jl_array_len(mi->backedges); + while (i < n) { + jl_method_instance_t *be; + i = get_next_edge(mi->backedges, i, NULL, &be); + mark_backedges_in_worklist(be, visited, found); + } +} + // When we infer external method instances, ensure they link back to the // package. Otherwise they might be, e.g., for external macros -static int has_backedge_to_worklist(jl_method_instance_t *mi, htable_t *visited) +static int has_backedge_to_worklist(jl_method_instance_t *mi, htable_t *visited, int depth) { - void **bp = ptrhash_bp(visited, mi); - // HT_NOTFOUND: not yet analyzed - // HT_NOTFOUND + 1: doesn't link back - // HT_NOTFOUND + 2: does link back - if (*bp != HT_NOTFOUND) - return (char*)*bp - (char*)HT_NOTFOUND - 1; - *bp = (void*)((char*)HT_NOTFOUND + 1); // preliminarily mark as "not found" - // TODO: this algorithm deals with cycles incorrectly jl_module_t *mod = mi->def.module; if (jl_is_method(mod)) mod = ((jl_method_t*)mod)->module; assert(jl_is_module(mod)); if (mi->precompiled || module_in_worklist(mod)) { - *bp = (void*)((char*)HT_NOTFOUND + 2); // found return 1; } if (!mi->backedges) { return 0; } - size_t i, n = jl_array_len(mi->backedges); - for (i = 0; i < n; i++) { - jl_method_instance_t *be = (jl_method_instance_t*)jl_array_ptr_ref(mi->backedges, i); - if (has_backedge_to_worklist(be, visited)) { - bp = ptrhash_bp(visited, mi); // re-acquire since rehashing might change the location - *bp = (void*)((char*)HT_NOTFOUND + 2); // found - return 1; + void **bp = ptrhash_bp(visited, mi); + // HT_NOTFOUND: not yet analyzed + // HT_NOTFOUND + 1: no link back + // HT_NOTFOUND + 2: does link back + // HT_NOTFOUND + 3 + depth: in-progress + int found = (char*)*bp - (char*)HT_NOTFOUND; + if (found) + return found - 1; + *bp = (void*)((char*)HT_NOTFOUND + 3 + depth); // preliminarily mark as in-progress + size_t i = 0, n = jl_array_len(mi->backedges); + int cycle = 0; + while (i < n) { + jl_method_instance_t *be; + i = get_next_edge(mi->backedges, i, NULL, &be); + int child_found = has_backedge_to_worklist(be, visited, depth + 1); + if (child_found == 1) { + found = 1; + break; + } + else if (child_found >= 2 && child_found - 2 < cycle) { + // record the cycle will resolve at depth "cycle" + cycle = child_found - 2; + assert(cycle); } } - return 0; + if (!found && cycle && cycle != depth) + return cycle + 2; + bp = ptrhash_bp(visited, mi); // re-acquire since rehashing might change the location + *bp = (void*)((char*)HT_NOTFOUND + 1 + found); + if (cycle) { + // If we are the top of the current cycle, now mark all other parts of + // our cycle by re-walking the backedges graph and marking all WIP + // items as found. + // Be careful to only re-walk as far as we had originally scanned above. + // Or if we found a backedge, also mark all of the other parts of the + // cycle as also having an backedge. + n = i; + i = 0; + while (i < n) { + jl_method_instance_t *be; + i = get_next_edge(mi->backedges, i, NULL, &be); + mark_backedges_in_worklist(be, visited, found); + } + } + return found; } // given the list of MethodInstances that were inferred during the // build, select those that are external and have at least one -// relocatable CodeInstance. +// relocatable CodeInstance and are inferred to be called from the worklist +// or explicitly added by a precompile statement. static size_t queue_external_mis(jl_array_t *list) { + if (list == NULL) + return 0; size_t i, n = 0; htable_t visited; - if (list) { - assert(jl_is_array(list)); - size_t n0 = jl_array_len(list); - htable_new(&visited, n0); - for (i = 0; i < n0; i++) { - jl_method_instance_t *mi = (jl_method_instance_t*)jl_array_ptr_ref(list, i); - assert(jl_is_method_instance(mi)); - if (jl_is_method(mi->def.value)) { - jl_method_t *m = mi->def.method; - if (!module_in_worklist(m->module)) { - jl_code_instance_t *ci = mi->cache; - int relocatable = 0; - while (ci) { + assert(jl_is_array(list)); + size_t n0 = jl_array_len(list); + htable_new(&visited, n0); + for (i = 0; i < n0; i++) { + jl_method_instance_t *mi = (jl_method_instance_t*)jl_array_ptr_ref(list, i); + assert(jl_is_method_instance(mi)); + if (jl_is_method(mi->def.value)) { + jl_method_t *m = mi->def.method; + if (!module_in_worklist(m->module)) { + jl_code_instance_t *ci = mi->cache; + int relocatable = 0; + while (ci) { + if (ci->max_world == ~(size_t)0) relocatable |= ci->relocatability; - ci = ci->next; - } - if (relocatable && ptrhash_get(&external_mis, mi) == HT_NOTFOUND) { - if (has_backedge_to_worklist(mi, &visited)) { - ptrhash_put(&external_mis, mi, mi); - n++; - } + ci = ci->next; + } + if (relocatable && ptrhash_get(&external_mis, mi) == HT_NOTFOUND) { + int found = has_backedge_to_worklist(mi, &visited, 1); + assert(found == 0 || found == 1); + if (found == 1) { + ptrhash_put(&external_mis, mi, mi); + n++; } } } } - htable_free(&visited); } + htable_free(&visited); return n; } @@ -947,12 +994,16 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li if (backedges) { // filter backedges to only contain pointers // to items that we will actually store (internal >= 2) - size_t ins, i, l = jl_array_len(backedges); - jl_method_instance_t **b_edges = (jl_method_instance_t**)jl_array_data(backedges); - for (ins = i = 0; i < l; i++) { - jl_method_instance_t *backedge = b_edges[i]; + size_t ins = 0, i = 0, l = jl_array_len(backedges); + jl_value_t **b_edges = (jl_value_t**)jl_array_data(backedges); + jl_value_t *invokeTypes; + jl_method_instance_t *backedge; + while (i < l) { + i = get_next_edge(backedges, i, &invokeTypes, &backedge); if (module_in_worklist(backedge->def.method->module) || method_instance_in_queue(backedge)) { - b_edges[ins++] = backedge; + if (invokeTypes) + b_edges[ins++] = invokeTypes; + b_edges[ins++] = (jl_value_t*)backedge; } } if (ins != l) @@ -993,7 +1044,7 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li } else { write_uint8(s->s, TAG_INT64); - write_int64(s->s, *(int64_t*)data); + write_uint64(s->s, *(int64_t*)data); } } else if (jl_typeis(v, jl_int32_type)) { @@ -1157,7 +1208,7 @@ static void serialize_htable_keys(jl_serializer_state *s, htable_t *ht, int nite // or method instances not in the queue // // from MethodTables -static void jl_collect_missing_backedges_to_mod(jl_methtable_t *mt) +static void jl_collect_missing_backedges(jl_methtable_t *mt) { jl_array_t *backedges = mt->backedges; if (backedges) { @@ -1168,7 +1219,9 @@ static void jl_collect_missing_backedges_to_mod(jl_methtable_t *mt) jl_array_t **edges = (jl_array_t**)ptrhash_bp(&edges_map, (void*)caller); if (*edges == HT_NOTFOUND) *edges = jl_alloc_vec_any(0); - jl_array_ptr_1d_push(*edges, missing_callee); + // To stay synchronized with the format from MethodInstances (specifically for `invoke`d calls), + // we have to push a pair of values. But in this case the callee is unknown, so we leave it NULL. + push_edge(*edges, missing_callee, NULL); } } } @@ -1178,13 +1231,15 @@ static void collect_backedges(jl_method_instance_t *callee) JL_GC_DISABLED { jl_array_t *backedges = callee->backedges; if (backedges) { - size_t i, l = jl_array_len(backedges); - for (i = 0; i < l; i++) { - jl_method_instance_t *caller = (jl_method_instance_t*)jl_array_ptr_ref(backedges, i); + size_t i = 0, l = jl_array_len(backedges); + jl_value_t *invokeTypes; + jl_method_instance_t *caller; + while (i < l) { + i = get_next_edge(backedges, i, &invokeTypes, &caller); jl_array_t **edges = (jl_array_t**)ptrhash_bp(&edges_map, caller); if (*edges == HT_NOTFOUND) *edges = jl_alloc_vec_any(0); - jl_array_ptr_1d_push(*edges, (jl_value_t*)callee); + push_edge(*edges, invokeTypes, callee); } } } @@ -1242,7 +1297,7 @@ static void jl_collect_extext_methods_from_mod(jl_array_t *s, jl_module_t *m) JL (jl_value_t*)mt != jl_nothing && (mt != jl_type_type_mt && mt != jl_nonfunction_mt)) { jl_collect_methtable_from_mod(s, mt); - jl_collect_missing_backedges_to_mod(mt); + jl_collect_missing_backedges(mt); } } } @@ -1268,6 +1323,15 @@ static void jl_collect_extext_methods_from_mod(jl_array_t *s, jl_module_t *m) JL } } +static void register_backedge(htable_t *all_callees, jl_value_t *invokeTypes, jl_value_t *c) +{ + if (invokeTypes) + ptrhash_put(all_callees, invokeTypes, c); + else + ptrhash_put(all_callees, c, c); + +} + // flatten the backedge map reachable from caller into callees static void jl_collect_backedges_to(jl_method_instance_t *caller, htable_t *all_callees) JL_GC_DISABLED { @@ -1278,11 +1342,13 @@ static void jl_collect_backedges_to(jl_method_instance_t *caller, htable_t *all_ *callees = *pcallees; assert(callees != HT_NOTFOUND); *pcallees = (jl_array_t*) HT_NOTFOUND; - size_t i, l = jl_array_len(callees); - for (i = 0; i < l; i++) { - jl_value_t *c = jl_array_ptr_ref(callees, i); - ptrhash_put(all_callees, c, c); - if (jl_is_method_instance(c)) { + size_t i = 0, l = jl_array_len(callees); + jl_method_instance_t *c; + jl_value_t *invokeTypes; + while (i < l) { + i = get_next_edge(callees, i, &invokeTypes, &c); + register_backedge(all_callees, invokeTypes, (jl_value_t*)c); + if (c && jl_is_method_instance(c)) { jl_collect_backedges_to((jl_method_instance_t*)c, all_callees); } } @@ -1291,12 +1357,14 @@ static void jl_collect_backedges_to(jl_method_instance_t *caller, htable_t *all_ // Extract `edges` and `ext_targets` from `edges_map` // This identifies internal->external edges in the call graph, pulling them out for special treatment. -static void jl_collect_backedges( /* edges */ jl_array_t *s, /* ext_targets */ jl_array_t *t) +static void jl_collect_backedges(jl_array_t *edges, jl_array_t *ext_targets) { htable_t all_targets; // target => tgtindex mapping htable_t all_callees; // MIs called by worklist methods (eff. Set{MethodInstance}) htable_new(&all_targets, 0); htable_new(&all_callees, 0); + jl_value_t *invokeTypes; + jl_method_instance_t *c; size_t i; void **table = edges_map.table; // edges is caller => callees size_t table_size = edges_map.size; @@ -1309,11 +1377,11 @@ static void jl_collect_backedges( /* edges */ jl_array_t *s, /* ext_targets */ j continue; assert(jl_is_method_instance(caller) && jl_is_method(caller->def.method)); if (module_in_worklist(caller->def.method->module) || method_instance_in_queue(caller)) { - size_t i, l = jl_array_len(callees); - for (i = 0; i < l; i++) { - jl_value_t *c = jl_array_ptr_ref(callees, i); - ptrhash_put(&all_callees, c, c); - if (jl_is_method_instance(c)) { + size_t i = 0, l = jl_array_len(callees); + while (i < l) { + i = get_next_edge(callees, i, &invokeTypes, &c); + register_backedge(&all_callees, invokeTypes, (jl_value_t*)c); + if (c && jl_is_method_instance(c)) { jl_collect_backedges_to((jl_method_instance_t*)c, &all_callees); } } @@ -1321,18 +1389,21 @@ static void jl_collect_backedges( /* edges */ jl_array_t *s, /* ext_targets */ j void **pc = all_callees.table; size_t j; int valid = 1; + int mode; for (j = 0; valid && j < all_callees.size; j += 2) { if (pc[j + 1] != HT_NOTFOUND) { jl_value_t *callee = (jl_value_t*)pc[j]; void *target = ptrhash_get(&all_targets, (void*)callee); if (target == HT_NOTFOUND) { - jl_method_instance_t *callee_mi = (jl_method_instance_t*)callee; jl_value_t *sig; if (jl_is_method_instance(callee)) { - sig = callee_mi->specTypes; + sig = ((jl_method_instance_t*)callee)->specTypes; + mode = 1; } else { sig = callee; + callee = (jl_value_t*)pc[j+1]; + mode = 2; } size_t min_valid = 0; size_t max_valid = ~(size_t)0; @@ -1347,9 +1418,10 @@ static void jl_collect_backedges( /* edges */ jl_array_t *s, /* ext_targets */ j jl_method_match_t *match = (jl_method_match_t *)jl_array_ptr_ref(matches, k); jl_array_ptr_set(matches, k, match->method); } - jl_array_ptr_1d_push(t, callee); - jl_array_ptr_1d_push(t, matches); - target = (char*)HT_NOTFOUND + jl_array_len(t) / 2; + jl_array_ptr_1d_push(ext_targets, mode == 1 ? NULL : sig); + jl_array_ptr_1d_push(ext_targets, callee); + jl_array_ptr_1d_push(ext_targets, matches); + target = (char*)HT_NOTFOUND + jl_array_len(ext_targets) / 3; ptrhash_put(&all_targets, (void*)callee, target); } jl_array_grow_end(callees, 1); @@ -1358,8 +1430,8 @@ static void jl_collect_backedges( /* edges */ jl_array_t *s, /* ext_targets */ j } htable_reset(&all_callees, 100); if (valid) { - jl_array_ptr_1d_push(s, (jl_value_t*)caller); - jl_array_ptr_1d_push(s, (jl_value_t*)callees); + jl_array_ptr_1d_push(edges, (jl_value_t*)caller); + jl_array_ptr_1d_push(edges, (jl_value_t*)callees); } } } @@ -1549,7 +1621,7 @@ static int64_t write_dependency_list(ios_t *s, jl_array_t **udepsp) ios_seek(s, initial_pos); write_uint64(s, pos - initial_pos); ios_seek(s, pos); - write_int64(s, 0); + write_uint64(s, 0); } return pos; } @@ -2057,6 +2129,10 @@ static void jl_deserialize_struct(jl_serializer_state *s, jl_value_t *v) JL_GC_D entry->min_world = 1; entry->max_world = 0; } + } else if (dt == jl_globalref_type) { + jl_globalref_t *r = (jl_globalref_t*)v; + jl_binding_t *b = jl_get_binding_if_bound(r->mod, r->name); + r->bnd_cache = b && b->value ? b : NULL; } } @@ -2294,7 +2370,45 @@ void remove_code_instance_from_validation(jl_code_instance_t *codeinst) ptrhash_remove(&new_code_instance_validate, codeinst); } -static void jl_insert_method_instances(jl_array_t *list) +static int do_selective_invoke_backedge_invalidation(jl_methtable_t *mt, jl_value_t *mworld, jl_method_instance_t *mi, size_t world) +{ + jl_value_t *invokeTypes; + jl_method_instance_t *caller; + size_t jins = 0, j0, j = 0, nbe = jl_array_len(mi->backedges); + while (j < nbe) { + j0 = j; + j = get_next_edge(mi->backedges, j, &invokeTypes, &caller); + if (invokeTypes) { + struct jl_typemap_assoc search = {invokeTypes, world, NULL, 0, ~(size_t)0}; + jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(mt->defs, &search, /*offs*/0, /*subtype*/0); + if (entry) { + jl_value_t *imworld = entry->func.value; + if (jl_is_method(imworld) && mi->def.method == (jl_method_t*)imworld) { + // this one is OK + // in case we deleted some earlier ones, move this earlier + for (; j0 < j; jins++, j0++) { + jl_array_ptr_set(mi->backedges, jins, jl_array_ptr_ref(mi->backedges, j0)); + } + continue; + } + } + } + invalidate_backedges(&remove_code_instance_from_validation, caller, world, "jl_insert_method_instance caller"); + // The codeinst of this mi haven't yet been removed + jl_code_instance_t *codeinst = caller->cache; + while (codeinst) { + remove_code_instance_from_validation(codeinst); + codeinst = codeinst->next; + } + } + jl_array_del_end(mi->backedges, j - jins); + if (jins == 0) { + return 0; + } + return 1; +} + +static void jl_insert_method_instances(jl_array_t *list) JL_GC_DISABLED { size_t i, l = jl_array_len(list); // Validate the MethodInstances @@ -2303,29 +2417,48 @@ static void jl_insert_method_instances(jl_array_t *list) size_t world = jl_atomic_load_acquire(&jl_world_counter); for (i = 0; i < l; i++) { jl_method_instance_t *mi = (jl_method_instance_t*)jl_array_ptr_ref(list, i); + int valid = 1; assert(jl_is_method_instance(mi)); if (jl_is_method(mi->def.method)) { - // Is this still the method we'd be calling? - jl_methtable_t *mt = jl_method_table_for(mi->specTypes); - struct jl_typemap_assoc search = {(jl_value_t*)mi->specTypes, world, NULL, 0, ~(size_t)0}; - jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(mt->defs, &search, /*offs*/0, /*subtype*/1); - if (entry) { - jl_value_t *mworld = entry->func.value; - if (jl_is_method(mworld) && mi->def.method != (jl_method_t*)mworld && jl_type_morespecific(((jl_method_t*)mworld)->sig, mi->def.method->sig)) { - jl_array_uint8_set(valids, i, 0); - invalidate_backedges(&remove_code_instance_from_validation, mi, world, "jl_insert_method_instance"); - // The codeinst of this mi haven't yet been removed - jl_code_instance_t *codeinst = mi->cache; - while (codeinst) { - remove_code_instance_from_validation(codeinst); - codeinst = codeinst->next; - } - if (_jl_debug_method_invalidation) { - jl_array_ptr_1d_push(_jl_debug_method_invalidation, mworld); - jl_array_ptr_1d_push(_jl_debug_method_invalidation, jl_cstr_to_string("jl_method_table_insert")); // GC disabled + jl_method_t *m = mi->def.method; + if (m->deleted_world != ~(size_t)0) { + // The method we depended on has been deleted, invalidate + valid = 0; + } else { + // Is this still the method we'd be calling? + jl_methtable_t *mt = jl_method_table_for(mi->specTypes); + struct jl_typemap_assoc search = {(jl_value_t*)mi->specTypes, world, NULL, 0, ~(size_t)0}; + jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(mt->defs, &search, /*offs*/0, /*subtype*/0); + if (entry) { + jl_value_t *mworld = entry->func.value; + if (jl_is_method(mworld) && mi->def.method != (jl_method_t*)mworld && jl_type_morespecific(((jl_method_t*)mworld)->sig, mi->def.method->sig)) { + if (!mi->backedges) { + valid = 0; + } else { + // There's still a chance this is valid, if any caller made this via `invoke` and the invoke-signature is still valid. + // Selectively go through all the backedges, invalidating those not made via `invoke` and validating those that are. + if (!do_selective_invoke_backedge_invalidation(mt, mworld, mi, world)) { + m = (jl_method_t*)mworld; + valid = 0; + } + } } } } + if (!valid) { + // None of the callers were valid, so invalidate `mi` too + jl_array_uint8_set(valids, i, 0); + invalidate_backedges(&remove_code_instance_from_validation, mi, world, "jl_insert_method_instance"); + jl_code_instance_t *codeinst = mi->cache; + while (codeinst) { + remove_code_instance_from_validation(codeinst); + codeinst = codeinst->next; + } + if (_jl_debug_method_invalidation) { + jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)m); + jl_array_ptr_1d_push(_jl_debug_method_invalidation, jl_cstr_to_string("jl_method_table_insert")); // GC disabled + } + } } } // While it's tempting to just remove the invalidated MIs altogether, @@ -2342,36 +2475,43 @@ static void jl_insert_method_instances(jl_array_t *list) if (milive != mi) { // A previously-loaded module compiled this method, so the one we deserialized will be dropped. // But make sure the backedges are copied over. + jl_value_t *invokeTypes; + jl_method_instance_t *be, *belive; if (mi->backedges) { if (!milive->backedges) { // Copy all the backedges (after looking up the live ones) - size_t j, n = jl_array_len(mi->backedges); + size_t j = 0, jlive = 0, n = jl_array_len(mi->backedges); milive->backedges = jl_alloc_vec_any(n); jl_gc_wb(milive, milive->backedges); - for (j = 0; j < n; j++) { - jl_method_instance_t *be = (jl_method_instance_t*)jl_array_ptr_ref(mi->backedges, j); - jl_method_instance_t *belive = (jl_method_instance_t*)ptrhash_get(&uniquing_table, be); + while (j < n) { + j = get_next_edge(mi->backedges, j, &invokeTypes, &be); + belive = (jl_method_instance_t*)ptrhash_get(&uniquing_table, be); if (belive == HT_NOTFOUND) belive = be; - jl_array_ptr_set(milive->backedges, j, belive); + jlive = set_next_edge(milive->backedges, jlive, invokeTypes, belive); } } else { // Copy the missing backedges (this is an O(N^2) algorithm, but many methods have few MethodInstances) - size_t j, k, n = jl_array_len(mi->backedges), nlive = jl_array_len(milive->backedges); - for (j = 0; j < n; j++) { - jl_method_instance_t *be = (jl_method_instance_t*)jl_array_ptr_ref(mi->backedges, j); - jl_method_instance_t *belive = (jl_method_instance_t*)ptrhash_get(&uniquing_table, be); + size_t j = 0, k, n = jl_array_len(mi->backedges), nlive = jl_array_len(milive->backedges); + jl_value_t *invokeTypes2; + jl_method_instance_t *belive2; + while (j < n) { + j = get_next_edge(mi->backedges, j, &invokeTypes, &be); + belive = (jl_method_instance_t*)ptrhash_get(&uniquing_table, be); if (belive == HT_NOTFOUND) belive = be; int found = 0; - for (k = 0; k < nlive; k++) { - if (belive == (jl_method_instance_t*)jl_array_ptr_ref(milive->backedges, k)) { + k = 0; + while (k < nlive) { + k = get_next_edge(milive->backedges, k, &invokeTypes2, &belive2); + if (belive == belive2 && ((invokeTypes == NULL && invokeTypes2 == NULL) || + (invokeTypes && invokeTypes2 && jl_egal(invokeTypes, invokeTypes2)))) { found = 1; break; } } if (!found) - jl_array_ptr_1d_push(milive->backedges, (jl_value_t*)belive); + push_edge(milive->backedges, invokeTypes, belive); } } } @@ -2398,23 +2538,24 @@ static void jl_insert_method_instances(jl_array_t *list) // verify that these edges intersect with the same methods as before static void jl_verify_edges(jl_array_t *targets, jl_array_t **pvalids) { - size_t i, l = jl_array_len(targets) / 2; + size_t i, l = jl_array_len(targets) / 3; jl_array_t *valids = jl_alloc_array_1d(jl_array_uint8_type, l); memset(jl_array_data(valids), 1, l); jl_value_t *loctag = NULL; JL_GC_PUSH1(&loctag); *pvalids = valids; for (i = 0; i < l; i++) { - jl_value_t *callee = jl_array_ptr_ref(targets, i * 2); + jl_value_t *invokesig = jl_array_ptr_ref(targets, i * 3); + jl_value_t *callee = jl_array_ptr_ref(targets, i * 3 + 1); jl_method_instance_t *callee_mi = (jl_method_instance_t*)callee; jl_value_t *sig; - if (jl_is_method_instance(callee)) { - sig = callee_mi->specTypes; + if (callee && jl_is_method_instance(callee)) { + sig = invokesig == NULL ? callee_mi->specTypes : invokesig; } else { - sig = callee; + sig = callee == NULL ? invokesig : callee; } - jl_array_t *expected = (jl_array_t*)jl_array_ptr_ref(targets, i * 2 + 1); + jl_array_t *expected = (jl_array_t*)jl_array_ptr_ref(targets, i * 3 + 2); assert(jl_is_array(expected)); int valid = 1; size_t min_valid = 0; @@ -2454,20 +2595,20 @@ static void jl_verify_edges(jl_array_t *targets, jl_array_t **pvalids) } // Restore backedges to external targets -// `targets` is [callee1, matches1, ...], the global set of non-worklist callees of worklist-owned methods. -// `list` = [caller1, targets_indexes1, ...], the list of worklist-owned methods calling external methods. -static void jl_insert_backedges(jl_array_t *list, jl_array_t *targets) +// `edges` = [caller1, targets_indexes1, ...], the list of worklist-owned methods calling external methods. +// `ext_targets` is [invokesig1, callee1, matches1, ...], the global set of non-worklist callees of worklist-owned methods. +static void jl_insert_backedges(jl_array_t *edges, jl_array_t *ext_targets) { - // map(enable, ((list[i] => targets[list[i + 1] .* 2]) for i in 1:2:length(list) if all(valids[list[i + 1]]))) - size_t i, l = jl_array_len(list); + // foreach(enable, ((edges[2i-1] => ext_targets[edges[2i] .* 3]) for i in 1:length(edges)÷2 if all(valids[edges[2i]]))) + size_t i, l = jl_array_len(edges); jl_array_t *valids = NULL; jl_value_t *loctag = NULL; JL_GC_PUSH2(&valids, &loctag); - jl_verify_edges(targets, &valids); + jl_verify_edges(ext_targets, &valids); for (i = 0; i < l; i += 2) { - jl_method_instance_t *caller = (jl_method_instance_t*)jl_array_ptr_ref(list, i); + jl_method_instance_t *caller = (jl_method_instance_t*)jl_array_ptr_ref(edges, i); assert(jl_is_method_instance(caller) && jl_is_method(caller->def.method)); - jl_array_t *idxs_array = (jl_array_t*)jl_array_ptr_ref(list, i + 1); + jl_array_t *idxs_array = (jl_array_t*)jl_array_ptr_ref(edges, i + 1); assert(jl_isa((jl_value_t*)idxs_array, jl_array_int32_type)); int32_t *idxs = (int32_t*)jl_array_data(idxs_array); int valid = 1; @@ -2480,18 +2621,20 @@ static void jl_insert_backedges(jl_array_t *list, jl_array_t *targets) // if this callee is still valid, add all the backedges for (j = 0; j < jl_array_len(idxs_array); j++) { int32_t idx = idxs[j]; - jl_value_t *callee = jl_array_ptr_ref(targets, idx * 2); - if (jl_is_method_instance(callee)) { - jl_method_instance_add_backedge((jl_method_instance_t*)callee, caller); + jl_value_t *callee = jl_array_ptr_ref(ext_targets, idx * 3 + 1); + if (callee && jl_is_method_instance(callee)) { + jl_value_t *invokesig = jl_array_ptr_ref(ext_targets, idx * 3); + jl_method_instance_add_backedge((jl_method_instance_t*)callee, invokesig, caller); } else { - jl_methtable_t *mt = jl_method_table_for(callee); + jl_value_t *sig = callee == NULL ? jl_array_ptr_ref(ext_targets, idx * 3) : callee; + jl_methtable_t *mt = jl_method_table_for(sig); // FIXME: rarely, `callee` has an unexpected `Union` signature, // see https://github.com/JuliaLang/julia/pull/43990#issuecomment-1030329344 // Fix the issue and turn this back into an `assert((jl_value_t*)mt != jl_nothing)` // This workaround exposes us to (rare) 265-violations. if ((jl_value_t*)mt != jl_nothing) - jl_method_table_add_backedge(mt, callee, (jl_value_t*)caller); + jl_method_table_add_backedge(mt, sig, (jl_value_t*)caller); } } // then enable it @@ -2739,7 +2882,10 @@ JL_DLLEXPORT int jl_save_incremental(const char *fname, jl_array_t *worklist) int en = jl_gc_enable(0); // edges map is not gc-safe jl_array_t *extext_methods = jl_alloc_vec_any(0); // [method1, simplesig1, ...], worklist-owned "extending external" methods added to functions owned by modules outside the worklist - jl_array_t *ext_targets = jl_alloc_vec_any(0); // [callee1, matches1, ...] non-worklist callees of worklist-owned methods + jl_array_t *ext_targets = jl_alloc_vec_any(0); // [invokesig1, callee1, matches1, ...] non-worklist callees of worklist-owned methods + // ordinary dispatch: invokesig=NULL, callee is MethodInstance + // `invoke` dispatch: invokesig is signature, callee is MethodInstance + // abstract call: callee is signature jl_array_t *edges = jl_alloc_vec_any(0); // [caller1, ext_targets_indexes1, ...] for worklist-owned methods calling external methods int n_ext_mis = queue_external_mis(newly_inferred); @@ -2753,11 +2899,11 @@ JL_DLLEXPORT int jl_save_incremental(const char *fname, jl_array_t *worklist) jl_collect_extext_methods_from_mod(extext_methods, m); } jl_collect_methtable_from_mod(extext_methods, jl_type_type_mt); - jl_collect_missing_backedges_to_mod(jl_type_type_mt); + jl_collect_missing_backedges(jl_type_type_mt); jl_collect_methtable_from_mod(extext_methods, jl_nonfunction_mt); - jl_collect_missing_backedges_to_mod(jl_nonfunction_mt); + jl_collect_missing_backedges(jl_nonfunction_mt); - // jl_collect_extext_methods_from_mod and jl_collect_missing_backedges_to_mod accumulate data in edges_map. + // jl_collect_extext_methods_from_mod and jl_collect_missing_backedges accumulate data in edges_map. // Process this to extract `edges` and `ext_targets`. jl_collect_backedges(edges, ext_targets); @@ -2788,7 +2934,7 @@ JL_DLLEXPORT int jl_save_incremental(const char *fname, jl_array_t *worklist) // Go back and update the source-text position to point to the current position int64_t posfile = ios_pos(&f); ios_seek(&f, srctextpos); - write_int64(&f, posfile); + write_uint64(&f, posfile); ios_seek_end(&f); // Each source-text file is written as // int32: length of abspath diff --git a/src/gc-alloc-profiler.h b/src/gc-alloc-profiler.h index 8be6fed21a899..3fd8bf4388a0a 100644 --- a/src/gc-alloc-profiler.h +++ b/src/gc-alloc-profiler.h @@ -14,7 +14,7 @@ extern "C" { // The public interface to call from Julia for allocations profiling // --------------------------------------------------------------------- -// Forward-declaration to avoid depenency in header file. +// Forward-declaration to avoid dependency in header file. struct jl_raw_alloc_t; // Defined in gc-alloc-profiler.cpp typedef struct { diff --git a/src/gc.c b/src/gc.c index 61dc4c937fe8e..4cd692fb66f2f 100644 --- a/src/gc.c +++ b/src/gc.c @@ -3486,7 +3486,7 @@ void jl_gc_init(void) // on a big memory machine, set max_collect_interval to totalmem / nthreads / 2 uint64_t total_mem = uv_get_total_memory(); uint64_t constrained_mem = uv_get_constrained_memory(); - if (constrained_mem > 0 && constrained_mem < total_mem) + if (constrained_mem != 0) total_mem = constrained_mem; size_t maxmem = total_mem / jl_n_threads / 2; if (maxmem > max_collect_interval) @@ -3494,7 +3494,7 @@ void jl_gc_init(void) #endif // We allocate with abandon until we get close to the free memory on the machine. - uint64_t free_mem = uv_get_free_memory(); + uint64_t free_mem = uv_get_available_memory(); uint64_t high_water_mark = free_mem / 10 * 7; // 70% high water mark if (high_water_mark < max_total_memory) diff --git a/src/gf.c b/src/gf.c index c9d91ec836a0b..7330e4de4b275 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1445,18 +1445,23 @@ static void invalidate_method_instance(void (*f)(jl_code_instance_t*), jl_method codeinst->max_world = max_world; } assert(codeinst->max_world <= max_world); + JL_GC_PUSH1(&codeinst); (*f)(codeinst); + JL_GC_POP(); codeinst = jl_atomic_load_relaxed(&codeinst->next); } // recurse to all backedges to update their valid range also jl_array_t *backedges = replaced->backedges; if (backedges) { + JL_GC_PUSH1(&backedges); replaced->backedges = NULL; - size_t i, l = jl_array_len(backedges); - for (i = 0; i < l; i++) { - jl_method_instance_t *replaced = (jl_method_instance_t*)jl_array_ptr_ref(backedges, i); + size_t i = 0, l = jl_array_len(backedges); + jl_method_instance_t *replaced; + while (i < l) { + i = get_next_edge(backedges, i, NULL, &replaced); invalidate_method_instance(f, replaced, max_world, depth + 1); } + JL_GC_POP(); } JL_UNLOCK(&replaced->def.method->writelock); } @@ -1469,11 +1474,14 @@ void invalidate_backedges(void (*f)(jl_code_instance_t*), jl_method_instance_t * if (backedges) { // invalidate callers (if any) replaced_mi->backedges = NULL; - size_t i, l = jl_array_len(backedges); - jl_method_instance_t **replaced = (jl_method_instance_t**)jl_array_ptr_data(backedges); - for (i = 0; i < l; i++) { - invalidate_method_instance(f, replaced[i], max_world, 1); + JL_GC_PUSH1(&backedges); + size_t i = 0, l = jl_array_len(backedges); + jl_method_instance_t *replaced; + while (i < l) { + i = get_next_edge(backedges, i, NULL, &replaced); + invalidate_method_instance(f, replaced, max_world, 1); } + JL_GC_POP(); } JL_UNLOCK(&replaced_mi->def.method->writelock); if (why && _jl_debug_method_invalidation) { @@ -1486,23 +1494,34 @@ void invalidate_backedges(void (*f)(jl_code_instance_t*), jl_method_instance_t * } // add a backedge from callee to caller -JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, jl_method_instance_t *caller) +JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, jl_value_t *invokesig, jl_method_instance_t *caller) { JL_LOCK(&callee->def.method->writelock); + if (invokesig == jl_nothing) + invokesig = NULL; // julia uses `nothing` but C uses NULL (#undef) if (!callee->backedges) { // lazy-init the backedges array - callee->backedges = jl_alloc_vec_any(1); + callee->backedges = jl_alloc_vec_any(0); jl_gc_wb(callee, callee->backedges); - jl_array_ptr_set(callee->backedges, 0, caller); + push_edge(callee->backedges, invokesig, caller); } else { - size_t i, l = jl_array_len(callee->backedges); - for (i = 0; i < l; i++) { - if (jl_array_ptr_ref(callee->backedges, i) == (jl_value_t*)caller) + size_t i = 0, l = jl_array_len(callee->backedges); + int found = 0; + jl_value_t *invokeTypes; + jl_method_instance_t *mi; + while (i < l) { + i = get_next_edge(callee->backedges, i, &invokeTypes, &mi); + // TODO: it would be better to canonicalize (how?) the Tuple-type so + // that we don't have to call `jl_egal` + if (mi == caller && ((invokesig == NULL && invokeTypes == NULL) || + (invokesig && invokeTypes && jl_egal(invokesig, invokeTypes)))) { + found = 1; break; + } } - if (i == l) { - jl_array_ptr_1d_push(callee->backedges, (jl_value_t*)caller); + if (!found) { + push_edge(callee->backedges, invokesig, caller); } } JL_UNLOCK(&callee->def.method->writelock); @@ -1832,11 +1851,41 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method if (k != n) continue; } - jl_array_ptr_1d_push(oldmi, (jl_value_t*)mi); - invalidate_external(mi, max_world); + // Before deciding whether to invalidate `mi`, check each backedge for `invoke`s if (mi->backedges) { - invalidated = 1; - invalidate_backedges(&do_nothing_with_codeinst, mi, max_world, "jl_method_table_insert"); + jl_array_t *backedges = mi->backedges; + size_t ib = 0, insb = 0, nb = jl_array_len(backedges); + jl_value_t *invokeTypes; + jl_method_instance_t *caller; + while (ib < nb) { + ib = get_next_edge(backedges, ib, &invokeTypes, &caller); + if (!invokeTypes) { + // ordinary dispatch, invalidate + invalidate_method_instance(&do_nothing_with_codeinst, caller, max_world, 1); + invalidated = 1; + } else { + // invoke-dispatch, check invokeTypes for validity + struct jl_typemap_assoc search = {invokeTypes, method->primary_world, NULL, 0, ~(size_t)0}; + oldentry = jl_typemap_assoc_by_type(jl_atomic_load_relaxed(&mt->defs), &search, /*offs*/0, /*subtype*/0); + if (oldentry && oldentry->func.method == mi->def.method) { + // We can safely keep this method + jl_array_ptr_set(backedges, insb++, invokeTypes); + jl_array_ptr_set(backedges, insb++, caller); + } else { + invalidate_method_instance(&do_nothing_with_codeinst, caller, max_world, 1); + invalidated = 1; + } + } + } + jl_array_del_end(backedges, nb - insb); + } + if (!mi->backedges || jl_array_len(mi->backedges) == 0) { + jl_array_ptr_1d_push(oldmi, (jl_value_t*)mi); + invalidate_external(mi, max_world); + if (mi->backedges) { + invalidated = 1; + invalidate_backedges(&do_nothing_with_codeinst, mi, max_world, "jl_method_table_insert"); + } } } } @@ -1955,7 +2004,7 @@ JL_DLLEXPORT jl_value_t *jl_matching_methods(jl_tupletype_t *types, jl_value_t * if (ambig != NULL) *ambig = 0; jl_value_t *unw = jl_unwrap_unionall((jl_value_t*)types); - if (jl_is_tuple_type(unw) && jl_tparam0(unw) == jl_bottom_type) + if (jl_is_tuple_type(unw) && (unw == (jl_value_t*)jl_emptytuple_type || jl_tparam0(unw) == jl_bottom_type)) return (jl_value_t*)jl_an_empty_vec_any; if (mt == jl_nothing) mt = (jl_value_t*)jl_method_table_for(unw); @@ -2279,16 +2328,9 @@ static void jl_compile_now(jl_method_instance_t *mi) } } -JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types) +JL_DLLEXPORT void jl_compile_method_instance(jl_method_instance_t *mi, jl_tupletype_t *types, size_t world) { - size_t world = jl_atomic_load_acquire(&jl_world_counter); size_t tworld = jl_typeinf_world; - size_t min_valid = 0; - size_t max_valid = ~(size_t)0; - jl_method_instance_t *mi = jl_get_specialization1(types, world, &min_valid, &max_valid, 1); - if (mi == NULL) - return 0; - JL_GC_PROMISE_ROOTED(mi); mi->precompiled = 1; if (jl_generating_output()) { jl_compile_now(mi); @@ -2297,7 +2339,7 @@ JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types) // additional useful methods that should be compiled //ALT: if (jl_is_datatype(types) && ((jl_datatype_t*)types)->isdispatchtuple && !jl_egal(mi->specTypes, types)) //ALT: if (jl_subtype(types, mi->specTypes)) - if (!jl_subtype(mi->specTypes, (jl_value_t*)types)) { + if (types && !jl_subtype(mi->specTypes, (jl_value_t*)types)) { jl_svec_t *tpenv2 = jl_emptysvec; jl_value_t *types2 = NULL; JL_GC_PUSH2(&tpenv2, &types2); @@ -2318,6 +2360,18 @@ JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types) // we should generate the native code immediately in preparation for use. (void)jl_compile_method_internal(mi, world); } +} + +JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types) +{ + size_t world = jl_atomic_load_acquire(&jl_world_counter); + size_t min_valid = 0; + size_t max_valid = ~(size_t)0; + jl_method_instance_t *mi = jl_get_specialization1(types, world, &min_valid, &max_valid, 1); + if (mi == NULL) + return 0; + JL_GC_PROMISE_ROOTED(mi); + jl_compile_method_instance(mi, types, world); return 1; } @@ -3328,24 +3382,37 @@ int jl_has_concrete_subtype(jl_value_t *typ) //static jl_mutex_t typeinf_lock; #define typeinf_lock jl_codegen_lock +static jl_mutex_t inference_timing_mutex; static uint64_t inference_start_time = 0; static uint8_t inference_is_measuring_compile_time = 0; -JL_DLLEXPORT void jl_typeinf_begin(void) +JL_DLLEXPORT void jl_typeinf_timing_begin(void) { - JL_LOCK(&typeinf_lock); if (jl_atomic_load_relaxed(&jl_measure_compile_time_enabled)) { - inference_start_time = jl_hrtime(); - inference_is_measuring_compile_time = 1; + JL_LOCK_NOGC(&inference_timing_mutex); + if (inference_is_measuring_compile_time++ == 0) { + inference_start_time = jl_hrtime(); + } + JL_UNLOCK_NOGC(&inference_timing_mutex); } } -JL_DLLEXPORT void jl_typeinf_end(void) +JL_DLLEXPORT void jl_typeinf_timing_end(void) { - if (typeinf_lock.count == 1 && inference_is_measuring_compile_time) { + JL_LOCK_NOGC(&inference_timing_mutex); + if (--inference_is_measuring_compile_time == 0) { jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, (jl_hrtime() - inference_start_time)); - inference_is_measuring_compile_time = 0; } + JL_UNLOCK_NOGC(&inference_timing_mutex); +} + +JL_DLLEXPORT void jl_typeinf_lock_begin(void) +{ + JL_LOCK(&typeinf_lock); +} + +JL_DLLEXPORT void jl_typeinf_lock_end(void) +{ JL_UNLOCK(&typeinf_lock); } diff --git a/src/interpreter.c b/src/interpreter.c index 0b6666f2637f6..1f9c416d99b1b 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -151,6 +151,17 @@ jl_value_t *jl_eval_global_var(jl_module_t *m, jl_sym_t *e) return v; } +jl_value_t *jl_eval_globalref(jl_globalref_t *g) +{ + if (g->bnd_cache) { + jl_value_t *v = jl_atomic_load_relaxed(&g->bnd_cache->value); + if (v == NULL) + jl_undefined_var_error(g->name); + return v; + } + return jl_eval_global_var(g->mod, g->name); +} + static int jl_source_nslots(jl_code_info_t *src) JL_NOTSAFEPOINT { return jl_array_len(src->slotflags); @@ -190,7 +201,7 @@ static jl_value_t *eval_value(jl_value_t *e, interpreter_state *s) return jl_quotenode_value(e); } if (jl_is_globalref(e)) { - return jl_eval_global_var(jl_globalref_mod(e), jl_globalref_name(e)); + return jl_eval_globalref((jl_globalref_t*)e); } if (jl_is_symbol(e)) { // bare symbols appear in toplevel exprs not wrapped in `thunk` return jl_eval_global_var(s->module, (jl_sym_t*)e); diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 117971a083db8..31f47bd7166c4 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -1357,7 +1357,7 @@ static Value *emit_untyped_intrinsic(jl_codectx_t &ctx, intrinsic f, Value **arg return ctx.builder.CreateCall(fmaintr, {x, y, z}); } case muladd_float: { - // LLVM 5.0 can create FMA in the backend for contractable fmul and fadd + // LLVM 5.0 can create FMA in the backend for contractible fmul and fadd // Emitting fmul and fadd here since they are easier for other LLVM passes to // optimize. auto mathb = math_builder(ctx, false, true); diff --git a/src/ircode.c b/src/ircode.c index 5dae26cfadf8c..6da4045035c33 100644 --- a/src/ircode.c +++ b/src/ircode.c @@ -80,7 +80,7 @@ static void jl_encode_as_indexed_root(jl_ircode_state *s, jl_value_t *v) assert(id >= 0); if (rr.key) { write_uint8(s->s, TAG_RELOC_METHODROOT); - write_int64(s->s, rr.key); + write_uint64(s->s, rr.key); } if (id < 256) { write_uint8(s->s, TAG_METHODROOT); @@ -283,7 +283,7 @@ static void jl_encode_value_(jl_ircode_state *s, jl_value_t *v, int as_literal) } else { write_uint8(s->s, TAG_INT64); - write_int64(s->s, *(int64_t*)data); + write_uint64(s->s, *(int64_t*)data); } } else if (jl_typeis(v, jl_int32_type)) { @@ -797,6 +797,7 @@ JL_DLLEXPORT jl_array_t *jl_compress_ir(jl_method_t *m, jl_code_info_t *code) ios_write(s.s, (char*)jl_array_data(code->codelocs), nstmt * sizeof(int32_t)); } + write_uint8(s.s, code->has_fcall); write_uint8(s.s, s.relocatability); ios_flush(s.s); @@ -809,6 +810,7 @@ JL_DLLEXPORT jl_array_t *jl_compress_ir(jl_method_t *m, jl_code_info_t *code) jl_gc_enable(en); JL_UNLOCK(&m->writelock); // Might GC JL_GC_POP(); + return v; } @@ -878,6 +880,7 @@ JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t ios_readall(s.s, (char*)jl_array_data(code->codelocs), nstmt * sizeof(int32_t)); } + code->has_fcall = read_uint8(s.s); (void) read_uint8(s.s); // relocatability assert(ios_getc(s.s) == -1); @@ -892,6 +895,7 @@ JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t code->rettype = metadata->rettype; code->parent = metadata->def; } + return code; } diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 1709c62326238..a0dd11e7f009e 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -5,6 +5,7 @@ #include #include "llvm/IR/Mangler.h" +#include #include #include #include @@ -35,8 +36,6 @@ using namespace llvm; -#include "julia.h" -#include "julia_internal.h" #include "codegen_shared.h" #include "jitlayers.h" #include "julia_assert.h" @@ -48,10 +47,30 @@ using namespace llvm; # endif # include # include +# if JL_LLVM_VERSION >= 150000 +# include +# endif #else # include #endif +#define DEBUG_TYPE "julia_jitlayers" + +STATISTIC(LinkedGlobals, "Number of globals linked"); +STATISTIC(CompiledCodeinsts, "Number of codeinsts compiled directly"); +STATISTIC(MaxWorkqueueSize, "Maximum number of elements in the workqueue"); +STATISTIC(IndirectCodeinsts, "Number of dependent codeinsts compiled"); +STATISTIC(SpecFPtrCount, "Number of specialized function pointers compiled"); +STATISTIC(UnspecFPtrCount, "Number of specialized function pointers compiled"); +STATISTIC(ModulesAdded, "Number of modules added to the JIT"); +STATISTIC(ModulesOptimized, "Number of modules optimized by the JIT"); +STATISTIC(OptO0, "Number of modules optimized at level -O0"); +STATISTIC(OptO1, "Number of modules optimized at level -O1"); +STATISTIC(OptO2, "Number of modules optimized at level -O2"); +STATISTIC(OptO3, "Number of modules optimized at level -O3"); +STATISTIC(ModulesMerged, "Number of modules merged"); +STATISTIC(InternedGlobals, "Number of global constants interned in the string pool"); + #ifdef _COMPILER_MSAN_ENABLED_ // TODO: This should not be necessary on ELF x86_64, but LLVM's implementation // of the TLS relocations is currently broken, so enable this unconditionally. @@ -104,8 +123,6 @@ static void *getTLSAddress(void *control) } #endif -#define DEBUG_TYPE "jitlayers" - // Snooping on which functions are being compiled, and how long it takes extern "C" JL_DLLEXPORT void jl_dump_compiles_impl(void *s) @@ -124,6 +141,7 @@ static uint64_t getAddressForFunction(StringRef fname); void jl_link_global(GlobalVariable *GV, void *addr) { + ++LinkedGlobals; Constant *P = literal_static_pointer_val(addr, GV->getValueType()); GV->setInitializer(P); if (jl_options.image_codegen) { @@ -214,6 +232,9 @@ static jl_callptr_t _jl_compile_codeinst( orc::ThreadSafeModule &M = std::get<0>(def.second); jl_add_to_ee(M, NewExports); } + ++CompiledCodeinsts; + MaxWorkqueueSize.updateMax(emitted.size()); + IndirectCodeinsts += emitted.size() - 1; } JL_TIMING(LLVM_MODULE_FINISH); @@ -365,8 +386,6 @@ extern "C" JL_DLLEXPORT jl_code_instance_t *jl_generate_fptr_impl(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world) { JL_LOCK(&jl_codegen_lock); // also disables finalizers, to prevent any unexpected recursion - auto ctx = jl_ExecutionEngine->getContext(); - auto &context = *ctx; uint64_t compiler_start_time = 0; uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled); bool is_recompile = false; @@ -409,7 +428,8 @@ jl_code_instance_t *jl_generate_fptr_impl(jl_method_instance_t *mi JL_PROPAGATES jl_atomic_cmpswap_relaxed(&codeinst->inferred, &null, jl_nothing); } } - _jl_compile_codeinst(codeinst, src, world, context); + ++SpecFPtrCount; + _jl_compile_codeinst(codeinst, src, world, *jl_ExecutionEngine->getContext()); if (jl_atomic_load_relaxed(&codeinst->invoke) == NULL) codeinst = NULL; } @@ -434,8 +454,6 @@ void jl_generate_fptr_for_unspecialized_impl(jl_code_instance_t *unspec) return; } JL_LOCK(&jl_codegen_lock); - auto ctx = jl_ExecutionEngine->getContext(); - auto &context = *ctx; uint64_t compiler_start_time = 0; uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled); if (measure_compile_time_enabled) @@ -459,7 +477,8 @@ void jl_generate_fptr_for_unspecialized_impl(jl_code_instance_t *unspec) src = (jl_code_info_t*)unspec->def->uninferred; } assert(src && jl_is_code_info(src)); - _jl_compile_codeinst(unspec, src, unspec->min_world, context); + ++UnspecFPtrCount; + _jl_compile_codeinst(unspec, src, unspec->min_world, *jl_ExecutionEngine->getContext()); if (jl_atomic_load_relaxed(&unspec->invoke) == NULL) { // if we hit a codegen bug (or ran into a broken generated function or llvmcall), fall back to the interpreter as a last resort jl_atomic_store_release(&unspec->invoke, jl_fptr_interpret_call_addr); @@ -489,8 +508,6 @@ jl_value_t *jl_dump_method_asm_impl(jl_method_instance_t *mi, size_t world, // (using sentinel value `1` instead) // so create an exception here so we can print pretty our lies JL_LOCK(&jl_codegen_lock); // also disables finalizers, to prevent any unexpected recursion - auto ctx = jl_ExecutionEngine->getContext(); - auto &context = *ctx; uint64_t compiler_start_time = 0; uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled); if (measure_compile_time_enabled) @@ -512,7 +529,7 @@ jl_value_t *jl_dump_method_asm_impl(jl_method_instance_t *mi, size_t world, specfptr = (uintptr_t)jl_atomic_load_relaxed(&codeinst->specptr.fptr); if (src && jl_is_code_info(src)) { if (fptr == (uintptr_t)jl_fptr_const_return_addr && specfptr == 0) { - fptr = (uintptr_t)_jl_compile_codeinst(codeinst, src, world, context); + fptr = (uintptr_t)_jl_compile_codeinst(codeinst, src, world, *jl_ExecutionEngine->getContext()); specfptr = (uintptr_t)jl_atomic_load_relaxed(&codeinst->specptr.fptr); } } @@ -551,6 +568,7 @@ static auto countBasicBlocks(const Function &F) } void JuliaOJIT::OptSelLayerT::emit(std::unique_ptr R, orc::ThreadSafeModule TSM) { + ++ModulesOptimized; size_t optlevel = SIZE_MAX; TSM.withModuleDo([&](Module &M) { if (jl_generating_output()) { @@ -721,6 +739,50 @@ class JLDebuginfoPlugin : public ObjectLinkingLayer::Plugin { }); } }; + +class JLMemoryUsagePlugin : public ObjectLinkingLayer::Plugin { +private: + std::atomic &total_size; + +public: + + JLMemoryUsagePlugin(std::atomic &total_size) + : total_size(total_size) {} + + Error notifyFailed(orc::MaterializationResponsibility &MR) override { + return Error::success(); + } + Error notifyRemovingResources(orc::ResourceKey K) override { + return Error::success(); + } + void notifyTransferringResources(orc::ResourceKey DstKey, + orc::ResourceKey SrcKey) override {} + + void modifyPassConfig(orc::MaterializationResponsibility &, + jitlink::LinkGraph &, + jitlink::PassConfiguration &Config) override { + Config.PostAllocationPasses.push_back([this](jitlink::LinkGraph &G) { + size_t graph_size = 0; + for (auto block : G.blocks()) { + graph_size += block->getSize(); + } + this->total_size.fetch_add(graph_size, std::memory_order_relaxed); + return Error::success(); + }); + } +}; + +// TODO: Port our memory management optimisations to JITLink instead of using the +// default InProcessMemoryManager. +std::unique_ptr createJITLinkMemoryManager() { +#if JL_LLVM_VERSION < 140000 + return std::make_unique(); +#elif JL_LLVM_VERSION < 150000 + return cantFail(jitlink::InProcessMemoryManager::Create()); +#else + return cantFail(orc::MapperJITLinkMemoryManager::CreateWithMapper()); +#endif +} } # ifdef LLVM_SHLIB @@ -950,7 +1012,11 @@ namespace { namespace { +#ifndef JL_USE_NEW_PM typedef legacy::PassManager PassManager; +#else + typedef NewPM PassManager; +#endif orc::JITTargetMachineBuilder createJTMBFromTM(TargetMachine &TM, int optlevel) { return orc::JITTargetMachineBuilder(TM.getTargetTriple()) @@ -972,6 +1038,7 @@ namespace { } }; +#ifndef JL_USE_NEW_PM struct PMCreator { std::unique_ptr TM; int optlevel; @@ -987,7 +1054,7 @@ namespace { swap(*this, other); return *this; } - std::unique_ptr operator()() { + auto operator()() { auto PM = std::make_unique(); addTargetPasses(PM.get(), TM->getTargetTriple(), TM->getTargetIRAnalysis()); addOptimizationPasses(PM.get(), optlevel); @@ -995,6 +1062,17 @@ namespace { return PM; } }; +#else + struct PMCreator { + orc::JITTargetMachineBuilder JTMB; + OptimizationLevel O; + PMCreator(TargetMachine &TM, int optlevel) : JTMB(createJTMBFromTM(TM, optlevel)), O(getOptLevel(optlevel)) {} + + auto operator()() { + return std::make_unique(cantFail(JTMB.createTargetMachine()), O); + } + }; +#endif struct OptimizerT { OptimizerT(TargetMachine &TM, int optlevel) : optlevel(optlevel), PMs(PMCreator(TM, optlevel)) {} @@ -1051,6 +1129,22 @@ namespace { } } }); + switch (optlevel) { + case 0: + ++OptO0; + break; + case 1: + ++OptO1; + break; + case 2: + ++OptO2; + break; + case 3: + ++OptO3; + break; + default: + llvm_unreachable("optlevel is between 0 and 3!"); + } return Expected{std::move(TSM)}; } private: @@ -1096,18 +1190,13 @@ JuliaOJIT::JuliaOJIT() ContextPool([](){ auto ctx = std::make_unique(); #ifdef JL_LLVM_OPAQUE_POINTERS - ctx->enableOpaquePointers(); + ctx->setOpaquePointers(true); #endif return orc::ThreadSafeContext(std::move(ctx)); }), #ifdef JL_USE_JITLINK - // TODO: Port our memory management optimisations to JITLink instead of using the - // default InProcessMemoryManager. -# if JL_LLVM_VERSION < 140000 - ObjectLayer(ES, std::make_unique()), -# else - ObjectLayer(ES, cantFail(jitlink::InProcessMemoryManager::Create())), -# endif + MemMgr(createJITLinkMemoryManager()), + ObjectLayer(ES, *MemMgr), #else MemMgr(createRTDyldMemoryManager()), ObjectLayer( @@ -1138,6 +1227,7 @@ JuliaOJIT::JuliaOJIT() ES, std::move(ehRegistrar))); ObjectLayer.addPlugin(std::make_unique()); + ObjectLayer.addPlugin(std::make_unique(total_size)); #else ObjectLayer.setNotifyLoaded( [this](orc::MaterializationResponsibility &MR, @@ -1230,6 +1320,7 @@ void JuliaOJIT::addGlobalMapping(StringRef Name, uint64_t Addr) void JuliaOJIT::addModule(orc::ThreadSafeModule TSM) { JL_TIMING(LLVM_MODULE_FINISH); + ++ModulesAdded; std::vector NewExports; TSM.withModuleDo([&](Module &M) { jl_decorate_module(M); @@ -1387,8 +1478,7 @@ std::string JuliaOJIT::getMangledName(const GlobalValue *GV) #ifdef JL_USE_JITLINK size_t JuliaOJIT::getTotalBytes() const { - // TODO: Implement in future custom JITLink memory manager. - return 0; + return total_size.load(std::memory_order_relaxed); } #else size_t getRTDyldMemoryManagerTotalBytes(RTDyldMemoryManager *mm); @@ -1408,6 +1498,7 @@ JuliaOJIT *jl_ExecutionEngine; // Comdat is also removed, since the JIT doesn't need it void jl_merge_module(orc::ThreadSafeModule &destTSM, orc::ThreadSafeModule srcTSM) { + ++ModulesMerged; destTSM.withModuleDo([&](Module &dest) { srcTSM.withModuleDo([&](Module &src) { assert(&dest != &src && "Cannot merge module with itself!"); @@ -1521,6 +1612,7 @@ void jl_merge_module(orc::ThreadSafeModule &destTSM, orc::ThreadSafeModule srcTS // making a copy per object file of output. void JuliaOJIT::shareStrings(Module &M) { + ++InternedGlobals; std::vector erase; for (auto &GV : M.globals()) { if (!GV.hasInitializer() || !GV.isConstant()) diff --git a/src/jitlayers.h b/src/jitlayers.h index 54a76630330f8..ba38abff0d6f4 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -41,7 +41,9 @@ // and feature support (e.g. Windows, JITEventListeners for various profilers, // etc.). Thus, we currently only use JITLink where absolutely required, that is, // for Mac/aarch64. -#if defined(_OS_DARWIN_) && defined(_CPU_AARCH64_) +// #define JL_FORCE_JITLINK + +#if defined(_OS_DARWIN_) && defined(_CPU_AARCH64_) || defined(JL_FORCE_JITLINK) # if JL_LLVM_VERSION < 130000 # pragma message("On aarch64-darwin, LLVM version >= 13 is required for JITLink; fallback suffers from occasional segfaults") # endif @@ -78,9 +80,14 @@ struct OptimizationOptions { bool lower_intrinsics; bool dump_native; bool external_use; - - static constexpr OptimizationOptions defaults() { - return {true, false, false}; + bool llvm_only; + + static constexpr OptimizationOptions defaults( + bool lower_intrinsics=true, + bool dump_native=false, + bool external_use=false, + bool llvm_only=false) { + return {lower_intrinsics, dump_native, external_use, llvm_only}; } }; @@ -481,6 +488,9 @@ class JuliaOJIT { #ifndef JL_USE_JITLINK const std::shared_ptr MemMgr; +#else + std::atomic total_size; + const std::unique_ptr MemMgr; #endif ObjLayerT ObjectLayer; const std::array, 4> Pipelines; diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index b77acc1eb3858..f47e5bcb17592 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -97,6 +97,7 @@ XX(jl_close_uv) \ XX(jl_code_for_staged) \ XX(jl_compile_hint) \ + XX(jl_compile_method_instance) \ XX(jl_compress_argnames) \ XX(jl_compress_ir) \ XX(jl_compute_fieldtypes) \ @@ -478,8 +479,10 @@ XX(jl_tty_set_mode) \ XX(jl_tupletype_fill) \ XX(jl_typeassert) \ - XX(jl_typeinf_begin) \ - XX(jl_typeinf_end) \ + XX(jl_typeinf_lock_begin) \ + XX(jl_typeinf_lock_end) \ + XX(jl_typeinf_timing_begin) \ + XX(jl_typeinf_timing_end) \ XX(jl_typename_str) \ XX(jl_typeof_str) \ XX(jl_types_equal) \ diff --git a/src/jltypes.c b/src/jltypes.c index 8eb43076e46a5..b45c34ed7e5ed 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2392,16 +2392,10 @@ void jl_init_types(void) JL_GC_DISABLED jl_svec(1, jl_slotnumber_type), jl_emptysvec, 0, 0, 1); - jl_globalref_type = - jl_new_datatype(jl_symbol("GlobalRef"), core, jl_any_type, jl_emptysvec, - jl_perm_symsvec(2, "mod", "name"), - jl_svec(2, jl_module_type, jl_symbol_type), - jl_emptysvec, 0, 0, 2); - jl_code_info_type = jl_new_datatype(jl_symbol("CodeInfo"), core, jl_any_type, jl_emptysvec, - jl_perm_symsvec(20, + jl_perm_symsvec(21, "code", "codelocs", "ssavaluetypes", @@ -2420,9 +2414,10 @@ void jl_init_types(void) JL_GC_DISABLED "inlining_cost", "propagate_inbounds", "pure", + "has_fcall", "constprop", "purity"), - jl_svec(20, + jl_svec(21, jl_array_any_type, jl_array_int32_type, jl_any_type, @@ -2441,6 +2436,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_uint16_type, jl_bool_type, jl_bool_type, + jl_bool_type, jl_uint8_type, jl_uint8_type), jl_emptysvec, @@ -2532,7 +2528,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_any_type, jl_simplevector_type, jl_any_type, - jl_any_type, + jl_array_any_type, jl_any_type, jl_any_type, jl_bool_type, @@ -2692,6 +2688,12 @@ void jl_init_types(void) JL_GC_DISABLED jl_value_t *pointer_void = jl_apply_type1((jl_value_t*)jl_pointer_type, (jl_value_t*)jl_nothing_type); + jl_globalref_type = + jl_new_datatype(jl_symbol("GlobalRef"), core, jl_any_type, jl_emptysvec, + jl_perm_symsvec(3, "mod", "name", "binding"), + jl_svec(3, jl_module_type, jl_symbol_type, pointer_void), + jl_emptysvec, 0, 0, 3); + tv = jl_svec2(tvar("A"), tvar("R")); jl_opaque_closure_type = (jl_unionall_t*)jl_new_datatype(jl_symbol("OpaqueClosure"), core, jl_function_type, tv, jl_perm_symsvec(5, "captures", "world", "source", "invoke", "specptr"), diff --git a/src/julia.h b/src/julia.h index 30a3533156775..644ce0dbd78ae 100644 --- a/src/julia.h +++ b/src/julia.h @@ -283,6 +283,7 @@ typedef struct _jl_code_info_t { uint16_t inlining_cost; uint8_t propagate_inbounds; uint8_t pure; + uint8_t has_fcall; // uint8 settings uint8_t constprop; // 0 = use heuristic; 1 = aggressive; 2 = none _jl_purity_overrides_t purity; @@ -362,7 +363,7 @@ struct _jl_method_instance_t { jl_value_t *specTypes; // argument types this was specialized for jl_svec_t *sparam_vals; // static parameter values, indexed by def.method->sparam_syms jl_value_t *uninferred; // cached uncompressed code, for generated functions, top-level thunks, or the interpreter - jl_array_t *backedges; // list of method-instances which contain a call into this method-instance + jl_array_t *backedges; // list of method-instances which call this method-instance; `invoke` records (invokesig, caller) pairs jl_array_t *callbacks; // list of callback functions to inform external caches about invalidations _Atomic(struct _jl_code_instance_t*) cache; uint8_t inInference; // flags to tell if inference is running on this object @@ -602,6 +603,13 @@ typedef struct _jl_module_t { jl_mutex_t lock; } jl_module_t; +typedef struct { + jl_module_t *mod; + jl_sym_t *name; + // Not serialized. Caches the value of jl_get_binding(mod, name). + jl_binding_t *bnd_cache; +} jl_globalref_t; + // one Type-to-Value entry typedef struct _jl_typemap_entry_t { JL_DATA_TYPE @@ -650,7 +658,7 @@ typedef struct _jl_methtable_t { intptr_t max_args; // max # of non-vararg arguments in a signature jl_value_t *kwsorter; // keyword argument sorter function jl_module_t *module; // used for incremental serialization to locate original binding - jl_array_t *backedges; + jl_array_t *backedges; // (sig, caller::MethodInstance) pairs jl_mutex_t writelock; uint8_t offs; // 0, or 1 to skip splitting typemap on first (function) argument uint8_t frozen; // whether this accepts adding new methods @@ -1548,6 +1556,7 @@ JL_DLLEXPORT jl_value_t *jl_get_nth_field_noalloc(jl_value_t *v JL_PROPAGATES_RO JL_DLLEXPORT jl_value_t *jl_get_nth_field_checked(jl_value_t *v, size_t i); JL_DLLEXPORT void jl_set_nth_field(jl_value_t *v, size_t i, jl_value_t *rhs) JL_NOTSAFEPOINT; JL_DLLEXPORT int jl_field_isdefined(jl_value_t *v, size_t i) JL_NOTSAFEPOINT; +JL_DLLEXPORT int jl_field_isdefined_checked(jl_value_t *v, size_t i); JL_DLLEXPORT jl_value_t *jl_get_field(jl_value_t *o, const char *fld); JL_DLLEXPORT jl_value_t *jl_value_ptr(jl_value_t *a); int jl_uniontype_size(jl_value_t *ty, size_t *sz); @@ -1614,6 +1623,7 @@ JL_DLLEXPORT int jl_get_module_max_methods(jl_module_t *m); // get binding for reading JL_DLLEXPORT jl_binding_t *jl_get_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); JL_DLLEXPORT jl_binding_t *jl_get_binding_or_error(jl_module_t *m, jl_sym_t *var); +JL_DLLEXPORT jl_binding_t *jl_get_binding_if_bound(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT jl_value_t *jl_module_globalref(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT jl_value_t *jl_binding_type(jl_module_t *m, jl_sym_t *var); // get binding for assignment @@ -1624,6 +1634,8 @@ JL_DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT int jl_defines_or_exports_p(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT int jl_binding_resolved_p(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var); +JL_DLLEXPORT int jl_binding_is_const(jl_binding_t *b); +JL_DLLEXPORT int jl_binding_boundp(jl_binding_t *b); JL_DLLEXPORT jl_value_t *jl_get_global(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); JL_DLLEXPORT void jl_set_global(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT); JL_DLLEXPORT void jl_set_const(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT); diff --git a/src/julia_gcext.h b/src/julia_gcext.h index 6787dafb4b7ee..631d9c2910330 100644 --- a/src/julia_gcext.h +++ b/src/julia_gcext.h @@ -76,7 +76,7 @@ JL_DLLEXPORT void jl_gc_mark_queue_objarray(jl_ptls_t ptls, jl_value_t *parent, // Sweep functions will not automatically be called for objects of // foreign types, as that may not always be desired. Only calling // jl_gc_schedule_foreign_sweepfunc() on an object of a foreign type -// will result in the custome sweep function actually being called. +// will result in the custom sweep function actually being called. // This must be done at most once per object and should usually be // done right after allocating the object. JL_DLLEXPORT void jl_gc_schedule_foreign_sweepfunc(jl_ptls_t ptls, jl_value_t * bj); diff --git a/src/julia_internal.h b/src/julia_internal.h index 07ec5e8aedda2..635a14b6a2f26 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -596,6 +596,7 @@ JL_DLLEXPORT jl_code_instance_t *jl_get_method_inferred( jl_method_instance_t *jl_get_unspecialized_from_mi(jl_method_instance_t *method JL_PROPAGATES_ROOT); jl_method_instance_t *jl_get_unspecialized(jl_method_t *def JL_PROPAGATES_ROOT); +JL_DLLEXPORT void jl_compile_method_instance(jl_method_instance_t *mi, jl_tupletype_t *types, size_t world); JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types); jl_code_info_t *jl_code_for_interpreter(jl_method_instance_t *lam JL_PROPAGATES_ROOT); int jl_code_requires_compiler(jl_code_info_t *src); @@ -604,6 +605,10 @@ JL_DLLEXPORT jl_code_info_t *jl_new_code_info_uninit(void); void jl_resolve_globals_in_ir(jl_array_t *stmts, jl_module_t *m, jl_svec_t *sparam_vals, int binding_effects); +int get_next_edge(jl_array_t *list, int i, jl_value_t** invokesig, jl_method_instance_t **caller) JL_NOTSAFEPOINT; +int set_next_edge(jl_array_t *list, int i, jl_value_t *invokesig, jl_method_instance_t *caller); +void push_edge(jl_array_t *list, jl_value_t *invokesig, jl_method_instance_t *caller); + JL_DLLEXPORT void jl_add_method_root(jl_method_t *m, jl_module_t *mod, jl_value_t* root); void jl_append_method_roots(jl_method_t *m, uint64_t modid, jl_array_t* roots); int get_root_reference(rle_reference *rr, jl_method_t *m, size_t i); @@ -949,7 +954,7 @@ JL_DLLEXPORT jl_value_t *jl_methtable_lookup(jl_methtable_t *mt, jl_value_t *typ JL_DLLEXPORT jl_method_instance_t *jl_specializations_get_linfo( jl_method_t *m JL_PROPAGATES_ROOT, jl_value_t *type, jl_svec_t *sparams); jl_method_instance_t *jl_specializations_get_or_insert(jl_method_instance_t *mi_ins); -JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, jl_method_instance_t *caller); +JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, jl_value_t *invokesig, jl_method_instance_t *caller); JL_DLLEXPORT void jl_method_table_add_backedge(jl_methtable_t *mt, jl_value_t *typ, jl_value_t *caller); uint32_t jl_module_next_counter(jl_module_t *m) JL_NOTSAFEPOINT; @@ -984,7 +989,7 @@ jl_value_t *jl_parse(const char *text, size_t text_len, jl_value_t *filename, // 2. An "extended entry": a mixture of raw data and pointers to julia objects // which must be treated as GC roots. // -// A single extended entry is seralized using multiple elements from the raw +// A single extended entry is serialized using multiple elements from the raw // buffer; if `e` is the pointer to the first slot we have: // // e[0] JL_BT_NON_PTR_ENTRY - Special marker to distinguish extended entries diff --git a/src/llvm-alloc-opt.cpp b/src/llvm-alloc-opt.cpp index 9caa45e193912..5e44249e7b9c0 100644 --- a/src/llvm-alloc-opt.cpp +++ b/src/llvm-alloc-opt.cpp @@ -27,12 +27,12 @@ #include +#include "passes.h" #include "codegen_shared.h" #include "julia.h" #include "julia_internal.h" #include "llvm-pass-helpers.h" #include "llvm-alloc-helpers.h" -#include "passes.h" #include #include diff --git a/src/llvm-cpufeatures.cpp b/src/llvm-cpufeatures.cpp index 1c21ddba49be6..6211d284bdd24 100644 --- a/src/llvm-cpufeatures.cpp +++ b/src/llvm-cpufeatures.cpp @@ -26,7 +26,6 @@ #include #include -#include "julia.h" #include "jitlayers.h" #define DEBUG_TYPE "cpufeatures" diff --git a/src/llvm-final-gc-lowering.cpp b/src/llvm-final-gc-lowering.cpp index 0ef7289df827c..e7e9fe2f4f26a 100644 --- a/src/llvm-final-gc-lowering.cpp +++ b/src/llvm-final-gc-lowering.cpp @@ -3,6 +3,7 @@ #include "llvm-version.h" #include "passes.h" +#include #include #include #include @@ -18,6 +19,13 @@ #include "llvm-pass-helpers.h" #define DEBUG_TYPE "final_gc_lowering" +STATISTIC(NewGCFrameCount, "Number of lowered newGCFrameFunc intrinsics"); +STATISTIC(PushGCFrameCount, "Number of lowered pushGCFrameFunc intrinsics"); +STATISTIC(PopGCFrameCount, "Number of lowered popGCFrameFunc intrinsics"); +STATISTIC(GetGCFrameSlotCount, "Number of lowered getGCFrameSlotFunc intrinsics"); +STATISTIC(GCAllocBytesCount, "Number of lowered GCAllocBytesFunc intrinsics"); +STATISTIC(QueueGCRootCount, "Number of lowered queueGCRootFunc intrinsics"); +STATISTIC(QueueGCBindingCount, "Number of lowered queueGCBindingFunc intrinsics"); using namespace llvm; @@ -66,6 +74,7 @@ struct FinalLowerGC: private JuliaPassContext { Value *FinalLowerGC::lowerNewGCFrame(CallInst *target, Function &F) { + ++NewGCFrameCount; assert(target->arg_size() == 1); unsigned nRoots = cast(target->getArgOperand(0))->getLimitedValue(INT_MAX); @@ -98,7 +107,7 @@ Value *FinalLowerGC::lowerNewGCFrame(CallInst *target, Function &F) ConstantInt::get(Type::getInt32Ty(F.getContext()), sizeof(jl_value_t*) * (nRoots + 2)), // len ConstantInt::get(Type::getInt1Ty(F.getContext()), 0)}; // volatile CallInst *zeroing = CallInst::Create(memset, makeArrayRef(args)); - cast(zeroing)->setDestAlignment(16); + cast(zeroing)->setDestAlignment(Align(16)); zeroing->setMetadata(LLVMContext::MD_tbaa, tbaa_gcframe); zeroing->insertAfter(tempSlot_i8); @@ -107,6 +116,7 @@ Value *FinalLowerGC::lowerNewGCFrame(CallInst *target, Function &F) void FinalLowerGC::lowerPushGCFrame(CallInst *target, Function &F) { + ++PushGCFrameCount; assert(target->arg_size() == 2); auto gcframe = target->getArgOperand(0); unsigned nRoots = cast(target->getArgOperand(1))->getLimitedValue(INT_MAX); @@ -136,6 +146,7 @@ void FinalLowerGC::lowerPushGCFrame(CallInst *target, Function &F) void FinalLowerGC::lowerPopGCFrame(CallInst *target, Function &F) { + ++PopGCFrameCount; assert(target->arg_size() == 1); auto gcframe = target->getArgOperand(0); @@ -155,6 +166,7 @@ void FinalLowerGC::lowerPopGCFrame(CallInst *target, Function &F) Value *FinalLowerGC::lowerGetGCFrameSlot(CallInst *target, Function &F) { + ++GetGCFrameSlotCount; assert(target->arg_size() == 2); auto gcframe = target->getArgOperand(0); auto index = target->getArgOperand(1); @@ -174,6 +186,7 @@ Value *FinalLowerGC::lowerGetGCFrameSlot(CallInst *target, Function &F) Value *FinalLowerGC::lowerQueueGCRoot(CallInst *target, Function &F) { + ++QueueGCRootCount; assert(target->arg_size() == 1); target->setCalledFunction(queueRootFunc); return target; @@ -181,6 +194,7 @@ Value *FinalLowerGC::lowerQueueGCRoot(CallInst *target, Function &F) Value *FinalLowerGC::lowerQueueGCBinding(CallInst *target, Function &F) { + ++QueueGCBindingCount; assert(target->arg_size() == 1); target->setCalledFunction(queueBindingFunc); return target; @@ -188,6 +202,7 @@ Value *FinalLowerGC::lowerQueueGCBinding(CallInst *target, Function &F) Value *FinalLowerGC::lowerGCAllocBytes(CallInst *target, Function &F) { + ++GCAllocBytesCount; assert(target->arg_size() == 2); auto sz = (size_t)cast(target->getArgOperand(1))->getZExtValue(); // This is strongly architecture and OS dependent diff --git a/src/llvm-late-gc-lowering.cpp b/src/llvm-late-gc-lowering.cpp index 1fab161a4766e..8847a3e34be51 100644 --- a/src/llvm-late-gc-lowering.cpp +++ b/src/llvm-late-gc-lowering.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "llvm/Analysis/CFG.h" #include #include @@ -749,6 +750,7 @@ void LateLowerGCFrame::LiftPhi(State &S, PHINode *Phi) { } if (!isa(Phi->getType())) S.AllCompositeNumbering[Phi] = Numbers; + SmallVector, 4> CastedRoots(NumRoots); for (unsigned i = 0; i < Phi->getNumIncomingValues(); ++i) { Value *Incoming = Phi->getIncomingValue(i); BasicBlock *IncomingBB = Phi->getIncomingBlock(i); @@ -766,8 +768,27 @@ void LateLowerGCFrame::LiftPhi(State &S, PHINode *Phi) { BaseElem = Base; else BaseElem = IncomingBases[i]; - if (BaseElem->getType() != T_prjlvalue) - BaseElem = new BitCastInst(BaseElem, T_prjlvalue, "", Terminator); + if (BaseElem->getType() != T_prjlvalue) { + auto &remap = CastedRoots[i][BaseElem]; + if (!remap) { + if (auto constant = dyn_cast(BaseElem)) { + remap = ConstantExpr::getBitCast(constant, T_prjlvalue, ""); + } else { + Instruction *InsertBefore; + if (auto arg = dyn_cast(BaseElem)) { + InsertBefore = &*arg->getParent()->getEntryBlock().getFirstInsertionPt(); + } else { + assert(isa(BaseElem) && "Unknown value type detected!"); + InsertBefore = cast(BaseElem)->getNextNonDebugInstruction(); + } + while (isa(InsertBefore)) { + InsertBefore = InsertBefore->getNextNonDebugInstruction(); + } + remap = new BitCastInst(BaseElem, T_prjlvalue, "", InsertBefore); + } + } + BaseElem = remap; + } lift->addIncoming(BaseElem, IncomingBB); } } @@ -1288,7 +1309,7 @@ void LateLowerGCFrame::FixUpRefinements(ArrayRef PHINumbers, State &S) // value of -1 or -2 in the refinement map), or may be externally rooted by refinement to other // values. Thus a value is not externally rooted if it either: // either: - // - Has no refinements (all obiviously externally rooted values are annotated by -1/-2 in the + // - Has no refinements (all obviously externally rooted values are annotated by -1/-2 in the // refinement map). // - Recursively reaches a not-externally rooted value through its refinements // @@ -2614,7 +2635,8 @@ void LateLowerGCFrame::PlaceRootsAndUpdateCalls(std::vector &Colors, State unsigned AllocaSlot = 2; // first two words are metadata auto replace_alloca = [this, gcframe, &AllocaSlot, T_int32](AllocaInst *&AI) { // Pick a slot for the alloca. - unsigned align = AI->getAlignment() / sizeof(void*); // TODO: use DataLayout pointer size + AI->getAlign(); + unsigned align = AI->getAlign().value() / sizeof(void*); // TODO: use DataLayout pointer size assert(align <= 16 / sizeof(void*) && "Alignment exceeds llvm-final-gc-lowering abilities"); if (align > 1) AllocaSlot = LLT_ALIGN(AllocaSlot, align); diff --git a/src/llvm-lower-handlers.cpp b/src/llvm-lower-handlers.cpp index d4d4aa965b175..881d2252eacbf 100644 --- a/src/llvm-lower-handlers.cpp +++ b/src/llvm-lower-handlers.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,8 @@ #define DEBUG_TYPE "lower_handlers" #undef DEBUG +STATISTIC(MaxExceptionHandlerDepth, "Maximum nesting of exception handlers"); +STATISTIC(ExceptionHandlerBuffers, "Number of exception handler buffers inserted"); using namespace llvm; @@ -156,6 +159,8 @@ static bool lowerExcHandlers(Function &F) { /* Remember the depth at the BB boundary */ ExitDepth[BB] = Depth; } + MaxExceptionHandlerDepth.updateMax(MaxDepth); + ExceptionHandlerBuffers += MaxDepth; /* Step 2: EH Frame lowering */ // Allocate stack space for each handler. We allocate these as separate diff --git a/src/llvm-propagate-addrspaces.cpp b/src/llvm-propagate-addrspaces.cpp index 97ae9d0555a8f..e2d390a5e4395 100644 --- a/src/llvm-propagate-addrspaces.cpp +++ b/src/llvm-propagate-addrspaces.cpp @@ -22,9 +22,8 @@ #include #include -#include "codegen_shared.h" -#include "julia.h" #include "passes.h" +#include "codegen_shared.h" #define DEBUG_TYPE "propagate_julia_addrspaces" diff --git a/src/llvm-remove-addrspaces.cpp b/src/llvm-remove-addrspaces.cpp index a3f3cbb1fee72..814e31ec2252f 100644 --- a/src/llvm-remove-addrspaces.cpp +++ b/src/llvm-remove-addrspaces.cpp @@ -12,9 +12,8 @@ #include #include -#include "codegen_shared.h" -#include "julia.h" #include "passes.h" +#include "codegen_shared.h" #define DEBUG_TYPE "remove_addrspaces" diff --git a/src/llvm-simdloop.cpp b/src/llvm-simdloop.cpp index c9a38a6a879b8..1848b429869dd 100644 --- a/src/llvm-simdloop.cpp +++ b/src/llvm-simdloop.cpp @@ -38,6 +38,7 @@ STATISTIC(SimdLoops, "Number of loops with SIMD instructions"); STATISTIC(IVDepInstructions, "Number of instructions marked ivdep"); STATISTIC(ReductionChains, "Number of reduction chains folded"); STATISTIC(ReductionChainLength, "Total sum of instructions folded from reduction chain"); +STATISTIC(MaxChainLength, "Max length of reduction chain"); STATISTIC(AddChains, "Addition reduction chains"); STATISTIC(MulChains, "Multiply reduction chains"); @@ -119,11 +120,14 @@ static void enableUnsafeAlgebraIfReduction(PHINode *Phi, Loop *L) break; } ++ReductionChains; + int length = 0; for (chainVector::const_iterator K=chain.begin(); K!=chain.end(); ++K) { LLVM_DEBUG(dbgs() << "LSL: marking " << **K << "\n"); (*K)->setFast(true); - ++ReductionChainLength; + ++length; } + ReductionChainLength += length; + MaxChainLength.updateMax(length); } static bool markLoopInfo(Module &M, Function *marker, function_ref GetLI) diff --git a/src/method.c b/src/method.c index 1abacfaa58e55..f0e2598750801 100644 --- a/src/method.c +++ b/src/method.c @@ -377,7 +377,9 @@ static void jl_code_info_set_ir(jl_code_info_t *li, jl_expr_t *ir) else if (jl_is_expr(st) && ((jl_expr_t*)st)->head == jl_return_sym) { jl_array_ptr_set(body, j, jl_new_struct(jl_returnnode_type, jl_exprarg(st, 0))); } - + else if (jl_is_expr(st) && (((jl_expr_t*)st)->head == jl_foreigncall_sym || ((jl_expr_t*)st)->head == jl_cfunction_sym)) { + li->has_fcall = 1; + } if (is_flag_stmt) jl_array_uint8_set(li->ssaflags, j, 0); else { @@ -471,6 +473,7 @@ JL_DLLEXPORT jl_code_info_t *jl_new_code_info_uninit(void) src->inlining_cost = UINT16_MAX; src->propagate_inbounds = 0; src->pure = 0; + src->has_fcall = 0; src->edges = jl_nothing; src->constprop = 0; src->purity.bits = 0; @@ -784,6 +787,49 @@ JL_DLLEXPORT jl_method_t *jl_new_method_uninit(jl_module_t *module) return m; } +// backedges ------------------------------------------------------------------ + +// Use this in a `while` loop to iterate over the backedges in a MethodInstance. +// `*invokesig` will be NULL if the call was made by ordinary dispatch, otherwise +// it will be the signature supplied in an `invoke` call. +// If you don't need `invokesig`, you can set it to NULL on input. +// Initialize iteration with `i = 0`. Returns `i` for the next backedge to be extracted. +int get_next_edge(jl_array_t *list, int i, jl_value_t** invokesig, jl_method_instance_t **caller) JL_NOTSAFEPOINT +{ + jl_value_t *item = jl_array_ptr_ref(list, i); + if (jl_is_method_instance(item)) { + // Not an `invoke` call, it's just the MethodInstance + if (invokesig != NULL) + *invokesig = NULL; + *caller = (jl_method_instance_t*)item; + return i + 1; + } + assert(jl_is_type(item)); + // An `invoke` call, it's a (sig, MethodInstance) pair + if (invokesig != NULL) + *invokesig = item; + *caller = (jl_method_instance_t*)jl_array_ptr_ref(list, i + 1); + if (*caller) + assert(jl_is_method_instance(*caller)); + return i + 2; +} + +int set_next_edge(jl_array_t *list, int i, jl_value_t *invokesig, jl_method_instance_t *caller) +{ + if (invokesig) + jl_array_ptr_set(list, i++, invokesig); + jl_array_ptr_set(list, i++, caller); + return i; +} + +void push_edge(jl_array_t *list, jl_value_t *invokesig, jl_method_instance_t *caller) +{ + if (invokesig) + jl_array_ptr_1d_push(list, invokesig); + jl_array_ptr_1d_push(list, (jl_value_t*)caller); + return; +} + // method definition ---------------------------------------------------------- jl_method_t *jl_make_opaque_closure_method(jl_module_t *module, jl_value_t *name, @@ -911,12 +957,6 @@ JL_DLLEXPORT jl_method_t* jl_method_def(jl_svec_t *argdata, size_t i, na = jl_svec_len(atypes); argtype = (jl_value_t*)jl_apply_tuple_type(atypes); - for (i = jl_svec_len(tvars); i > 0; i--) { - jl_value_t *tv = jl_svecref(tvars, i - 1); - if (!jl_is_typevar(tv)) - jl_type_error("method signature", (jl_value_t*)jl_tvar_type, tv); - argtype = jl_new_struct(jl_unionall_type, tv, argtype); - } jl_methtable_t *external_mt = mt; if (!mt) @@ -926,6 +966,12 @@ JL_DLLEXPORT jl_method_t* jl_method_def(jl_svec_t *argdata, if (mt->frozen) jl_error("cannot add methods to a builtin function"); + assert(jl_is_linenode(functionloc)); + jl_sym_t *file = (jl_sym_t*)jl_linenode_file(functionloc); + if (!jl_is_symbol(file)) + file = jl_empty_sym; + int32_t line = jl_linenode_line(functionloc); + // TODO: derive our debug name from the syntax instead of the type name = mt->name; if (mt == jl_type_type_mt || mt == jl_nonfunction_mt || external_mt) { @@ -942,6 +988,29 @@ JL_DLLEXPORT jl_method_t* jl_method_def(jl_svec_t *argdata, } } } + + for (i = jl_svec_len(tvars); i > 0; i--) { + jl_value_t *tv = jl_svecref(tvars, i - 1); + if (!jl_is_typevar(tv)) + jl_type_error("method signature", (jl_value_t*)jl_tvar_type, tv); + if (!jl_has_typevar(argtype, (jl_tvar_t*)tv)) // deprecate this to an error in v2 + jl_printf(JL_STDERR, + "WARNING: method definition for %s at %s:%d declares type variable %s but does not use it.\n", + jl_symbol_name(name), + jl_symbol_name(file), + line, + jl_symbol_name(((jl_tvar_t*)tv)->name)); + argtype = jl_new_struct(jl_unionall_type, tv, argtype); + } + if (jl_has_free_typevars(argtype)) { + jl_exceptionf(jl_argumenterror_type, + "method definition for %s at %s:%d has free type variables", + jl_symbol_name(name), + jl_symbol_name(file), + line); + } + + if (!jl_is_code_info(f)) { // this occurs when there is a closure being added to an out-of-scope function // the user should only do this at the toplevel @@ -956,20 +1025,10 @@ JL_DLLEXPORT jl_method_t* jl_method_def(jl_svec_t *argdata, m->name = name; m->isva = isva; m->nargs = nargs; - assert(jl_is_linenode(functionloc)); - jl_value_t *file = jl_linenode_file(functionloc); - m->file = jl_is_symbol(file) ? (jl_sym_t*)file : jl_empty_sym; - m->line = jl_linenode_line(functionloc); + m->file = file; + m->line = line; jl_method_set_source(m, f); - if (jl_has_free_typevars(argtype)) { - jl_exceptionf(jl_argumenterror_type, - "method definition for %s at %s:%d has free type variables", - jl_symbol_name(name), - jl_symbol_name(m->file), - m->line); - } - for (i = 0; i < na; i++) { jl_value_t *elt = jl_svecref(atypes, i); if (!jl_is_type(elt) && !jl_is_typevar(elt) && !jl_is_vararg(elt)) { @@ -979,22 +1038,22 @@ JL_DLLEXPORT jl_method_t* jl_method_def(jl_svec_t *argdata, "invalid type for argument number %d in method definition for %s at %s:%d", i, jl_symbol_name(name), - jl_symbol_name(m->file), - m->line); + jl_symbol_name(file), + line); else jl_exceptionf(jl_argumenterror_type, "invalid type for argument %s in method definition for %s at %s:%d", jl_symbol_name(argname), jl_symbol_name(name), - jl_symbol_name(m->file), - m->line); + jl_symbol_name(file), + line); } if (jl_is_vararg(elt) && i < na-1) jl_exceptionf(jl_argumenterror_type, "Vararg on non-final argument in method definition for %s at %s:%d", jl_symbol_name(name), - jl_symbol_name(m->file), - m->line); + jl_symbol_name(file), + line); } #ifdef RECORD_METHOD_ORDER diff --git a/src/module.c b/src/module.c index 92393563dd8cb..805f4ca1affac 100644 --- a/src/module.c +++ b/src/module.c @@ -363,6 +363,20 @@ static jl_binding_t *jl_get_binding_(jl_module_t *m, jl_sym_t *var, modstack_t * return b; } +JL_DLLEXPORT jl_binding_t *jl_get_binding_if_bound(jl_module_t *m, jl_sym_t *var) +{ + JL_LOCK(&m->lock); + jl_binding_t *b = _jl_get_module_binding(m, var); + JL_UNLOCK(&m->lock); + if (b == HT_NOTFOUND || b->owner == NULL) { + return NULL; + } + if (b->owner != m || b->name != var) + return jl_get_binding_if_bound(b->owner, b->name); + return b; +} + + // get owner of binding when accessing m.var, without resolving the binding JL_DLLEXPORT jl_value_t *jl_binding_owner(jl_module_t *m, jl_sym_t *var) { @@ -410,17 +424,29 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_or_error(jl_module_t *m, jl_sym_t *var return b; } +JL_DLLEXPORT jl_globalref_t *jl_new_globalref(jl_module_t *mod, jl_sym_t *name, jl_binding_t *b) +{ + jl_task_t *ct = jl_current_task; + jl_globalref_t *g = (jl_globalref_t *)jl_gc_alloc(ct->ptls, sizeof(jl_globalref_t), jl_globalref_type); + g->mod = mod; + jl_gc_wb(g, g->mod); + g->name = name; + g->bnd_cache = b; + return g; +} + JL_DLLEXPORT jl_value_t *jl_module_globalref(jl_module_t *m, jl_sym_t *var) { JL_LOCK(&m->lock); - jl_binding_t *b = (jl_binding_t*)ptrhash_get(&m->bindings, var); + jl_binding_t *b = _jl_get_module_binding(m, var); if (b == HT_NOTFOUND) { JL_UNLOCK(&m->lock); - return jl_new_struct(jl_globalref_type, m, var); + return (jl_value_t *)jl_new_globalref(m, var, NULL); } jl_value_t *globalref = jl_atomic_load_relaxed(&b->globalref); if (globalref == NULL) { - jl_value_t *newref = jl_new_struct(jl_globalref_type, m, var); + jl_value_t *newref = (jl_value_t *)jl_new_globalref(m, var, + !b->owner ? NULL : b->owner == m ? b : _jl_get_module_binding(b->owner, b->name)); if (jl_atomic_cmpswap_relaxed(&b->globalref, &globalref, newref)) { JL_GC_PROMISE_ROOTED(newref); globalref = newref; @@ -662,12 +688,18 @@ JL_DLLEXPORT jl_binding_t *jl_get_module_binding(jl_module_t *m JL_PROPAGATES_RO return b == HT_NOTFOUND ? NULL : b; } + +JL_DLLEXPORT jl_value_t *jl_binding_value(jl_binding_t *b JL_PROPAGATES_ROOT) +{ + return jl_atomic_load_relaxed(&b->value); +} + JL_DLLEXPORT jl_value_t *jl_get_global(jl_module_t *m, jl_sym_t *var) { jl_binding_t *b = jl_get_binding(m, var); if (b == NULL) return NULL; if (b->deprecated) jl_binding_deprecation_warning(m, b); - return b->value; + return jl_binding_value(b); } JL_DLLEXPORT void jl_set_global(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT) @@ -696,10 +728,22 @@ JL_DLLEXPORT void jl_set_const(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var jl_symbol_name(bp->name)); } +JL_DLLEXPORT int jl_binding_is_const(jl_binding_t *b) +{ + assert(b); + return b->constp; +} + +JL_DLLEXPORT int jl_binding_boundp(jl_binding_t *b) +{ + assert(b); + return b->value != 0; +} + JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var) { jl_binding_t *b = jl_get_binding(m, var); - return b && b->constp; + return b && jl_binding_is_const(b); } // set the deprecated flag for a binding: diff --git a/src/options.h b/src/options.h index 75a3e6e02c1bc..6d2764fa91dfd 100644 --- a/src/options.h +++ b/src/options.h @@ -128,7 +128,7 @@ // controls for when threads sleep #define THREAD_SLEEP_THRESHOLD_NAME "JULIA_THREAD_SLEEP_THRESHOLD" -#define DEFAULT_THREAD_SLEEP_THRESHOLD 16*1000 // nanoseconds (16us) +#define DEFAULT_THREAD_SLEEP_THRESHOLD 100*1000 // nanoseconds (100us) // defaults for # threads #define NUM_THREADS_NAME "JULIA_NUM_THREADS" diff --git a/src/pipeline.cpp b/src/pipeline.cpp index d9602ad7010d4..10709989f55b0 100644 --- a/src/pipeline.cpp +++ b/src/pipeline.cpp @@ -12,6 +12,7 @@ // analysis passes #include #include +#include #include #include #include @@ -115,7 +116,7 @@ namespace { // TODO: Consider add more passes like in // addGeneralOptsForMemorySanitizer. EarlyCSEPass makes visible // difference on size. It's not clear if the rest is still - // usefull. InstCombinePass breakes + // useful. InstCombinePass breaks // compiler-rt/test/msan/select_origin.cpp. } MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); @@ -172,11 +173,10 @@ namespace { // } } - void addVerificationPasses(ModulePassManager &MPM) { - FunctionPassManager FPM; - FPM.addPass(GCInvariantVerifierPass()); - FPM.addPass(VerifierPass()); - MPM.addPass(llvm::createModuleToFunctionPassAdaptor(std::move(FPM))); + void addVerificationPasses(ModulePassManager &MPM, bool llvm_only) { + if (!llvm_only) + MPM.addPass(llvm::createModuleToFunctionPassAdaptor(GCInvariantVerifierPass())); + MPM.addPass(VerifierPass()); } auto basicSimplifyCFGOptions() { @@ -207,16 +207,17 @@ namespace { //the PassBuilder extension point callbacks //For now we'll maintain the insertion points even though they don't do anything //for the sake of documentation - void invokePipelineStartCallbacks(ModulePassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} - void invokePeepholeEPCallbacks(FunctionPassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} - void invokeEarlySimplificationCallbacks(ModulePassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} - void invokeCGSCCCallbacks(CGSCCPassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} - void invokeOptimizerEarlyCallbacks(ModulePassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} - void invokeLateLoopOptimizationCallbacks(LoopPassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} - void invokeLoopOptimizerEndCallbacks(LoopPassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} - void invokeScalarOptimizerCallbacks(FunctionPassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} - void invokeVectorizerCallbacks(FunctionPassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} - void invokeOptimizerLastCallbacks(ModulePassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} + //If PB is a nullptr, don't invoke anything (this happens when running julia from opt) + void invokePipelineStartCallbacks(ModulePassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} + void invokePeepholeEPCallbacks(FunctionPassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} + void invokeEarlySimplificationCallbacks(ModulePassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} + void invokeCGSCCCallbacks(CGSCCPassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} + void invokeOptimizerEarlyCallbacks(ModulePassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} + void invokeLateLoopOptimizationCallbacks(LoopPassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} + void invokeLoopOptimizerEndCallbacks(LoopPassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} + void invokeScalarOptimizerCallbacks(FunctionPassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} + void invokeVectorizerCallbacks(FunctionPassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} + void invokeOptimizerLastCallbacks(ModulePassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} } //The actual pipelines @@ -239,15 +240,17 @@ namespace { //? loop sink pass //? hot-cold splitting pass +#define JULIA_PASS(ADD_PASS) if (!options.llvm_only) { ADD_PASS; } else do;while (0) + //Use for O1 and below -void buildBasicPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLevel O, OptimizationOptions options) { +void buildBasicPipeline(ModulePassManager &MPM, PassBuilder *PB, OptimizationLevel O, OptimizationOptions options) { // #ifdef JL_DEBUG_BUILD - addVerificationPasses(MPM); + addVerificationPasses(MPM, options.llvm_only); // #endif invokePipelineStartCallbacks(MPM, PB, O); MPM.addPass(ConstantMergePass()); if (!options.dump_native) { - MPM.addPass(CPUFeatures()); + JULIA_PASS(MPM.addPass(CPUFeatures())); if (O.getSpeedupLevel() > 0) { MPM.addPass(createModuleToFunctionPassAdaptor(InstSimplifyPass())); } @@ -271,7 +274,7 @@ void buildBasicPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLev MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); } invokeOptimizerEarlyCallbacks(MPM, PB, O); - MPM.addPass(LowerSIMDLoop()); + JULIA_PASS(MPM.addPass(LowerSIMDLoop())); { FunctionPassManager FPM; { @@ -288,21 +291,21 @@ void buildBasicPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLev //TODO no barrier pass? { FunctionPassManager FPM; - FPM.addPass(LowerExcHandlers()); - FPM.addPass(GCInvariantVerifierPass(false)); + JULIA_PASS(FPM.addPass(LowerExcHandlers())); + JULIA_PASS(FPM.addPass(GCInvariantVerifierPass(false))); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } - MPM.addPass(RemoveNI()); - MPM.addPass(createModuleToFunctionPassAdaptor(LateLowerGC())); - MPM.addPass(FinalLowerGCPass()); - MPM.addPass(LowerPTLSPass(options.dump_native)); + JULIA_PASS(MPM.addPass(RemoveNI())); + JULIA_PASS(MPM.addPass(createModuleToFunctionPassAdaptor(LateLowerGC()))); + JULIA_PASS(MPM.addPass(FinalLowerGCPass())); + JULIA_PASS(MPM.addPass(LowerPTLSPass(options.dump_native))); } else { - MPM.addPass(RemoveNI()); + JULIA_PASS(MPM.addPass(RemoveNI())); } - MPM.addPass(LowerSIMDLoop()); // TODO why do we do this twice + JULIA_PASS(MPM.addPass(LowerSIMDLoop())); // TODO why do we do this twice if (options.dump_native) { - MPM.addPass(MultiVersioning(options.external_use)); - MPM.addPass(CPUFeatures()); + JULIA_PASS(MPM.addPass(MultiVersioning(options.external_use))); + JULIA_PASS(MPM.addPass(CPUFeatures())); if (O.getSpeedupLevel() > 0) { FunctionPassManager FPM; FPM.addPass(InstSimplifyPass()); @@ -312,19 +315,19 @@ void buildBasicPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLev } invokeOptimizerLastCallbacks(MPM, PB, O); addSanitizerPasses(MPM, O); - MPM.addPass(createModuleToFunctionPassAdaptor(DemoteFloat16())); + JULIA_PASS(MPM.addPass(createModuleToFunctionPassAdaptor(DemoteFloat16()))); } //Use for O2 and above -void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLevel O, OptimizationOptions options) { +void buildFullPipeline(ModulePassManager &MPM, PassBuilder *PB, OptimizationLevel O, OptimizationOptions options) { // #ifdef JL_DEBUG_BUILD - addVerificationPasses(MPM); + addVerificationPasses(MPM, options.llvm_only); // #endif invokePipelineStartCallbacks(MPM, PB, O); MPM.addPass(ConstantMergePass()); { FunctionPassManager FPM; - FPM.addPass(PropagateJuliaAddrspacesPass()); + JULIA_PASS(FPM.addPass(PropagateJuliaAddrspacesPass())); //TODO consider not using even basic simplification //options here, and adding a run of CVP to take advantage //of the unsimplified codegen information (e.g. known @@ -342,7 +345,7 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve invokeCGSCCCallbacks(CGPM, PB, O); { FunctionPassManager FPM; - FPM.addPass(AllocOptPass()); + JULIA_PASS(FPM.addPass(AllocOptPass())); FPM.addPass(InstCombinePass()); FPM.addPass(SimplifyCFGPass(basicSimplifyCFGOptions())); CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM))); @@ -350,9 +353,9 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); } if (options.dump_native) { - MPM.addPass(MultiVersioning(options.external_use)); + JULIA_PASS(MPM.addPass(MultiVersioning(options.external_use))); } - MPM.addPass(CPUFeatures()); + JULIA_PASS(MPM.addPass(CPUFeatures())); { FunctionPassManager FPM; FPM.addPass(SROAPass()); @@ -361,7 +364,7 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve FPM.addPass(CorrelatedValuePropagationPass()); FPM.addPass(ReassociatePass()); FPM.addPass(EarlyCSEPass()); - FPM.addPass(AllocOptPass()); + JULIA_PASS(FPM.addPass(AllocOptPass())); invokePeepholeEPCallbacks(FPM, PB, O); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } @@ -374,11 +377,14 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve invokeLateLoopOptimizationCallbacks(LPM1, PB, O); //We don't know if the loop callbacks support MSSA FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM1), /*UseMemorySSA = */false)); - LPM2.addPass(LICMPass()); - LPM2.addPass(JuliaLICMPass()); +#if JL_LLVM_VERSION < 150000 +#define LICMOptions() +#endif + LPM2.addPass(LICMPass(LICMOptions())); + JULIA_PASS(LPM2.addPass(JuliaLICMPass())); LPM2.addPass(SimpleLoopUnswitchPass()); - LPM2.addPass(LICMPass()); - LPM2.addPass(JuliaLICMPass()); + LPM2.addPass(LICMPass(LICMOptions())); + JULIA_PASS(LPM2.addPass(JuliaLICMPass())); //LICM needs MemorySSA now, so we must use it FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM2), /*UseMemorySSA = */true)); } @@ -394,7 +400,7 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM), /*UseMemorySSA = */false)); } FPM.addPass(LoopUnrollPass()); - FPM.addPass(AllocOptPass()); + JULIA_PASS(FPM.addPass(AllocOptPass())); FPM.addPass(SROAPass()); FPM.addPass(InstSimplifyPass()); FPM.addPass(GVNPass()); @@ -411,7 +417,7 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve FPM.addPass(DSEPass()); invokePeepholeEPCallbacks(FPM, PB, O); FPM.addPass(SimplifyCFGPass(aggressiveSimplifyCFGOptions())); - FPM.addPass(AllocOptPass()); + JULIA_PASS(FPM.addPass(AllocOptPass())); { LoopPassManager LPM; LPM.addPass(LoopDeletionPass()); @@ -434,15 +440,15 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve //TODO barrier pass? { FunctionPassManager FPM; - FPM.addPass(LowerExcHandlers()); - FPM.addPass(GCInvariantVerifierPass(false)); + JULIA_PASS(FPM.addPass(LowerExcHandlers())); + JULIA_PASS(FPM.addPass(GCInvariantVerifierPass(false))); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } // Needed **before** LateLowerGCFrame on LLVM < 12 // due to bug in `CreateAlignmentAssumption`. - MPM.addPass(RemoveNI()); - MPM.addPass(createModuleToFunctionPassAdaptor(LateLowerGC())); - MPM.addPass(FinalLowerGCPass()); + JULIA_PASS(MPM.addPass(RemoveNI())); + JULIA_PASS(MPM.addPass(createModuleToFunctionPassAdaptor(LateLowerGC()))); + JULIA_PASS(MPM.addPass(FinalLowerGCPass())); { FunctionPassManager FPM; FPM.addPass(GVNPass()); @@ -450,7 +456,7 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve FPM.addPass(DCEPass()); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } - MPM.addPass(LowerPTLSPass(options.dump_native)); + JULIA_PASS(MPM.addPass(LowerPTLSPass(options.dump_native))); { FunctionPassManager FPM; FPM.addPass(InstCombinePass()); @@ -458,11 +464,11 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } } else { - MPM.addPass(RemoveNI()); + JULIA_PASS(MPM.addPass(RemoveNI())); } { FunctionPassManager FPM; - FPM.addPass(CombineMulAdd()); + JULIA_PASS(FPM.addPass(CombineMulAdd())); FPM.addPass(DivRemPairsPass()); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } @@ -470,12 +476,14 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve addSanitizerPasses(MPM, O); { FunctionPassManager FPM; - FPM.addPass(DemoteFloat16()); + JULIA_PASS(FPM.addPass(DemoteFloat16())); FPM.addPass(GVNPass()); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } } +#undef JULIA_PASS + namespace { auto createPIC(StandardInstrumentations &SI) { auto PIC = std::make_unique(); @@ -553,9 +561,9 @@ PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME); ModulePassManager createMPM(PassBuilder &PB, OptimizationLevel O, OptimizationOptions options) { ModulePassManager MPM; if (O.getSpeedupLevel() < 2) - buildBasicPipeline(MPM, PB, O, options); + buildBasicPipeline(MPM, &PB, O, options); else - buildFullPipeline(MPM, PB, O, options); + buildFullPipeline(MPM, &PB, O, options); return MPM; } } @@ -602,3 +610,108 @@ OptimizationLevel getOptLevel(int optlevel) { } llvm_unreachable("cannot get here!"); } + +//This part is also basically stolen from LLVM's PassBuilder.cpp file +static llvm::Optional> parseJuliaPipelineOptions(StringRef name) { + if (name.consume_front("julia")) { + auto O = OptimizationLevel::O2; + auto options = OptimizationOptions::defaults(); + if (!name.empty() && (!name.consume_front("<") || !name.consume_back(">"))) { + assert(false && "Expected pass options to be enclosed in <>!"); + } + std::map option_pointers = { +#define OPTION(name) {#name, &options.name} + OPTION(lower_intrinsics), + OPTION(dump_native), + OPTION(external_use), + OPTION(llvm_only) +#undef OPTION + }; + while (!name.empty()) { + StringRef option; + std::tie(option, name) = name.split(';'); + bool enable = !option.consume_front("no_"); + auto it = option_pointers.find(option); + if (it == option_pointers.end()) { + if (option.consume_front("level=")) { + int level = 2; + if (option.getAsInteger(0, level)) { + assert(false && "Non-integer passed to julia level!"); + } + switch (std::min(std::max(level, 0), 3)) { + case 0: + O = OptimizationLevel::O0; + break; + case 1: + O = OptimizationLevel::O1; + break; + case 2: + O = OptimizationLevel::O2; + break; + case 3: + O = OptimizationLevel::O3; + break; + } + } else { + errs() << "Unable to find julia option '" << option << "'!"; + assert(false && "Invalid option passed to julia pass!"); + } + } else { + *it->second = enable; + } + } + return {{O, options}}; + } + return {}; +} + +// new pass manager plugin + +// NOTE: Instead of exporting all the constructors in passes.h we could +// forward the callbacks to the respective passes. LLVM seems to prefer this, +// and when we add the full pass builder having them directly will be helpful. +void registerCallbacks(PassBuilder &PB) { + PB.registerPipelineParsingCallback( + [](StringRef Name, FunctionPassManager &PM, + ArrayRef InnerPipeline) { +#define FUNCTION_PASS(NAME, CREATE_PASS) if (Name == NAME) { PM.addPass(CREATE_PASS); return true; } +#include "llvm-julia-passes.inc" +#undef FUNCTION_PASS + return false; + }); + + PB.registerPipelineParsingCallback( + [](StringRef Name, ModulePassManager &PM, + ArrayRef InnerPipeline) { +#define MODULE_PASS(NAME, CREATE_PASS) if (Name == NAME) { PM.addPass(CREATE_PASS); return true; } +#include "llvm-julia-passes.inc" +#undef MODULE_PASS + //Add full pipelines here + auto julia_options = parseJuliaPipelineOptions(Name); + if (julia_options) { + ModulePassManager pipeline; + if (julia_options->first.getSpeedupLevel() < 2) { + buildBasicPipeline(pipeline, nullptr, julia_options->first, julia_options->second); + } else { + buildFullPipeline(pipeline, nullptr, julia_options->first, julia_options->second); + } + PM.addPass(std::move(pipeline)); + return true; + } + return false; + }); + + PB.registerPipelineParsingCallback( + [](StringRef Name, LoopPassManager &PM, + ArrayRef InnerPipeline) { +#define LOOP_PASS(NAME, CREATE_PASS) if (Name == NAME) { PM.addPass(CREATE_PASS); return true; } +#include "llvm-julia-passes.inc" +#undef LOOP_PASS + return false; + }); +} + +extern "C" JL_DLLEXPORT ::llvm::PassPluginLibraryInfo +llvmGetPassPluginInfo() { + return {LLVM_PLUGIN_API_VERSION, "Julia", "1", registerCallbacks}; +} diff --git a/src/serialize.h b/src/serialize.h index 69aaeb4c39787..020cafc74c962 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -92,7 +92,7 @@ static inline uint64_t read_uint64(ios_t *s) JL_NOTSAFEPOINT return x; } -static inline void write_int64(ios_t *s, int64_t i) JL_NOTSAFEPOINT +static inline void write_uint64(ios_t *s, uint64_t i) JL_NOTSAFEPOINT { ios_write(s, (char*)&i, 8); } @@ -121,6 +121,19 @@ static inline uint32_t read_uint32(ios_t *s) JL_NOTSAFEPOINT return x; } +#ifdef _P64 +#define write_uint(s, i) write_uint64(s, i) +#else +#define write_uint(s, i) write_uint32(s, i) +#endif + +#ifdef _P64 +#define read_uint(s) read_uint64(s) +#else +#define read_uint(s) read_uint32(s) +#endif + + void *jl_lookup_ser_tag(jl_value_t *v); void *jl_lookup_common_symbol(jl_value_t *v); jl_value_t *jl_deser_tag(uint8_t tag); diff --git a/src/signal-handling.c b/src/signal-handling.c index 43782bf4070f2..ba890daa5a9bb 100644 --- a/src/signal-handling.c +++ b/src/signal-handling.c @@ -6,8 +6,8 @@ #include #include "julia.h" #include "julia_internal.h" -#ifndef _OS_WINDOWS_ #include +#ifndef _OS_WINDOWS_ #include #endif diff --git a/src/staticdata.c b/src/staticdata.c index 2e0c69dad3afc..4f80ee1d131a5 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -59,6 +59,7 @@ done by `get_item_for_reloc`. #include #include #include // printf +#include // PRIxPTR #include "julia.h" #include "julia_internal.h" @@ -315,7 +316,7 @@ static const jl_fptr_args_t id_to_fptrs[] = { &jl_f_ifelse, &jl_f__structtype, &jl_f__abstracttype, &jl_f__primitivetype, &jl_f__typebody, &jl_f__setsuper, &jl_f__equiv_typedef, &jl_f_get_binding_type, &jl_f_set_binding_type, &jl_f_opaque_closure_call, &jl_f_donotdelete, &jl_f_compilerbarrier, - &jl_f_getglobal, &jl_f_setglobal, &jl_f_finalizer, + &jl_f_getglobal, &jl_f_setglobal, &jl_f_finalizer, &jl_f__compute_sparams, &jl_f__svec_ref, NULL }; typedef struct { @@ -362,9 +363,28 @@ typedef enum { } jl_callingconv_t; +//#ifdef _P64 +//#define RELOC_TAG_OFFSET 61 +//#else // this supports up to 8 RefTags, 512MB of pointer data, and 4/2 (64/32-bit) GB of constant data. -// if a larger size is required, will need to add support for writing larger relocations in many cases below #define RELOC_TAG_OFFSET 29 +//#endif + +#if RELOC_TAG_OFFSET <= 32 +typedef uint32_t reloc_t; +#else +typedef uint64_t reloc_t; +#endif +static void write_reloc_t(ios_t *s, uintptr_t reloc_id) JL_NOTSAFEPOINT +{ + if (sizeof(reloc_t) <= sizeof(uint32_t)) { + assert(reloc_id < UINT32_MAX); + write_uint32(s, reloc_id); + } + else { + write_uint64(s, reloc_id); + } +} // --- Static Compile --- @@ -576,6 +596,10 @@ static void jl_serialize_value__(jl_serializer_state *s, jl_value_t *v, int recu jl_serialize_value(s, tn->partial); } else if (t->layout->nfields > 0) { + if (jl_typeis(v, jl_globalref_type)) { + // Don't save the cached binding reference in staticdata + ((jl_globalref_t*)v)->bnd_cache = NULL; + } char *data = (char*)jl_data_ptr(v); size_t i, np = t->layout->npointers; for (i = 0; i < np; i++) { @@ -626,10 +650,9 @@ static void record_gvar(jl_serializer_state *s, int gid, uintptr_t reloc_id) JL_ { if (gid == 0) return; - ios_ensureroom(s->gvar_record, gid * sizeof(uint32_t)); - ios_seek(s->gvar_record, (gid - 1) * sizeof(uint32_t)); - assert(reloc_id < UINT32_MAX); - write_uint32(s->gvar_record, reloc_id); + ios_ensureroom(s->gvar_record, gid * sizeof(reloc_t)); + ios_seek(s->gvar_record, (gid - 1) * sizeof(reloc_t)); + write_reloc_t(s->gvar_record, reloc_id); } @@ -648,7 +671,7 @@ static void write_padding(ios_t *s, size_t nb) JL_NOTSAFEPOINT static void write_pointer(ios_t *s) JL_NOTSAFEPOINT { assert((ios_pos(s) & (sizeof(void*) - 1)) == 0 && "stream misaligned for writing a word-sized value"); - write_padding(s, sizeof(void*)); + write_uint(s, 0); } // Return the integer `id` for `v`. Generically this is looked up in `backref_table`, @@ -1103,18 +1126,20 @@ static void jl_write_values(jl_serializer_state *s) assert(invokeptr_id > 0); ios_ensureroom(s->fptr_record, invokeptr_id * sizeof(void*)); ios_seek(s->fptr_record, (invokeptr_id - 1) * sizeof(void*)); - write_uint32(s->fptr_record, ~reloc_offset); + write_reloc_t(s->fptr_record, (uint32_t)~reloc_offset); #ifdef _P64 - write_padding(s->fptr_record, 4); + if (sizeof(reloc_t) < 8) + write_padding(s->fptr_record, 8 - sizeof(reloc_t)); #endif } if (specfptr_id) { assert(specfptr_id > invokeptr_id && specfptr_id > 0); ios_ensureroom(s->fptr_record, specfptr_id * sizeof(void*)); ios_seek(s->fptr_record, (specfptr_id - 1) * sizeof(void*)); - write_uint32(s->fptr_record, reloc_offset); + write_reloc_t(s->fptr_record, reloc_offset); #ifdef _P64 - write_padding(s->fptr_record, 4); + if (sizeof(reloc_t) < 8) + write_padding(s->fptr_record, 8 - sizeof(reloc_t)); #endif } } @@ -1237,14 +1262,6 @@ static void jl_write_gv_tagrefs(jl_serializer_state *s) } } -static inline uint32_t load_uint32(uintptr_t *base) -{ - uint32_t v = jl_load_unaligned_i32((void*)*base); - *base += 4; - return v; -} - - // In deserialization, create Symbols and set up the // index for backreferencing static void jl_read_symbols(jl_serializer_state *s) @@ -1253,7 +1270,8 @@ static void jl_read_symbols(jl_serializer_state *s) uintptr_t base = (uintptr_t)&s->symbols->buf[0]; uintptr_t end = base + s->symbols->size; while (base < end) { - uint32_t len = load_uint32(&base); + uint32_t len = jl_load_unaligned_i32((void*)base); + base += 4; const char *str = (const char*)base; base += len + 1; //printf("symbol %3d: %s\n", len, str); @@ -1311,7 +1329,7 @@ static uintptr_t get_reloc_for_item(uintptr_t reloc_item, size_t reloc_offset) } // Compute target location at deserialization -static inline uintptr_t get_item_for_reloc(jl_serializer_state *s, uintptr_t base, size_t size, uint32_t reloc_id) +static inline uintptr_t get_item_for_reloc(jl_serializer_state *s, uintptr_t base, size_t size, uintptr_t reloc_id) { enum RefTags tag = (enum RefTags)(reloc_id >> RELOC_TAG_OFFSET); size_t offset = (reloc_id & (((uintptr_t)1 << RELOC_TAG_OFFSET) - 1)); @@ -1383,10 +1401,9 @@ static void jl_write_skiplist(ios_t *s, char *base, size_t size, arraylist_t *li *pv = get_reloc_for_item(item, *pv); // record pos in relocations list // TODO: save space by using delta-compression - assert(pos < UINT32_MAX); - write_uint32(s, pos); + write_reloc_t(s, pos); } - write_uint32(s, 0); + write_reloc_t(s, 0); } @@ -1403,9 +1420,8 @@ static void jl_read_relocations(jl_serializer_state *s, uint8_t bits) uintptr_t base = (uintptr_t)&s->s->buf[0]; size_t size = s->s->size; while (1) { - uintptr_t val = (uintptr_t)&s->relocs->buf[s->relocs->bpos]; - uint32_t offset = load_uint32(&val); - s->relocs->bpos += sizeof(uint32_t); + uintptr_t offset = *(reloc_t*)&s->relocs->buf[(uintptr_t)s->relocs->bpos]; + s->relocs->bpos += sizeof(reloc_t); if (offset == 0) break; uintptr_t *pv = (uintptr_t*)(base + offset); @@ -1415,16 +1431,17 @@ static void jl_read_relocations(jl_serializer_state *s, uint8_t bits) } } -static char* sysimg_base; -static char* sysimg_relocs; +static char *sysimg_base; +static char *sysimg_relocs; void gc_sweep_sysimg(void) { - uintptr_t base = (uintptr_t)sysimg_base; - uintptr_t relocs = (uintptr_t)sysimg_relocs; - if (relocs == 0) + char *base = sysimg_base; + reloc_t *relocs = (reloc_t*)sysimg_relocs; + if (relocs == NULL) return; while (1) { - uint32_t offset = load_uint32(&relocs); + uintptr_t offset = *relocs; + relocs++; if (offset == 0) break; jl_taggedvalue_t *o = (jl_taggedvalue_t*)(base + offset); @@ -1436,13 +1453,12 @@ void gc_sweep_sysimg(void) static void _jl_write_value(jl_serializer_state *s, jl_value_t *v) { if (v == NULL) { - write_uint32(s->s, 0); + write_reloc_t(s->s, 0); return; } uintptr_t item = backref_id(s, v); uintptr_t reloc = get_reloc_for_item(item, 0); - assert(reloc < UINT32_MAX); - write_uint32(s->s, reloc); + write_reloc_t(s->s, reloc); } @@ -1450,9 +1466,8 @@ static jl_value_t *jl_read_value(jl_serializer_state *s) { uintptr_t base = (uintptr_t)&s->s->buf[0]; size_t size = s->s->size; - uintptr_t val = base + s->s->bpos; - uint32_t offset = load_uint32(&val); - s->s->bpos += sizeof(uint32_t); + uintptr_t offset = *(reloc_t*)(base + (uintptr_t)s->s->bpos); + s->s->bpos += sizeof(reloc_t); if (offset == 0) return NULL; return (jl_value_t*)get_item_for_reloc(s, base, size, offset); @@ -1475,12 +1490,11 @@ static void jl_update_all_fptrs(jl_serializer_state *s) jl_method_instance_t **linfos = (jl_method_instance_t**)&s->fptr_record->buf[0]; uint32_t clone_idx = 0; for (i = 0; i < sysimg_fvars_max; i++) { - uintptr_t val = (uintptr_t)&linfos[i]; - uint32_t offset = load_uint32(&val); + reloc_t offset = *(reloc_t*)&linfos[i]; linfos[i] = NULL; if (offset != 0) { int specfunc = 1; - if (offset & ((uintptr_t)1 << (8 * sizeof(uint32_t) - 1))) { + if (offset & ((uintptr_t)1 << (8 * sizeof(reloc_t) - 1))) { // if high bit is set, this is the func wrapper, not the specfunc specfunc = 0; offset = ~offset; @@ -1522,15 +1536,16 @@ static void jl_update_all_gvars(jl_serializer_state *s) size_t gvname_index = 0; uintptr_t base = (uintptr_t)&s->s->buf[0]; size_t size = s->s->size; - uintptr_t gvars = (uintptr_t)&s->gvar_record->buf[0]; - uintptr_t end = gvars + s->gvar_record->size; + reloc_t *gvars = (reloc_t*)&s->gvar_record->buf[0]; + reloc_t *end = gvars + s->gvar_record->size / sizeof(reloc_t); while (gvars < end) { - uint32_t offset = load_uint32(&gvars); + uintptr_t offset = *gvars; if (offset) { uintptr_t v = get_item_for_reloc(s, base, size, offset); *sysimg_gvars(sysimg_gvars_base, gvname_index) = v; } gvname_index += 1; + gvars++; } } @@ -1546,14 +1561,14 @@ static void jl_finalize_serializer(jl_serializer_state *s, arraylist_t *list) size_t item = (size_t)list->items[i]; size_t reloc_offset = (size_t)layout_table.items[item]; assert(reloc_offset != 0); - write_uint32(s->s, (uint32_t)reloc_offset); - write_uint32(s->s, (uint32_t)((uintptr_t)list->items[i + 1])); + write_reloc_t(s->s, reloc_offset); + write_uint8(s->s, (uintptr_t)list->items[i + 1]); } - write_uint32(s->s, 0); + write_reloc_t(s->s, 0); } -static void jl_reinit_item(jl_value_t *v, int how) JL_GC_DISABLED +static void jl_reinit_item(jl_value_t *v, uint8_t how) JL_GC_DISABLED { switch (how) { case 1: { // rehash IdDict @@ -1605,11 +1620,17 @@ static void jl_finalize_deserializer(jl_serializer_state *s) JL_GC_DISABLED // run reinitialization functions uintptr_t base = (uintptr_t)&s->s->buf[0]; while (1) { - size_t offset = read_uint32(s->s); + size_t offset; + if (sizeof(reloc_t) <= 4) { + offset = read_uint32(s->s); + } + else { + offset = read_uint64(s->s); + } if (offset == 0) break; jl_value_t *v = (jl_value_t*)(base + offset); - jl_reinit_item(v, read_uint32(s->s)); + jl_reinit_item(v, read_uint8(s->s)); } } @@ -1940,54 +1961,72 @@ static void jl_save_system_image_to_stream(ios_t *f) JL_GC_DISABLED } { // step 2: build all the sysimg sections - write_padding(&sysimg, sizeof(uint32_t)); + write_padding(&sysimg, sizeof(uintptr_t)); jl_write_values(&s); jl_write_relocations(&s); jl_write_gv_syms(&s, jl_get_root_symbol()); jl_write_gv_tagrefs(&s); } - if (sysimg.size > ((uintptr_t)1 << RELOC_TAG_OFFSET) || - const_data.size > ((uintptr_t)1 << RELOC_TAG_OFFSET)*sizeof(void*)) { - jl_printf(JL_STDERR, "ERROR: system image too large\n"); + if (sysimg.size > ((uintptr_t)1 << RELOC_TAG_OFFSET)) { + jl_printf( + JL_STDERR, + "ERROR: system image too large: sysimg.size is %jd but the limit is %" PRIxPTR "\n", + (intmax_t)sysimg.size, + ((uintptr_t)1 << RELOC_TAG_OFFSET) + ); + jl_exit(1); + } + if (const_data.size / sizeof(void*) > ((uintptr_t)1 << RELOC_TAG_OFFSET)) { + jl_printf( + JL_STDERR, + "ERROR: system image too large: const_data.size is %jd but the limit is %" PRIxPTR "\n", + (intmax_t)const_data.size, + ((uintptr_t)1 << RELOC_TAG_OFFSET)*sizeof(void*) + ); jl_exit(1); } // step 3: combine all of the sections into one file - write_uint32(f, sysimg.size - sizeof(uint32_t)); - ios_seek(&sysimg, sizeof(uint32_t)); + write_uint(f, sysimg.size - sizeof(uintptr_t)); + ios_seek(&sysimg, sizeof(uintptr_t)); ios_copyall(f, &sysimg); ios_close(&sysimg); - write_uint32(f, const_data.size); + write_uint(f, const_data.size); // realign stream to max-alignment for data - write_padding(f, LLT_ALIGN(ios_pos(f), 16) - ios_pos(f)); + write_padding(f, LLT_ALIGN(ios_pos(f), JL_CACHE_BYTE_ALIGNMENT) - ios_pos(f)); ios_seek(&const_data, 0); ios_copyall(f, &const_data); ios_close(&const_data); - write_uint32(f, symbols.size); + write_uint(f, symbols.size); + write_padding(f, LLT_ALIGN(ios_pos(f), 8) - ios_pos(f)); ios_seek(&symbols, 0); ios_copyall(f, &symbols); ios_close(&symbols); - write_uint32(f, relocs.size); + write_uint(f, relocs.size); + write_padding(f, LLT_ALIGN(ios_pos(f), 8) - ios_pos(f)); ios_seek(&relocs, 0); ios_copyall(f, &relocs); ios_close(&relocs); - write_uint32(f, gvar_record.size); + write_uint(f, gvar_record.size); + write_padding(f, LLT_ALIGN(ios_pos(f), 8) - ios_pos(f)); ios_seek(&gvar_record, 0); ios_copyall(f, &gvar_record); ios_close(&gvar_record); - write_uint32(f, fptr_record.size); + write_uint(f, fptr_record.size); + write_padding(f, LLT_ALIGN(ios_pos(f), 8) - ios_pos(f)); ios_seek(&fptr_record, 0); ios_copyall(f, &fptr_record); ios_close(&fptr_record); { // step 4: record locations of special roots s.s = f; + write_padding(f, LLT_ALIGN(ios_pos(f), 8) - ios_pos(f)); size_t i; for (i = 0; tags[i] != NULL; i++) { jl_value_t *tag = *tags[i]; @@ -1996,8 +2035,8 @@ static void jl_save_system_image_to_stream(ios_t *f) JL_GC_DISABLED jl_write_value(&s, jl_global_roots_table); jl_write_value(&s, s.ptls->root_task->tls); write_uint32(f, jl_get_gs_ctr()); - write_uint32(f, jl_atomic_load_acquire(&jl_world_counter)); - write_uint32(f, jl_typeinf_world); + write_uint(f, jl_atomic_load_acquire(&jl_world_counter)); + write_uint(f, jl_typeinf_world); jl_finalize_serializer(&s, &reinit_list); jl_finalize_serializer(&s, &ccallable_list); } @@ -2084,37 +2123,43 @@ static void jl_restore_system_image_from_stream(ios_t *f) JL_GC_DISABLED // step 1: read section map assert(ios_pos(f) == 0 && f->bm == bm_mem); - size_t sizeof_sysimg = read_uint32(f); - ios_static_buffer(&sysimg, f->buf, sizeof_sysimg + sizeof(uint32_t)); + size_t sizeof_sysimg = read_uint(f); + ios_static_buffer(&sysimg, f->buf, sizeof_sysimg + sizeof(uintptr_t)); ios_skip(f, sizeof_sysimg); - size_t sizeof_constdata = read_uint32(f); + size_t sizeof_constdata = read_uint(f); // realign stream to max-alignment for data - ios_seek(f, LLT_ALIGN(ios_pos(f), 16)); + ios_seek(f, LLT_ALIGN(ios_pos(f), JL_CACHE_BYTE_ALIGNMENT)); ios_static_buffer(&const_data, f->buf + f->bpos, sizeof_constdata); ios_skip(f, sizeof_constdata); - size_t sizeof_symbols = read_uint32(f); + size_t sizeof_symbols = read_uint(f); + ios_seek(f, LLT_ALIGN(ios_pos(f), 8)); ios_static_buffer(&symbols, f->buf + f->bpos, sizeof_symbols); ios_skip(f, sizeof_symbols); - size_t sizeof_relocations = read_uint32(f); + size_t sizeof_relocations = read_uint(f); + ios_seek(f, LLT_ALIGN(ios_pos(f), 8)); assert(!ios_eof(f)); ios_static_buffer(&relocs, f->buf + f->bpos, sizeof_relocations); ios_skip(f, sizeof_relocations); - size_t sizeof_gvar_record = read_uint32(f); + size_t sizeof_gvar_record = read_uint(f); + ios_seek(f, LLT_ALIGN(ios_pos(f), 8)); assert(!ios_eof(f)); ios_static_buffer(&gvar_record, f->buf + f->bpos, sizeof_gvar_record); ios_skip(f, sizeof_gvar_record); - size_t sizeof_fptr_record = read_uint32(f); + size_t sizeof_fptr_record = read_uint(f); + ios_seek(f, LLT_ALIGN(ios_pos(f), 8)); assert(!ios_eof(f)); ios_static_buffer(&fptr_record, f->buf + f->bpos, sizeof_fptr_record); ios_skip(f, sizeof_fptr_record); // step 2: get references to special values s.s = f; + ios_seek(f, LLT_ALIGN(ios_pos(f), 8)); + assert(!ios_eof(f)); size_t i; for (i = 0; tags[i] != NULL; i++) { jl_value_t **tag = tags[i]; @@ -2130,8 +2175,8 @@ static void jl_restore_system_image_from_stream(ios_t *f) JL_GC_DISABLED jl_init_box_caches(); uint32_t gs_ctr = read_uint32(f); - jl_atomic_store_release(&jl_world_counter, read_uint32(f)); - jl_typeinf_world = read_uint32(f); + jl_atomic_store_release(&jl_world_counter, read_uint(f)); + jl_typeinf_world = read_uint(f); jl_set_gs_ctr(gs_ctr); s.s = NULL; diff --git a/src/subtype.c b/src/subtype.c index c01ee54e683be..d6322503e9278 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -74,7 +74,11 @@ typedef struct jl_varbinding_t { // 1 - var.ub = ub; return var // 2 - either (var.ub = ub; return var), or return ub int8_t constraintkind; - int8_t intvalued; // must be integer-valued; i.e. occurs as N in Vararg{_,N} + // intvalued: must be integer-valued; i.e. occurs as N in Vararg{_,N} + // 0: No restriction + // 1: must be unbounded/ or fixed to a `Int`/typevar + // 2: we have some imprecise vararg length intersection that can be improved if this var is const valued. + int8_t intvalued; int8_t limited; int16_t depth0; // # of invariant constructors nested around the UnionAll type for this var // when this variable's integer value is compared to that of another, @@ -773,37 +777,9 @@ static int subtype_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8 // widen Type{x} to typeof(x) in argument position if (!vb.occurs_inv) vb.lb = widen_Type(vb.lb); - // fill variable values into `envout` up to `envsz` - if (e->envidx < e->envsz) { - jl_value_t *val; - if (vb.intvalued && vb.lb == (jl_value_t*)jl_any_type) - val = (jl_value_t*)jl_wrap_vararg(NULL, NULL); - else if (!vb.occurs_inv && vb.lb != jl_bottom_type) - val = is_leaf_bound(vb.lb) ? vb.lb : (jl_value_t*)jl_new_typevar(u->var->name, jl_bottom_type, vb.lb); - else if (vb.lb == vb.ub) - val = vb.lb; - else if (vb.lb != jl_bottom_type) - // TODO: for now return the least solution, which is what - // method parameters expect. - val = vb.lb; - else if (vb.lb == u->var->lb && vb.ub == u->var->ub) - val = (jl_value_t*)u->var; - else - val = (jl_value_t*)jl_new_typevar(u->var->name, vb.lb, vb.ub); - jl_value_t *oldval = e->envout[e->envidx]; - // if we try to assign different variable values (due to checking - // multiple union members), consider the value unknown. - if (oldval && !jl_egal(oldval, val)) - e->envout[e->envidx] = (jl_value_t*)u->var; - else - e->envout[e->envidx] = fix_inferred_var_bound(u->var, val); - // TODO: substitute the value (if any) of this variable into previous envout entries } - } - else { - ans = R ? subtype(t, u->body, e, param) : - subtype(u->body, t, e, param); - } + else + ans = subtype(u->body, t, e, param); // handle the "diagonal dispatch" rule, which says that a type var occurring more // than once, and only in covariant position, is constrained to concrete types. E.g. @@ -850,6 +826,33 @@ static int subtype_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8 } } + // fill variable values into `envout` up to `envsz` + if (R && ans && e->envidx < e->envsz) { + jl_value_t *val; + if (vb.intvalued && vb.lb == (jl_value_t*)jl_any_type) + val = (jl_value_t*)jl_wrap_vararg(NULL, NULL); + else if (!vb.occurs_inv && vb.lb != jl_bottom_type) + val = is_leaf_bound(vb.lb) ? vb.lb : (jl_value_t*)jl_new_typevar(u->var->name, jl_bottom_type, vb.lb); + else if (vb.lb == vb.ub) + val = vb.lb; + else if (vb.lb != jl_bottom_type) + // TODO: for now return the least solution, which is what + // method parameters expect. + val = vb.lb; + else if (vb.lb == u->var->lb && vb.ub == u->var->ub) + val = (jl_value_t*)u->var; + else + val = (jl_value_t*)jl_new_typevar(u->var->name, vb.lb, vb.ub); + jl_value_t *oldval = e->envout[e->envidx]; + // if we try to assign different variable values (due to checking + // multiple union members), consider the value unknown. + if (oldval && !jl_egal(oldval, val)) + e->envout[e->envidx] = (jl_value_t*)u->var; + else + e->envout[e->envidx] = fix_inferred_var_bound(u->var, val); + // TODO: substitute the value (if any) of this variable into previous envout entries + } + JL_GC_POP(); return ans; } @@ -1390,10 +1393,18 @@ static int exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_value_ e->Lunions.more = 0; if (subtype(x, y, e, param)) return 1; - restore_env(e, saved, se); int set = e->Runions.more; - if (!set) + if (set) { + // We preserve `envout` here as `subtype_unionall` needs previous assigned env values. + int oldidx = e->envidx; + e->envidx = e->envsz; + restore_env(e, saved, se); + e->envidx = oldidx; + } + else { + restore_env(e, saved, se); return 0; + } for (int i = set; i <= lastset; i++) statestack_set(&e->Runions, i, 0); lastset = set - 1; @@ -2165,13 +2176,24 @@ static jl_value_t *set_var_to_const(jl_varbinding_t *bb, jl_value_t *v JL_MAYBE_ offset = -othervar->offset; assert(!othervar || othervar->offset == -offset); if (bb->lb == jl_bottom_type && bb->ub == (jl_value_t*)jl_any_type) { - if (jl_is_long(v)) - v = jl_box_long(jl_unbox_long(v) + offset); - bb->lb = bb->ub = v; + if (offset == 0) + bb->lb = bb->ub = v; + else if (jl_is_long(v)) { + size_t iv = jl_unbox_long(v); + v = jl_box_long(iv + offset); + bb->lb = bb->ub = v; + // Here we always return the shorter `Vararg`'s length. + if (offset > 0) + return jl_box_long(iv); + } + else + return jl_bottom_type; } else if (jl_is_long(v) && jl_is_long(bb->lb)) { - if (jl_unbox_long(v) != jl_unbox_long(bb->lb)) + if (jl_unbox_long(v) + offset != jl_unbox_long(bb->lb)) return jl_bottom_type; + // Here we always return the shorter `Vararg`'s length. + if (offset < 0) return bb->lb; } else if (!jl_egal(v, bb->lb)) { return jl_bottom_type; @@ -2186,11 +2208,17 @@ static jl_value_t *bound_var_below(jl_tvar_t *tv, jl_varbinding_t *bb, jl_stenv_ return jl_bottom_type; record_var_occurrence(bb, e, 2); if (jl_is_long(bb->lb)) { - if (bb->offset == 0) - return bb->lb; - if (jl_unbox_long(bb->lb) < bb->offset) + ssize_t blb = jl_unbox_long(bb->lb); + if ((blb < bb->offset) || (blb < 0)) return jl_bottom_type; - return jl_box_long(jl_unbox_long(bb->lb) - bb->offset); + // Here we always return the shorter `Vararg`'s length. + if (bb->offset <= 0) + return bb->lb; + return jl_box_long(blb - bb->offset); + } + if (bb->offset > 0) { + bb->intvalued = 2; + return NULL; } return (jl_value_t*)tv; } @@ -2280,6 +2308,26 @@ static int check_unsat_bound(jl_value_t *t, jl_tvar_t *v, jl_stenv_t *e) JL_NOTS return 0; } +static int has_free_vararg_length(jl_value_t *a, jl_stenv_t *e) { + if (jl_is_unionall(a)) + a = jl_unwrap_unionall(a); + if (jl_is_datatype(a) && jl_is_tuple_type((jl_datatype_t *)a)) { + size_t lx = jl_nparams((jl_datatype_t *)a); + if (lx > 0) { + jl_value_t *la = jl_tparam((jl_datatype_t *)a, lx-1); + if (jl_is_vararg(la)) { + jl_value_t *len = jl_unwrap_vararg_num((jl_vararg_t *)la); + // return 1 if we meet a vararg with Null length + if (!len) return 1; + // or a typevar not in the current env. + if (jl_is_typevar(len)) + return lookup(e, (jl_tvar_t *)len) == NULL; + } + } + } + return 0; +} + static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int8_t R, int param) { jl_varbinding_t *bb = lookup(e, b); @@ -2334,6 +2382,11 @@ static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int } } bb->ub = ub; + // We get a imprecise Tuple here. Don't change `lb` and return the typevar directly. + if (has_free_vararg_length(ub, e) && !has_free_vararg_length(a, e)) { + JL_GC_POP(); + return (jl_value_t*)b; + } bb->lb = ub; } JL_GC_POP(); @@ -2443,6 +2496,10 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind } } + // vb is still unbounded. + if (vb->intvalued == 2 && !(varval && jl_is_long(varval))) + vb->intvalued = 1; + // TODO: this can prevent us from matching typevar identities later if (!varval && (vb->lb != vb->var->lb || vb->ub != vb->var->ub)) newvar = jl_new_typevar(vb->var->name, vb->lb, vb->ub); @@ -2635,7 +2692,7 @@ static jl_value_t *intersect_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_ e->vars->limited = 1; } else if (res != jl_bottom_type) { - if (vb.concrete || vb.occurs_inv>1 || u->var->lb != jl_bottom_type || (vb.occurs_inv && vb.occurs_cov)) { + if (vb.concrete || vb.occurs_inv>1 || vb.intvalued > 1 || u->var->lb != jl_bottom_type || (vb.occurs_inv && vb.occurs_cov)) { restore_env(e, NULL, &se); vb.occurs_cov = vb.occurs_inv = 0; vb.constraintkind = vb.concrete ? 1 : 2; @@ -2670,7 +2727,7 @@ static int intersect_vararg_length(jl_value_t *v, ssize_t n, jl_stenv_t *e, int8 } static jl_value_t *intersect_invariant(jl_value_t *x, jl_value_t *y, jl_stenv_t *e); -static jl_value_t *intersect_varargs(jl_vararg_t *vmx, jl_vararg_t *vmy, jl_stenv_t *e, int param) +static jl_value_t *intersect_varargs(jl_vararg_t *vmx, jl_vararg_t *vmy, ssize_t offset, jl_stenv_t *e, int param) { // Vararg: covariant in first parameter, invariant in second jl_value_t *xp1=jl_unwrap_vararg(vmx), *xp2=jl_unwrap_vararg_num(vmx), @@ -2688,19 +2745,24 @@ static jl_value_t *intersect_varargs(jl_vararg_t *vmx, jl_vararg_t *vmy, jl_sten JL_GC_POP(); return ii; } + jl_varbinding_t *xb = NULL, *yb = NULL; if (xp2 && jl_is_typevar(xp2)) { - jl_varbinding_t *xb = lookup(e, (jl_tvar_t*)xp2); - if (xb) xb->intvalued = 1; - if (!yp2) { - i2 = bound_var_below((jl_tvar_t*)xp2, xb, e); + xb = lookup(e, (jl_tvar_t*)xp2); + if (xb) { + if (xb->intvalued == 0) xb->intvalued = 1; + xb->offset = offset; } + if (!yp2) + i2 = bound_var_below((jl_tvar_t*)xp2, xb, e); } if (yp2 && jl_is_typevar(yp2)) { - jl_varbinding_t *yb = lookup(e, (jl_tvar_t*)yp2); - if (yb) yb->intvalued = 1; - if (!xp2) { - i2 = bound_var_below((jl_tvar_t*)yp2, yb, e); + yb = lookup(e, (jl_tvar_t*)yp2); + if (yb) { + if (yb->intvalued == 0) yb->intvalued = 1; + yb->offset = -offset; } + if (!xp2) + i2 = bound_var_below((jl_tvar_t*)yp2, yb, e); } if (xp2 && yp2) { // Vararg{T,N} <: Vararg{T2,N2}; equate N and N2 @@ -2711,6 +2773,8 @@ static jl_value_t *intersect_varargs(jl_vararg_t *vmx, jl_vararg_t *vmy, jl_sten i2 = jl_bottom_type; } } + if (xb) xb->offset = 0; + if (yb) yb->offset = 0; ii = i2 == jl_bottom_type ? (jl_value_t*)jl_bottom_type : (jl_value_t*)jl_wrap_vararg(ii, i2); JL_GC_POP(); return ii; @@ -2749,28 +2813,14 @@ static jl_value_t *intersect_tuple(jl_datatype_t *xd, jl_datatype_t *yd, jl_sten res = (jl_value_t*)jl_apply_tuple_type_v(jl_svec_data(params), i); break; } - jl_varbinding_t *xb=NULL, *yb=NULL; jl_value_t *ii = NULL; - if (vx && vy) { - // {A^n...,Vararg{T,N}} ∩ {Vararg{S,M}} = {(A∩S)^n...,Vararg{T∩S,N}} plus N = M-n - jl_value_t *xlen = jl_unwrap_vararg_num(xi); - if (xlen && jl_is_typevar(xlen)) { - xb = lookup(e, (jl_tvar_t*)xlen); - if (xb) - xb->offset = ly-lx; - } - jl_value_t *ylen = jl_unwrap_vararg_num(yi); - if (ylen && jl_is_typevar(ylen)) { - yb = lookup(e, (jl_tvar_t*)ylen); - if (yb) - yb->offset = lx-ly; - } + if (vx && vy) ii = intersect_varargs((jl_vararg_t*)xi, (jl_vararg_t*)yi, + ly - lx, // xi's offset: {A^n...,Vararg{T,N}} ∩ {Vararg{S,M}} + // {(A∩S)^n...,Vararg{T∩S,N}} plus N = M-n e, param); - if (xb) xb->offset = 0; - if (yb) yb->offset = 0; - } else { + else { if (vx) xi = jl_unwrap_vararg(xi); if (vy) @@ -2779,6 +2829,13 @@ static jl_value_t *intersect_tuple(jl_datatype_t *xd, jl_datatype_t *yd, jl_sten } if (ii == jl_bottom_type) { if (vx && vy) { + jl_varbinding_t *xb=NULL, *yb=NULL; + jl_value_t *xlen = jl_unwrap_vararg_num(xi); + if (xlen && jl_is_typevar(xlen)) + xb = lookup(e, (jl_tvar_t*)xlen); + jl_value_t *ylen = jl_unwrap_vararg_num(yi); + if (ylen && jl_is_typevar(ylen)) + yb = lookup(e, (jl_tvar_t*)ylen); int len = i > j ? i : j; if ((xb && jl_is_long(xb->lb) && lx-1+jl_unbox_long(xb->lb) != len) || (yb && jl_is_long(yb->lb) && ly-1+jl_unbox_long(yb->lb) != len)) { @@ -2877,6 +2934,11 @@ static jl_value_t *intersect_invariant(jl_value_t *x, jl_value_t *y, jl_stenv_t jl_value_t *ii = intersect(x, y, e, 2); e->invdepth--; e->Rinvdepth--; + // Skip the following subtype check if `ii` was returned from `set_vat_to_const`. + // As `var_gt`/`var_lt` might not handle `Vararg` length offset correctly. + // TODO: fix this on subtype side and remove this branch. + if (jl_is_long(ii) && ((jl_is_typevar(x) && jl_is_long(y)) || (jl_is_typevar(y) && jl_is_long(x)))) + return ii; if (jl_is_typevar(x) && jl_is_typevar(y) && (jl_is_typevar(ii) || !jl_is_type(ii))) return ii; if (ii == jl_bottom_type) { @@ -2894,13 +2956,10 @@ static jl_value_t *intersect_invariant(jl_value_t *x, jl_value_t *y, jl_stenv_t jl_savedenv_t se; JL_GC_PUSH2(&ii, &root); save_env(e, &root, &se); - if (!subtype_in_env_existential(x, y, e, 0, e->invdepth)) { + if (!subtype_in_env_existential(x, y, e, 0, e->invdepth)) + ii = NULL; + else if (!subtype_in_env_existential(y, x, e, 0, e->invdepth)) ii = NULL; - } - else { - if (!subtype_in_env_existential(y, x, e, 0, e->invdepth)) - ii = NULL; - } restore_env(e, root, &se); free_env(&se); JL_GC_POP(); @@ -2994,7 +3053,15 @@ static jl_value_t *intersect(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int pa record_var_occurrence(yy, e, param); return y; } - return intersect(y, xub, e, param); + if (!xx || xx->offset == 0) + return intersect(y, xub, e, param); + // try to propagate the x's offset to xub. + jl_varbinding_t *tvb = lookup(e, (jl_tvar_t*)xub); + assert(tvb && tvb->offset == 0); + tvb->offset = xx->offset; + jl_value_t *res = intersect(y, xub, e, param); + tvb->offset = 0; + return res; } record_var_occurrence(yy, e, param); if (!jl_is_type(ylb) && !jl_is_typevar(ylb)) { @@ -3035,19 +3102,24 @@ static jl_value_t *intersect(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int pa lb = ylb; else lb = simple_join(xlb, ylb); - if (yy) { + if (yy && yy->offset == 0) { yy->lb = lb; if (!reachable_var(ub, (jl_tvar_t*)y, e)) yy->ub = ub; assert(yy->ub != y); assert(yy->lb != y); } - if (xx && !reachable_var(y, (jl_tvar_t*)x, e)) { + if (xx && xx->offset == 0 && !reachable_var(y, (jl_tvar_t*)x, e)) { xx->lb = y; xx->ub = y; assert(xx->ub != x); } JL_GC_POP(); + // Here we always return the shorter `Vararg`'s length. + if ((xx && xx->offset < 0) || (yy && yy->offset > 0)) { + if (yy) yy->intvalued = 2; + return x; + } return y; } record_var_occurrence(xx, e, param); @@ -3176,18 +3248,15 @@ static int merge_env(jl_stenv_t *e, jl_value_t **root, jl_savedenv_t *se, int co } int n = 0; jl_varbinding_t *v = e->vars; - jl_value_t *ub = NULL, *vub = NULL; - JL_GC_PUSH2(&ub, &vub); + jl_value_t *b1 = NULL, *b2 = NULL; + JL_GC_PUSH2(&b1, &b2); while (v != NULL) { - if (v->ub != v->var->ub || v->lb != v->var->lb) { - jl_value_t *lb = jl_svecref(*root, n); - if (v->lb != lb) - jl_svecset(*root, n, lb ? jl_bottom_type : v->lb); - ub = jl_svecref(*root, n+1); - vub = v->ub; - if (vub != ub) - jl_svecset(*root, n+1, ub ? simple_join(ub, vub) : vub); - } + b1 = jl_svecref(*root, n); + b2 = v->lb; + jl_svecset(*root, n, simple_meet(b1, b2)); + b1 = jl_svecref(*root, n+1); + b2 = v->ub; + jl_svecset(*root, n+1, simple_join(b1, b2)); n = n + 3; v = v->prev; } diff --git a/stdlib/Artifacts/src/Artifacts.jl b/stdlib/Artifacts/src/Artifacts.jl index b446fdb12dd68..5c02803959f05 100644 --- a/stdlib/Artifacts/src/Artifacts.jl +++ b/stdlib/Artifacts/src/Artifacts.jl @@ -88,7 +88,7 @@ function load_overrides(;force::Bool = false)::Dict{Symbol, Any} # # Overrides per UUID/bound name are intercepted upon Artifacts.toml load, and new # entries within the "hash" overrides are generated on-the-fly. Thus, all redirects - # mechanisticly happen through the "hash" overrides. + # mechanistically happen through the "hash" overrides. overrides = Dict{Symbol,Any}( # Overrides by UUID :UUID => Dict{Base.UUID,Dict{String,Union{String,SHA1}}}(), @@ -267,7 +267,7 @@ function unpack_platform(entry::Dict{String,Any}, name::String, end if !haskey(entry, "arch") - @error("Invalid artifacts file at '$(artifacts_toml)': platform-specific artifact entrty '$name' missing 'arch' key") + @error("Invalid artifacts file at '$(artifacts_toml)': platform-specific artifact entry '$name' missing 'arch' key") return nothing end @@ -325,7 +325,7 @@ function process_overrides(artifact_dict::Dict, pkg_uuid::Base.UUID) # override for this UUID, and inserting new overrides for those hashes. overrides = load_overrides() if haskey(overrides[:UUID], pkg_uuid) - pkg_overrides = overrides[:UUID][pkg_uuid] + pkg_overrides = overrides[:UUID][pkg_uuid]::Dict{String, <:Any} for name in keys(artifact_dict) # Skip names that we're not overriding @@ -570,7 +570,7 @@ end raw""" split_artifact_slash(name::String) -Splits an artifact indexing string by path deliminters, isolates the first path element, +Splits an artifact indexing string by path delimiters, isolates the first path element, returning that and the `joinpath()` of the remaining arguments. This normalizes all path separators to the native path separator for the current platform. Examples: diff --git a/stdlib/Dates/src/deprecated.jl b/stdlib/Dates/src/deprecated.jl index 3c8a58f6e75e7..b50d8501e7570 100644 --- a/stdlib/Dates/src/deprecated.jl +++ b/stdlib/Dates/src/deprecated.jl @@ -65,3 +65,6 @@ for op in (:+, :-) end end end + +@deprecate argerror(msg::String) ArgumentError(msg) false +@deprecate argerror() nothing false diff --git a/stdlib/Dates/src/io.jl b/stdlib/Dates/src/io.jl index 0443c79f16ab9..c6682a0246ce7 100644 --- a/stdlib/Dates/src/io.jl +++ b/stdlib/Dates/src/io.jl @@ -55,7 +55,7 @@ Base.show(io::IO, ::MIME"text/plain", t::Time) = print(io, t) Base.print(io::IO, t::Time) = print(io, string(t)) function Base.show(io::IO, t::Time) - if get(io, :compact, false) + if get(io, :compact, false)::Bool print(io, t) else values = [ diff --git a/stdlib/Dates/src/periods.jl b/stdlib/Dates/src/periods.jl index da877d922bf56..7eb71ff2905cf 100644 --- a/stdlib/Dates/src/periods.jl +++ b/stdlib/Dates/src/periods.jl @@ -383,68 +383,42 @@ end # hitting the deprecated construct-to-convert fallback. (::Type{T})(p::Period) where {T<:Period} = convert(T, p)::T -# FixedPeriod conversions and promotion rules -const fixedperiod_conversions = [(:Week, 7), (:Day, 24), (:Hour, 60), (:Minute, 60), (:Second, 1000), - (:Millisecond, 1000), (:Microsecond, 1000), (:Nanosecond, 1)] -for i = 1:length(fixedperiod_conversions) - T, n = fixedperiod_conversions[i] - N = Int64(1) - for j = (i - 1):-1:1 # less-precise periods - Tc, nc = fixedperiod_conversions[j] - N *= nc - vmax = typemax(Int64) ÷ N - vmin = typemin(Int64) ÷ N - @eval function Base.convert(::Type{$T}, x::$Tc) - $vmin ≤ value(x) ≤ $vmax || throw(InexactError(:convert, $T, x)) - return $T(value(x) * $N) +# Conversions and promotion rules +function define_conversions(periods) + for i = eachindex(periods) + T, n = periods[i] + N = Int64(1) + for j = (i - 1):-1:firstindex(periods) # less-precise periods + Tc, nc = periods[j] + N *= nc + vmax = typemax(Int64) ÷ N + vmin = typemin(Int64) ÷ N + @eval function Base.convert(::Type{$T}, x::$Tc) + $vmin ≤ value(x) ≤ $vmax || throw(InexactError(:convert, $T, x)) + return $T(value(x) * $N) + end + end + N = n + for j = (i + 1):lastindex(periods) # more-precise periods + Tc, nc = periods[j] + @eval Base.convert(::Type{$T}, x::$Tc) = $T(divexact(value(x), $N)) + @eval Base.promote_rule(::Type{$T}, ::Type{$Tc}) = $Tc + N *= nc end - end - N = n - for j = (i + 1):length(fixedperiod_conversions) # more-precise periods - Tc, nc = fixedperiod_conversions[j] - @eval Base.convert(::Type{$T}, x::$Tc) = $T(divexact(value(x), $N)) - @eval Base.promote_rule(::Type{$T}, ::Type{$Tc}) = $Tc - N *= nc - end -end - -# other periods with fixed conversions but which aren't fixed time periods -const OtherPeriod = Union{Month, Quarter, Year} -let vmax = typemax(Int64) ÷ 12, vmin = typemin(Int64) ÷ 12 - @eval function Base.convert(::Type{Month}, x::Year) - $vmin ≤ value(x) ≤ $vmax || throw(InexactError(:convert, Month, x)) - Month(value(x) * 12) - end -end -Base.convert(::Type{Year}, x::Month) = Year(divexact(value(x), 12)) -Base.promote_rule(::Type{Year}, ::Type{Month}) = Month - -let vmax = typemax(Int64) ÷ 4, vmin = typemin(Int64) ÷ 4 - @eval function Base.convert(::Type{Quarter}, x::Year) - $vmin ≤ value(x) ≤ $vmax || throw(InexactError(:convert, Quarter, x)) - Quarter(value(x) * 4) - end -end -Base.convert(::Type{Year}, x::Quarter) = Year(divexact(value(x), 4)) -Base.promote_rule(::Type{Year}, ::Type{Quarter}) = Quarter - -let vmax = typemax(Int64) ÷ 3, vmin = typemin(Int64) ÷ 3 - @eval function Base.convert(::Type{Month}, x::Quarter) - $vmin ≤ value(x) ≤ $vmax || throw(InexactError(:convert, Month, x)) - Month(value(x) * 3) end end -Base.convert(::Type{Quarter}, x::Month) = Quarter(divexact(value(x), 3)) -Base.promote_rule(::Type{Quarter}, ::Type{Month}) = Month - +define_conversions([(:Week, 7), (:Day, 24), (:Hour, 60), (:Minute, 60), (:Second, 1000), + (:Millisecond, 1000), (:Microsecond, 1000), (:Nanosecond, 1)]) +define_conversions([(:Year, 4), (:Quarter, 3), (:Month, 1)]) # fixed is not comparable to other periods, except when both are zero (#37459) +const OtherPeriod = Union{Month, Quarter, Year} (==)(x::FixedPeriod, y::OtherPeriod) = iszero(x) & iszero(y) (==)(x::OtherPeriod, y::FixedPeriod) = y == x const zero_or_fixedperiod_seed = UInt === UInt64 ? 0x5b7fc751bba97516 : 0xeae0fdcb const nonzero_otherperiod_seed = UInt === UInt64 ? 0xe1837356ff2d2ac9 : 0x170d1b00 -otherperiod_seed(x::OtherPeriod) = iszero(value(x)) ? zero_or_fixedperiod_seed : nonzero_otherperiod_seed +otherperiod_seed(x) = iszero(value(x)) ? zero_or_fixedperiod_seed : nonzero_otherperiod_seed # tons() will overflow for periods longer than ~300,000 years, implying a hash collision # which is relatively harmless given how infrequently such periods should appear Base.hash(x::FixedPeriod, h::UInt) = hash(tons(x), h + zero_or_fixedperiod_seed) diff --git a/stdlib/Dates/src/types.jl b/stdlib/Dates/src/types.jl index 0cdac884fb7fe..1d9769a05bd3d 100644 --- a/stdlib/Dates/src/types.jl +++ b/stdlib/Dates/src/types.jl @@ -103,7 +103,7 @@ end UTM(x) = UTInstant(Millisecond(x)) UTD(x) = UTInstant(Day(x)) -# Calendar types provide rules for interpretating instant +# Calendar types provide rules for interpreting instant # timelines in human-readable form. abstract type Calendar <: AbstractTime end @@ -199,20 +199,11 @@ daysinmonth(y,m) = DAYSINMONTH[m] + (m == 2 && isleapyear(y)) """ validargs(::Type{<:TimeType}, args...) -> Union{ArgumentError, Nothing} -Determine whether the given arguments consitute valid inputs for the given type. +Determine whether the given arguments constitute valid inputs for the given type. Returns either an `ArgumentError`, or [`nothing`](@ref) in case of success. """ function validargs end -""" - argerror([msg]) -> Union{ArgumentError, Nothing} - -Return an `ArgumentError` object with the given message, -or [`nothing`](@ref) if no message is provided. For use by `validargs`. -""" -argerror(msg::String) = ArgumentError(msg) -argerror() = nothing - # Julia uses 24-hour clocks internally, but user input can be AM/PM with 12pm == noon and 12am == midnight. @enum AMPM AM PM TWENTYFOURHOUR function adjusthour(h::Int64, ampm::AMPM) @@ -240,18 +231,18 @@ end function validargs(::Type{DateTime}, y::Int64, m::Int64, d::Int64, h::Int64, mi::Int64, s::Int64, ms::Int64, ampm::AMPM=TWENTYFOURHOUR) - 0 < m < 13 || return argerror("Month: $m out of range (1:12)") - 0 < d < daysinmonth(y, m) + 1 || return argerror("Day: $d out of range (1:$(daysinmonth(y, m)))") + 0 < m < 13 || return ArgumentError("Month: $m out of range (1:12)") + 0 < d < daysinmonth(y, m) + 1 || return ArgumentError("Day: $d out of range (1:$(daysinmonth(y, m)))") if ampm == TWENTYFOURHOUR # 24-hour clock -1 < h < 24 || (h == 24 && mi==s==ms==0) || - return argerror("Hour: $h out of range (0:23)") + return ArgumentError("Hour: $h out of range (0:23)") else - 0 < h < 13 || return argerror("Hour: $h out of range (1:12)") + 0 < h < 13 || return ArgumentError("Hour: $h out of range (1:12)") end - -1 < mi < 60 || return argerror("Minute: $mi out of range (0:59)") - -1 < s < 60 || return argerror("Second: $s out of range (0:59)") - -1 < ms < 1000 || return argerror("Millisecond: $ms out of range (0:999)") - return argerror() + -1 < mi < 60 || return ArgumentError("Minute: $mi out of range (0:59)") + -1 < s < 60 || return ArgumentError("Second: $s out of range (0:59)") + -1 < ms < 1000 || return ArgumentError("Millisecond: $ms out of range (0:999)") + return nothing end DateTime(dt::Base.Libc.TmStruct) = DateTime(1900 + dt.year, 1 + dt.month, dt.mday, dt.hour, dt.min, dt.sec) @@ -268,9 +259,9 @@ function Date(y::Int64, m::Int64=1, d::Int64=1) end function validargs(::Type{Date}, y::Int64, m::Int64, d::Int64) - 0 < m < 13 || return argerror("Month: $m out of range (1:12)") - 0 < d < daysinmonth(y, m) + 1 || return argerror("Day: $d out of range (1:$(daysinmonth(y, m)))") - return argerror() + 0 < m < 13 || return ArgumentError("Month: $m out of range (1:12)") + 0 < d < daysinmonth(y, m) + 1 || return ArgumentError("Day: $d out of range (1:$(daysinmonth(y, m)))") + return nothing end Date(dt::Base.Libc.TmStruct) = Date(1900 + dt.year, 1 + dt.month, dt.mday) @@ -289,16 +280,16 @@ end function validargs(::Type{Time}, h::Int64, mi::Int64, s::Int64, ms::Int64, us::Int64, ns::Int64, ampm::AMPM=TWENTYFOURHOUR) if ampm == TWENTYFOURHOUR # 24-hour clock - -1 < h < 24 || return argerror("Hour: $h out of range (0:23)") + -1 < h < 24 || return ArgumentError("Hour: $h out of range (0:23)") else - 0 < h < 13 || return argerror("Hour: $h out of range (1:12)") + 0 < h < 13 || return ArgumentError("Hour: $h out of range (1:12)") end - -1 < mi < 60 || return argerror("Minute: $mi out of range (0:59)") - -1 < s < 60 || return argerror("Second: $s out of range (0:59)") - -1 < ms < 1000 || return argerror("Millisecond: $ms out of range (0:999)") - -1 < us < 1000 || return argerror("Microsecond: $us out of range (0:999)") - -1 < ns < 1000 || return argerror("Nanosecond: $ns out of range (0:999)") - return argerror() + -1 < mi < 60 || return ArgumentError("Minute: $mi out of range (0:59)") + -1 < s < 60 || return ArgumentError("Second: $s out of range (0:59)") + -1 < ms < 1000 || return ArgumentError("Millisecond: $ms out of range (0:999)") + -1 < us < 1000 || return ArgumentError("Microsecond: $us out of range (0:999)") + -1 < ns < 1000 || return ArgumentError("Nanosecond: $ns out of range (0:999)") + return nothing end Time(dt::Base.Libc.TmStruct) = Time(dt.hour, dt.min, dt.sec) diff --git a/stdlib/Dates/test/accessors.jl b/stdlib/Dates/test/accessors.jl index 819fa8c40ddbc..b690a81d70e49 100644 --- a/stdlib/Dates/test/accessors.jl +++ b/stdlib/Dates/test/accessors.jl @@ -29,7 +29,7 @@ using Test @test Dates.yearmonthday(730120) == (2000, 1, 1) end @testset "year/month/day" begin - # year, month, and day return the indivial components + # year, month, and day return the individual components # of yearmonthday, avoiding additional calculations when possible @test Dates.year(-1) == 0 @test Dates.month(-1) == 12 diff --git a/stdlib/Dates/test/periods.jl b/stdlib/Dates/test/periods.jl index c37a1666375a9..7b23ffcb5d4e1 100644 --- a/stdlib/Dates/test/periods.jl +++ b/stdlib/Dates/test/periods.jl @@ -283,7 +283,7 @@ Beat(p::Period) = Beat(Dates.toms(p) ÷ 86400) Dates.toms(b::Beat) = Dates.value(b) * 86400 Dates._units(b::Beat) = " beat" * (abs(Dates.value(b)) == 1 ? "" : "s") Base.promote_rule(::Type{Dates.Day}, ::Type{Beat}) = Dates.Millisecond - Base.convert(::Type{T}, b::Beat) where {T<:Dates.Millisecond} = T(Dates.toms(b)) + Base.convert(::Type{T}, b::Beat) where {T<:Dates.Millisecond} = T(Dates.toms(b))::T @test Beat(1000) == Dates.Day(1) @test Beat(1) < Dates.Day(1) diff --git a/stdlib/Distributed/src/cluster.jl b/stdlib/Distributed/src/cluster.jl index 37f1660e19478..4845640a1a913 100644 --- a/stdlib/Distributed/src/cluster.jl +++ b/stdlib/Distributed/src/cluster.jl @@ -22,7 +22,7 @@ Some are used by the cluster manager to add workers to an already-initialized ho * `count` -- the number of workers to be launched on the host * `exename` -- the path to the Julia executable on the host, defaults to `"\$(Sys.BINDIR)/julia"` or `"\$(Sys.BINDIR)/julia-debug"` - * `exeflags` -- flags to use when lauching Julia remotely + * `exeflags` -- flags to use when launching Julia remotely The `userdata` field is used to store information for each worker by external managers. diff --git a/stdlib/Distributed/src/remotecall.jl b/stdlib/Distributed/src/remotecall.jl index d4bf767537c1d..0554f47670eb3 100644 --- a/stdlib/Distributed/src/remotecall.jl +++ b/stdlib/Distributed/src/remotecall.jl @@ -321,7 +321,7 @@ function process_worker(rr) w = worker_from_id(rr.where)::Worker msg = (remoteref_id(rr), myid()) - # Needs to aquire a lock on the del_msg queue + # Needs to acquire a lock on the del_msg queue T = Threads.@spawn begin publish_del_msg!($w, $msg) end diff --git a/stdlib/Distributed/src/workerpool.jl b/stdlib/Distributed/src/workerpool.jl index 0cada2db103de..89e52667c82c9 100644 --- a/stdlib/Distributed/src/workerpool.jl +++ b/stdlib/Distributed/src/workerpool.jl @@ -73,7 +73,7 @@ wp_local_length(pool::AbstractWorkerPool) = length(pool.workers) wp_local_isready(pool::AbstractWorkerPool) = isready(pool.channel) function wp_local_put!(pool::AbstractWorkerPool, w::Int) - # In case of default_worker_pool, the master is implictly considered a worker, i.e., + # In case of default_worker_pool, the master is implicitly considered a worker, i.e., # it is not present in pool.workers. # Confirm the that the worker is part of a pool before making it available. w in pool.workers && put!(pool.channel, w) diff --git a/stdlib/Distributed/test/distributed_exec.jl b/stdlib/Distributed/test/distributed_exec.jl index 8ed55550e61b9..9dffbe0e41994 100644 --- a/stdlib/Distributed/test/distributed_exec.jl +++ b/stdlib/Distributed/test/distributed_exec.jl @@ -993,7 +993,7 @@ end let @test_throws RemoteException remotecall_fetch(()->LocalFoo.foo, 2) - bad_thunk = ()->NonexistantModule.f() + bad_thunk = ()->NonexistentModule.f() @test_throws RemoteException remotecall_fetch(bad_thunk, 2) # Test that the stream is still usable diff --git a/stdlib/FileWatching/src/FileWatching.jl b/stdlib/FileWatching/src/FileWatching.jl index e266bff7ec7d1..cfb7ede3b09ee 100644 --- a/stdlib/FileWatching/src/FileWatching.jl +++ b/stdlib/FileWatching/src/FileWatching.jl @@ -744,7 +744,9 @@ end watch_file(path::AbstractString, timeout_s::Real=-1) Watch file or directory `path` for changes until a change occurs or `timeout_s` seconds have -elapsed. +elapsed. This function does not poll the file system and instead uses platform-specific +functionality to receive notifications from the operating system (e.g. via inotify on Linux). +See the NodeJS documentation linked below for details. The returned value is an object with boolean fields `changed`, `renamed`, and `timedout`, giving the result of watching the file. @@ -773,7 +775,9 @@ watch_file(s::AbstractString, timeout_s::Real=-1) = watch_file(String(s), Float6 watch_folder(path::AbstractString, timeout_s::Real=-1) Watches a file or directory `path` for changes until a change has occurred or `timeout_s` -seconds have elapsed. +seconds have elapsed. This function does not poll the file system and instead uses platform-specific +functionality to receive notifications from the operating system (e.g. via inotify on Linux). +See the NodeJS documentation linked below for details. This will continuing tracking changes for `path` in the background until `unwatch_folder` is called on the same `path`. diff --git a/stdlib/FileWatching/test/pidfile.jl b/stdlib/FileWatching/test/pidfile.jl index fae745131bca3..77cf10470eb06 100644 --- a/stdlib/FileWatching/test/pidfile.jl +++ b/stdlib/FileWatching/test/pidfile.jl @@ -273,11 +273,17 @@ end # Just for coverage's sake, run a test with do-block syntax lock_times = Float64[] synchronizer = Base.Event() + synchronizer2 = Base.Event() t_loop = @async begin - wait(synchronizer) for idx in 1:100 - t = @elapsed mkpidlock("do_block_pidfile") do - # nothing + t = @elapsed begin + if idx == 1 + wait(synchronizer) + notify(synchronizer2) + end + mkpidlock("do_block_pidfile") do + # nothing + end end sleep(0.01) push!(lock_times, t) @@ -286,6 +292,7 @@ end isdefined(Base, :errormonitor) && Base.errormonitor(t_loop) mkpidlock("do_block_pidfile") do notify(synchronizer) + wait(synchronizer2) sleep(3) end wait(t_loop) diff --git a/stdlib/FileWatching/test/runtests.jl b/stdlib/FileWatching/test/runtests.jl index 68ef79e9cc4f4..65e0433d559b0 100644 --- a/stdlib/FileWatching/test/runtests.jl +++ b/stdlib/FileWatching/test/runtests.jl @@ -12,11 +12,13 @@ using Base: uv_error, Experimental # Odd numbered pipes are tested for reads # Even numbered pipes are tested for timeouts # Writable ends are always tested for write-ability before a write +ismacos_arm = ((Sys.ARCH == :aarch64) && (Sys.isapple())) #https://github.com/JuliaLang/julia/issues/46185 +ismacos_x86 = ((Sys.ARCH == :x86_64) && (Sys.isapple())) #Used to disable the unreliable macos tests n = 20 intvls = [2, .2, .1, .005, .00001] - pipe_fds = fill((Base.INVALID_OS_HANDLE, Base.INVALID_OS_HANDLE), n) + for i in 1:n if Sys.iswindows() || i > n ÷ 2 uv_error("socketpair", ccall(:uv_socketpair, Cint, (Cint, Cint, Ptr{NTuple{2, Base.OS_HANDLE}}, Cint, Cint), 1, (Sys.iswindows() ? 6 : 0), Ref(pipe_fds, i), 0, 0)) @@ -32,7 +34,9 @@ for i in 1:n if !fd_in_limits && Sys.islinux() run(`ls -la /proc/$(getpid())/fd`) end - @test fd_in_limits + if !ismacos_arm + @test fd_in_limits + end end function pfd_tst_reads(idx, intvl) @@ -183,16 +187,19 @@ function test_init_afile() @test(watch_folder(dir) == (F_PATH => FileWatching.FileEvent(FileWatching.UV_RENAME))) @test close(open(file, "w")) === nothing sleep(3) - let c - c = watch_folder(dir, 0) - if F_GETPATH - @test c.first == F_PATH - @test c.second.changed ⊻ c.second.renamed - @test !c.second.timedout - else # we don't expect to be able to detect file changes in this case - @test c.first == "" - @test !c.second.changed && !c.second.renamed - @test c.second.timedout + if !ismacos_x86 + let c + c = watch_folder(dir, 0) + + if F_GETPATH + @test c.first == F_PATH + @test c.second.changed ⊻ c.second.renamed + @test !c.second.timedout + else # we don't expect to be able to detect file changes in this case + @test c.first == "" + @test !c.second.changed && !c.second.renamed + @test c.second.timedout + end end end @test unwatch_folder(dir) === nothing @@ -370,9 +377,9 @@ test_monitor_wait_poll() test_watch_file_timeout(0.2) test_watch_file_change(6) -if !((Sys.ARCH == :x86_64) && (Sys.isapple())) #These tests tend to fail a lot on x86-apple - test_dirmonitor_wait2(0.2) #because the os can reorder the events - test_dirmonitor_wait2(0.2) #see https://github.com/dotnet/runtime/issues/30415 +if !ismacos_x86 + test_dirmonitor_wait2(0.2) + test_dirmonitor_wait2(0.2) mv(file, file * "~") mv(file * "~", file) diff --git a/stdlib/InteractiveUtils/src/codeview.jl b/stdlib/InteractiveUtils/src/codeview.jl index 3937eeb4ba2e8..ce7e76ae4cfd7 100644 --- a/stdlib/InteractiveUtils/src/codeview.jl +++ b/stdlib/InteractiveUtils/src/codeview.jl @@ -27,19 +27,19 @@ end # displaying type warnings -function warntype_type_printer(io::IO, @nospecialize(ty), used::Bool) - used || return - str = "::$ty" +function warntype_type_printer(io::IO; @nospecialize(type), used::Bool, show_type::Bool=true, _...) + (show_type && used) || return nothing + str = "::$type" if !highlighting[:warntype] print(io, str) - elseif ty isa Union && is_expected_union(ty) + elseif type isa Union && is_expected_union(type) Base.emphasize(io, str, Base.warn_color()) # more mild user notification - elseif ty isa Type && (!Base.isdispatchelem(ty) || ty == Core.Box) + elseif type isa Type && (!Base.isdispatchelem(type) || type == Core.Box) Base.emphasize(io, str) else Base.printstyled(io, str, color=:cyan) # show the "good" type end - nothing + return nothing end # True if one can be pretty certain that the compiler handles this union well, @@ -66,7 +66,7 @@ Not all non-leaf types are particularly problematic for performance, and the per characteristics of a particular type is an implementation detail of the compiler. `code_warntype` will err on the side of coloring types red if they might be a performance concern, so some types may be colored red even if they do not impact performance. -Small unions of concrete types are usually not a concern, so these are highlighed in yellow. +Small unions of concrete types are usually not a concern, so these are highlighted in yellow. Keyword argument `debuginfo` may be one of `:source` or `:none` (default), to specify the verbosity of code comments. @@ -140,13 +140,13 @@ function code_warntype(io::IO, @nospecialize(f), @nospecialize(t=Base.default_tt end print(io, " ", slotnames[i]) if isa(slottypes, Vector{Any}) - warntype_type_printer(io, slottypes[i], true) + warntype_type_printer(io; type=slottypes[i], used=true) end println(io) end end print(io, "Body") - warntype_type_printer(io, rettype, true) + warntype_type_printer(io; type=rettype, used=true) println(io) irshow_config = Base.IRShow.IRShowConfig(lineprinter(src), warntype_type_printer) Base.IRShow.show_ir(lambda_io, src, irshow_config) @@ -269,7 +269,7 @@ Keyword argument `debuginfo` may be one of source (default) or none, to specify function code_llvm(io::IO, @nospecialize(f), @nospecialize(types), raw::Bool, dump_module::Bool=false, optimize::Bool=true, debuginfo::Symbol=:default) d = _dump_function(f, types, false, false, !raw, dump_module, :att, optimize, debuginfo, false) - if highlighting[:llvm] && get(io, :color, false) + if highlighting[:llvm] && get(io, :color, false)::Bool print_llvm(io, d) else print(io, d) @@ -296,7 +296,7 @@ See also: [`@code_native`](@ref), [`code_llvm`](@ref), [`code_typed`](@ref) and function code_native(io::IO, @nospecialize(f), @nospecialize(types=Base.default_tt(f)); dump_module::Bool=true, syntax::Symbol=:att, debuginfo::Symbol=:default, binary::Bool=false) d = _dump_function(f, types, true, false, false, dump_module, syntax, true, debuginfo, binary) - if highlighting[:native] && get(io, :color, false) + if highlighting[:native] && get(io, :color, false)::Bool print_native(io, d) else print(io, d) diff --git a/stdlib/InteractiveUtils/src/macros.jl b/stdlib/InteractiveUtils/src/macros.jl index 816438af86684..98189f62edf6f 100644 --- a/stdlib/InteractiveUtils/src/macros.jl +++ b/stdlib/InteractiveUtils/src/macros.jl @@ -24,7 +24,8 @@ function recursive_dotcalls!(ex, args, i=1) end end (start, branches) = ex.head === :. ? (1, ex.args[2].args) : (2, ex.args) - for j in start:length(branches) + length_branches = length(branches)::Integer + for j in start:length_branches branch, i = recursive_dotcalls!(branches[j], args, i) branches[j] = branch end diff --git a/stdlib/LibGit2/src/LibGit2.jl b/stdlib/LibGit2/src/LibGit2.jl index c699e120584ae..cd7dd01615648 100644 --- a/stdlib/LibGit2/src/LibGit2.jl +++ b/stdlib/LibGit2/src/LibGit2.jl @@ -477,7 +477,7 @@ current changes. Note that this detaches the current HEAD. # Examples ```julia -repo = LibGit2.init(repo_path) +repo = LibGit2.GitRepo(repo_path) open(joinpath(LibGit2.path(repo), "file1"), "w") do f write(f, "111\n") end diff --git a/stdlib/LibGit2/src/gitcredential.jl b/stdlib/LibGit2/src/gitcredential.jl index 1b97c29cd933e..acfde02578523 100644 --- a/stdlib/LibGit2/src/gitcredential.jl +++ b/stdlib/LibGit2/src/gitcredential.jl @@ -219,7 +219,7 @@ function credential_helpers(cfg::GitConfig, cred::GitCredential) helpers = GitCredentialHelper[] # https://git-scm.com/docs/gitcredentials#gitcredentials-helper - for entry in GitConfigIter(cfg, r"credential.*\.helper") + for entry in GitConfigIter(cfg, r"credential.*\.helper$") section, url, name, value = split_cfg_entry(entry) @assert name == "helper" diff --git a/stdlib/LibGit2/src/oid.jl b/stdlib/LibGit2/src/oid.jl index 1074f003ebd2f..937684439419f 100644 --- a/stdlib/LibGit2/src/oid.jl +++ b/stdlib/LibGit2/src/oid.jl @@ -154,7 +154,7 @@ end Get a shortened identifier (`GitShortHash`) of `obj`. The minimum length (in characters) is determined by the `core.abbrev` config option, and will be of sufficient length to -unambiuously identify the object in the repository. +unambiguously identify the object in the repository. """ function GitShortHash(obj::GitObject) ensure_initialized() diff --git a/stdlib/LibGit2/test/libgit2-tests.jl b/stdlib/LibGit2/test/libgit2-tests.jl index 4dbd1837045e9..4ace98a0b1ac8 100644 --- a/stdlib/LibGit2/test/libgit2-tests.jl +++ b/stdlib/LibGit2/test/libgit2-tests.jl @@ -1011,7 +1011,7 @@ mktempdir() do dir LibGit2.Signature(repo) catch ex # these test configure repo with new signature - # in case when global one does not exsist + # in case when global one does not exist @test isa(ex, LibGit2.Error.GitError) == true cfg = LibGit2.GitConfig(repo) @@ -1994,7 +1994,7 @@ mktempdir() do dir @test parse(GitCredentialHelper, "store") == GitCredentialHelper(`git credential-store`) end - @testset "empty helper" begin + @testset "credential_helpers" begin config_path = joinpath(dir, config_file) # Note: LibGit2.set! doesn't allow us to set duplicates or ordering @@ -2007,16 +2007,14 @@ mktempdir() do dir [credential] helper = !echo second """) + # Git for Windows uses this config (see issue #45693) + write(fp,""" + [credential "helperselector"] + selected = manager-core + """) end LibGit2.with(LibGit2.GitConfig(config_path, LibGit2.Consts.CONFIG_LEVEL_APP)) do cfg - iter = LibGit2.GitConfigIter(cfg, r"credential.*\.helper") - @test LibGit2.split_cfg_entry.(iter) == [ - ("credential", "", "helper", "!echo first"), - ("credential", "https://mygithost", "helper", ""), - ("credential", "", "helper", "!echo second"), - ] - expected = [ GitCredentialHelper(`echo first`), GitCredentialHelper(`echo second`), diff --git a/stdlib/LibUV_jll/Project.toml b/stdlib/LibUV_jll/Project.toml index 9a46adb07cc95..6f68176fc97e7 100644 --- a/stdlib/LibUV_jll/Project.toml +++ b/stdlib/LibUV_jll/Project.toml @@ -1,6 +1,6 @@ name = "LibUV_jll" uuid = "183b4373-6708-53ba-ad28-60e28bb38547" -version = "2.0.1+8" +version = "2.0.1+11" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" diff --git a/stdlib/LinearAlgebra/docs/src/index.md b/stdlib/LinearAlgebra/docs/src/index.md index 9e6d05aedcdd9..3c0004757788b 100644 --- a/stdlib/LinearAlgebra/docs/src/index.md +++ b/stdlib/LinearAlgebra/docs/src/index.md @@ -324,6 +324,8 @@ LinearAlgebra.dot(::Any, ::Any, ::Any) LinearAlgebra.cross LinearAlgebra.axpy! LinearAlgebra.axpby! +LinearAlgebra.rotate! +LinearAlgebra.reflect! LinearAlgebra.factorize LinearAlgebra.Diagonal LinearAlgebra.Bidiagonal diff --git a/stdlib/LinearAlgebra/src/LinearAlgebra.jl b/stdlib/LinearAlgebra/src/LinearAlgebra.jl index 79c55979ef8e0..b107777e7ae85 100644 --- a/stdlib/LinearAlgebra/src/LinearAlgebra.jl +++ b/stdlib/LinearAlgebra/src/LinearAlgebra.jl @@ -20,6 +20,7 @@ using Base: IndexLinear, promote_eltype, promote_op, promote_typeof, @propagate_inbounds, reduce, typed_hvcat, typed_vcat, require_one_based_indexing, Splat using Base.Broadcast: Broadcasted, broadcasted +using Base.PermutedDimsArrays: CommutativeOps using OpenBLAS_jll using libblastrampoline_jll import Libdl @@ -104,6 +105,7 @@ export istril, istriu, kron, + kron!, ldiv!, ldlt!, ldlt, @@ -459,15 +461,23 @@ _cut_B(x::AbstractVector, r::UnitRange) = length(x) > length(r) ? x[r] : x _cut_B(X::AbstractMatrix, r::UnitRange) = size(X, 1) > length(r) ? X[r,:] : X # SymTridiagonal ev can be the same length as dv, but the last element is -# ignored. However, some methods can fail if they read the entired ev +# ignored. However, some methods can fail if they read the entire ev # rather than just the meaningful elements. This is a helper function # for getting only the meaningful elements of ev. See #41089 -_evview(S::SymTridiagonal) = @view S.ev[begin:length(S.dv) - 1] +_evview(S::SymTridiagonal) = @view S.ev[begin:begin + length(S.dv) - 2] ## append right hand side with zeros if necessary _zeros(::Type{T}, b::AbstractVector, n::Integer) where {T} = zeros(T, max(length(b), n)) _zeros(::Type{T}, B::AbstractMatrix, n::Integer) where {T} = zeros(T, max(size(B, 1), n), size(B, 2)) +# convert to Vector, if necessary +_makevector(x::Vector) = x +_makevector(x::AbstractVector) = Vector(x) + +# append a zero element / drop the last element +_pushzero(A) = (B = similar(A, length(A)+1); @inbounds B[begin:end-1] .= A; @inbounds B[end] = zero(eltype(B)); B) +_droplast!(A) = deleteat!(A, lastindex(A)) + # General fallback definition for handling under- and overdetermined system as well as square problems # While this definition is pretty general, it does e.g. promote to common element type of lhs and rhs # which is required by LAPACK but not SuiteSpase which allows real-complex solves in some cases. Hence, diff --git a/stdlib/LinearAlgebra/src/adjtrans.jl b/stdlib/LinearAlgebra/src/adjtrans.jl index cd0e433bf4fb2..1a67b7f69e24a 100644 --- a/stdlib/LinearAlgebra/src/adjtrans.jl +++ b/stdlib/LinearAlgebra/src/adjtrans.jl @@ -308,8 +308,8 @@ IndexStyle(::Type{<:AdjOrTransAbsMat}) = IndexCartesian() @propagate_inbounds getindex(v::AdjOrTransAbsVec, ::Colon, ::Colon) = wrapperop(v)(v.parent[:]) # conversion of underlying storage -convert(::Type{Adjoint{T,S}}, A::Adjoint) where {T,S} = Adjoint{T,S}(convert(S, A.parent)) -convert(::Type{Transpose{T,S}}, A::Transpose) where {T,S} = Transpose{T,S}(convert(S, A.parent)) +convert(::Type{Adjoint{T,S}}, A::Adjoint) where {T,S} = Adjoint{T,S}(convert(S, A.parent))::Adjoint{T,S} +convert(::Type{Transpose{T,S}}, A::Transpose) where {T,S} = Transpose{T,S}(convert(S, A.parent))::Transpose{T,S} # Strides and pointer for transposed strided arrays — but only if the elements are actually stored in memory Base.strides(A::Adjoint{<:Real, <:AbstractVector}) = (stride(A.parent, 2), stride(A.parent, 1)) @@ -378,22 +378,36 @@ Broadcast.broadcast_preserving_zero_d(f, tvs::Union{Number,TransposeAbsVec}...) ### reductions -# faster to sum the Array than to work through the wrapper -Base._mapreduce_dim(f, op, init::Base._InitialValue, A::Transpose, dims::Colon) = - transpose(Base._mapreduce_dim(_sandwich(transpose, f), _sandwich(transpose, op), init, parent(A), dims)) -Base._mapreduce_dim(f, op, init::Base._InitialValue, A::Adjoint, dims::Colon) = - adjoint(Base._mapreduce_dim(_sandwich(adjoint, f), _sandwich(adjoint, op), init, parent(A), dims)) +# faster to sum the Array than to work through the wrapper (but only in commutative reduction ops as in Base/permuteddimsarray.jl) +Base._mapreduce_dim(f, op::CommutativeOps, init::Base._InitialValue, A::Transpose, dims::Colon) = + Base._mapreduce_dim(f∘transpose, op, init, parent(A), dims) +Base._mapreduce_dim(f, op::CommutativeOps, init::Base._InitialValue, A::Adjoint, dims::Colon) = + Base._mapreduce_dim(f∘adjoint, op, init, parent(A), dims) +# in prod, use fast path only in the commutative case to avoid surprises +Base._mapreduce_dim(f::typeof(identity), op::Union{typeof(*),typeof(Base.mul_prod)}, init::Base._InitialValue, A::Transpose{<:Union{Real,Complex}}, dims::Colon) = + Base._mapreduce_dim(f∘transpose, op, init, parent(A), dims) +Base._mapreduce_dim(f::typeof(identity), op::Union{typeof(*),typeof(Base.mul_prod)}, init::Base._InitialValue, A::Adjoint{<:Union{Real,Complex}}, dims::Colon) = + Base._mapreduce_dim(f∘adjoint, op, init, parent(A), dims) +# count allows for optimization only if the parent array has Bool eltype +Base._count(::typeof(identity), A::Transpose{Bool}, ::Colon, init) = Base._count(identity, parent(A), :, init) +Base._count(::typeof(identity), A::Adjoint{Bool}, ::Colon, init) = Base._count(identity, parent(A), :, init) +Base._any(f, A::Transpose, ::Colon) = Base._any(f∘transpose, parent(A), :) +Base._any(f, A::Adjoint, ::Colon) = Base._any(f∘adjoint, parent(A), :) +Base._all(f, A::Transpose, ::Colon) = Base._all(f∘transpose, parent(A), :) +Base._all(f, A::Adjoint, ::Colon) = Base._all(f∘adjoint, parent(A), :) # sum(A'; dims) -Base.mapreducedim!(f, op, B::AbstractArray, A::TransposeAbsMat) = - transpose(Base.mapreducedim!(_sandwich(transpose, f), _sandwich(transpose, op), transpose(B), parent(A))) -Base.mapreducedim!(f, op, B::AbstractArray, A::AdjointAbsMat) = - adjoint(Base.mapreducedim!(_sandwich(adjoint, f), _sandwich(adjoint, op), adjoint(B), parent(A))) - -_sandwich(adj::Function, fun) = (xs...,) -> adj(fun(map(adj, xs)...)) -for fun in [:identity, :add_sum, :mul_prod] #, :max, :min] - @eval _sandwich(::Function, ::typeof(Base.$fun)) = Base.$fun -end - +Base.mapreducedim!(f, op::CommutativeOps, B::AbstractArray, A::TransposeAbsMat) = + (Base.mapreducedim!(f∘transpose, op, switch_dim12(B), parent(A)); B) +Base.mapreducedim!(f, op::CommutativeOps, B::AbstractArray, A::AdjointAbsMat) = + (Base.mapreducedim!(f∘adjoint, op, switch_dim12(B), parent(A)); B) +Base.mapreducedim!(f::typeof(identity), op::Union{typeof(*),typeof(Base.mul_prod)}, B::AbstractArray, A::TransposeAbsMat{<:Union{Real,Complex}}) = + (Base.mapreducedim!(f∘transpose, op, switch_dim12(B), parent(A)); B) +Base.mapreducedim!(f::typeof(identity), op::Union{typeof(*),typeof(Base.mul_prod)}, B::AbstractArray, A::AdjointAbsMat{<:Union{Real,Complex}}) = + (Base.mapreducedim!(f∘adjoint, op, switch_dim12(B), parent(A)); B) + +switch_dim12(B::AbstractVector) = permutedims(B) +switch_dim12(B::AbstractArray{<:Any,0}) = B +switch_dim12(B::AbstractArray) = PermutedDimsArray(B, (2, 1, ntuple(Base.Fix1(+,2), ndims(B) - 2)...)) ### linear algebra diff --git a/stdlib/LinearAlgebra/src/bidiag.jl b/stdlib/LinearAlgebra/src/bidiag.jl index 317ed15af770c..958466f25e1b5 100644 --- a/stdlib/LinearAlgebra/src/bidiag.jl +++ b/stdlib/LinearAlgebra/src/bidiag.jl @@ -200,11 +200,17 @@ promote_rule(::Type{<:Tridiagonal}, ::Type{<:Bidiagonal}) = Tridiagonal # When asked to convert Bidiagonal to AbstractMatrix{T}, preserve structure by converting to Bidiagonal{T} <: AbstractMatrix{T} AbstractMatrix{T}(A::Bidiagonal) where {T} = convert(Bidiagonal{T}, A) -convert(T::Type{<:Bidiagonal}, m::AbstractMatrix) = m isa T ? m : T(m) +convert(::Type{T}, m::AbstractMatrix) where {T<:Bidiagonal} = m isa T ? m : T(m)::T similar(B::Bidiagonal, ::Type{T}) where {T} = Bidiagonal(similar(B.dv, T), similar(B.ev, T), B.uplo) similar(B::Bidiagonal, ::Type{T}, dims::Union{Dims{1},Dims{2}}) where {T} = zeros(T, dims...) +function kron(A::Diagonal, B::Bidiagonal) + # `_droplast!` is only guaranteed to work with `Vector` + kdv = _makevector(kron(diag(A), B.dv)) + kev = _droplast!(_makevector(kron(diag(A), _pushzero(B.ev)))) + Bidiagonal(kdv, kev, B.uplo) +end ################### # LAPACK routines # @@ -702,14 +708,15 @@ function dot(x::AbstractVector, B::Bidiagonal, y::AbstractVector) require_one_based_indexing(x, y) nx, ny = length(x), length(y) (nx == size(B, 1) == ny) || throw(DimensionMismatch()) - if iszero(nx) - return dot(zero(eltype(x)), zero(eltype(B)), zero(eltype(y))) + if nx ≤ 1 + nx == 0 && return dot(zero(eltype(x)), zero(eltype(B)), zero(eltype(y))) + return dot(x[1], B.dv[1], y[1]) end ev, dv = B.ev, B.dv - if B.uplo == 'U' + @inbounds if B.uplo == 'U' x₀ = x[1] r = dot(x[1], dv[1], y[1]) - @inbounds for j in 2:nx-1 + for j in 2:nx-1 x₋, x₀ = x₀, x[j] r += dot(adjoint(ev[j-1])*x₋ + adjoint(dv[j])*x₀, y[j]) end @@ -719,7 +726,7 @@ function dot(x::AbstractVector, B::Bidiagonal, y::AbstractVector) x₀ = x[1] x₊ = x[2] r = dot(adjoint(dv[1])*x₀ + adjoint(ev[1])*x₊, y[1]) - @inbounds for j in 2:nx-1 + for j in 2:nx-1 x₀, x₊ = x₊, x[j+1] r += dot(adjoint(dv[j])*x₀ + adjoint(ev[j])*x₊, y[j]) end diff --git a/stdlib/LinearAlgebra/src/blas.jl b/stdlib/LinearAlgebra/src/blas.jl index 4a83fcecbc8d9..7547a60f390d4 100644 --- a/stdlib/LinearAlgebra/src/blas.jl +++ b/stdlib/LinearAlgebra/src/blas.jl @@ -167,7 +167,7 @@ end # Level 1 # A help function to pick the pointer and inc for 1d like inputs. @inline function vec_pointer_stride(x::AbstractArray, stride0check = nothing) - Base._checkcontiguous(Bool, x) && return pointer(x), 1 # simpify runtime check when possibe + Base._checkcontiguous(Bool, x) && return pointer(x), 1 # simplify runtime check when possibe st, ptr = checkedstride(x), pointer(x) isnothing(stride0check) || (st == 0 && throw(stride0check)) ptr += min(st, 0) * sizeof(eltype(x)) * (length(x) - 1) diff --git a/stdlib/LinearAlgebra/src/bunchkaufman.jl b/stdlib/LinearAlgebra/src/bunchkaufman.jl index e0502b6f6dcfd..622c9263daf7b 100644 --- a/stdlib/LinearAlgebra/src/bunchkaufman.jl +++ b/stdlib/LinearAlgebra/src/bunchkaufman.jl @@ -80,7 +80,7 @@ BunchKaufman(A::AbstractMatrix{T}, ipiv::AbstractVector{<:Integer}, uplo::Abstra symmetric::Bool, rook::Bool, info::BlasInt) where {T} = BunchKaufman{T,typeof(A),typeof(ipiv)}(A, ipiv, uplo, symmetric, rook, info) # backwards-compatible constructors (remove with Julia 2.0) -@deprecate(BunchKaufman(LD, ipiv, uplo, symmetric, rook, info) where {T,S}, +@deprecate(BunchKaufman{T,S}(LD, ipiv, uplo, symmetric, rook, info) where {T,S}, BunchKaufman{T,S,typeof(ipiv)}(LD, ipiv, uplo, symmetric, rook, info), false) # iteration for destructuring into components diff --git a/stdlib/LinearAlgebra/src/dense.jl b/stdlib/LinearAlgebra/src/dense.jl index 6fea7d006b6b6..bcf9443f7632c 100644 --- a/stdlib/LinearAlgebra/src/dense.jl +++ b/stdlib/LinearAlgebra/src/dense.jl @@ -350,27 +350,67 @@ function tr(A::Matrix{T}) where T t end +_kronsize(A::AbstractMatrix, B::AbstractMatrix) = map(*, size(A), size(B)) +_kronsize(A::AbstractMatrix, B::AbstractVector) = (size(A, 1)*length(B), size(A, 2)) +_kronsize(A::AbstractVector, B::AbstractMatrix) = (length(A)*size(B, 1), size(B, 2)) + """ kron!(C, A, B) -`kron!` is the in-place version of [`kron`](@ref). Computes `kron(A, B)` and stores the result in `C` -overwriting the existing value of `C`. - -!!! tip - Bounds checking can be disabled by [`@inbounds`](@ref), but you need to take care of the shape - of `C`, `A`, `B` yourself. +Computes the Kronecker product of `A` and `B` and stores the result in `C`, +overwriting the existing content of `C`. This is the in-place version of [`kron`](@ref). !!! compat "Julia 1.6" This function requires Julia 1.6 or later. """ -@inline function kron!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix) - require_one_based_indexing(A, B) - @boundscheck (size(C) == (size(A,1)*size(B,1), size(A,2)*size(B,2))) || throw(DimensionMismatch()) - m = 0 - @inbounds for j = 1:size(A,2), l = 1:size(B,2), i = 1:size(A,1) +function kron!(C::AbstractVecOrMat, A::AbstractVecOrMat, B::AbstractVecOrMat) + size(C) == _kronsize(A, B) || throw(DimensionMismatch("kron!")) + _kron!(C, A, B) +end +function kron!(c::AbstractVector, a::AbstractVector, b::AbstractVector) + length(c) == length(a) * length(b) || throw(DimensionMismatch("kron!")) + m = firstindex(c) + @inbounds for i in eachindex(a) + ai = a[i] + for k in eachindex(b) + c[m] = ai*b[k] + m += 1 + end + end + return c +end +kron!(c::AbstractVecOrMat, a::AbstractVecOrMat, b::Number) = mul!(c, a, b) +kron!(c::AbstractVecOrMat, a::Number, b::AbstractVecOrMat) = mul!(c, a, b) + +function _kron!(C, A::AbstractMatrix, B::AbstractMatrix) + m = firstindex(C) + @inbounds for j in axes(A,2), l in axes(B,2), i in axes(A,1) Aij = A[i,j] - for k = 1:size(B,1) - C[m += 1] = Aij*B[k,l] + for k in axes(B,1) + C[m] = Aij*B[k,l] + m += 1 + end + end + return C +end +function _kron!(C, A::AbstractMatrix, b::AbstractVector) + m = firstindex(C) + @inbounds for j in axes(A,2), i in axes(A,1) + Aij = A[i,j] + for k in eachindex(b) + C[m] = Aij*b[k] + m += 1 + end + end + return C +end +function _kron!(C, a::AbstractVector, B::AbstractMatrix) + m = firstindex(C) + @inbounds for l in axes(B,2), i in eachindex(a) + ai = a[i] + for k in axes(B,1) + C[m] = ai*B[k,l] + m += 1 end end return C @@ -379,7 +419,7 @@ end """ kron(A, B) -Kronecker tensor product of two vectors or two matrices. +Computes the Kronecker product of two vectors, matrices or numbers. For real vectors `v` and `w`, the Kronecker product is related to the outer product by `kron(v,w) == vec(w * transpose(v))` or @@ -422,31 +462,16 @@ julia> reshape(kron(v,w), (length(w), length(v))) 5 10 ``` """ -function kron(a::AbstractMatrix{T}, b::AbstractMatrix{S}) where {T,S} - R = Matrix{promote_op(*,T,S)}(undef, size(a,1)*size(b,1), size(a,2)*size(b,2)) - return @inbounds kron!(R, a, b) +function kron(A::AbstractVecOrMat{T}, B::AbstractVecOrMat{S}) where {T,S} + R = Matrix{promote_op(*,T,S)}(undef, _kronsize(A, B)) + return kron!(R, A, B) end - -kron!(c::AbstractVecOrMat, a::AbstractVecOrMat, b::Number) = mul!(c, a, b) -kron!(c::AbstractVecOrMat, a::Number, b::AbstractVecOrMat) = mul!(c, a, b) - -Base.@propagate_inbounds function kron!(c::AbstractVector, a::AbstractVector, b::AbstractVector) - C = reshape(c, length(a)*length(b), 1) - A = reshape(a ,length(a), 1) - B = reshape(b, length(b), 1) - kron!(C, A, B) - return c +function kron(a::AbstractVector{T}, b::AbstractVector{S}) where {T,S} + c = Vector{promote_op(*,T,S)}(undef, length(a)*length(b)) + return kron!(c, a, b) end - -Base.@propagate_inbounds kron!(C::AbstractMatrix, a::AbstractMatrix, b::AbstractVector) = kron!(C, a, reshape(b, length(b), 1)) -Base.@propagate_inbounds kron!(C::AbstractMatrix, a::AbstractVector, b::AbstractMatrix) = kron!(C, reshape(a, length(a), 1), b) - kron(a::Number, b::Union{Number, AbstractVecOrMat}) = a * b kron(a::AbstractVecOrMat, b::Number) = a * b -kron(a::AbstractVector, b::AbstractVector) = vec(kron(reshape(a ,length(a), 1), reshape(b, length(b), 1))) -kron(a::AbstractMatrix, b::AbstractVector) = kron(a, reshape(b, length(b), 1)) -kron(a::AbstractVector, b::AbstractMatrix) = kron(reshape(a, length(a), 1), b) - kron(a::AdjointAbsVec, b::AdjointAbsVec) = adjoint(kron(adjoint(a), adjoint(b))) kron(a::AdjOrTransAbsVec, b::AdjOrTransAbsVec) = transpose(kron(transpose(a), transpose(b))) @@ -697,7 +722,7 @@ function exp!(A::StridedMatrix{T}) where T<:BlasFloat V = mul!(tmp2, A6, tmp1, true, true) tmp1 .= V .+ U - tmp2 .= V .- U # tmp2 aleady contained V but this seems more readable + tmp2 .= V .- U # tmp2 already contained V but this seems more readable X = LAPACK.gesv!(tmp2, tmp1)[1] # X now contains r_13 in Higham 2008 if s > 0 @@ -1580,21 +1605,22 @@ julia> X = sylvester(A, B, C) -4.46667 1.93333 3.73333 -1.8 -julia> A*X + X*B + C -2×2 Matrix{Float64}: - 2.66454e-15 1.77636e-15 - -3.77476e-15 4.44089e-16 +julia> A*X + X*B ≈ -C +true ``` """ -function sylvester(A::StridedMatrix{T},B::StridedMatrix{T},C::StridedMatrix{T}) where T<:BlasFloat +function sylvester(A::AbstractMatrix, B::AbstractMatrix, C::AbstractMatrix) + T = promote_type(float(eltype(A)), float(eltype(B)), float(eltype(C))) + return sylvester(copy_similar(A, T), copy_similar(B, T), copy_similar(C, T)) +end +function sylvester(A::AbstractMatrix{T}, B::AbstractMatrix{T}, C::AbstractMatrix{T}) where {T<:BlasFloat} RA, QA = schur(A) RB, QB = schur(B) - - D = -(adjoint(QA) * (C*QB)) - Y, scale = LAPACK.trsyl!('N','N', RA, RB, D) - rmul!(QA*(Y * adjoint(QB)), inv(scale)) + D = QA' * C * QB + D .= .-D + Y, scale = LAPACK.trsyl!('N', 'N', RA, RB, D) + rmul!(QA * Y * QB', inv(scale)) end -sylvester(A::StridedMatrix{T}, B::StridedMatrix{T}, C::StridedMatrix{T}) where {T<:Integer} = sylvester(float(A), float(B), float(C)) Base.@propagate_inbounds function _sylvester_2x1!(A, B, C) b = B[1] @@ -1652,18 +1678,19 @@ julia> X = lyap(A, B) 0.5 -0.5 -0.5 0.25 -julia> A*X + X*A' + B -2×2 Matrix{Float64}: - 0.0 6.66134e-16 - 6.66134e-16 8.88178e-16 +julia> A*X + X*A' ≈ -B +true ``` """ -function lyap(A::StridedMatrix{T}, C::StridedMatrix{T}) where {T<:BlasFloat} +function lyap(A::AbstractMatrix, C::AbstractMatrix) + T = promote_type(float(eltype(A)), float(eltype(C))) + return lyap(copy_similar(A, T), copy_similar(C, T)) +end +function lyap(A::AbstractMatrix{T}, C::AbstractMatrix{T}) where {T<:BlasFloat} R, Q = schur(A) - - D = -(adjoint(Q) * (C*Q)) + D = Q' * C * Q + D .= .-D Y, scale = LAPACK.trsyl!('N', T <: Complex ? 'C' : 'T', R, R, D) - rmul!(Q*(Y * adjoint(Q)), inv(scale)) + rmul!(Q * Y * Q', inv(scale)) end -lyap(A::StridedMatrix{T}, C::StridedMatrix{T}) where {T<:Integer} = lyap(float(A), float(C)) lyap(a::Union{Real,Complex}, c::Union{Real,Complex}) = -c/(2real(a)) diff --git a/stdlib/LinearAlgebra/src/diagonal.jl b/stdlib/LinearAlgebra/src/diagonal.jl index 8895e4cf5e892..819b7af73b359 100644 --- a/stdlib/LinearAlgebra/src/diagonal.jl +++ b/stdlib/LinearAlgebra/src/diagonal.jl @@ -368,6 +368,12 @@ end return out end +function (*)(Da::Diagonal, A::AbstractMatrix, Db::Diagonal) + _muldiag_size_check(Da, A) + _muldiag_size_check(A, Db) + return broadcast(*, Da.diag, A, permutedims(Db.diag)) +end + # Get ambiguous method if try to unify AbstractVector/AbstractMatrix here using AbstractVecOrMat @inline mul!(out::AbstractVector, D::Diagonal, V::AbstractVector, alpha::Number, beta::Number) = _muldiag!(out, D, V, alpha, beta) @@ -590,7 +596,21 @@ end return C end -kron(A::Diagonal{<:Number}, B::Diagonal{<:Number}) = Diagonal(kron(A.diag, B.diag)) +kron(A::Diagonal, B::Diagonal) = Diagonal(kron(A.diag, B.diag)) + +function kron(A::Diagonal, B::SymTridiagonal) + kdv = kron(diag(A), B.dv) + # We don't need to drop the last element + kev = kron(diag(A), _pushzero(_evview(B))) + SymTridiagonal(kdv, kev) +end +function kron(A::Diagonal, B::Tridiagonal) + # `_droplast!` is only guaranteed to work with `Vector` + kd = _makevector(kron(diag(A), B.d)) + kdl = _droplast!(_makevector(kron(diag(A), _pushzero(B.dl)))) + kdu = _droplast!(_makevector(kron(diag(A), _pushzero(B.du)))) + Tridiagonal(kdl, kd, kdu) +end @inline function kron!(C::AbstractMatrix, A::Diagonal, B::AbstractMatrix) require_one_based_indexing(B) @@ -808,6 +828,8 @@ end @deprecate cholesky!(A::Diagonal, ::Val{false}; check::Bool = true) cholesky!(A::Diagonal, NoPivot(); check) false @deprecate cholesky(A::Diagonal, ::Val{false}; check::Bool = true) cholesky(A::Diagonal, NoPivot(); check) false +inv(C::Cholesky{<:Any,<:Diagonal}) = Diagonal(map(inv∘abs2, C.factors.diag)) + @inline cholcopy(A::Diagonal) = copymutable_oftype(A, choltype(A)) @inline cholcopy(A::RealHermSymComplexHerm{<:Real,<:Diagonal}) = copymutable_oftype(A, choltype(A)) diff --git a/stdlib/LinearAlgebra/src/exceptions.jl b/stdlib/LinearAlgebra/src/exceptions.jl index ae29b8bc2f7b9..a8d81aad3e067 100644 --- a/stdlib/LinearAlgebra/src/exceptions.jl +++ b/stdlib/LinearAlgebra/src/exceptions.jl @@ -50,7 +50,7 @@ end Exception thrown when a matrix factorization/solve encounters a zero in a pivot (diagonal) position and cannot proceed. This may *not* mean that the matrix is singular: -it may be fruitful to switch to a diffent factorization such as pivoted LU +it may be fruitful to switch to a different factorization such as pivoted LU that can re-order variables to eliminate spurious zero pivots. The `info` field indicates the location of (one of) the zero pivot(s). """ diff --git a/stdlib/LinearAlgebra/src/factorization.jl b/stdlib/LinearAlgebra/src/factorization.jl index 82c593f9bd7c4..a5bcdf66ecc7c 100644 --- a/stdlib/LinearAlgebra/src/factorization.jl +++ b/stdlib/LinearAlgebra/src/factorization.jl @@ -54,9 +54,9 @@ function det(F::Factorization) end convert(::Type{T}, f::T) where {T<:Factorization} = f -convert(::Type{T}, f::Factorization) where {T<:Factorization} = T(f) +convert(::Type{T}, f::Factorization) where {T<:Factorization} = T(f)::T -convert(::Type{T}, f::Factorization) where {T<:AbstractArray} = T(f) +convert(::Type{T}, f::Factorization) where {T<:AbstractArray} = T(f)::T ### General promotion rules Factorization{T}(F::Factorization{T}) where {T} = F diff --git a/stdlib/LinearAlgebra/src/givens.jl b/stdlib/LinearAlgebra/src/givens.jl index 155d8d6f23ce6..6074bb1ed3b94 100644 --- a/stdlib/LinearAlgebra/src/givens.jl +++ b/stdlib/LinearAlgebra/src/givens.jl @@ -3,6 +3,9 @@ # givensAlgorithm functions are derived from LAPACK, see below abstract type AbstractRotation{T} end +struct AdjointRotation{T,S<:AbstractRotation{T}} <: AbstractRotation{T} + R::S +end transpose(R::AbstractRotation) = error("transpose not implemented for $(typeof(R)). Consider using adjoint instead of transpose.") @@ -10,16 +13,19 @@ function (*)(R::AbstractRotation{T}, A::AbstractVecOrMat{S}) where {T,S} TS = typeof(zero(T)*zero(S) + zero(T)*zero(S)) lmul!(convert(AbstractRotation{TS}, R), copy_similar(A, TS)) end -(*)(A::AbstractVector, adjR::Adjoint{<:Any,<:AbstractRotation}) = _absvecormat_mul_adjrot(A, adjR) -(*)(A::AbstractMatrix, adjR::Adjoint{<:Any,<:AbstractRotation}) = _absvecormat_mul_adjrot(A, adjR) -function _absvecormat_mul_adjrot(A::AbstractVecOrMat{T}, adjR::Adjoint{<:Any,<:AbstractRotation{S}}) where {T,S} - R = adjR.parent +function (*)(adjR::AdjointRotation{T}, A::AbstractVecOrMat{S}) where {T,S} + TS = typeof(zero(T)*zero(S) + zero(T)*zero(S)) + lmul!(convert(AbstractRotation{TS}, adjR.R)', copy_similar(A, TS)) +end +(*)(A::AbstractVector, adjR::AdjointRotation) = _absvecormat_mul_adjrot(A, adjR) +(*)(A::AbstractMatrix, adjR::AdjointRotation) = _absvecormat_mul_adjrot(A, adjR) +function _absvecormat_mul_adjrot(A::AbstractVecOrMat{T}, adjR::AdjointRotation{S}) where {T,S} TS = typeof(zero(T)*zero(S) + zero(T)*zero(S)) - rmul!(TS.(A), convert(AbstractRotation{TS}, R)') + rmul!(copy_similar(A, TS), convert(AbstractRotation{TS}, adjR.R)') end function(*)(A::AbstractMatrix{T}, R::AbstractRotation{S}) where {T,S} TS = typeof(zero(T)*zero(S) + zero(T)*zero(S)) - rmul!(TS.(A), convert(AbstractRotation{TS}, R)) + rmul!(copy_similar(A, TS), convert(AbstractRotation{TS}, R)) end """ @@ -44,7 +50,7 @@ struct Rotation{T} <: AbstractRotation{T} end convert(::Type{T}, r::T) where {T<:AbstractRotation} = r -convert(::Type{T}, r::AbstractRotation) where {T<:AbstractRotation} = T(r) +convert(::Type{T}, r::AbstractRotation) where {T<:AbstractRotation} = T(r)::T Givens(i1, i2, c, s) = Givens(i1, i2, promote(c, s)...) Givens{T}(G::Givens{T}) where {T} = G @@ -55,12 +61,11 @@ AbstractRotation{T}(G::Givens) where {T} = Givens{T}(G) AbstractRotation{T}(R::Rotation) where {T} = Rotation{T}(R) adjoint(G::Givens) = Givens(G.i1, G.i2, G.c', -G.s) -adjoint(R::Rotation) = Adjoint(R) -function Base.copy(aG::Adjoint{<:Any,<:Givens}) - G = aG.parent - return Givens(G.i1, G.i2, conj(G.c), -G.s) -end -Base.copy(aR::Adjoint{<:Any,Rotation{T}}) where {T} = Rotation{T}(reverse!([r' for r in aR.parent.rotations])) +adjoint(R::AbstractRotation) = AdjointRotation(R) +adjoint(adjR::AdjointRotation) = adjR.R + +Base.copy(aR::AdjointRotation{T,Rotation{T}}) where {T} = + Rotation{T}([r' for r in Iterators.reverse(aR.R.rotations)]) floatmin2(::Type{Float32}) = reinterpret(Float32, 0x26000000) floatmin2(::Type{Float64}) = reinterpret(Float64, 0x21a0000000000000) @@ -291,7 +296,7 @@ function givens(f::T, g::T, i1::Integer, i2::Integer) where T c, s, r = givensAlgorithm(f, g) if i1 > i2 s = -conj(s) - i1,i2 = i2,i1 + i1, i2 = i2, i1 end Givens(i1, i2, c, s), r end @@ -329,9 +334,7 @@ B[i2] = 0 See also [`LinearAlgebra.Givens`](@ref). """ -givens(x::AbstractVector, i1::Integer, i2::Integer) = - givens(x[i1], x[i2], i1, i2) - +givens(x::AbstractVector, i1::Integer, i2::Integer) = givens(x[i1], x[i2], i1, i2) function getindex(G::Givens, i::Integer, j::Integer) if i == j @@ -386,23 +389,24 @@ function lmul!(R::Rotation, A::AbstractMatrix) end return A end -function rmul!(A::AbstractMatrix, adjR::Adjoint{<:Any,<:Rotation}) - R = adjR.parent +function rmul!(A::AbstractMatrix, R::Rotation) + @inbounds for i = 1:length(R.rotations) + rmul!(A, R.rotations[i]) + end + return A +end +function lmul!(adjR::AdjointRotation{<:Any,<:Rotation}, A::AbstractMatrix) + R = adjR.R + @inbounds for i = 1:length(R.rotations) + lmul!(adjoint(R.rotations[i]), A) + end + return A +end +function rmul!(A::AbstractMatrix, adjR::AdjointRotation{<:Any,<:Rotation}) + R = adjR.R @inbounds for i = 1:length(R.rotations) rmul!(A, adjoint(R.rotations[i])) end return A end -*(G1::Givens{T}, G2::Givens{T}) where {T} = Rotation(push!(push!(Givens{T}[], G2), G1)) - -# TODO: None of the following disambiguation methods are great. They should perhaps -# instead be MethodErrors, or revised. -# -# disambiguation methods: *(Adj/Trans of AbsVec or AbsMat, Adj of AbstractRotation) -*(A::Adjoint{<:Any,<:AbstractVector}, B::Adjoint{<:Any,<:AbstractRotation}) = copy(A) * B -*(A::Adjoint{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:AbstractRotation}) = copy(A) * B -*(A::Transpose{<:Any,<:AbstractVector}, B::Adjoint{<:Any,<:AbstractRotation}) = copy(A) * B -*(A::Transpose{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:AbstractRotation}) = copy(A) * B -# disambiguation methods: *(Diag/AbsTri, Adj of AbstractRotation) -*(A::Diagonal, B::Adjoint{<:Any,<:AbstractRotation}) = A * copy(B) -*(A::AbstractTriangular, B::Adjoint{<:Any,<:AbstractRotation}) = A * copy(B) +*(G1::Givens{T}, G2::Givens{T}) where {T} = Rotation([G2, G1]) diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index 81eb9e3d3012a..2216d1858d46f 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -66,7 +66,7 @@ end gemv!(y, 'N', A, x, alpha, beta) # Complex matrix times real vector. -# Reinterpret the matrix as a real matrix and do real matvec compuation. +# Reinterpret the matrix as a real matrix and do real matvec computation. @inline mul!(y::StridedVector{Complex{T}}, A::StridedVecOrMat{Complex{T}}, x::StridedVector{T}, alpha::Number, beta::Number) where {T<:BlasReal} = gemv!(y, 'N', A, x, alpha, beta) @@ -469,7 +469,7 @@ end # Supporting functions for matrix multiplication -# copy transposed(adjoint) of upper(lower) side-digonals. Optionally include diagonal. +# copy transposed(adjoint) of upper(lower) side-diagonals. Optionally include diagonal. @inline function copytri!(A::AbstractMatrix, uplo::AbstractChar, conjugate::Bool=false, diag::Bool=false) n = checksquare(A) off = diag ? 0 : 1 diff --git a/stdlib/LinearAlgebra/src/special.jl b/stdlib/LinearAlgebra/src/special.jl index d4cff63dcc045..7fcace8e4ef71 100644 --- a/stdlib/LinearAlgebra/src/special.jl +++ b/stdlib/LinearAlgebra/src/special.jl @@ -2,13 +2,6 @@ # Methods operating on different special matrix types - -# Usually, reducedim_initarray calls similar, which yields a sparse matrix for a -# Diagonal/Bidiagonal/Tridiagonal/SymTridiagonal matrix. However, reducedim should -# yield a dense vector to increase performance. -Base.reducedim_initarray(A::Union{Diagonal,Bidiagonal,Tridiagonal,SymTridiagonal}, region, init, ::Type{R}) where {R} = fill(convert(R, init), Base.reduced_indices(A,region)) - - # Interconversion between special matrix types # conversions from Diagonal to other special matrix types @@ -62,20 +55,20 @@ end const ConvertibleSpecialMatrix = Union{Diagonal,Bidiagonal,SymTridiagonal,Tridiagonal,AbstractTriangular} const PossibleTriangularMatrix = Union{Diagonal, Bidiagonal, AbstractTriangular} -convert(T::Type{<:Diagonal}, m::ConvertibleSpecialMatrix) = m isa T ? m : - isdiag(m) ? T(m) : throw(ArgumentError("matrix cannot be represented as Diagonal")) -convert(T::Type{<:SymTridiagonal}, m::ConvertibleSpecialMatrix) = m isa T ? m : - issymmetric(m) && isbanded(m, -1, 1) ? T(m) : throw(ArgumentError("matrix cannot be represented as SymTridiagonal")) -convert(T::Type{<:Tridiagonal}, m::ConvertibleSpecialMatrix) = m isa T ? m : - isbanded(m, -1, 1) ? T(m) : throw(ArgumentError("matrix cannot be represented as Tridiagonal")) +convert(::Type{T}, m::ConvertibleSpecialMatrix) where {T<:Diagonal} = m isa T ? m : + isdiag(m) ? T(m)::T : throw(ArgumentError("matrix cannot be represented as Diagonal")) +convert(::Type{T}, m::ConvertibleSpecialMatrix) where {T<:SymTridiagonal} = m isa T ? m : + issymmetric(m) && isbanded(m, -1, 1) ? T(m)::T : throw(ArgumentError("matrix cannot be represented as SymTridiagonal")) +convert(::Type{T}, m::ConvertibleSpecialMatrix) where {T<:Tridiagonal} = m isa T ? m : + isbanded(m, -1, 1) ? T(m)::T : throw(ArgumentError("matrix cannot be represented as Tridiagonal")) -convert(T::Type{<:LowerTriangular}, m::Union{LowerTriangular,UnitLowerTriangular}) = m isa T ? m : T(m) -convert(T::Type{<:UpperTriangular}, m::Union{UpperTriangular,UnitUpperTriangular}) = m isa T ? m : T(m) +convert(::Type{T}, m::Union{LowerTriangular,UnitLowerTriangular}) where {T<:LowerTriangular} = m isa T ? m : T(m)::T +convert(::Type{T}, m::Union{UpperTriangular,UnitUpperTriangular}) where {T<:UpperTriangular} = m isa T ? m : T(m)::T -convert(T::Type{<:LowerTriangular}, m::PossibleTriangularMatrix) = m isa T ? m : - istril(m) ? T(m) : throw(ArgumentError("matrix cannot be represented as LowerTriangular")) -convert(T::Type{<:UpperTriangular}, m::PossibleTriangularMatrix) = m isa T ? m : - istriu(m) ? T(m) : throw(ArgumentError("matrix cannot be represented as UpperTriangular")) +convert(::Type{T}, m::PossibleTriangularMatrix) where {T<:LowerTriangular} = m isa T ? m : + istril(m) ? T(m)::T : throw(ArgumentError("matrix cannot be represented as LowerTriangular")) +convert(::Type{T}, m::PossibleTriangularMatrix) where {T<:UpperTriangular} = m isa T ? m : + istriu(m) ? T(m)::T : throw(ArgumentError("matrix cannot be represented as UpperTriangular")) # Constructs two method definitions taking into account (assumed) commutativity # e.g. @commutative f(x::S, y::T) where {S,T} = x+y is the same is defining diff --git a/stdlib/LinearAlgebra/src/structuredbroadcast.jl b/stdlib/LinearAlgebra/src/structuredbroadcast.jl index 95a1842702291..ccf95f88a1bee 100644 --- a/stdlib/LinearAlgebra/src/structuredbroadcast.jl +++ b/stdlib/LinearAlgebra/src/structuredbroadcast.jl @@ -126,6 +126,7 @@ fails as `zero(::Tuple{Int})` is not defined. However, """ iszerodefined(::Type) = false iszerodefined(::Type{<:Number}) = true +iszerodefined(::Type{<:AbstractArray{T}}) where T = iszerodefined(T) fzeropreserving(bc) = (v = fzero(bc); !ismissing(v) && (iszerodefined(typeof(v)) ? iszero(v) : v == 0)) # Like sparse matrices, we assume that the zero-preservation property of a broadcasted diff --git a/stdlib/LinearAlgebra/src/svd.jl b/stdlib/LinearAlgebra/src/svd.jl index d0ac4d957e60d..c58c83bcb5a98 100644 --- a/stdlib/LinearAlgebra/src/svd.jl +++ b/stdlib/LinearAlgebra/src/svd.jl @@ -26,10 +26,10 @@ julia> F = svd(A) SVD{Float64, Float64, Matrix{Float64}, Vector{Float64}} U factor: 4×4 Matrix{Float64}: - 0.0 1.0 0.0 0.0 - 1.0 0.0 0.0 0.0 - 0.0 0.0 0.0 -1.0 - 0.0 0.0 1.0 0.0 + 0.0 1.0 0.0 0.0 + 1.0 0.0 0.0 0.0 + 0.0 0.0 0.0 1.0 + 0.0 0.0 -1.0 0.0 singular values: 4-element Vector{Float64}: 3.0 @@ -38,10 +38,10 @@ singular values: 0.0 Vt factor: 4×5 Matrix{Float64}: - -0.0 0.0 1.0 -0.0 0.0 - 0.447214 0.0 0.0 0.0 0.894427 - -0.0 1.0 0.0 -0.0 0.0 - 0.0 0.0 0.0 1.0 0.0 + -0.0 0.0 1.0 -0.0 0.0 + 0.447214 0.0 0.0 0.0 0.894427 + 0.0 -1.0 0.0 0.0 0.0 + 0.0 0.0 0.0 1.0 0.0 julia> F.U * Diagonal(F.S) * F.Vt 4×5 Matrix{Float64}: diff --git a/stdlib/LinearAlgebra/src/symmetric.jl b/stdlib/LinearAlgebra/src/symmetric.jl index 7347dd6f78639..96638477ce717 100644 --- a/stdlib/LinearAlgebra/src/symmetric.jl +++ b/stdlib/LinearAlgebra/src/symmetric.jl @@ -192,8 +192,8 @@ for (S, H) in ((:Symmetric, :Hermitian), (:Hermitian, :Symmetric)) end end -convert(T::Type{<:Symmetric}, m::Union{Symmetric,Hermitian}) = m isa T ? m : T(m) -convert(T::Type{<:Hermitian}, m::Union{Symmetric,Hermitian}) = m isa T ? m : T(m) +convert(::Type{T}, m::Union{Symmetric,Hermitian}) where {T<:Symmetric} = m isa T ? m : T(m)::T +convert(::Type{T}, m::Union{Symmetric,Hermitian}) where {T<:Hermitian} = m isa T ? m : T(m)::T const HermOrSym{T, S} = Union{Hermitian{T,S}, Symmetric{T,S}} const RealHermSym{T<:Real,S} = Union{Hermitian{T,S}, Symmetric{T,S}} diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index d939a5df0da01..a0edfdcd3c40a 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -674,7 +674,7 @@ mul!(C::AbstractMatrix, A::AbstractTriangular, adjB::Adjoint{<:Any,<:AbstractVec mul!(C::AbstractVecOrMat, A::AbstractTriangular, adjB::Adjoint{<:Any,<:AbstractVecOrMat}) = (B = adjB.parent; lmul!(A, adjoint!(C, B))) -# The three methods are neceesary to avoid ambiguities with definitions in matmul.jl +# The three methods are necessary to avoid ambiguities with definitions in matmul.jl mul!(C::AbstractVector , A::AbstractTriangular, B::AbstractVector) = lmul!(A, copyto!(C, B)) mul!(C::AbstractMatrix , A::AbstractTriangular, B::AbstractVecOrMat) = lmul!(A, copyto!(C, B)) mul!(C::AbstractVecOrMat, A::AbstractTriangular, B::AbstractVecOrMat) = lmul!(A, copyto!(C, B)) diff --git a/stdlib/LinearAlgebra/src/tridiag.jl b/stdlib/LinearAlgebra/src/tridiag.jl index a686ab4421954..70556d1c92a0b 100644 --- a/stdlib/LinearAlgebra/src/tridiag.jl +++ b/stdlib/LinearAlgebra/src/tridiag.jl @@ -256,21 +256,24 @@ end function dot(x::AbstractVector, S::SymTridiagonal, y::AbstractVector) require_one_based_indexing(x, y) nx, ny = length(x), length(y) - (nx == size(S, 1) == ny) || throw(DimensionMismatch()) - if iszero(nx) - return dot(zero(eltype(x)), zero(eltype(S)), zero(eltype(y))) + (nx == size(S, 1) == ny) || throw(DimensionMismatch("dot")) + if nx ≤ 1 + nx == 0 && return dot(zero(eltype(x)), zero(eltype(S)), zero(eltype(y))) + return dot(x[1], S.dv[1], y[1]) end dv, ev = S.dv, S.ev - x₀ = x[1] - x₊ = x[2] - sub = transpose(ev[1]) - r = dot(adjoint(dv[1])*x₀ + adjoint(sub)*x₊, y[1]) - @inbounds for j in 2:nx-1 - x₋, x₀, x₊ = x₀, x₊, x[j+1] - sup, sub = transpose(sub), transpose(ev[j]) - r += dot(adjoint(sup)*x₋ + adjoint(dv[j])*x₀ + adjoint(sub)*x₊, y[j]) - end - r += dot(adjoint(transpose(sub))*x₀ + adjoint(dv[nx])*x₊, y[nx]) + @inbounds begin + x₀ = x[1] + x₊ = x[2] + sub = transpose(ev[1]) + r = dot(adjoint(dv[1])*x₀ + adjoint(sub)*x₊, y[1]) + for j in 2:nx-1 + x₋, x₀, x₊ = x₀, x₊, x[j+1] + sup, sub = transpose(sub), transpose(ev[j]) + r += dot(adjoint(sup)*x₋ + adjoint(dv[j])*x₀ + adjoint(sub)*x₊, y[j]) + end + r += dot(adjoint(transpose(sub))*x₀ + adjoint(dv[nx])*x₊, y[nx]) + end return r end @@ -841,18 +844,21 @@ function dot(x::AbstractVector, A::Tridiagonal, y::AbstractVector) require_one_based_indexing(x, y) nx, ny = length(x), length(y) (nx == size(A, 1) == ny) || throw(DimensionMismatch()) - if iszero(nx) - return dot(zero(eltype(x)), zero(eltype(A)), zero(eltype(y))) - end - x₀ = x[1] - x₊ = x[2] - dl, d, du = A.dl, A.d, A.du - r = dot(adjoint(d[1])*x₀ + adjoint(dl[1])*x₊, y[1]) - @inbounds for j in 2:nx-1 - x₋, x₀, x₊ = x₀, x₊, x[j+1] - r += dot(adjoint(du[j-1])*x₋ + adjoint(d[j])*x₀ + adjoint(dl[j])*x₊, y[j]) - end - r += dot(adjoint(du[nx-1])*x₀ + adjoint(d[nx])*x₊, y[nx]) + if nx ≤ 1 + nx == 0 && return dot(zero(eltype(x)), zero(eltype(A)), zero(eltype(y))) + return dot(x[1], A.d[1], y[1]) + end + @inbounds begin + x₀ = x[1] + x₊ = x[2] + dl, d, du = A.dl, A.d, A.du + r = dot(adjoint(d[1])*x₀ + adjoint(dl[1])*x₊, y[1]) + for j in 2:nx-1 + x₋, x₀, x₊ = x₀, x₊, x[j+1] + r += dot(adjoint(du[j-1])*x₋ + adjoint(d[j])*x₀ + adjoint(dl[j])*x₊, y[j]) + end + r += dot(adjoint(du[nx-1])*x₀ + adjoint(d[nx])*x₊, y[nx]) + end return r end diff --git a/stdlib/LinearAlgebra/src/uniformscaling.jl b/stdlib/LinearAlgebra/src/uniformscaling.jl index 661bd28cb8f91..428acf469c9b2 100644 --- a/stdlib/LinearAlgebra/src/uniformscaling.jl +++ b/stdlib/LinearAlgebra/src/uniformscaling.jl @@ -118,7 +118,7 @@ function show(io::IO, ::MIME"text/plain", J::UniformScaling) end copy(J::UniformScaling) = UniformScaling(J.λ) -Base.convert(::Type{UniformScaling{T}}, J::UniformScaling) where {T} = UniformScaling(convert(T, J.λ)) +Base.convert(::Type{UniformScaling{T}}, J::UniformScaling) where {T} = UniformScaling(convert(T, J.λ))::UniformScaling{T} conj(J::UniformScaling) = UniformScaling(conj(J.λ)) real(J::UniformScaling) = UniformScaling(real(J.λ)) diff --git a/stdlib/LinearAlgebra/test/adjtrans.jl b/stdlib/LinearAlgebra/test/adjtrans.jl index 7b782d463768d..e96ea28531d37 100644 --- a/stdlib/LinearAlgebra/test/adjtrans.jl +++ b/stdlib/LinearAlgebra/test/adjtrans.jl @@ -588,24 +588,52 @@ end @test transpose(Int[]) * Int[] == 0 end -@testset "reductions: $adjtrans" for adjtrans in [transpose, adjoint] - mat = rand(ComplexF64, 3,5) - @test sum(adjtrans(mat)) ≈ sum(collect(adjtrans(mat))) - @test sum(adjtrans(mat), dims=1) ≈ sum(collect(adjtrans(mat)), dims=1) - @test sum(adjtrans(mat), dims=(1,2)) ≈ sum(collect(adjtrans(mat)), dims=(1,2)) - - @test sum(imag, adjtrans(mat)) ≈ sum(imag, collect(adjtrans(mat))) - @test sum(imag, adjtrans(mat), dims=1) ≈ sum(imag, collect(adjtrans(mat)), dims=1) - - mat = [rand(ComplexF64,2,2) for _ in 1:3, _ in 1:5] - @test sum(adjtrans(mat)) ≈ sum(collect(adjtrans(mat))) - @test sum(adjtrans(mat), dims=1) ≈ sum(collect(adjtrans(mat)), dims=1) - @test sum(adjtrans(mat), dims=(1,2)) ≈ sum(collect(adjtrans(mat)), dims=(1,2)) - - @test sum(imag, adjtrans(mat)) ≈ sum(imag, collect(adjtrans(mat))) - @test sum(x -> x[1,2], adjtrans(mat)) ≈ sum(x -> x[1,2], collect(adjtrans(mat))) - @test sum(imag, adjtrans(mat), dims=1) ≈ sum(imag, collect(adjtrans(mat)), dims=1) - @test sum(x -> x[1,2], adjtrans(mat), dims=1) ≈ sum(x -> x[1,2], collect(adjtrans(mat)), dims=1) +@testset "reductions: $adjtrans" for adjtrans in (transpose, adjoint) + for (reduction, reduction!, op) in ((sum, sum!, +), (prod, prod!, *), (minimum, minimum!, min), (maximum, maximum!, max)) + T = op in (max, min) ? Float64 : ComplexF64 + mat = rand(T, 3,5) + rd1 = zeros(T, 1, 3) + rd2 = zeros(T, 5, 1) + rd3 = zeros(T, 1, 1) + @test reduction(adjtrans(mat)) ≈ reduction(copy(adjtrans(mat))) + @test reduction(adjtrans(mat), dims=1) ≈ reduction(copy(adjtrans(mat)), dims=1) + @test reduction(adjtrans(mat), dims=2) ≈ reduction(copy(adjtrans(mat)), dims=2) + @test reduction(adjtrans(mat), dims=(1,2)) ≈ reduction(copy(adjtrans(mat)), dims=(1,2)) + + @test reduction!(rd1, adjtrans(mat)) ≈ reduction!(rd1, copy(adjtrans(mat))) + @test reduction!(rd2, adjtrans(mat)) ≈ reduction!(rd2, copy(adjtrans(mat))) + @test reduction!(rd3, adjtrans(mat)) ≈ reduction!(rd3, copy(adjtrans(mat))) + + @test reduction(imag, adjtrans(mat)) ≈ reduction(imag, copy(adjtrans(mat))) + @test reduction(imag, adjtrans(mat), dims=1) ≈ reduction(imag, copy(adjtrans(mat)), dims=1) + @test reduction(imag, adjtrans(mat), dims=2) ≈ reduction(imag, copy(adjtrans(mat)), dims=2) + @test reduction(imag, adjtrans(mat), dims=(1,2)) ≈ reduction(imag, copy(adjtrans(mat)), dims=(1,2)) + + @test Base.mapreducedim!(imag, op, rd1, adjtrans(mat)) ≈ Base.mapreducedim!(imag, op, rd1, copy(adjtrans(mat))) + @test Base.mapreducedim!(imag, op, rd2, adjtrans(mat)) ≈ Base.mapreducedim!(imag, op, rd2, copy(adjtrans(mat))) + @test Base.mapreducedim!(imag, op, rd3, adjtrans(mat)) ≈ Base.mapreducedim!(imag, op, rd3, copy(adjtrans(mat))) + + op in (max, min) && continue + mat = [rand(T,2,2) for _ in 1:3, _ in 1:5] + rd1 = fill(zeros(T, 2, 2), 1, 3) + rd2 = fill(zeros(T, 2, 2), 5, 1) + rd3 = fill(zeros(T, 2, 2), 1, 1) + @test reduction(adjtrans(mat)) ≈ reduction(copy(adjtrans(mat))) + @test reduction(adjtrans(mat), dims=1) ≈ reduction(copy(adjtrans(mat)), dims=1) + @test reduction(adjtrans(mat), dims=2) ≈ reduction(copy(adjtrans(mat)), dims=2) + @test reduction(adjtrans(mat), dims=(1,2)) ≈ reduction(copy(adjtrans(mat)), dims=(1,2)) + + @test reduction(imag, adjtrans(mat)) ≈ reduction(imag, copy(adjtrans(mat))) + @test reduction(x -> x[1,2], adjtrans(mat)) ≈ reduction(x -> x[1,2], copy(adjtrans(mat))) + @test reduction(imag, adjtrans(mat), dims=1) ≈ reduction(imag, copy(adjtrans(mat)), dims=1) + @test reduction(x -> x[1,2], adjtrans(mat), dims=1) ≈ reduction(x -> x[1,2], copy(adjtrans(mat)), dims=1) + end + # see #46605 + Ac = [1 2; 3 4]' + @test mapreduce(identity, (x, y) -> 10x+y, copy(Ac)) == mapreduce(identity, (x, y) -> 10x+y, Ac) == 1234 + @test extrema([3,7,4]') == (3, 7) + @test mapreduce(x -> [x;;;], +, [1, 2, 3]') == sum(x -> [x;;;], [1, 2, 3]') == [6;;;] + @test mapreduce(string, *, [1 2; 3 4]') == mapreduce(string, *, copy([1 2; 3 4]')) == "1234" end end # module TestAdjointTranspose diff --git a/stdlib/LinearAlgebra/test/bidiag.jl b/stdlib/LinearAlgebra/test/bidiag.jl index 8e589ffed31b6..c3242b705f110 100644 --- a/stdlib/LinearAlgebra/test/bidiag.jl +++ b/stdlib/LinearAlgebra/test/bidiag.jl @@ -623,14 +623,14 @@ end end @testset "generalized dot" begin - for elty in (Float64, ComplexF64) - dv = randn(elty, 5) - ev = randn(elty, 4) - x = randn(elty, 5) - y = randn(elty, 5) + for elty in (Float64, ComplexF64), n in (5, 1) + dv = randn(elty, n) + ev = randn(elty, n-1) + x = randn(elty, n) + y = randn(elty, n) for uplo in (:U, :L) B = Bidiagonal(dv, ev, uplo) - @test dot(x, B, y) ≈ dot(B'x, y) ≈ dot(x, Matrix(B), y) + @test dot(x, B, y) ≈ dot(B'x, y) ≈ dot(x, B*y) ≈ dot(x, Matrix(B), y) end dv = Vector{elty}(undef, 0) ev = Vector{elty}(undef, 0) @@ -638,7 +638,7 @@ end y = Vector{elty}(undef, 0) for uplo in (:U, :L) B = Bidiagonal(dv, ev, uplo) - @test dot(x, B, y) ≈ dot(zero(elty), zero(elty), zero(elty)) + @test dot(x, B, y) === zero(elty) end end end diff --git a/stdlib/LinearAlgebra/test/cholesky.jl b/stdlib/LinearAlgebra/test/cholesky.jl index 8e6cac65f7dfb..d1d00e2326dfb 100644 --- a/stdlib/LinearAlgebra/test/cholesky.jl +++ b/stdlib/LinearAlgebra/test/cholesky.jl @@ -303,6 +303,7 @@ end v = rand(5) @test cholesky(Diagonal(v)) \ B ≈ Diagonal(v) \ B @test B / cholesky(Diagonal(v)) ≈ B / Diagonal(v) + @test inv(cholesky(Diagonal(v)))::Diagonal ≈ Diagonal(1 ./ v) end struct WrappedVector{T} <: AbstractVector{T} diff --git a/stdlib/LinearAlgebra/test/dense.jl b/stdlib/LinearAlgebra/test/dense.jl index 9bdc732d1f67a..01f573bf43674 100644 --- a/stdlib/LinearAlgebra/test/dense.jl +++ b/stdlib/LinearAlgebra/test/dense.jl @@ -132,8 +132,20 @@ bimg = randn(n,2)/2 @testset "Lyapunov/Sylvester" begin x = lyap(a, a2) @test -a2 ≈ a*x + x*a' + y = lyap(a', a2') + @test y ≈ lyap(Array(a'), Array(a2')) + @test -a2' ≈ a'y + y*a + z = lyap(Tridiagonal(a)', Diagonal(a2)) + @test z ≈ lyap(Array(Tridiagonal(a)'), Array(Diagonal(a2))) + @test -Diagonal(a2) ≈ Tridiagonal(a)'*z + z*Tridiagonal(a) x2 = sylvester(a[1:3, 1:3], a[4:n, 4:n], a2[1:3,4:n]) @test -a2[1:3, 4:n] ≈ a[1:3, 1:3]*x2 + x2*a[4:n, 4:n] + y2 = sylvester(a[1:3, 1:3]', a[4:n, 4:n]', a2[4:n,1:3]') + @test y2 ≈ sylvester(Array(a[1:3, 1:3]'), Array(a[4:n, 4:n]'), Array(a2[4:n,1:3]')) + @test -a2[4:n, 1:3]' ≈ a[1:3, 1:3]'*y2 + y2*a[4:n, 4:n]' + z2 = sylvester(Tridiagonal(a[1:3, 1:3]), Diagonal(a[4:n, 4:n]), a2[1:3,4:n]) + @test z2 ≈ sylvester(Array(Tridiagonal(a[1:3, 1:3])), Array(Diagonal(a[4:n, 4:n])), Array(a2[1:3,4:n])) + @test -a2[1:3, 4:n] ≈ Tridiagonal(a[1:3, 1:3])*z2 + z2*Diagonal(a[4:n, 4:n]) end @testset "Matrix square root" begin diff --git a/stdlib/LinearAlgebra/test/diagonal.jl b/stdlib/LinearAlgebra/test/diagonal.jl index 2cbedf49440ea..3e6f456c3de1e 100644 --- a/stdlib/LinearAlgebra/test/diagonal.jl +++ b/stdlib/LinearAlgebra/test/diagonal.jl @@ -462,6 +462,43 @@ end @test kron(Ad, Ad).diag == kron([1, 2, 3], [1, 2, 3]) end +# Define a vector type that does not support `deleteat!`, to ensure that `kron` handles this +struct SimpleVector{T} <: AbstractVector{T} + vec::Vector{T} +end +SimpleVector(x::SimpleVector) = SimpleVector(Vector(x.vec)) +SimpleVector{T}(::UndefInitializer, n::Integer) where {T} = SimpleVector(Vector{T}(undef, n)) +Base.:(==)(x::SimpleVector, y::SimpleVector) = x == y +Base.axes(x::SimpleVector) = axes(x.vec) +Base.convert(::Type{Vector{T}}, x::SimpleVector) where {T} = convert(Vector{T}, x.vec) +Base.convert(::Type{Vector}, x::SimpleVector{T}) where {T} = convert(Vector{T}, x) +Base.convert(::Type{Array{T}}, x::SimpleVector) where {T} = convert(Vector{T}, x) +Base.convert(::Type{Array}, x::SimpleVector) = convert(Vector, x) +Base.copyto!(x::SimpleVector, y::SimpleVector) = (copyto!(x.vec, y.vec); x) +Base.eltype(::Type{SimpleVector{T}}) where {T} = T +Base.getindex(x::SimpleVector, ind...) = getindex(x.vec, ind...) +Base.kron(x::SimpleVector, y::SimpleVector) = SimpleVector(kron(x.vec, y.vec)) +Base.promote_rule(::Type{<:AbstractVector{T}}, ::Type{SimpleVector{U}}) where {T,U} = Vector{promote_type(T, U)} +Base.promote_rule(::Type{SimpleVector{T}}, ::Type{SimpleVector{U}}) where {T,U} = SimpleVector{promote_type(T, U)} +Base.setindex!(x::SimpleVector, val, ind...) = (setindex!(x.vec, val, ind...), x) +Base.similar(x::SimpleVector, ::Type{T}) where {T} = SimpleVector(similar(x.vec, T)) +Base.similar(x::SimpleVector, ::Type{T}, dims::Dims{1}) where {T} = SimpleVector(similar(x.vec, T, dims)) +Base.size(x::SimpleVector) = size(x.vec) + +@testset "kron (issue #46456)" for repr in Any[identity, SimpleVector] + A = Diagonal(repr(randn(10))) + BL = Bidiagonal(repr(randn(10)), repr(randn(9)), :L) + BU = Bidiagonal(repr(randn(10)), repr(randn(9)), :U) + C = SymTridiagonal(repr(randn(10)), repr(randn(9))) + Cl = SymTridiagonal(repr(randn(10)), repr(randn(10))) + D = Tridiagonal(repr(randn(9)), repr(randn(10)), repr(randn(9))) + @test kron(A, BL)::Bidiagonal == kron(Array(A), Array(BL)) + @test kron(A, BU)::Bidiagonal == kron(Array(A), Array(BU)) + @test kron(A, C)::SymTridiagonal == kron(Array(A), Array(C)) + @test kron(A, Cl)::SymTridiagonal == kron(Array(A), Array(Cl)) + @test kron(A, D)::Tridiagonal == kron(Array(A), Array(D)) +end + @testset "svdvals and eigvals (#11120/#11247)" begin D = Diagonal(Matrix{Float64}[randn(3,3), randn(2,2)]) @test sort([svdvals(D)...;], rev = true) ≈ svdvals([D.diag[1] zeros(3,2); zeros(2,3) D.diag[2]]) @@ -653,6 +690,16 @@ end @test D2 == D * D end +@testset "multiplication of 2 Diagonal and a Matix (#46400)" begin + A = randn(10, 10) + D = Diagonal(randn(10)) + D2 = Diagonal(randn(10)) + @test D * A * D2 ≈ D * (A * D2) + @test D * A * D2 ≈ (D * A) * D2 + @test_throws DimensionMismatch Diagonal(ones(9)) * A * D2 + @test_throws DimensionMismatch D * A * Diagonal(ones(9)) +end + @testset "multiplication of QR Q-factor and Diagonal (#16615 spot test)" begin D = Diagonal(randn(5)) Q = qr(randn(5, 5)).Q @@ -1059,4 +1106,27 @@ end @test outTri === mul!(outTri, UTriA, D, 2, 1)::Tri == mul!(out, Matrix(UTriA), D, 2, 1) end +struct SMatrix1{T} <: AbstractArray{T,2} + elt::T +end +Base.:(==)(A::SMatrix1, B::SMatrix1) = A.elt == B.elt +Base.zero(::Type{SMatrix1{T}}) where {T} = SMatrix1(zero(T)) +Base.iszero(A::SMatrix1) = iszero(A.elt) +Base.getindex(A::SMatrix1, inds...) = A.elt +Base.size(::SMatrix1) = (1, 1) +@testset "map for Diagonal matrices (#46292)" begin + A = Diagonal([1]) + @test A isa Diagonal{Int,Vector{Int}} + @test 2*A isa Diagonal{Int,Vector{Int}} + @test A.+1 isa Matrix{Int} + # Numeric element types remain diagonal + B = map(SMatrix1, A) + @test B == fill(SMatrix1(1), 1, 1) + @test B isa Diagonal{SMatrix1{Int},Vector{SMatrix1{Int}}} + # Non-numeric element types become dense + C = map(a -> SMatrix1(string(a)), A) + @test C == fill(SMatrix1(string(1)), 1, 1) + @test C isa Matrix{SMatrix1{String}} +end + end # module TestDiagonal diff --git a/stdlib/LinearAlgebra/test/givens.jl b/stdlib/LinearAlgebra/test/givens.jl index c1d0caf7b8883..9f23fe4ffaa61 100644 --- a/stdlib/LinearAlgebra/test/givens.jl +++ b/stdlib/LinearAlgebra/test/givens.jl @@ -3,7 +3,7 @@ module TestGivens using Test, LinearAlgebra, Random -using LinearAlgebra: rmul!, lmul!, Givens +using LinearAlgebra: Givens, Rotation # Test givens rotations @testset for elty in (Float32, Float64, ComplexF32, ComplexF64) @@ -14,7 +14,7 @@ using LinearAlgebra: rmul!, lmul!, Givens end @testset for A in (raw_A, view(raw_A, 1:10, 1:10)) Ac = copy(A) - R = LinearAlgebra.Rotation(LinearAlgebra.Givens{elty}[]) + R = Rotation(Givens{elty}[]) for j = 1:8 for i = j+2:10 G, _ = givens(A, j+1, i, j) @@ -25,14 +25,19 @@ using LinearAlgebra: rmul!, lmul!, Givens @test lmul!(G,Matrix{elty}(I, 10, 10)) == [G[i,j] for i=1:10,j=1:10] @testset "transposes" begin - @test G'*G*Matrix(elty(1)I, 10, 10) ≈ Matrix(I, 10, 10) + @test (@inferred G'*G)*Matrix(elty(1)I, 10, 10) ≈ Matrix(I, 10, 10) @test (G*Matrix(elty(1)I, 10, 10))*G' ≈ Matrix(I, 10, 10) - @test copy(R')*(R*Matrix(elty(1)I, 10, 10)) ≈ Matrix(I, 10, 10) + @test (@inferred copy(R'))*(R*Matrix(elty(1)I, 10, 10)) ≈ Matrix(I, 10, 10) @test_throws ErrorException transpose(G) @test_throws ErrorException transpose(R) end end end + @test (R')' === R + @test R * A ≈ (A' * R')' ≈ lmul!(R, copy(A)) + @test A * R ≈ (R' * A')' ≈ rmul!(copy(A), R) + @test R' * A ≈ lmul!(R', copy(A)) + @test A * R' ≈ rmul!(copy(A), R') @test_throws ArgumentError givens(A, 3, 3, 2) @test_throws ArgumentError givens(one(elty),zero(elty),2,2) G, _ = givens(one(elty),zero(elty),11,12) diff --git a/stdlib/LinearAlgebra/test/special.jl b/stdlib/LinearAlgebra/test/special.jl index 3d83e2bf91204..78cbf655933cd 100644 --- a/stdlib/LinearAlgebra/test/special.jl +++ b/stdlib/LinearAlgebra/test/special.jl @@ -256,8 +256,7 @@ end @test hvcat((1,1), specialmata, specialmatb) == hvcat((1,1), MA, MB) @test cat(specialmata, specialmatb; dims=(1,2)) == cat(MA, MB; dims=(1,2)) end - # Test concatenating pairwise combinations of special matrices with sparse matrices, - # dense matrices, or dense vectors + # Test concatenating pairwise combinations of special matrices with dense matrices or dense vectors densevec = fill(1., N) densemat = diagm(0 => densevec) for specialmat in specialmats diff --git a/stdlib/LinearAlgebra/test/structuredbroadcast.jl b/stdlib/LinearAlgebra/test/structuredbroadcast.jl index 4aeca31a79a03..4855446bc194b 100644 --- a/stdlib/LinearAlgebra/test/structuredbroadcast.jl +++ b/stdlib/LinearAlgebra/test/structuredbroadcast.jl @@ -200,7 +200,7 @@ end Bu2 = 2 .* Bl @test typeof(Bl2) <: Bidiagonal && Bl2.uplo == 'L' - # Example of Nested Brodacasts + # Example of Nested Broadcasts tmp = (1 .* 2) .* (Bidiagonal(1:3, 1:2, 'U') .* (3 .* 4)) .* (5 .* Bidiagonal(1:3, 1:2, 'L')) @test typeof(tmp) <: Tridiagonal diff --git a/stdlib/LinearAlgebra/test/tridiag.jl b/stdlib/LinearAlgebra/test/tridiag.jl index ecdf6b416baa5..0698a583c8d45 100644 --- a/stdlib/LinearAlgebra/test/tridiag.jl +++ b/stdlib/LinearAlgebra/test/tridiag.jl @@ -434,7 +434,11 @@ end @testset "generalized dot" begin x = fill(convert(elty, 1), n) y = fill(convert(elty, 1), n) - @test dot(x, A, y) ≈ dot(A'x, y) + @test dot(x, A, y) ≈ dot(A'x, y) ≈ dot(x, A*y) + @test dot([1], SymTridiagonal([1], Int[]), [1]) == 1 + @test dot([1], Tridiagonal(Int[], [1], Int[]), [1]) == 1 + @test dot(Int[], SymTridiagonal(Int[], Int[]), Int[]) === 0 + @test dot(Int[], Tridiagonal(Int[], Int[], Int[]), Int[]) === 0 end end end diff --git a/stdlib/Logging/src/ConsoleLogger.jl b/stdlib/Logging/src/ConsoleLogger.jl index bb040aac91858..359b4019fb17c 100644 --- a/stdlib/Logging/src/ConsoleLogger.jl +++ b/stdlib/Logging/src/ConsoleLogger.jl @@ -118,7 +118,7 @@ function handle_message(logger::ConsoleLogger, level::LogLevel, message, _module # split into lines. msglines = [(indent=0, msg=l) for l in split(chomp(convert(String, string(message))::String), '\n')] stream = logger.stream - if !isopen(stream) + if !(isopen(stream)::Bool) stream = stderr end dsize = displaysize(stream)::Tuple{Int,Int} diff --git a/stdlib/NetworkOptions.version b/stdlib/NetworkOptions.version index 483d6bd51694b..0cb2701f710e1 100644 --- a/stdlib/NetworkOptions.version +++ b/stdlib/NetworkOptions.version @@ -1,4 +1,4 @@ NETWORKOPTIONS_BRANCH = master -NETWORKOPTIONS_SHA1 = 4d3df6445bbca0556a7a9f2abb0e48ba7d774f5a +NETWORKOPTIONS_SHA1 = 8ce1e104eeddcf9c7ccb387dc4811ddb1c750cc2 NETWORKOPTIONS_GIT_URL := https://github.com/JuliaLang/NetworkOptions.jl.git NETWORKOPTIONS_TAR_URL = https://api.github.com/repos/JuliaLang/NetworkOptions.jl/tarball/$1 diff --git a/stdlib/OpenBLAS_jll/Project.toml b/stdlib/OpenBLAS_jll/Project.toml index 21fa9e9f0a0e6..f04e3491ad22b 100644 --- a/stdlib/OpenBLAS_jll/Project.toml +++ b/stdlib/OpenBLAS_jll/Project.toml @@ -1,6 +1,6 @@ name = "OpenBLAS_jll" uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" -version = "0.3.20+0" +version = "0.3.21+0" [deps] CompilerSupportLibraries_jll = "e66e0078-7015-5450-92f7-15fbd957f2ae" @@ -8,7 +8,7 @@ Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" [compat] -julia = "1.7" +julia = "1.9" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 49cb1c091ea5f..cc29b6aa26d2f 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = master -PKG_SHA1 = 8d77a6cac48113d143e028209aa28f10d5473032 +PKG_SHA1 = 3cbbd860afd4c2a50a80a04fa229fe5cd5bddc76 PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 diff --git a/stdlib/Printf/src/Printf.jl b/stdlib/Printf/src/Printf.jl index c8c6df9179730..9f14961aa2acf 100644 --- a/stdlib/Printf/src/Printf.jl +++ b/stdlib/Printf/src/Printf.jl @@ -89,7 +89,7 @@ struct InvalidFormatStringError <: Exception end function Base.showerror(io::IO, err::InvalidFormatStringError) - io_has_color = get(io, :color, false) + io_has_color = get(io, :color, false)::Bool println(io, "InvalidFormatStringError: ", err.message) print(io, " \"", @view(err.format[begin:prevind(err.format, err.start_color)])) @@ -281,7 +281,7 @@ end @inline function fmt(buf, pos, arg, spec::Spec{T}) where {T <: Strings} leftalign, hash, width, prec = spec.leftalign, spec.hash, spec.width, spec.precision str = string(arg) - slen = textwidth(str) + (hash ? arg isa AbstractString ? 2 : 1 : 0) + slen = textwidth(str)::Int + (hash ? arg isa AbstractString ? 2 : 1 : 0) op = p = prec == -1 ? slen : min(slen, prec) if !leftalign && width > p for _ = 1:(width - p) diff --git a/stdlib/Profile/src/Profile.jl b/stdlib/Profile/src/Profile.jl index 705fcb6fa1dc5..3621fe63bcaac 100644 --- a/stdlib/Profile/src/Profile.jl +++ b/stdlib/Profile/src/Profile.jl @@ -992,8 +992,8 @@ function tree!(root::StackFrameTree{T}, all::Vector{UInt64}, lidict::Union{LineI root.count += 1 startframe = i elseif !skip - pushfirst!(build, parent) if recur === :flat || recur === :flatc + pushfirst!(build, parent) # Rewind the `parent` tree back, if this exact ip was already present *higher* in the current tree found = false for j in 1:(startframe - i) diff --git a/stdlib/REPL/docs/src/index.md b/stdlib/REPL/docs/src/index.md index 203f377c9ba63..d696c069fbdb7 100644 --- a/stdlib/REPL/docs/src/index.md +++ b/stdlib/REPL/docs/src/index.md @@ -259,6 +259,7 @@ to do so), or pressing Esc and then the key. | `^W` | Delete previous text up to the nearest whitespace | | `meta-w` | Copy the current region in the kill ring | | `meta-W` | "Kill" the current region, placing the text in the kill ring | +| `^U` | "Kill" to beginning of line, placing the text in the kill ring | | `^K` | "Kill" to end of line, placing the text in the kill ring | | `^Y` | "Yank" insert the text from the kill ring | | `meta-y` | Replace a previously yanked text with an older entry from the kill ring | @@ -413,7 +414,7 @@ Tab completion can also help completing fields: ```julia-repl julia> x = 3 + 4im; -julia> julia> x.[TAB][TAB] +julia> x.[TAB][TAB] im re julia> import UUIDs @@ -616,6 +617,20 @@ julia> REPL.activate(CustomMod) var 8 bytes Int64 ``` +## IPython mode + +It is possible to get an interface which is similar to the IPython REPL with numbered input prompts and output prefixes. This is done by calling `REPL.ipython_mode!()`. If you want to have this enabled on startup, add +```julia +atreplinit() do repl + if !isdefined(repl, :interface) + repl.interface = REPL.setup_interface(repl) + end + REPL.ipython_mode!(repl) +end +``` + +to your `startup.jl` file. + ## TerminalMenus TerminalMenus is a submodule of the Julia REPL and enables small, low-profile interactive menus in the terminal. diff --git a/stdlib/REPL/src/LineEdit.jl b/stdlib/REPL/src/LineEdit.jl index 0d00063b5c880..047411c21d12f 100644 --- a/stdlib/REPL/src/LineEdit.jl +++ b/stdlib/REPL/src/LineEdit.jl @@ -49,6 +49,9 @@ mutable struct Prompt <: TextInterface prompt_prefix::Union{String,Function} # Same as prefix except after the prompt prompt_suffix::Union{String,Function} + output_prefix::Union{String,Function} + output_prefix_prefix::Union{String,Function} + output_prefix_suffix::Union{String,Function} keymap_dict::Dict{Char,Any} repl::Union{AbstractREPL,Nothing} complete::CompletionProvider @@ -322,23 +325,28 @@ end # Show available completions function show_completions(s::PromptState, completions::Vector{String}) - colmax = maximum(map(length, completions)) - num_cols = max(div(width(terminal(s)), colmax+2), 1) - entries_per_col, r = divrem(length(completions), num_cols) - entries_per_col += r != 0 # skip any lines of input after the cursor cmove_down(terminal(s), input_string_newlines_aftercursor(s)) println(terminal(s)) - for row = 1:entries_per_col - for col = 0:num_cols - idx = row + col*entries_per_col - if idx <= length(completions) - cmove_col(terminal(s), (colmax+2)*col+1) + if any(Base.Fix1(occursin, '\n'), completions) + foreach(Base.Fix1(println, terminal(s)), completions) + else + colmax = 2 + maximum(length, completions; init=1) # n.b. length >= textwidth + num_cols = max(div(width(terminal(s)), colmax), 1) + n = length(completions) + entries_per_col = cld(n, num_cols) + idx = 0 + for _ in 1:entries_per_col + for col = 0:(num_cols-1) + idx += 1 + idx > n && break + cmove_col(terminal(s), colmax*col+1) print(terminal(s), completions[idx]) end + println(terminal(s)) end - println(terminal(s)) end + # make space for the prompt for i = 1:input_string_newlines(s) println(terminal(s)) @@ -1447,7 +1455,6 @@ default_completion_cb(::IOBuffer) = [] default_enter_cb(_) = true write_prompt(terminal::AbstractTerminal, s::PromptState, color::Bool) = write_prompt(terminal, s.p, color) - function write_prompt(terminal::AbstractTerminal, p::Prompt, color::Bool) prefix = prompt_string(p.prompt_prefix) suffix = prompt_string(p.prompt_suffix) @@ -1459,6 +1466,17 @@ function write_prompt(terminal::AbstractTerminal, p::Prompt, color::Bool) return width end +function write_output_prefix(io::IO, p::Prompt, color::Bool) + prefix = prompt_string(p.output_prefix_prefix) + suffix = prompt_string(p.output_prefix_suffix) + print(io, prefix) + color && write(io, Base.text_colors[:bold]) + width = write_prompt(io, p.output_prefix, color) + color && write(io, Base.text_colors[:normal]) + print(io, suffix) + return width +end + # On Windows, when launching external processes, we cannot control what assumption they make on the # console mode. We thus forcibly reset the console mode at the start of the prompt to ensure they do # not leave the console mode in a corrupt state. @@ -1490,7 +1508,7 @@ end end # returns the width of the written prompt -function write_prompt(terminal, s::Union{AbstractString,Function}, color::Bool) +function write_prompt(terminal::Union{IO, AbstractTerminal}, s::Union{AbstractString,Function}, color::Bool) @static Sys.iswindows() && _reset_console_mode() promptstr = prompt_string(s)::String write(terminal, promptstr) @@ -1548,7 +1566,7 @@ function normalize_keys(keymap::Union{Dict{Char,Any},AnyDict}) return ret end -function add_nested_key!(keymap::Dict, key::Union{String, Char}, value; override = false) +function add_nested_key!(keymap::Dict{Char, Any}, key::Union{String, Char}, value; override::Bool = false) y = iterate(key) while y !== nothing c, i = y @@ -1563,7 +1581,7 @@ function add_nested_key!(keymap::Dict, key::Union{String, Char}, value; override elseif !(c in keys(keymap) && isa(keymap[c], Dict)) keymap[c] = Dict{Char,Any}() end - keymap = keymap[c] + keymap = keymap[c]::Dict{Char, Any} end end @@ -1708,7 +1726,7 @@ end function getEntry(keymap::Dict{Char,Any},key::Union{String,Char}) v = keymap for c in key - if !haskey(v,c) + if !(haskey(v,c)::Bool) return nothing end v = v[c] @@ -2586,6 +2604,9 @@ function Prompt(prompt ; prompt_prefix = "", prompt_suffix = "", + output_prefix = "", + output_prefix_prefix = "", + output_prefix_suffix = "", keymap_dict = default_keymap_dict, repl = nothing, complete = EmptyCompletionProvider(), @@ -2594,8 +2615,8 @@ function Prompt(prompt hist = EmptyHistoryProvider(), sticky = false) - return Prompt(prompt, prompt_prefix, prompt_suffix, keymap_dict, repl, - complete, on_enter, on_done, hist, sticky) + return Prompt(prompt, prompt_prefix, prompt_suffix, output_prefix, output_prefix_prefix, output_prefix_suffix, + keymap_dict, repl, complete, on_enter, on_done, hist, sticky) end run_interface(::Prompt) = nothing diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 9ef9d6b8a6f26..c7bc30b8d4b10 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -260,7 +260,12 @@ function display(d::REPLDisplay, mime::MIME"text/plain", x) x = Ref{Any}(x) with_repl_linfo(d.repl) do io io = IOContext(io, :limit => true, :module => active_module(d)::Module) - get(io, :color, false) && write(io, answer_color(d.repl)) + if d.repl isa LineEditREPL + mistate = d.repl.mistate + mode = LineEdit.mode(mistate) + LineEdit.write_output_prefix(io, mode, get(io, :color, false)::Bool) + end + get(io, :color, false)::Bool && write(io, answer_color(d.repl)) if isdefined(d.repl, :options) && isdefined(d.repl.options, :iocontext) # this can override the :limit property set initially io = foldl(IOContext, d.repl.options.iocontext, init=io) @@ -354,8 +359,7 @@ end consumer is an optional function that takes a REPLBackend as an argument """ -function run_repl(repl::AbstractREPL, @nospecialize(consumer = x -> nothing); backend_on_current_task::Bool = true) - backend = REPLBackend() +function run_repl(repl::AbstractREPL, @nospecialize(consumer = x -> nothing); backend_on_current_task::Bool = true, backend = REPLBackend()) backend_ref = REPLBackendRef(backend) cleanup = @task try destroy(backend_ref, t) @@ -467,7 +471,7 @@ mutable struct LineEditREPL <: AbstractREPL in_help,envcolors,false,nothing, opts, nothing, Tuple{String,Int}[]) end end -outstream(r::LineEditREPL) = r.t isa TTYTerminal ? r.t.out_stream : r.t +outstream(r::LineEditREPL) = (t = r.t; t isa TTYTerminal ? t.out_stream : t) specialdisplay(r::LineEditREPL) = r.specialdisplay specialdisplay(r::AbstractREPL) = nothing terminal(r::LineEditREPL) = r.t @@ -1062,7 +1066,7 @@ function setup_interface( shell_prompt_len = length(SHELL_PROMPT) help_prompt_len = length(HELP_PROMPT) - jl_prompt_regex = r"^(?:\(.+\) )?julia> " + jl_prompt_regex = r"^In \[[0-9]+\]: |^(?:\(.+\) )?julia> " pkg_prompt_regex = r"^(?:\(.+\) )?pkg> " # Canonicalize user keymap input @@ -1388,4 +1392,65 @@ function run_frontend(repl::StreamREPL, backend::REPLBackendRef) nothing end +module IPython + +using ..REPL + +__current_ast_transforms() = isdefined(Base, :active_repl_backend) ? Base.active_repl_backend.ast_transforms : REPL.repl_ast_transforms + +function repl_eval_counter(hp) + length(hp.history)-hp.start_idx +end + +function out_transform(x, repl::LineEditREPL, n::Ref{Int}) + return quote + julia_prompt = $repl.interface.modes[1] + mod = $REPL.active_module() + if !isdefined(mod, :Out) + setglobal!(mod, :Out, Dict{Int, Any}()) + end + local __temp_val = $x # workaround https://github.com/JuliaLang/julia/issues/46451 + if __temp_val !== getglobal(mod, :Out) && __temp_val !== nothing # remove this? + getglobal(mod, :Out)[$(n[])] = __temp_val + end + __temp_val + end +end + +function set_prompt(repl::LineEditREPL, n::Ref{Int}) + julia_prompt = repl.interface.modes[1] + julia_prompt.prompt = function() + n[] = repl_eval_counter(julia_prompt.hist)+1 + string("In [", n[], "]: ") + end +end + +function set_output_prefix(repl::LineEditREPL, n::Ref{Int}) + julia_prompt = repl.interface.modes[1] + if REPL.hascolor(repl) + julia_prompt.output_prefix_prefix = Base.text_colors[:red] + end + julia_prompt.output_prefix = () -> string("Out[", n[], "]: ") +end + +function __current_ast_transforms(backend) + if backend === nothing + isdefined(Base, :active_repl_backend) ? Base.active_repl_backend.ast_transforms : REPL.repl_ast_transforms + else + backend.ast_transforms + end +end + + +function ipython_mode!(repl::LineEditREPL=Base.active_repl, backend=nothing) + n = Ref{Int}(0) + set_prompt(repl, n) + set_output_prefix(repl, n) + push!(__current_ast_transforms(backend), ast -> out_transform(ast, repl, n)) + return +end +end + +import .IPython.ipython_mode! + end # module diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 7658a227b51cd..83bc5fa255e9e 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -409,9 +409,9 @@ function get_value(sym::Expr, fn) end sym.head !== :. && return (nothing, false) for ex in sym.args - ex, found = get_value(ex, fn) + ex, found = get_value(ex, fn)::Tuple{Any, Bool} !found && return (nothing, false) - fn, found = get_value(ex, fn) + fn, found = get_value(ex, fn)::Tuple{Any, Bool} !found && return (nothing, false) end return (fn, true) diff --git a/stdlib/REPL/test/lineedit.jl b/stdlib/REPL/test/lineedit.jl index 4b9ba05b2b1e6..90badda189348 100644 --- a/stdlib/REPL/test/lineedit.jl +++ b/stdlib/REPL/test/lineedit.jl @@ -906,3 +906,17 @@ end @test get_last_word("a[b[]]") == "b" @test get_last_word("a[]") == "a[]" end + +@testset "issue #45836" begin + term = FakeTerminal(IOBuffer(), IOBuffer(), IOBuffer()) + promptstate = REPL.LineEdit.init_state(term, REPL.LineEdit.mode(new_state())) + strings = ["abcdef", "123456", "ijklmn"] + REPL.LineEdit.show_completions(promptstate, strings) + completion = String(take!(term.out_stream)) + @test completion == "\033[0B\n\rabcdef\r\033[8C123456\r\033[16Cijklmn\n" + strings2 = ["abcdef", "123456\nijklmn"] + promptstate = REPL.LineEdit.init_state(term, REPL.LineEdit.mode(new_state())) + REPL.LineEdit.show_completions(promptstate, strings2) + completion2 = String(take!(term.out_stream)) + @test completion2 == "\033[0B\nabcdef\n123456\nijklmn\n" +end diff --git a/stdlib/REPL/test/repl.jl b/stdlib/REPL/test/repl.jl index fcc571d8a44ef..0312e59419b1b 100644 --- a/stdlib/REPL/test/repl.jl +++ b/stdlib/REPL/test/repl.jl @@ -707,6 +707,11 @@ fake_repl() do stdin_write, stdout_read, repl wait(c) @test Main.A == 2 + # Test removal of prefix in single statement paste + sendrepl2("\e[200~In [12]: A = 2.2\e[201~\n") + wait(c) + @test Main.A == 2.2 + # Test removal of prefix in multiple statement paste sendrepl2("""\e[200~ julia> mutable struct T17599; a::Int; end @@ -1548,3 +1553,37 @@ fake_repl() do stdin_write, stdout_read, repl LineEdit.edit_input(s, input_f) @test buffercontents(LineEdit.buffer(s)) == "1234αβ56γ" end + +# Non standard output_prefix, tested via `ipython_mode!` +fake_repl() do stdin_write, stdout_read, repl + repl.interface = REPL.setup_interface(repl) + + backend = REPL.REPLBackend() + repltask = @async begin + REPL.run_repl(repl; backend) + end + + REPL.ipython_mode!(repl, backend) + + global c = Condition() + sendrepl2(cmd) = write(stdin_write, "$cmd\n notify($(curmod_prefix)c)\n") + + sendrepl2("\"z\" * \"z\"\n") + wait(c) + s = String(readuntil(stdout_read, "\"zz\""; keep=true)) + @test contains(s, "In [1]") + @test contains(s, "Out[1]: \"zz\"") + + sendrepl2("\"y\" * \"y\"\n") + wait(c) + s = String(readuntil(stdout_read, "\"yy\""; keep=true)) + @test contains(s, "Out[3]: \"yy\"") + + sendrepl2("Out[1] * Out[3]\n") + wait(c) + s = String(readuntil(stdout_read, "\"zzyy\""; keep=true)) + @test contains(s, "Out[5]: \"zzyy\"") + + write(stdin_write, '\x04') + Base.wait(repltask) +end diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl index 5d6232e4b7626..79821ba8de6e8 100644 --- a/stdlib/REPL/test/replcompletions.jl +++ b/stdlib/REPL/test/replcompletions.jl @@ -524,7 +524,7 @@ let s = "CompletionFoo.test4(CompletionFoo.test_y_array[1]()[1], CompletionFoo.t @test c[1] == string(first(methods(Main.CompletionFoo.test4, Tuple{String, String}))) end -# Test that string escaption is handled correct +# Test that string escaping is handled correct let s = """CompletionFoo.test4("\\"",""" c, r, res = test_complete(s) @test !res diff --git a/stdlib/REPL/test/runtests.jl b/stdlib/REPL/test/runtests.jl index 2d46491103d01..e152677ccf7bb 100644 --- a/stdlib/REPL/test/runtests.jl +++ b/stdlib/REPL/test/runtests.jl @@ -1,5 +1,8 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +# Make a copy of the original environment +original_env = copy(ENV) + module REPLTests include("repl.jl") end @@ -15,3 +18,13 @@ end module TerminalMenusTest include("TerminalMenus/runtests.jl") end + +# Restore the original environment +for k in keys(ENV) + if !haskey(original_env, k) + delete!(ENV, k) + end +end +for (k, v) in pairs(original_env) + ENV[k] = v +end diff --git a/stdlib/Random/src/RNGs.jl b/stdlib/Random/src/RNGs.jl index f79f113bc95eb..02ea1477961ac 100644 --- a/stdlib/Random/src/RNGs.jl +++ b/stdlib/Random/src/RNGs.jl @@ -466,7 +466,7 @@ end ##### Array : internal functions -# internal array-like type to circumevent the lack of flexibility with reinterpret +# internal array-like type to circumvent the lack of flexibility with reinterpret struct UnsafeView{T} <: DenseArray{T,1} ptr::Ptr{T} len::Int diff --git a/stdlib/Random/src/Random.jl b/stdlib/Random/src/Random.jl index 02bc609e55679..b9adb5ae39f54 100644 --- a/stdlib/Random/src/Random.jl +++ b/stdlib/Random/src/Random.jl @@ -215,7 +215,7 @@ end # TODO: make constraining constructors to enforce that those # types are <: Sampler{T} -##### Adapter to generate a randome value in [0, n] +##### Adapter to generate a random value in [0, n] struct LessThan{T<:Integer,S} <: Sampler{T} sup::T diff --git a/stdlib/Random/src/generation.jl b/stdlib/Random/src/generation.jl index ddbf6dce98bec..61e722a7719db 100644 --- a/stdlib/Random/src/generation.jl +++ b/stdlib/Random/src/generation.jl @@ -132,7 +132,7 @@ rand(r::AbstractRNG, sp::SamplerTrivial{<:UniformBits{T}}) where {T} = # rand_generic methods are intended to help RNG implementors with common operations # we don't call them simply `rand` as this can easily contribute to create -# amibuities with user-side methods (forcing the user to resort to @eval) +# ambiguities with user-side methods (forcing the user to resort to @eval) rand_generic(r::AbstractRNG, T::Union{Bool,Int8,UInt8,Int16,UInt16,Int32,UInt32}) = rand(r, UInt52Raw()) % T[] diff --git a/stdlib/Serialization/src/Serialization.jl b/stdlib/Serialization/src/Serialization.jl index a5c9fec8080b7..98bf7d447b3ec 100644 --- a/stdlib/Serialization/src/Serialization.jl +++ b/stdlib/Serialization/src/Serialization.jl @@ -79,7 +79,7 @@ const TAGS = Any[ @assert length(TAGS) == 255 -const ser_version = 19 # do not make changes without bumping the version #! +const ser_version = 20 # do not make changes without bumping the version #! format_version(::AbstractSerializer) = ser_version format_version(s::Serializer) = s.version @@ -364,7 +364,8 @@ function serialize_mod_names(s::AbstractSerializer, m::Module) p = parentmodule(m) if p === m || m === Base key = Base.root_module_key(m) - serialize(s, key.uuid === nothing ? nothing : key.uuid.value) + uuid = key.uuid + serialize(s, uuid === nothing ? nothing : uuid.value) serialize(s, Symbol(key.name)) else serialize_mod_names(s, p) @@ -1191,6 +1192,9 @@ function deserialize(s::AbstractSerializer, ::Type{CodeInfo}) end ci.propagate_inbounds = deserialize(s) ci.pure = deserialize(s) + if format_version(s) >= 20 + ci.has_fcall = deserialize(s) + end if format_version(s) >= 14 ci.constprop = deserialize(s)::UInt8 end diff --git a/stdlib/SharedArrays/src/SharedArrays.jl b/stdlib/SharedArrays/src/SharedArrays.jl index a961be4e534b3..90de5fbac75be 100644 --- a/stdlib/SharedArrays/src/SharedArrays.jl +++ b/stdlib/SharedArrays/src/SharedArrays.jl @@ -374,7 +374,7 @@ function SharedArray{TS,N}(A::Array{TA,N}) where {TS,TA,N} copyto!(S, A) end -convert(T::Type{<:SharedArray}, a::Array) = T(a) +convert(T::Type{<:SharedArray}, a::Array) = T(a)::T function deepcopy_internal(S::SharedArray, stackdict::IdDict) haskey(stackdict, S) && return stackdict[S] diff --git a/stdlib/SparseArrays.version b/stdlib/SparseArrays.version index bf095fd75fdff..fde765d570f09 100644 --- a/stdlib/SparseArrays.version +++ b/stdlib/SparseArrays.version @@ -1,4 +1,4 @@ SPARSEARRAYS_BRANCH = main -SPARSEARRAYS_SHA1 = 78e48c331d18212b01dd23f7be18cae13425a16f +SPARSEARRAYS_SHA1 = 91814c1e84421a9c43b2776fc9dc96ec25104ac8 SPARSEARRAYS_GIT_URL := https://github.com/JuliaSparse/SparseArrays.jl.git SPARSEARRAYS_TAR_URL = https://api.github.com/repos/JuliaSparse/SparseArrays.jl/tarball/$1 diff --git a/stdlib/TOML/src/print.jl b/stdlib/TOML/src/print.jl index 059414152f727..46c5ecc357fbd 100644 --- a/stdlib/TOML/src/print.jl +++ b/stdlib/TOML/src/print.jl @@ -78,7 +78,7 @@ printvalue(f::MbyFunc, io::IO, value::Integer; _...) = Base.print(io, Int64(value)) # TOML specifies 64-bit signed long range for integer printvalue(f::MbyFunc, io::IO, value::AbstractFloat; _...) = Base.print(io, isnan(value) ? "nan" : - isinf(value) ? string(value > 0 ? "+" : "-", "inf") : + !(isfinite(value)::Bool) ? string(value > 0 ? "+" : "-", "inf") : Float64(value)) # TOML specifies IEEE 754 binary64 for float function printvalue(f::MbyFunc, io::IO, value::AbstractString; _...) Base.print(io, "\"") diff --git a/stdlib/TOML/test/testfiles/valid/arrays-hetergeneous.jl b/stdlib/TOML/test/testfiles/valid/arrays-heterogeneous.jl similarity index 100% rename from stdlib/TOML/test/testfiles/valid/arrays-hetergeneous.jl rename to stdlib/TOML/test/testfiles/valid/arrays-heterogeneous.jl diff --git a/stdlib/TOML/test/testfiles/valid/arrays-hetergeneous.json b/stdlib/TOML/test/testfiles/valid/arrays-heterogeneous.json similarity index 100% rename from stdlib/TOML/test/testfiles/valid/arrays-hetergeneous.json rename to stdlib/TOML/test/testfiles/valid/arrays-heterogeneous.json diff --git a/stdlib/TOML/test/testfiles/valid/arrays-hetergeneous.toml b/stdlib/TOML/test/testfiles/valid/arrays-heterogeneous.toml similarity index 100% rename from stdlib/TOML/test/testfiles/valid/arrays-hetergeneous.toml rename to stdlib/TOML/test/testfiles/valid/arrays-heterogeneous.toml diff --git a/stdlib/TOML/test/toml_test.jl b/stdlib/TOML/test/toml_test.jl index 45fbd20dbcdab..7ad28a2b7af7b 100644 --- a/stdlib/TOML/test/toml_test.jl +++ b/stdlib/TOML/test/toml_test.jl @@ -46,7 +46,7 @@ end @test check_valid("array-string-quote-comma") @test check_valid("array-string-with-comma") @test check_valid("array-table-array-string-backslash") -@test check_valid("arrays-hetergeneous") +@test check_valid("arrays-heterogeneous") @test check_valid("arrays-nested") @test check_valid("arrays") @test check_valid("bool") diff --git a/stdlib/Tar.version b/stdlib/Tar.version index 7ba08fd461f88..05c1ccad51df5 100644 --- a/stdlib/Tar.version +++ b/stdlib/Tar.version @@ -1,4 +1,4 @@ TAR_BRANCH = master -TAR_SHA1 = 56062695b92920c8b75e997fb0c8c3b015d04b78 +TAR_SHA1 = 5914ef9b542b3689287d4bc322320ad9e8d40feb TAR_GIT_URL := https://github.com/JuliaIO/Tar.jl.git TAR_TAR_URL = https://api.github.com/repos/JuliaIO/Tar.jl/tarball/$1 diff --git a/stdlib/Test/docs/src/index.md b/stdlib/Test/docs/src/index.md index 077d350554775..1db2f1ab967f1 100644 --- a/stdlib/Test/docs/src/index.md +++ b/stdlib/Test/docs/src/index.md @@ -332,6 +332,148 @@ Test.detect_ambiguities Test.detect_unbound_args ``` +## Workflow for Testing Packages + +Using the tools available to us in the previous sections, here is a potential workflow of creating a package and adding tests to it. + +### Generating an Example Package + +For this workflow, we will create a package called `Example`: + +```julia +pkg> generate Example +shell> cd Example +shell> mkdir test +pkg> activate . +``` + +### Creating Sample Functions + +The number one requirement for testing a package is to have functionality to test. +For that, we will add some simple functions to `Example` that we can test. +Add the following to `src/Example.jl`: + +```julia +module Example + +function greet() + "Hello world!" +end + +function simple_add(a, b) + a + b +end + +function type_multiply(a::Float64, b::Float64) + a * b +end + +end +``` + +### Creating a Test Environment + +From within the root of the `Example` package, navigate to the `test` directory, activate a new environment there, and add the `Test` package to the environment: + +```julia +shell> cd test +pkg> activate . +(test) pkg> add Test +``` + +### Testing Our Package + +Now, we are ready to add tests to `Example`. +It is standard practice to create a file within the `test` directory called `runtests.jl` which contains the test sets we want to run. +Go ahead and create that file within the `test` directory and add the following code to it: + +```julia +using Example +using Test + +@testset "Example tests" begin + + @testset "Math tests" begin + include("math_tests.jl") + end + + @testset "Greeting tests" begin + include("greeting_tests.jl") + end +end +``` + +We will need to create those two included files, `math_tests.jl` and `greeting_tests.jl`, and add some tests to them. + +> **Note:** Notice how we did not have to specify add `Example` into the `test` environment's `Project.toml`. +> This is a benefit of Julia's testing system that you could [read about more here](https://pkgdocs.julialang.org/dev/creating-packages/). + +#### Writing Tests for `math_tests.jl` + +Using our knowledge of `Test.jl`, here are some example tests we could add to `math_tests.jl`: + +```julia +@testset "Testset 1" begin + @test 2 == simple_add(1, 1) + @test 3.5 == simple_add(1, 2.5) + @test_throws MethodError simple_add(1, "A") + @test_throws MethodError simple_add(1, 2, 3) +end + +@testset "Testset 2" begin + @test 1.0 == type_multiply(1.0, 1.0) + @test isa(type_multiply(2.0, 2.0), Float64) + @test_throws MethodError type_multiply(1, 2.5) +end +``` + +#### Writing Tests for `greeting_tests.jl` + +Using our knowledge of `Test.jl`, here are some example tests we could add to `math_tests.jl`: + +```julia +@testset "Testset 3" begin + @test "Hello world!" == greet() + @test_throws MethodError greet("Antonia") +end +``` + +### Testing Our Package + +Now that we have added our tests and our `runtests.jl` script in `test`, we can test our `Example` package by going back to the root of the `Example` package environment and reactivating the `Example` environment: + +```julia +shell> cd .. +pkg> activate . +``` + +From there, we can finally run our test suite as follows: + +```julia +(Example) pkg> test + Testing Example + Status `/tmp/jl_Yngpvy/Project.toml` + [fa318bd2] Example v0.1.0 `/home/src/Projects/tmp/errata/Example` + [8dfed614] Test `@stdlib/Test` + Status `/tmp/jl_Yngpvy/Manifest.toml` + [fa318bd2] Example v0.1.0 `/home/src/Projects/tmp/errata/Example` + [2a0f44e3] Base64 `@stdlib/Base64` + [b77e0a4c] InteractiveUtils `@stdlib/InteractiveUtils` + [56ddb016] Logging `@stdlib/Logging` + [d6f4376e] Markdown `@stdlib/Markdown` + [9a3f8284] Random `@stdlib/Random` + [ea8e919c] SHA `@stdlib/SHA` + [9e88b42a] Serialization `@stdlib/Serialization` + [8dfed614] Test `@stdlib/Test` + Testing Running tests... +Test Summary: | Pass Total +Example tests | 9 9 + Testing Example tests passed +``` + +And if all went correctly, you should see a similar output as above. +Using `Test.jl`, more complicated tests can be added for packages but this should ideally point developers in the direction of how to get started with testing their own created packages. + ```@meta DocTestSetup = nothing ``` diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index 69714de01de50..9c029f8918887 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -1204,10 +1204,11 @@ function get_test_counts(ts::DefaultTestSet) end end ts.anynonpass = (fails + errors + c_fails + c_errors > 0) - duration = if isnothing(ts.time_end) + (; time_start, time_end) = ts + duration = if isnothing(time_end) "" else - dur_s = ts.time_end - ts.time_start + dur_s = time_end - time_start if dur_s < 60 string(round(dur_s, digits = 1), "s") else @@ -1314,7 +1315,7 @@ end # With begin/end or function call When @testset is used, with begin/end or a single function call, the macro -starts a new test set in which to evaulate the given expression. +starts a new test set in which to evaluate the given expression. If no custom testset type is given it defaults to creating a `DefaultTestSet`. `DefaultTestSet` records all the results and, if there are any `Fail`s or @@ -1518,7 +1519,7 @@ end function failfast_print() printstyled("\nFail-fast enabled:"; color = Base.error_color(), bold=true) - printstyled(" Fail or Error occured\n\n"; color = Base.error_color()) + printstyled(" Fail or Error occurred\n\n"; color = Base.error_color()) end """ @@ -2126,49 +2127,6 @@ function _check_bitarray_consistency(B::BitArray{N}) where N return true end -# 0.7 deprecations - -begin - approx_full(x::AbstractArray) = x - approx_full(x::Number) = x - approx_full(x) = full(x) - - function test_approx_eq(va, vb, Eps, astr, bstr) - va = approx_full(va) - vb = approx_full(vb) - la, lb = length(LinearIndices(va)), length(LinearIndices(vb)) - if la != lb - error("lengths of ", astr, " and ", bstr, " do not match: ", - "\n ", astr, " (length $la) = ", va, - "\n ", bstr, " (length $lb) = ", vb) - end - diff = real(zero(eltype(va))) - for (xa, xb) = zip(va, vb) - if isfinite(xa) && isfinite(xb) - diff = max(diff, abs(xa-xb)) - elseif !isequal(xa,xb) - error("mismatch of non-finite elements: ", - "\n ", astr, " = ", va, - "\n ", bstr, " = ", vb) - end - end - - if !isnan(Eps) && !(diff <= Eps) - sdiff = string("|", astr, " - ", bstr, "| <= ", Eps) - error("assertion failed: ", sdiff, - "\n ", astr, " = ", va, - "\n ", bstr, " = ", vb, - "\n difference = ", diff, " > ", Eps) - end - end - - array_eps(a::AbstractArray{Complex{T}}) where {T} = eps(float(maximum(x->(isfinite(x) ? abs(x) : T(NaN)), a))) - array_eps(a) = eps(float(maximum(x->(isfinite(x) ? abs(x) : oftype(x,NaN)), a))) - - test_approx_eq(va, vb, astr, bstr) = - test_approx_eq(va, vb, 1E4*length(LinearIndices(va))*max(array_eps(va), array_eps(vb)), astr, bstr) -end - include("logging.jl") end # module diff --git a/stdlib/Test/src/logging.jl b/stdlib/Test/src/logging.jl index 1afd726e09df4..4e444874d0fb8 100644 --- a/stdlib/Test/src/logging.jl +++ b/stdlib/Test/src/logging.jl @@ -120,9 +120,9 @@ end # Log testing tools # Failure result type for log testing -mutable struct LogTestFailure <: Result +struct LogTestFailure <: Result orig_expr - source::Union{Nothing,LineNumberNode} + source::LineNumberNode patterns logs end @@ -153,8 +153,8 @@ function record(ts::DefaultTestSet, t::LogTestFailure) println() end # Hack: convert to `Fail` so that test summarization works correctly - push!(ts.results, Fail(:test, t.orig_expr, t.logs, nothing, nothing, t.source)) - t + push!(ts.results, Fail(:test, t.orig_expr, t.logs, nothing, nothing, t.source, false)) + return t end """ diff --git a/stdlib/libLLVM_jll/Project.toml b/stdlib/libLLVM_jll/Project.toml index 0ff44a6fe7bcc..8332d68102f8e 100644 --- a/stdlib/libLLVM_jll/Project.toml +++ b/stdlib/libLLVM_jll/Project.toml @@ -1,6 +1,6 @@ name = "libLLVM_jll" uuid = "8f36deef-c2a5-5394-99ed-8e07531fb29a" -version = "14.0.5+3" +version = "14.0.6+0" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" diff --git a/test/arrayops.jl b/test/arrayops.jl index d4634a393aa86..45e7451c22a78 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -708,7 +708,7 @@ end ap = PermutedDimsArray(Array(a), (2,1,3)) @test strides(ap) == (3,1,12) - for A in [rand(1,2,3,4),rand(2,2,2,2),rand(5,6,5,6),rand(1,1,1,1)] + for A in [rand(1,2,3,4),rand(2,2,2,2),rand(5,6,5,6),rand(1,1,1,1), [rand(ComplexF64, 2,2) for _ in 1:2, _ in 1:3, _ in 1:2, _ in 1:4]] perm = randperm(4) @test isequal(A,permutedims(permutedims(A,perm),invperm(perm))) @test isequal(A,permutedims(permutedims(A,invperm(perm)),perm)) @@ -716,6 +716,10 @@ end @test sum(permutedims(A,perm)) ≈ sum(PermutedDimsArray(A,perm)) @test sum(permutedims(A,perm), dims=2) ≈ sum(PermutedDimsArray(A,perm), dims=2) @test sum(permutedims(A,perm), dims=(2,4)) ≈ sum(PermutedDimsArray(A,perm), dims=(2,4)) + + @test prod(permutedims(A,perm)) ≈ prod(PermutedDimsArray(A,perm)) + @test prod(permutedims(A,perm), dims=2) ≈ prod(PermutedDimsArray(A,perm), dims=2) + @test prod(permutedims(A,perm), dims=(2,4)) ≈ prod(PermutedDimsArray(A,perm), dims=(2,4)) end m = [1 2; 3 4] @@ -1136,7 +1140,7 @@ end @test isequal(setdiff([1,2,3,4], [7,8,9]), [1,2,3,4]) @test isequal(setdiff([1,2,3,4], Int64[]), Int64[1,2,3,4]) @test isequal(setdiff([1,2,3,4], [1,2,3,4,5]), Int64[]) - @test isequal(symdiff([1,2,3], [4,3,4]), [1,2]) + @test isequal(symdiff([1,2,3], [4,3,4]), [1,2,4]) @test isequal(symdiff(['e','c','a'], ['b','a','d']), ['e','c','b','d']) @test isequal(symdiff([1,2,3], [4,3], [5]), [1,2,4,5]) @test isequal(symdiff([1,2,3,4,5], [1,2,3], [3,4]), [3,5]) @@ -1203,10 +1207,9 @@ end @test o == fill(1, 3, 4) # issue #18524 - # m = mapslices(x->tuple(x), [1 2; 3 4], dims=1) # see variations of this below - # ERROR: fatal error in type inference (type bound), https://github.com/JuliaLang/julia/issues/43064 - # @test m[1,1] == ([1,3],) - # @test m[1,2] == ([2,4],) + m = mapslices(x->tuple(x), [1 2; 3 4], dims=1) # see variations of this below + @test m[1,1] == ([1,3],) + @test m[1,2] == ([2,4],) r = rand(Int8, 4,5,2) @test vec(mapslices(repr, r, dims=(2,1))) == map(repr, eachslice(r, dims=3)) @@ -1216,8 +1219,6 @@ end # failures @test_broken @inferred(mapslices(tuple, [1 2; 3 4], dims=1)) == [([1, 3],) ([2, 4],)] @test_broken @inferred(mapslices(transpose, r, dims=(1,3))) == permutedims(r, (3,2,1)) - # ERROR: fatal error in type inference (type bound), https://github.com/JuliaLang/julia/issues/43064 - @test_broken @inferred(mapslices(x -> tuple(x), [1 2; 3 4], dims=1)) == [([1, 3],) ([2, 4],)] # re-write, #40996 @test_throws ArgumentError mapslices(identity, rand(2,3), dims=0) # previously BoundsError diff --git a/test/bitset.jl b/test/bitset.jl index 1919da4f3702a..ca8e06adc1ec4 100644 --- a/test/bitset.jl +++ b/test/bitset.jl @@ -65,11 +65,13 @@ end @test !(-1 in BitSet(1:10)) end -# # issue #8570 -# This requires 2^29 bytes of storage, which is too much for a simple test -# s = BitSet(typemax(Int32)) -# @test length(s) === 1 -# for b in s; b; end +@testset "issue #8570" begin + let s + @test 400 > @allocated s = BitSet(typemax(Int32)) + @test length(s) === 1 + @test only(s) == typemax(Int32) + end +end @testset "union!, symdiff!" begin i = BitSet([1, 2, 3]) @@ -351,3 +353,12 @@ end # union! with an empty range doesn't modify the BitSet @test union!(x, b:a) == y end + +@testset "union!(::BitSet, ::AbstractUnitRange) when two ranges do not overlap" begin + # see #45574 + a, b = rand(-10000:-5000), rand(5000:10000) + c, d = minmax(rand(20000:30000, 2)...) + @test length(union!(BitSet(a:b), c:d)) == length(a:b) + length(c:d) + c, d = minmax(rand(-30000:-20000, 2)...) + @test length(union!(BitSet(a:b), c:d)) == length(a:b) + length(c:d) +end diff --git a/test/ccall.jl b/test/ccall.jl index 3a1b6ff3db733..e3d52cc1498db 100644 --- a/test/ccall.jl +++ b/test/ccall.jl @@ -1125,12 +1125,12 @@ struct Struct_AA64_2 v2::Float64 end -# This is a homogenious short vector aggregate +# This is a homogeneous short vector aggregate struct Struct_AA64_3 v1::VecReg{8,Int8} v2::VecReg{2,Float32} end -# This is NOT a homogenious short vector aggregate +# This is NOT a homogeneous short vector aggregate struct Struct_AA64_4 v2::VecReg{2,Float32} v1::VecReg{8,Int16} @@ -1590,6 +1590,32 @@ function caller22734(ptr) end @test caller22734(ptr22734) === 32.0 +# issue #46786 -- non-isbitstypes passed "by-value" +struct NonBits46786 + x::Union{Int16,NTuple{3,UInt8}} +end +let ptr = @cfunction(identity, NonBits46786, (NonBits46786,)) + obj1 = NonBits46786((0x01,0x02,0x03)) + obj2 = ccall(ptr, NonBits46786, (NonBits46786,), obj1) + @test obj1 === obj2 +end +let ptr = @cfunction(identity, Base.RefValue{NonBits46786}, (Base.RefValue{NonBits46786},)) + obj1 = Base.RefValue(NonBits46786((0x01,0x02,0x03))) + obj2 = ccall(ptr, Base.RefValue{NonBits46786}, (Base.RefValue{NonBits46786},), obj1) + @test obj1 !== obj2 + @test obj1.x === obj2.x +end + +mutable struct MutNonBits46786 + x::Union{Int16,NTuple{3,UInt8}} +end +let ptr = @cfunction(identity, MutNonBits46786, (MutNonBits46786,)) + obj1 = MutNonBits46786((0x01,0x02,0x03)) + obj2 = ccall(ptr, MutNonBits46786, (MutNonBits46786,), obj1) + @test obj1 !== obj2 + @test obj1.x === obj2.x +end + # 26297#issuecomment-371165725 # test that the first argument to cglobal is recognized as a tuple literal even through # macro expansion @@ -1791,7 +1817,7 @@ end str_identity = @cfunction(identity, Cstring, (Cstring,)) foo = @ccall $str_identity("foo"::Cstring)::Cstring @test unsafe_string(foo) == "foo" - # test interpolation of an expresison that returns a pointer. + # test interpolation of an expression that returns a pointer. foo = @ccall $(@cfunction(identity, Cstring, (Cstring,)))("foo"::Cstring)::Cstring @test unsafe_string(foo) == "foo" diff --git a/test/choosetests.jl b/test/choosetests.jl index f5775bbc00911..95ca708b1d142 100644 --- a/test/choosetests.jl +++ b/test/choosetests.jl @@ -140,10 +140,12 @@ function choosetests(choices = []) "strings/io", "strings/types"]) # do subarray before sparse but after linalg filtertests!(tests, "subarray") - filtertests!(tests, "compiler", ["compiler/inference", "compiler/effects", - "compiler/validation", "compiler/ssair", "compiler/irpasses", "compiler/codegen", - "compiler/inline", "compiler/contextual", "compiler/AbstractInterpreter", - "compiler/EscapeAnalysis/local", "compiler/EscapeAnalysis/interprocedural"]) + filtertests!(tests, "compiler", [ + "compiler/datastructures", "compiler/inference", "compiler/effects", + "compiler/validation", "compiler/ssair", "compiler/irpasses", + "compiler/codegen", "compiler/inline", "compiler/contextual", + "compiler/AbstractInterpreter", "compiler/EscapeAnalysis/local", + "compiler/EscapeAnalysis/interprocedural"]) filtertests!(tests, "compiler/EscapeAnalysis", [ "compiler/EscapeAnalysis/local", "compiler/EscapeAnalysis/interprocedural"]) filtertests!(tests, "stdlib", STDLIBS) diff --git a/test/clangsa/GCPushPop.cpp b/test/clangsa/GCPushPop.cpp index f8dcfdafa5aa9..ac9f3bfb354b8 100644 --- a/test/clangsa/GCPushPop.cpp +++ b/test/clangsa/GCPushPop.cpp @@ -3,6 +3,7 @@ // RUN: clang -D__clang_gcanalyzer__ --analyze -Xanalyzer -analyzer-output=text -Xclang -load -Xclang libGCCheckerPlugin%shlibext -Xclang -verify -I%julia_home/src -I%julia_home/src/support -I%julia_home/usr/include ${CLANGSA_FLAGS} ${CPPFLAGS} ${CFLAGS} -Xclang -analyzer-checker=core,julia.GCChecker --analyzer-no-default-checks -x c++ %s #include "julia.h" +#include void missingPop() { jl_value_t *x = NULL; @@ -34,3 +35,22 @@ void jl_gc_run_finalizers_in_list(jl_ptls_t ptls, arraylist_t *list) // run_finalizer(ptls, items[i], items[i + 1]); JL_GC_POP(); } + +void safepoint(void); +bool testfunc1() JL_NOTSAFEPOINT +{ + struct implied_struct1 { // expected-note{{Tried to call method defined here}} + std::string s; + struct implied_constructor { } x; + } x; // expected-warning{{Calling potential safepoint as CXXConstructorCall from function annotated JL_NOTSAFEPOINT}} + // expected-note@-1{{Calling potential safepoint as CXXConstructorCall from function annotated JL_NOTSAFEPOINT}} + return 1; +} +bool testfunc2() JL_NOTSAFEPOINT +{ + struct implied_struct2 { // expected-note{{Tried to call method defined here}} + std::string s; + } x{""}; + return 1; // expected-warning{{Calling potential safepoint as CXXDestructorCall from function annotated JL_NOTSAFEPOINT}} + // expected-note@-1{{Calling potential safepoint as CXXDestructorCall from function annotated JL_NOTSAFEPOINT}} +} diff --git a/test/compiler/AbstractInterpreter.jl b/test/compiler/AbstractInterpreter.jl index 3dc98ca4d513d..9250f6d22fae2 100644 --- a/test/compiler/AbstractInterpreter.jl +++ b/test/compiler/AbstractInterpreter.jl @@ -34,8 +34,9 @@ macro newinterp(name) end end -# `OverlayMethodTable` -# -------------------- +# OverlayMethodTable +# ================== + import Base.Experimental: @MethodTable, @overlay @newinterp MTOverlayInterp @@ -110,3 +111,122 @@ Base.@assume_effects :total totalcall(f, args...) = f(args...) return missing end end |> only === Nothing + +# AbstractLattice +# =============== + +using Core: SlotNumber, Argument +using Core.Compiler: slot_id, tmerge_fast_path +import .CC: + AbstractLattice, BaseInferenceLattice, IPOResultLattice, InferenceLattice, OptimizerLattice, + widen, is_valid_lattice, typeinf_lattice, ipo_lattice, optimizer_lattice, + widenconst, tmeet, tmerge, ⊑, abstract_eval_special_value, widenreturn, + widenlattice + +@newinterp TaintInterpreter +struct TaintLattice{PL<:AbstractLattice} <: CC.AbstractLattice + parent::PL +end +CC.widen(𝕃::TaintLattice) = 𝕃.parent +CC.is_valid_lattice(𝕃::TaintLattice, @nospecialize(elm)) = + is_valid_lattice(widenlattice(𝕃), elem) || isa(elm, Taint) + +struct InterTaintLattice{PL<:AbstractLattice} <: CC.AbstractLattice + parent::PL +end +CC.widen(𝕃::InterTaintLattice) = 𝕃.parent +CC.is_valid_lattice(𝕃::InterTaintLattice, @nospecialize(elm)) = + is_valid_lattice(widenlattice(𝕃), elem) || isa(elm, InterTaint) + +const AnyTaintLattice{L} = Union{TaintLattice{L},InterTaintLattice{L}} + +CC.typeinf_lattice(::TaintInterpreter) = InferenceLattice(TaintLattice(BaseInferenceLattice.instance)) +CC.ipo_lattice(::TaintInterpreter) = InferenceLattice(InterTaintLattice(IPOResultLattice.instance)) +CC.optimizer_lattice(::TaintInterpreter) = InterTaintLattice(OptimizerLattice()) + +struct Taint + typ + slots::BitSet + function Taint(@nospecialize(typ), slots::BitSet) + if typ isa Taint + slots = typ.slots ∪ slots + typ = typ.typ + end + return new(typ, slots) + end +end +Taint(@nospecialize(typ), id::Int) = Taint(typ, push!(BitSet(), id)) + +struct InterTaint + typ + slots::BitSet + function InterTaint(@nospecialize(typ), slots::BitSet) + if typ isa InterTaint + slots = typ.slots ∪ slots + typ = typ.typ + end + return new(typ, slots) + end +end +InterTaint(@nospecialize(typ), id::Int) = InterTaint(typ, push!(BitSet(), id)) + +const AnyTaint = Union{Taint, InterTaint} + +function CC.tmeet(𝕃::AnyTaintLattice, @nospecialize(v), @nospecialize(t::Type)) + T = isa(𝕃, TaintLattice) ? Taint : InterTaint + if isa(v, T) + v = v.typ + end + return tmeet(widenlattice(𝕃), v, t) +end +function CC.tmerge(𝕃::AnyTaintLattice, @nospecialize(typea), @nospecialize(typeb)) + r = tmerge_fast_path(𝕃, typea, typeb) + r !== nothing && return r + # type-lattice for Taint + T = isa(𝕃, TaintLattice) ? Taint : InterTaint + if isa(typea, T) + if isa(typeb, T) + return T( + tmerge(widenlattice(𝕃), typea.typ, typeb), + typea.slots ∪ typeb.slots) + else + typea = typea.typ + end + elseif isa(typeb, T) + typeb = typeb.typ + end + return tmerge(widenlattice(𝕃), typea, typeb) +end +function CC.:⊑(𝕃::AnyTaintLattice, @nospecialize(typea), @nospecialize(typeb)) + T = isa(𝕃, TaintLattice) ? Taint : InterTaint + if isa(typea, T) + if isa(typeb, T) + typea.slots ⊆ typeb.slots || return false + return ⊑(widenlattice(𝕃), typea.typ, typeb.typ) + end + typea = typea.typ + elseif isa(typeb, T) + return false + end + return ⊑(widenlattice(𝕃), typea, typeb) +end +CC.widenconst(taint::AnyTaint) = widenconst(taint.typ) + +function CC.abstract_eval_special_value(interp::TaintInterpreter, + @nospecialize(e), vtypes::CC.VarTable, sv::CC.InferenceState) + ret = @invoke CC.abstract_eval_special_value(interp::CC.AbstractInterpreter, + e::Any, vtypes::CC.VarTable, sv::CC.InferenceState) + if isa(e, SlotNumber) || isa(e, Argument) + return Taint(ret, slot_id(e)) + end + return ret +end + +function CC.widenreturn(𝕃::InferenceLattice{<:InterTaintLattice}, @nospecialize(rt), @nospecialize(bestguess), nargs::Int, slottypes::Vector{Any}, changes::CC.VarTable) + if isa(rt, Taint) + return InterTaint(rt.typ, BitSet((id for id in rt.slots if id ≤ nargs))) + end + return CC.widenreturn(widenlattice(𝕃), rt, bestguess, nargs, slottypes, changes) +end + +# code_typed(ifelse, (Bool, Int, Int); interp=TaintInterpreter()) diff --git a/test/compiler/EscapeAnalysis/EAUtils.jl b/test/compiler/EscapeAnalysis/EAUtils.jl index f8db1cb62f460..072c425139654 100644 --- a/test/compiler/EscapeAnalysis/EAUtils.jl +++ b/test/compiler/EscapeAnalysis/EAUtils.jl @@ -201,7 +201,7 @@ function run_passes_with_ea(interp::EscapeAnalyzer, ci::CodeInfo, sv::Optimizati cache_escapes!(interp, caller, state, cccopy(ir)) end catch err - @error "error happened within [IPO EA], insepct `Main.ir` and `Main.nargs`" + @error "error happened within [IPO EA], inspect `Main.ir` and `Main.nargs`" @eval Main (ir = $ir; nargs = $nargs) rethrow(err) end @@ -219,7 +219,7 @@ function run_passes_with_ea(interp::EscapeAnalyzer, ci::CodeInfo, sv::Optimizati try @timeit "[Local EA]" state = analyze_escapes(ir, nargs, true, get_escape_cache(interp)) catch err - @error "error happened within [Local EA], insepct `Main.ir` and `Main.nargs`" + @error "error happened within [Local EA], inspect `Main.ir` and `Main.nargs`" @eval Main (ir = $ir; nargs = $nargs) rethrow(err) end diff --git a/test/compiler/codegen.jl b/test/compiler/codegen.jl index 5db536af6222f..d7e87e00f1dac 100644 --- a/test/compiler/codegen.jl +++ b/test/compiler/codegen.jl @@ -754,3 +754,14 @@ struct MaybeTuple45476 end @test MaybeTuple45476((0,)).val[1] == 0f0 + +# Test int paths for getfield/isdefined +f_getfield_nospecialize(@nospecialize(x)) = getfield(x, 1) +f_isdefined_nospecialize(@nospecialize(x)) = isdefined(x, 1) + +@test !occursin("jl_box_int", get_llvm(f_getfield_nospecialize, Tuple{Any}, true, false, false)) +@test !occursin("jl_box_int", get_llvm(f_isdefined_nospecialize, Tuple{Any}, true, false, false)) + +# Test codegen for isa(::Any, Type) +f_isa_type(@nospecialize(x)) = isa(x, Type) +@test !occursin("jl_isa", get_llvm(f_isa_type, Tuple{Any}, true, false, false)) diff --git a/test/compiler/contextual.jl b/test/compiler/contextual.jl index e89b56e4bf6de..b2f51b2047563 100644 --- a/test/compiler/contextual.jl +++ b/test/compiler/contextual.jl @@ -1,5 +1,8 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +# Cassette +# ======== + module MiniCassette # A minimal demonstration of the cassette mechanism. Doesn't support all the # fancy features, but sufficient to exercise this code path in the compiler. @@ -129,17 +132,12 @@ foo(i) = i+bar(Val(1)) # Check that misbehaving pure functions propagate their error Base.@pure func1() = 42 Base.@pure func2() = (this_is_an_exception; func1()) - -let method = which(func2, ()) - mi = Core.Compiler.specialize_method(method, Tuple{typeof(func2)}, Core.svec()) - mi.inInference = true -end func3() = func2() @test_throws UndefVarError func3() - -## overlay method tables +# overlay method tables +# ===================== module OverlayModule @@ -157,7 +155,7 @@ end # parametric function def @overlay mt tan(x::T) where {T} = 3 -end +end # module OverlayModule methods = Base._methods_by_ftype(Tuple{typeof(sin), Float64}, nothing, 1, Base.get_world_counter()) @test only(methods).method.module === Base.Math diff --git a/test/compiler/datastructures.jl b/test/compiler/datastructures.jl new file mode 100644 index 0000000000000..0e75cfb7ace81 --- /dev/null +++ b/test/compiler/datastructures.jl @@ -0,0 +1,55 @@ +using Test + +@testset "CachedMethodTable" begin + # cache result should be separated per `limit` and `sig` + # https://github.com/JuliaLang/julia/pull/46799 + interp = Core.Compiler.NativeInterpreter() + table = Core.Compiler.method_table(interp) + sig = Tuple{typeof(*), Any, Any} + result1 = Core.Compiler.findall(sig, table; limit=-1) + result2 = Core.Compiler.findall(sig, table; limit=Core.Compiler.get_max_methods(*, @__MODULE__, interp)) + @test result1 !== Core.Compiler.missing && !Core.Compiler.isempty(result1.matches) + @test result2 === Core.Compiler.missing +end + +@testset "BitSetBoundedMinPrioritySet" begin + bsbmp = Core.Compiler.BitSetBoundedMinPrioritySet(5) + Core.Compiler.push!(bsbmp, 2) + Core.Compiler.push!(bsbmp, 2) + @test Core.Compiler.popfirst!(bsbmp) == 2 + Core.Compiler.push!(bsbmp, 1) + @test Core.Compiler.popfirst!(bsbmp) == 1 + @test Core.Compiler.isempty(bsbmp) +end + +@testset "basic heap functionality" begin + v = [2,3,1] + @test Core.Compiler.heapify!(v, Core.Compiler.Forward) === v + @test Core.Compiler.heappop!(v, Core.Compiler.Forward) === 1 + @test Core.Compiler.heappush!(v, 4, Core.Compiler.Forward) === v + @test Core.Compiler.heappop!(v, Core.Compiler.Forward) === 2 + @test Core.Compiler.heappop!(v, Core.Compiler.Forward) === 3 + @test Core.Compiler.heappop!(v, Core.Compiler.Forward) === 4 +end + +@testset "randomized heap correctness tests" begin + order = Core.Compiler.By(x -> -x[2]) + for i in 1:6 + heap = Tuple{Int, Int}[(rand(1:i), rand(1:i)) for _ in 1:2i] + mock = copy(heap) + @test Core.Compiler.heapify!(heap, order) === heap + sort!(mock, by=last) + + for _ in 1:6i + if rand() < .5 && !isempty(heap) + # The first entries may differ because heaps are not stable + @test last(Core.Compiler.heappop!(heap, order)) === last(pop!(mock)) + else + new = (rand(1:i), rand(1:i)) + Core.Compiler.heappush!(heap, new, order) + push!(mock, new) + sort!(mock, by=last) + end + end + end +end diff --git a/test/compiler/effects.jl b/test/compiler/effects.jl index 822d7489ee9fd..1a5043f49ddba 100644 --- a/test/compiler/effects.jl +++ b/test/compiler/effects.jl @@ -1,6 +1,106 @@ using Test include("irutils.jl") +# Test that the Core._apply_iterate bail path taints effects +function f_apply_bail(f) + f(()...) + return nothing +end +@test !Core.Compiler.is_removable_if_unused(Base.infer_effects(f_apply_bail)) +@test !fully_eliminated((Function,)) do f + f_apply_bail(f) + nothing +end + +# Test that arraysize has proper effect modeling +@test fully_eliminated(M->(size(M, 2); nothing), (Matrix{Float64},)) + +# Test that effect modeling for return_type doesn't incorrectly pick +# up the effects of the function being analyzed +f_throws() = error() +@noinline function return_type_unused(x) + Core.Compiler.return_type(f_throws, Tuple{}) + return x+1 +end +@test Core.Compiler.is_removable_if_unused(Base.infer_effects(return_type_unused, (Int,))) +@test fully_eliminated((Int,)) do x + return_type_unused(x) + return nothing +end + +# Test that ambiguous calls don't accidentally get nothrow effect +ambig_effects_test(a::Int, b) = 1 +ambig_effects_test(a, b::Int) = 1 +ambig_effects_test(a, b) = 1 +@test !Core.Compiler.is_nothrow(Base.infer_effects(ambig_effects_test, (Int, Any))) +global ambig_unknown_type_global::Any = 1 +@noinline function conditionally_call_ambig(b::Bool, a) + if b + ambig_effects_test(a, ambig_unknown_type_global) + end + return 0 +end +@test !fully_eliminated((Bool,)) do b + conditionally_call_ambig(b, 1) + return nothing +end + +# Test that a missing methtable identification gets tainted +# appropriately +struct FCallback; f::Union{Nothing, Function}; end +f_invoke_callback(fc) = let f=fc.f; (f !== nothing && f(); nothing); end +@test !Core.Compiler.is_removable_if_unused(Base.infer_effects(f_invoke_callback, (FCallback,))) +@test !fully_eliminated((FCallback,)) do fc + f_invoke_callback(fc) + return nothing +end + +# @assume_effects override +const ___CONST_DICT___ = Dict{Any,Any}(Symbol(c) => i for (i, c) in enumerate('a':'z')) +Base.@assume_effects :foldable concrete_eval( + f, args...; kwargs...) = f(args...; kwargs...) +@test fully_eliminated() do + concrete_eval(getindex, ___CONST_DICT___, :a) +end + +# terminates_globally override +# https://github.com/JuliaLang/julia/issues/41694 +Base.@assume_effects :terminates_globally function issue41694(x) + res = 1 + 1 < x < 20 || throw("bad") + while x > 1 + res *= x + x -= 1 + end + return res +end +@test Core.Compiler.is_foldable(Base.infer_effects(issue41694, (Int,))) +@test fully_eliminated() do + issue41694(2) +end + +Base.@assume_effects :terminates_globally function recur_termination1(x) + x == 1 && return 1 + 1 < x < 20 || throw("bad") + return x * recur_termination1(x-1) +end +@test Core.Compiler.is_foldable(Base.infer_effects(recur_termination1, (Int,))) +@test fully_eliminated() do + recur_termination1(12) +end + +Base.@assume_effects :terminates_globally function recur_termination21(x) + x == 1 && return 1 + 1 < x < 20 || throw("bad") + return recur_termination22(x) +end +recur_termination22(x) = x * recur_termination21(x-1) +@test Core.Compiler.is_foldable(Base.infer_effects(recur_termination21, (Int,))) +@test Core.Compiler.is_foldable(Base.infer_effects(recur_termination22, (Int,))) +@test fully_eliminated() do + recur_termination21(12) + recur_termination22(12) +end + # control flow backedge should taint `terminates` @test Base.infer_effects((Int,)) do n for i = 1:n; end @@ -104,6 +204,9 @@ function compare_inconsistent(x::T) where T end @test !compare_inconsistent(3) +# Effect modeling for Core.compilerbarrier +@test Base.infer_effects(Base.inferencebarrier, Tuple{Any}) |> Core.Compiler.is_removable_if_unused + # allocation/access of uninitialized fields should taint the :consistent-cy struct Maybe{T} x::T @@ -248,7 +351,7 @@ end |> !Core.Compiler.is_foldable entry_to_be_invalidated('a') end -@test !Core.Compiler.builtin_nothrow(Core.get_binding_type, Any[Rational{Int}, Core.Const(:foo)], Any) +@test !Core.Compiler.builtin_nothrow(Core.Compiler.fallback_lattice, Core.get_binding_type, Any[Rational{Int}, Core.Const(:foo)], Any) # Nothrow for assignment to globals global glob_assign_int::Int = 0 @@ -267,7 +370,7 @@ end # we should taint `nothrow` if the binding doesn't exist and isn't fixed yet, # as the cached effects can be easily wrong otherwise -# since the inference curently doesn't track "world-age" of global variables +# since the inference currently doesn't track "world-age" of global variables @eval global_assignment_undefinedyet() = $(GlobalRef(@__MODULE__, :UNDEFINEDYET)) = 42 setglobal!_nothrow_undefinedyet() = setglobal!(@__MODULE__, :UNDEFINEDYET, 42) let effects = Base.infer_effects() do @@ -552,3 +655,16 @@ end end # @testset "effects analysis on array construction" begin end # @testset "effects analysis on array ops" begin + +# Test that builtin_effects handles vararg correctly +@test !Core.Compiler.is_nothrow(Core.Compiler.builtin_effects(Core.Compiler.fallback_lattice, Core.isdefined, Any[String, Vararg{Any}], Bool)) + +# Test that :new can be eliminated even if an sparam is unknown +struct SparamUnused{T} + x + SparamUnused(x::T) where {T} = new{T}(x) +end +mksparamunused(x) = (SparamUnused(x); nothing) +let src = code_typed1(mksparamunused, (Any,)) + @test count(isnew, src.code) == 0 +end diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index cc955dbc64dab..226792b87c17d 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -163,7 +163,7 @@ tmerge_test(Tuple{}, Tuple{Complex, Vararg{Union{ComplexF32, ComplexF64}}}, @test Core.Compiler.tmerge(Vector{Int}, Core.Compiler.tmerge(Vector{String}, Union{Vector{Bool}, Vector{Symbol}})) == Vector @test Core.Compiler.tmerge(Base.BitIntegerType, Union{}) === Base.BitIntegerType @test Core.Compiler.tmerge(Union{}, Base.BitIntegerType) === Base.BitIntegerType -@test Core.Compiler.tmerge(Core.Compiler.InterConditional(1, Int, Union{}), Core.Compiler.InterConditional(2, String, Union{})) === Core.Compiler.Const(true) +@test Core.Compiler.tmerge(Core.Compiler.fallback_ipo_lattice, Core.Compiler.InterConditional(1, Int, Union{}), Core.Compiler.InterConditional(2, String, Union{})) === Core.Compiler.Const(true) struct SomethingBits x::Base.BitIntegerType @@ -379,7 +379,7 @@ struct A15259 x y end -# check that allocation was ellided +# check that allocation was elided @eval f15259(x,y) = (a = $(Expr(:new, :A15259, :x, :y)); (a.x, a.y, getfield(a,1), getfield(a, 2))) @test isempty(filter(x -> isa(x,Expr) && x.head === :(=) && isa(x.args[2], Expr) && x.args[2].head === :new, @@ -1160,6 +1160,9 @@ struct UnionIsdefinedB; x; end @test isdefined_tfunc(Union{UnionIsdefinedA,UnionIsdefinedB}, Const(:x)) === Const(true) @test isdefined_tfunc(Union{UnionIsdefinedA,UnionIsdefinedB}, Const(:y)) === Const(false) @test isdefined_tfunc(Union{UnionIsdefinedA,Nothing}, Const(:x)) === Bool +# https://github.com/aviatesk/JET.jl/issues/379 +fJET379(x::Union{Complex{T}, T}) where T = isdefined(x, :im) +@test only(Base.return_types(fJET379)) === Bool @noinline map3_22347(f, t::Tuple{}) = () @noinline map3_22347(f, t::Tuple) = (f(t[1]), map3_22347(f, Base.tail(t))...) @@ -1585,6 +1588,7 @@ g23024(TT::Tuple{DataType}) = f23024(TT[1], v23024) @test g23024((UInt8,)) === 2 @test !Core.Compiler.isconstType(Type{typeof(Union{})}) # could be Core.TypeofBottom or Type{Union{}} at runtime +@test !isa(Core.Compiler.getfield_tfunc(Type{Core.TypeofBottom}, Core.Compiler.Const(:name)), Core.Compiler.Const) @test Base.return_types(supertype, (Type{typeof(Union{})},)) == Any[Any] # issue #23685 @@ -3324,7 +3328,8 @@ f_generator_splat(t::Tuple) = tuple((identity(l) for l in t)...) @test Core.Compiler.sizeof_tfunc(UnionAll) === Int @test !Core.Compiler.sizeof_nothrow(UnionAll) -@test Base.return_types(Expr) == Any[Expr] +@test only(Base.return_types(Core._expr)) === Expr +@test only(Base.return_types(Core.svec, (Any,))) === Core.SimpleVector # Use a global constant to rely less on unrelated constant propagation const const_int32_typename = Int32.name @@ -4073,16 +4078,6 @@ g_max_methods(x) = f_max_methods(x) @test Core.Compiler.return_type(g_max_methods, Tuple{Int}) === Int @test Core.Compiler.return_type(g_max_methods, Tuple{Any}) === Any -# Unit tests for BitSetBoundedMinPrioritySet -let bsbmp = Core.Compiler.BitSetBoundedMinPrioritySet(5) - Core.Compiler.push!(bsbmp, 2) - Core.Compiler.push!(bsbmp, 2) - @test Core.Compiler.popfirst!(bsbmp) == 2 - Core.Compiler.push!(bsbmp, 1) - @test Core.Compiler.popfirst!(bsbmp) == 1 - @test Core.Compiler.isempty(bsbmp) -end - # Make sure return_type_tfunc doesn't accidentally cause bad inference if used # at top level. @test let @@ -4093,7 +4088,7 @@ end == Rational # vararg-tuple comparison within `PartialStruct` # https://github.com/JuliaLang/julia/issues/44965 let t = Core.Compiler.tuple_tfunc(Any[Core.Const(42), Vararg{Any}]) - @test Core.Compiler.issimplertype(t, t) + @test Core.Compiler.issimplertype(Core.Compiler.fallback_lattice, t, t) end # check the inference convergence with an empty vartable: @@ -4166,8 +4161,8 @@ for setting = (:type, :const, :conditional) end # https://github.com/JuliaLang/julia/issues/46426 -@noinline Base.@assume_effects :nothrow typebarrier() = Base.inferencebarrier(0.0) -@noinline Base.@assume_effects :nothrow constbarrier() = Base.compilerbarrier(:const, 0.0) +@noinline typebarrier() = Base.inferencebarrier(0.0) +@noinline constbarrier() = Base.compilerbarrier(:const, 0.0) let src = code_typed1() do typebarrier() end @@ -4184,3 +4179,46 @@ let src = code_typed1() do constbarrier() end |> only === Float64 end + +# Test that Const ⊑ PartialStruct respects vararg +@test Const((1,2)) ⊑ PartialStruct(Tuple{Vararg{Int}}, [Const(1), Vararg{Int}]) + +# Test that semi-concrete interpretation doesn't break on functions with while loops in them. +@Base.assume_effects :consistent :effect_free :terminates_globally function pure_annotated_loop(x::Int, y::Int) + for i = 1:2 + x += y + end + return y +end +call_pure_annotated_loop(x) = Val{pure_annotated_loop(x, 1)}() +@test only(Base.return_types(call_pure_annotated_loop, Tuple{Int})) === Val{1} + +function isa_kindtype(T::Type{<:AbstractVector}) + if isa(T, DataType) + # `T` here should be inferred as `DataType` rather than `Type{<:AbstractVector}` + return T.name.name # should be inferred as ::Symbol + end + return nothing +end +@test only(Base.return_types(isa_kindtype)) === Union{Nothing,Symbol} + +invoke_concretized1(a::Int) = a > 0 ? :int : nothing +invoke_concretized1(a::Integer) = a > 0 ? "integer" : nothing +# check if `invoke(invoke_concretized1, Tuple{Integer}, ::Int)` is foldable +@test Base.infer_effects((Int,)) do a + @invoke invoke_concretized1(a::Integer) +end |> Core.Compiler.is_foldable +@test Base.return_types() do + @invoke invoke_concretized1(42::Integer) +end |> only === String + +invoke_concretized2(a::Int) = a > 0 ? :int : nothing +invoke_concretized2(a::Integer) = a > 0 ? :integer : nothing +# check if `invoke(invoke_concretized2, Tuple{Integer}, ::Int)` is foldable +@test Base.infer_effects((Int,)) do a + @invoke invoke_concretized2(a::Integer) +end |> Core.Compiler.is_foldable +@test let + Base.Experimental.@force_compile + @invoke invoke_concretized2(42::Integer) +end === :integer diff --git a/test/compiler/inline.jl b/test/compiler/inline.jl index c94e12418e9a8..33cb793e908a0 100644 --- a/test/compiler/inline.jl +++ b/test/compiler/inline.jl @@ -601,7 +601,7 @@ g41299(f::Tf, args::Vararg{Any,N}) where {Tf,N} = f(args...) @test_throws TypeError g41299(>:, 1, 2) # https://github.com/JuliaLang/julia/issues/42078 -# idempotency of callsite inling +# idempotency of callsite inlining function getcache(mi::Core.MethodInstance) cache = Core.Compiler.code_cache(Core.Compiler.NativeInterpreter()) codeinf = Core.Compiler.get(cache, mi, nothing) @@ -638,7 +638,7 @@ let end begin - # more idempotency of callsite inling + # more idempotency of callsite inlining # ----------------------------------- # this test case requires forced constant propagation for callsite inlined function call, # particularly, in the following example, the inlinear will look up `+ₚ(::Point, ::Const(Point(2.25, 4.75)))` @@ -927,7 +927,7 @@ let # aggressive inlining of single, abstract method match (with constant-prop'e # both callsite should be inlined with constant-prop'ed result @test count(isinvoke(:isType), src.code) == 2 @test count(isinvoke(:has_free_typevars), src.code) == 0 - # `isGoodType(y::Any)` isn't fully convered, thus a runtime type check and fallback dynamic dispatch should be inserted + # `isGoodType(y::Any)` isn't fully covered, thus a runtime type check and fallback dynamic dispatch should be inserted @test count(iscall((src,isGoodType2)), src.code) == 1 end @@ -1078,17 +1078,6 @@ end nothing end -# Test that the Core._apply_iterate bail path taints effects -function f_apply_bail(f) - f(()...) - return nothing -end -f_call_apply_bail(f) = f_apply_bail(f) -@test !fully_eliminated(f_call_apply_bail, Tuple{Function}) - -# Test that arraysize has proper effect modeling -@test fully_eliminated(M->(size(M, 2); nothing), Tuple{Matrix{Float64}}) - # DCE of non-inlined callees @noinline noninlined_dce_simple(a) = identity(a) @test fully_eliminated((String,)) do s @@ -1116,72 +1105,6 @@ end nothing end -# Test that ambigous calls don't accidentally get nothrow effect -ambig_effect_test(a::Int, b) = 1 -ambig_effect_test(a, b::Int) = 1 -ambig_effect_test(a, b) = 1 -global ambig_unknown_type_global=1 -@noinline function conditionally_call_ambig(b::Bool, a) - if b - ambig_effect_test(a, ambig_unknown_type_global) - end - return 0 -end -function call_call_ambig(b::Bool) - conditionally_call_ambig(b, 1) - return 1 -end -@test !fully_eliminated(call_call_ambig, Tuple{Bool}) - -# Test that a missing methtable identification gets tainted -# appropriately -struct FCallback; f::Union{Nothing, Function}; end -f_invoke_callback(fc) = let f=fc.f; (f !== nothing && f(); nothing); end -function f_call_invoke_callback(f::FCallback) - f_invoke_callback(f) - return nothing -end -@test !fully_eliminated(f_call_invoke_callback, Tuple{FCallback}) - -# https://github.com/JuliaLang/julia/issues/41694 -Base.@assume_effects :terminates_globally function issue41694(x) - res = 1 - 1 < x < 20 || throw("bad") - while x > 1 - res *= x - x -= 1 - end - return res -end -@test fully_eliminated() do - issue41694(2) -end - -Base.@assume_effects :terminates_globally function recur_termination1(x) - x == 1 && return 1 - 1 < x < 20 || throw("bad") - return x * recur_termination1(x-1) -end -@test fully_eliminated() do - recur_termination1(12) -end -Base.@assume_effects :terminates_globally function recur_termination21(x) - x == 1 && return 1 - 1 < x < 20 || throw("bad") - return recur_termination22(x) -end -recur_termination22(x) = x * recur_termination21(x-1) -@test fully_eliminated() do - recur_termination21(12) + recur_termination22(12) -end - -const ___CONST_DICT___ = Dict{Any,Any}(Symbol(c) => i for (i, c) in enumerate('a':'z')) -Base.@assume_effects :foldable concrete_eval( - f, args...; kwargs...) = f(args...; kwargs...) -@test fully_eliminated() do - concrete_eval(getindex, ___CONST_DICT___, :a) -end - # https://github.com/JuliaLang/julia/issues/44732 struct Component44732 v @@ -1246,22 +1169,6 @@ end return maybe_error_int(1) end -# Test that effect modeling for return_type doesn't incorrectly pick -# up the effects of the function being analyzed -function f_throws() - error() -end - -@noinline function return_type_unused(x) - Core.Compiler.return_type(f_throws, Tuple{}) - return x+1 -end - -@test fully_eliminated(Tuple{Int}) do x - return_type_unused(x) - return nothing -end - # Test that inlining doesn't accidentally delete a bad return_type call f_bad_return_type() = Core.Compiler.return_type(+, 1, 2) @test_throws MethodError f_bad_return_type() @@ -1277,7 +1184,8 @@ end # Test that we can inline a finalizer for a struct that does not otherwise escape @noinline nothrow_side_effect(x) = - @Base.assume_effects :total !:effect_free @ccall jl_(x::Any)::Cvoid + Base.@assume_effects :total !:effect_free @ccall jl_(x::Any)::Cvoid +@test Core.Compiler.is_finalizer_inlineable(Base.infer_effects(nothrow_side_effect, (Nothing,))) mutable struct DoAllocNoEscape function DoAllocNoEscape() @@ -1379,24 +1287,42 @@ end # Test finalizers with static parameters mutable struct DoAllocNoEscapeSparam{T} - x::T - function finalizer_sparam(d::DoAllocNoEscapeSparam{T}) where {T} + x + @inline function finalizer_sparam(d::DoAllocNoEscapeSparam{T}) where {T} nothrow_side_effect(nothing) nothrow_side_effect(T) end - function DoAllocNoEscapeSparam{T}(x::T) where {T} + @inline function DoAllocNoEscapeSparam(x::T) where {T} finalizer(finalizer_sparam, new{T}(x)) end end -DoAllocNoEscapeSparam(x::T) where {T} = DoAllocNoEscapeSparam{T}(x) let src = code_typed1(Tuple{Any}) do x for i = 1:1000 DoAllocNoEscapeSparam(x) end end - # This requires more inlining enhancments. For now just make sure this - # doesn't error. - @test count(isnew, src.code) in (0, 1) # == 0 + @test count(x->isexpr(x, :static_parameter), src.code) == 0 # A bad inline might leave left-over :static_parameter + nnothrow_invokes = count(isinvoke(:nothrow_side_effect), src.code) + @test count(iscall(f->!isa(singleton_type(argextype(f, src)), Core.Builtin)), src.code) == + count(iscall((src, nothrow_side_effect)), src.code) == 2 - nnothrow_invokes + # TODO: Our effect modeling is not yet strong enough to fully eliminate this + @test_broken count(isnew, src.code) == 0 +end + +# Test finalizer varargs +function varargs_finalizer(args...) + nothrow_side_effect(args[1]) +end +mutable struct DoAllocNoEscapeNoVarargs + function DoAllocNoEscapeNoInline() + finalizer(noinline_finalizer, new()) + end +end +let src = code_typed1() do + for i = 1:1000 + DoAllocNoEscapeNoInline() + end + end end # Test noinline finalizer @@ -1439,6 +1365,206 @@ let src = code_typed1() do @test !any(isinvoke(:finalizer), src.code) end +const FINALIZATION_COUNT = Ref(0) +init_finalization_count!() = FINALIZATION_COUNT[] = 0 +get_finalization_count() = FINALIZATION_COUNT[] +@noinline add_finalization_count!(x) = FINALIZATION_COUNT[] += x +@noinline Base.@assume_effects :nothrow safeprint(io::IO, x...) = (@nospecialize; print(io, x...)) +@test Core.Compiler.is_finalizer_inlineable(Base.infer_effects(add_finalization_count!, (Int,))) + +mutable struct DoAllocWithField + x::Int + function DoAllocWithField(x::Int) + finalizer(new(x)) do this + add_finalization_count!(this.x) + end + end +end +mutable struct DoAllocWithFieldInter + x::Int +end +function register_finalizer!(obj::DoAllocWithFieldInter) + finalizer(obj) do this + add_finalization_count!(this.x) + end +end + +function const_finalization(io) + for i = 1:1000 + o = DoAllocWithField(1) + safeprint(io, o.x) + end +end +let src = code_typed1(const_finalization, (IO,)) + @test count(isinvoke(:add_finalization_count!), src.code) == 1 +end +let + init_finalization_count!() + const_finalization(IOBuffer()) + @test get_finalization_count() == 1000 +end + +# Test that finalizers that don't do anything are just erased from the IR +function useless_finalizer() + x = Ref(1) + finalizer(x) do x + nothing + end + return x +end +let src = code_typed1(useless_finalizer, ()) + @test count(iscall((src, Core.finalizer)), src.code) == 0 + @test length(src.code) == 2 +end + +# tests finalizer inlining when def/uses involve control flow +function cfg_finalization1(io) + for i = -999:1000 + o = DoAllocWithField(i) + if i == 1000 + safeprint(io, o.x, '\n') + elseif i > 0 + safeprint(io, o.x) + end + end +end +let src = code_typed1(cfg_finalization1, (IO,)) + @test count(isinvoke(:add_finalization_count!), src.code) == 1 +end +let + init_finalization_count!() + cfg_finalization1(IOBuffer()) + @test get_finalization_count() == 1000 +end + +function cfg_finalization2(io) + for i = -999:1000 + o = DoAllocWithField(1) + o.x = i # with `setfield!` + if i == 1000 + safeprint(io, o.x, '\n') + elseif i > 0 + safeprint(io, o.x) + end + end +end +let src = code_typed1(cfg_finalization2, (IO,)) + @test count(isinvoke(:add_finalization_count!), src.code) == 1 +end +let + init_finalization_count!() + cfg_finalization2(IOBuffer()) + @test get_finalization_count() == 1000 +end + +function cfg_finalization3(io) + for i = -999:1000 + o = DoAllocWithFieldInter(i) + register_finalizer!(o) + if i == 1000 + safeprint(io, o.x, '\n') + elseif i > 0 + safeprint(io, o.x) + end + end +end +let src = code_typed1(cfg_finalization3, (IO,)) + @test count(isinvoke(:add_finalization_count!), src.code) == 1 +end +let + init_finalization_count!() + cfg_finalization3(IOBuffer()) + @test get_finalization_count() == 1000 +end + +function cfg_finalization4(io) + for i = -999:1000 + o = DoAllocWithFieldInter(1) + o.x = i # with `setfield!` + register_finalizer!(o) + if i == 1000 + safeprint(io, o.x, '\n') + elseif i > 0 + safeprint(io, o.x) + end + end +end +let src = code_typed1(cfg_finalization4, (IO,)) + @test count(isinvoke(:add_finalization_count!), src.code) == 1 +end +let + init_finalization_count!() + cfg_finalization4(IOBuffer()) + @test get_finalization_count() == 1000 +end + +function cfg_finalization5(io) + for i = -999:1000 + o = DoAllocWithFieldInter(i) + if i == 1000 + safeprint(io, o.x, '\n') + elseif i > 0 + safeprint(io, o.x) + end + register_finalizer!(o) + end +end +let src = code_typed1(cfg_finalization5, (IO,)) + @test count(isinvoke(:add_finalization_count!), src.code) == 1 +end +let + init_finalization_count!() + cfg_finalization5(IOBuffer()) + @test get_finalization_count() == 1000 +end + +function cfg_finalization6(io) + for i = -999:1000 + o = DoAllocWithField(0) + if i == 1000 + o.x = i # with `setfield!` + elseif i > 0 + safeprint(io, o.x, '\n') + end + end +end +let src = code_typed1(cfg_finalization6, (IO,)) + @test count(isinvoke(:add_finalization_count!), src.code) == 1 +end +let + init_finalization_count!() + cfg_finalization6(IOBuffer()) + @test get_finalization_count() == 1000 +end + + +function cfg_finalization7(io) + for i = -999:1000 + o = DoAllocWithField(0) + o.x = 0 + if i == 1000 + o.x = i # with `setfield!` + end + o.x = i + if i == 999 + o.x = i + end + o.x = 0 + if i == 1000 + o.x = i + end + end +end +let src = code_typed1(cfg_finalization7, (IO,)) + @test count(isinvoke(:add_finalization_count!), src.code) == 1 +end +let + init_finalization_count!() + cfg_finalization7(IOBuffer()) + @test get_finalization_count() == 1000 +end + + # optimize `[push!|pushfirst!](::Vector{Any}, x...)` @testset "optimize `$f(::Vector{Any}, x...)`" for f = Any[push!, pushfirst!] @eval begin @@ -1519,3 +1645,67 @@ function oc_capture_oc(z) return oc2(z) end @test fully_eliminated(oc_capture_oc, (Int,)) + +@eval struct OldVal{T} + x::T + (OV::Type{OldVal{T}})() where T = $(Expr(:new, :OV)) +end +with_unmatched_typeparam1(x::OldVal{i}) where {i} = i +with_unmatched_typeparam2() = [ Base.donotdelete(OldVal{i}()) for i in 1:10000 ] +function with_unmatched_typeparam3() + f(x::OldVal{i}) where {i} = i + r = 0 + for i = 1:10000 + r += f(OldVal{i}()) + end + return r +end + +@testset "Inlining with unmatched type parameters" begin + let src = code_typed1(with_unmatched_typeparam1, (Any,)) + @test !any(@nospecialize(x) -> isexpr(x, :call) && length(x.args) == 1, src.code) + end + let src = code_typed1(with_unmatched_typeparam2) + @test !any(@nospecialize(x) -> isexpr(x, :call) && length(x.args) == 1, src.code) + end + let src = code_typed1(with_unmatched_typeparam3) + @test !any(@nospecialize(x) -> isexpr(x, :call) && length(x.args) == 1, src.code) + end +end + +# Test that semi-concrete eval can inline constant results +function twice_sitofp(x::Int, y::Int) + x = Base.sitofp(Float64, x) + y = Base.sitofp(Float64, y) + return (x, y) +end +call_twice_sitofp(x::Int) = twice_sitofp(x, 2) + +let src = code_typed1(call_twice_sitofp, (Int,)) + @test count(iscall((src, Base.sitofp)), src.code) == 1 +end + +# Test getfield modeling of Type{Ref{_A}} where _A +@test Core.Compiler.getfield_tfunc(Type, Core.Compiler.Const(:parameters)) !== Union{} +@test !isa(Core.Compiler.getfield_tfunc(Type{Tuple{Union{Int, Float64}, Int}}, Core.Compiler.Const(:name)), Core.Compiler.Const) +@test fully_eliminated(Base.ismutable, Tuple{Base.RefValue}) + +# TODO: Remove compute sparams for vararg_retrival +fvarargN_inline(x::Tuple{Vararg{Int, N}}) where {N} = N +fvarargN_inline(args...) = fvarargN_inline(args) +let src = code_typed1(fvarargN_inline, (Tuple{Vararg{Int}},)) + @test_broken count(iscall((src, Core._compute_sparams)), src.code) == 0 && + count(iscall((src, Core._svec_ref)), src.code) == 0 && + count(iscall((src, Core.nfields)), src.code) == 1 +end + +# Test effect annotation of declined inline unionsplit +f_union_unmatched(x::Union{Nothing, Type{T}}) where {T} = nothing +let src = code_typed1((Any,)) do x + if isa(x, Union{Nothing, Type}) + f_union_unmatched(x) + end + nothing + end + @test count(iscall((src, f_union_unmatched)), src.code) == 0 +end diff --git a/test/compiler/irpasses.jl b/test/compiler/irpasses.jl index f39137a391b08..1e5948182adb1 100644 --- a/test/compiler/irpasses.jl +++ b/test/compiler/irpasses.jl @@ -960,7 +960,7 @@ let # effect-freeness computation for array allocation end end - # shouldn't eliminate errorneous dead allocations + # shouldn't eliminate erroneous dead allocations bad_dims = [-1, typemax(Int)] for dim in bad_dims, N in 1:10 dims = ntuple(i->dim, N) diff --git a/test/compiler/irutils.jl b/test/compiler/irutils.jl index b44a656ea7b34..76f883d6cea2c 100644 --- a/test/compiler/irutils.jl +++ b/test/compiler/irutils.jl @@ -17,7 +17,12 @@ function iscall((src, f)::Tuple{IR,Base.Callable}, @nospecialize(x)) where IR<:U singleton_type(argextype(x, src)) === f end end -iscall(pred::Base.Callable, @nospecialize(x)) = isexpr(x, :call) && pred(x.args[1]) +function iscall(pred::Base.Callable, @nospecialize(x)) + if isexpr(x, :(=)) + x = x.args[2] + end + return isexpr(x, :call) && pred(x.args[1]) +end # check if `x` is a statically-resolved call of a function whose name is `sym` isinvoke(y) = @nospecialize(x) -> isinvoke(y, x) diff --git a/test/compiler/ssair.jl b/test/compiler/ssair.jl index 1acd490a47295..469881b21f2dc 100644 --- a/test/compiler/ssair.jl +++ b/test/compiler/ssair.jl @@ -5,6 +5,8 @@ using Core.IR const Compiler = Core.Compiler using .Compiler: CFG, BasicBlock, NewSSAValue +include(normpath(@__DIR__, "irutils.jl")) + make_bb(preds, succs) = BasicBlock(Compiler.StmtRange(0, 0), preds, succs) function make_ci(code) @@ -69,8 +71,10 @@ let cfg = CFG(BasicBlock[ ], Int[]) dfs = Compiler.DFS(cfg.blocks) @test dfs.from_pre[dfs.to_parent_pre[dfs.to_pre[5]]] == 4 - let correct_idoms = Compiler.naive_idoms(cfg.blocks) + let correct_idoms = Compiler.naive_idoms(cfg.blocks), + correct_pidoms = Compiler.naive_idoms(cfg.blocks, true) @test Compiler.construct_domtree(cfg.blocks).idoms_bb == correct_idoms + @test Compiler.construct_postdomtree(cfg.blocks).idoms_bb == correct_pidoms # For completeness, reverse the order of pred/succ in the CFG and verify # the answer doesn't change (it does change the which node is chosen # as the semi-dominator, since it changes the DFS numbering). @@ -82,6 +86,7 @@ let cfg = CFG(BasicBlock[ d && (blocks[5] = make_bb(reverse(blocks[5].preds), blocks[5].succs)) cfg′ = CFG(blocks, cfg.index) @test Compiler.construct_domtree(cfg′.blocks).idoms_bb == correct_idoms + @test Compiler.construct_postdomtree(cfg′.blocks).idoms_bb == correct_pidoms end end end @@ -414,3 +419,45 @@ let test_userefs(body) end + +let ir = Base.code_ircode((Bool,Any)) do c, x + println(x, 1) #1 + if c + println(x, 2) #2 + else + println(x, 3) #3 + end + println(x, 4) #4 + end |> only |> first + # IR legality check + @test length(ir.cfg.blocks) == 4 + for i = 1:4 + @test any(ir.cfg.blocks[i].stmts) do j + inst = ir.stmts[j][:inst] + iscall((ir, println), inst) && + inst.args[3] == i + end + end + # domination analysis + domtree = Core.Compiler.construct_domtree(ir.cfg.blocks) + @test Core.Compiler.dominates(domtree, 1, 2) + @test Core.Compiler.dominates(domtree, 1, 3) + @test Core.Compiler.dominates(domtree, 1, 4) + for i = 2:4 + for j = 1:4 + i == j && continue + @test !Core.Compiler.dominates(domtree, i, j) + end + end + # post domination analysis + post_domtree = Core.Compiler.construct_postdomtree(ir.cfg.blocks) + @test Core.Compiler.postdominates(post_domtree, 4, 1) + @test Core.Compiler.postdominates(post_domtree, 4, 2) + @test Core.Compiler.postdominates(post_domtree, 4, 3) + for i = 1:3 + for j = 1:4 + i == j && continue + @test !Core.Compiler.postdominates(post_domtree, i, j) + end + end +end diff --git a/test/core.jl b/test/core.jl index a0bd78df8e1ce..b84f0ef76bd14 100644 --- a/test/core.jl +++ b/test/core.jl @@ -674,14 +674,14 @@ end f21900_cnt = 0 function f21900() for i = 1:1 - x = 0 + x_global_undefined_error = 0 end global f21900_cnt += 1 - x # should be global + x_global_undefined_error # should be global global f21900_cnt += -1000 nothing end -@test_throws UndefVarError(:x) f21900() +@test_throws UndefVarError(:x_global_undefined_error) f21900() @test f21900_cnt == 1 # use @eval so this runs as a toplevel scope block @@ -1407,6 +1407,7 @@ let @test occursin("is not properly aligned to $(sizeof(Int)) bytes", res.value.msg) res = @test_throws ArgumentError unsafe_wrap(Array, pointer(a) + 1, (1, 1)) @test occursin("is not properly aligned to $(sizeof(Int)) bytes", res.value.msg) + res = @test_throws MethodError unsafe_wrap(Vector{UInt8}, pointer(Int32[1]), (sizeof(Int32),)) end struct FooBar2515 @@ -1987,9 +1988,8 @@ mutable struct TupleParam{P} x::Bool end -function tupledispatch(a::TupleParam{(1,:a)}) - a.x -end +tupledispatch(a::TupleParam{(1,:a)}) = a.x +tupledispatch(a::TupleParam{(1,(:a,))}) = 42 # tuples can be used as type params let t1 = TupleParam{(1,:a)}(true), @@ -2001,6 +2001,10 @@ let t1 = TupleParam{(1,:a)}(true), # dispatch works properly @test tupledispatch(t1) == true @test_throws MethodError tupledispatch(t2) + + @test tupledispatch(TupleParam{(1,(:a,))}(true)) === 42 + @test_throws TypeError TupleParam{NamedTuple{(:a,), Tuple{Any}}((1,))} + @test_throws TypeError Val{NamedTuple{(:a,), Tuple{NamedTuple{<:Any,Tuple{Int}}}}(((x=2,),))} end # issue #5254 @@ -6910,9 +6914,9 @@ g27209(x) = f27209(x ? nothing : 1.0) # Issue 27240 @inline function foo27240() if rand(Bool) - return foo_nonexistant_27240 + return foo_nonexistent_27240 else - return bar_nonexistant_27240 + return bar_nonexistent_27240 end end bar27240() = foo27240() @@ -7809,6 +7813,13 @@ import .Foo45350: x45350 f45350() = (global x45350 = 2) @test_throws ErrorException f45350() +# #46503 - redefine `invoke`d methods +foo46503(@nospecialize(a), b::Union{Vector{Any}, Float64, Nothing}) = rand() +foo46503(a::Int, b::Nothing) = @invoke foo46503(a::Any, b) +@test 0 <= foo46503(1, nothing) <= 1 +foo46503(@nospecialize(a), b::Union{Nothing, Float64}) = rand() + 10 +@test 10 <= foo46503(1, nothing) <= 11 + @testset "effect override on Symbol(::String)" begin @test Core.Compiler.is_foldable(Base.infer_effects(Symbol, (String,))) end @@ -7816,3 +7827,13 @@ end @testset "error message for getfield with bad integer type" begin @test_throws "expected Union{$Int, Symbol}" getfield((1,2), Int8(1)) end + +# Correct isdefined error for isdefined of Module of Int fld +f_isdefined_one(@nospecialize(x)) = isdefined(x, 1) +@test (try; f_isdefined_one(@__MODULE__); catch err; err; end).got === 1 + +# Unspecialized retrieval of vararg length +fvarargN(x::Tuple{Vararg{Int, N}}) where {N} = N +fvarargN(args...) = fvarargN(args) +finvokevarargN() = Base.inferencebarrier(fvarargN)(1, 2, 3) +@test finvokevarargN() == 3 diff --git a/test/corelogging.jl b/test/corelogging.jl index 05a9ca378056d..9626f48e4b407 100644 --- a/test/corelogging.jl +++ b/test/corelogging.jl @@ -1,5 +1,8 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +# Make a copy of the original environment +original_env = copy(ENV) + using Test, Base.CoreLogging import Base.CoreLogging: BelowMinLevel, Debug, Info, Warn, Error, handle_message, shouldlog, min_enabled_level, catch_exceptions @@ -454,3 +457,13 @@ end end end + +# Restore the original environment +for k in keys(ENV) + if !haskey(original_env, k) + delete!(ENV, k) + end +end +for (k, v) in pairs(original_env) + ENV[k] = v +end diff --git a/test/deprecation_exec.jl b/test/deprecation_exec.jl index d91ea10c8cb48..4f19f9415ba29 100644 --- a/test/deprecation_exec.jl +++ b/test/deprecation_exec.jl @@ -36,6 +36,11 @@ module DeprecationTests # to test @deprecate # test that @deprecate_moved can be overridden by an import Base.@deprecate_moved foo1234 "Foo" Base.@deprecate_moved bar "Bar" false + + # test that positional and keyword arguments are forwarded when + # there is no explicit type annotation + new_return_args(args...; kwargs...) = args, NamedTuple(kwargs) + @deprecate old_return_args new_return_args end # module module Foo1234 export foo1234 @@ -108,6 +113,11 @@ begin # @deprecate T21972() end @test_deprecated "something" f21972() + + # test that positional and keyword arguments are forwarded when + # there is no explicit type annotation + @test DeprecationTests.old_return_args(1, 2, 3) == ((1, 2, 3),(;)) + @test DeprecationTests.old_return_args(1, 2, 3; a = 4, b = 5) == ((1, 2, 3), (a = 4, b = 5)) end f24658() = depwarn24658() @@ -171,7 +181,7 @@ begin #@deprecated error message # `Old{T}(args...) where {...} = new(args...)` or # `(Old{T} where {...})(args...) = new(args...)`. # Since nobody has requested this feature yet, make sure that it throws, until we - # conciously define + # consciously define @test_throws( "invalid usage of @deprecate", @eval @deprecate Foo{T} where {T <: Int} g true diff --git a/test/dict.jl b/test/dict.jl index de0ce88fb5a0f..65f8939bc6dfc 100644 --- a/test/dict.jl +++ b/test/dict.jl @@ -369,23 +369,107 @@ end end -struct RainBowString +struct RainbowString s::String -end - -function Base.show(io::IO, rbs::RainBowString) - for s in rbs.s - _, color = rand(Base.text_colors) - print(io, color, s, "\e[0m") + bold::Bool + other::Bool + valid::Bool + offset::Int +end +RainbowString(s, bold=false, other=false, valid=true) = RainbowString(s, bold, other, valid, 0) + +function Base.show(io::IO, rbs::RainbowString) + for (i, s) in enumerate(rbs.s) + if i ≤ rbs.offset + print(io, s) + continue + end + color = rbs.other ? string("\033[4", rand(1:7), 'm') : Base.text_colors[rand(0:255)] + if rbs.bold + printstyled(io, color, s; bold=true) + else + print(io, color, s) + end + if rbs.valid + print(io, '\033', '[', rbs.other ? "0" : "39", 'm') # end of color marker + end end end @testset "Display with colors" begin - d = Dict([randstring(8) => [RainBowString(randstring(8)) for i in 1:10] for j in 1:5]...) + d = Dict([randstring(8) => [RainbowString(randstring(8)) for i in 1:10] for j in 1:5]...) str = sprint(io -> show(io, MIME("text/plain"), d); context = (:displaysize=>(30,80), :color=>true, :limit=>true)) lines = split(str, '\n') - @test all(endswith('…'), lines[2:end]) + @test all(endswith("\033[0m…"), lines[2:end]) @test all(x -> length(x) > 100, lines[2:end]) + + d2 = Dict(:foo => RainbowString("bar")) + str2 = sprint(io -> show(io, MIME("text/plain"), d2); context = (:displaysize=>(30,80), :color=>true, :limit=>true)) + @test !occursin('…', str2) + @test endswith(str2, "\033[0m") + + d3 = Dict(:foo => RainbowString("bar", true)) + str3 = sprint(io -> show(io, MIME("text/plain"), d3); context = (:displaysize=>(30,80), :color=>true, :limit=>true)) + @test !occursin('…', str3) + @test endswith(str3, "\033[0m") + + d4 = Dict(RainbowString(randstring(8), true) => nothing) + str4 = sprint(io -> show(io, MIME("text/plain"), d4); context = (:displaysize=>(30,20), :color=>true, :limit=>true)) + @test endswith(str4, "\033[0m… => nothing") + + d5 = Dict(RainbowString(randstring(30), false, true, false) => nothing) + str5 = sprint(io -> show(io, MIME("text/plain"), d5); context = (:displaysize=>(30,30), :color=>true, :limit=>true)) + @test endswith(str5, "\033[0m… => nothing") + + d6 = Dict(randstring(8) => RainbowString(randstring(30), true, true, false) for _ in 1:3) + str6 = sprint(io -> show(io, MIME("text/plain"), d6); context = (:displaysize=>(30,30), :color=>true, :limit=>true)) + lines6 = split(str6, '\n') + @test all(endswith("\033[0m…"), lines6[2:end]) + @test all(x -> length(x) > 100, lines6[2:end]) + str6_long = sprint(io -> show(io, MIME("text/plain"), d6); context = (:displaysize=>(30,80), :color=>true, :limit=>true)) + lines6_long = split(str6_long, '\n') + @test all(endswith("\033[0m"), lines6_long[2:end]) + + d7 = Dict(randstring(8) => RainbowString(randstring(30))) + str7 = sprint(io -> show(io, MIME("text/plain"), d7); context = (:displaysize=>(30,20), :color=>true, :limit=>true)) + line7 = split(str7, '\n')[2] + @test endswith(line7, "\033[0m…") + @test length(line7) > 100 + + d8 = Dict(:x => RainbowString(randstring(10), false, false, false, 6)) + str8 = sprint(io -> show(io, MIME("text/plain"), d8); context = (:displaysize=>(30,14), :color=>true, :limit=>true)) + line8 = split(str8, '\n')[2] + @test !occursin("\033[", line8) + @test length(line8) == 14 + str8_long = sprint(io -> show(io, MIME("text/plain"), d8); context = (:displaysize=>(30,16), :color=>true, :limit=>true)) + line8_long = split(str8_long, '\n')[2] + @test endswith(line8_long, "\033[0m…") + @test length(line8_long) > 20 + + d9 = Dict(:x => RainbowString(repeat('苹', 5), false, true, false)) + str9 = sprint(io -> show(io, MIME("text/plain"), d9); context = (:displaysize=>(30,15), :color=>true, :limit=>true)) + @test endswith(str9, "\033[0m…") + @test count('苹', str9) == 3 + + d10 = Dict(:xy => RainbowString(repeat('苹', 5), false, true, false)) + str10 = sprint(io -> show(io, MIME("text/plain"), d10); context = (:displaysize=>(30,15), :color=>true, :limit=>true)) + @test endswith(str10, "\033[0m…") + @test count('苹', str10) == 2 + + d11 = Dict(RainbowString("abcdefgh", false, true, false) => 0, "123456" => 1) + str11 = sprint(io -> show(io, MIME("text/plain"), d11); context = (:displaysize=>(30,80), :color=>true, :limit=>true)) + _, line11_a, line11_b = split(str11, '\n') + @test endswith(line11_a, "h\033[0m => 0") || endswith(line11_b, "h\033[0m => 0") + @test endswith(line11_a, "6\" => 1") || endswith(line11_b, "6\" => 1") + + d12 = Dict(RainbowString(repeat(Char(48+i), 4), (i&1)==1, (i&2)==2, (i&4)==4) => i for i in 1:8) + str12 = sprint(io -> show(io, MIME("text/plain"), d12); context = (:displaysize=>(30,80), :color=>true, :limit=>true)) + @test !occursin('…', str12) + + d13 = Dict(RainbowString("foo\nbar") => 74) + str13 = sprint(io -> show(io, MIME("text/plain"), d13); context = (:displaysize=>(30,80), :color=>true, :limit=>true)) + @test count('\n', str13) == 1 + @test occursin('…', str13) end @testset "Issue #15739" begin # Compact REPL printouts of an `AbstractDict` use brackets when appropriate diff --git a/test/env.jl b/test/env.jl index 644d956af8fd4..479536813ec47 100644 --- a/test/env.jl +++ b/test/env.jl @@ -1,5 +1,8 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +# Make a copy of the original environment +original_env = copy(ENV) + using Random @test !("f=a=k=e=n=a=m=e" ∈ keys(ENV)) @@ -118,3 +121,13 @@ if Sys.iswindows() end end end + +# Restore the original environment +for k in keys(ENV) + if !haskey(original_env, k) + delete!(ENV, k) + end +end +for (k, v) in pairs(original_env) + ENV[k] = v +end diff --git a/test/errorshow.jl b/test/errorshow.jl index 6cd8dbba14637..c31f7d902a0d8 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -928,3 +928,8 @@ for (expr, errmsg) in end @test contains(sprint(showerror, err), errmsg) end + +let err_str + err_str = @except_str "a" + "b" MethodError + @test occursin("String concatenation is performed with *", err_str) +end diff --git a/test/file.jl b/test/file.jl index e29b3099d3ed9..9f834d77799ff 100644 --- a/test/file.jl +++ b/test/file.jl @@ -42,7 +42,7 @@ if !Sys.iswindows() || Sys.windows_version() >= Sys.WINDOWS_VISTA_VER # creation of symlink to directory that does not yet exist new_dir = joinpath(subdir, "new_dir") foo_file = joinpath(subdir, "new_dir", "foo") - nedlink = joinpath(subdir, "non_existant_dirlink") + nedlink = joinpath(subdir, "nonexistent_dirlink") symlink("new_dir", nedlink; dir_target=true) try readdir(nedlink) @@ -1453,7 +1453,7 @@ rm(dir) #################### mktempdir() do dir name1 = joinpath(dir, "apples") - name2 = joinpath(dir, "bannanas") + name2 = joinpath(dir, "bananas") @test !ispath(name1) @test touch(name1) == name1 @test isfile(name1) @@ -1651,7 +1651,7 @@ end if Sys.iswindows() @testset "mkdir/rm permissions" begin - # test delete permission in system folders (i.e. impliclty test chmod permissions) + # test delete permission in system folders (i.e. implicitly test chmod permissions) # issue #38433 @test withenv("TMP" => "C:\\") do mktempdir() do dir end diff --git a/test/gmp.jl b/test/gmp.jl index 1125f57b195b3..be11c70e5064f 100644 --- a/test/gmp.jl +++ b/test/gmp.jl @@ -227,6 +227,7 @@ let a, b @test 0 == sum(BigInt[]) isa BigInt @test prod(b) == foldl(*, b) @test 1 == prod(BigInt[]) isa BigInt + @test prod(BigInt[0, 0, 0]) == 0 # issue #46665 end @testset "Iterated arithmetic" begin diff --git a/test/iterators.jl b/test/iterators.jl index 0258de116caa3..ae6c4496e088e 100644 --- a/test/iterators.jl +++ b/test/iterators.jl @@ -843,6 +843,8 @@ end v, s = iterate(z) @test Base.isdone(z, s) end + # Stateful wrapping mutable iterators of known length (#43245) + @test length(Iterators.Stateful(Iterators.Stateful(1:5))) == 5 end @testset "pair for Svec" begin diff --git a/test/llvmpasses/.gitignore b/test/llvmpasses/.gitignore index aa144c71f85f8..4b99de76c491b 100644 --- a/test/llvmpasses/.gitignore +++ b/test/llvmpasses/.gitignore @@ -1 +1,2 @@ /Output/ +.lit_test_times.txt \ No newline at end of file diff --git a/test/llvmpasses/late-lower-gc.ll b/test/llvmpasses/late-lower-gc.ll index cb159f17ef5e9..cbc7c1c6726a8 100644 --- a/test/llvmpasses/late-lower-gc.ll +++ b/test/llvmpasses/late-lower-gc.ll @@ -125,6 +125,29 @@ top: ; CHECK: ret i32 } +; COM: the bugs here may be caught by death-by-verify-assertion +define {} addrspace(10)* @gclift_switch({} addrspace(13)* addrspace(10)* %input, i1 %unpredictable) { + top: + %0 = call {}*** @julia.get_pgcstack() + br i1 %unpredictable, label %mid1, label %mid2 + mid1: + br label %mid2 + mid2: + %root = phi {} addrspace(13)* addrspace(10)* [ %input, %top ], [ %input, %mid1 ] + %unrelated = phi i1 [ %unpredictable, %top ], [ %unpredictable, %mid1 ] + %1 = addrspacecast {} addrspace(13)* addrspace(10)* %root to {} addrspace(13)* addrspace(11)* + %2 = bitcast {} addrspace(13)* addrspace(11)* %1 to {} addrspace(11)* + switch i1 %unpredictable, label %end [ + i1 1, label %end + i1 0, label %end + ] + end: + %phi = phi {} addrspace(11)* [ %2, %mid2 ], [ %2, %mid2 ], [ %2, %mid2 ] + %ret = bitcast {} addrspace(13)* addrspace(10)* %input to {} addrspace(10)* + ; CHECK: %gclift + ret {} addrspace(10)* %ret +} + !0 = !{i64 0, i64 23} !1 = !{!1} !2 = !{!7} ; scope list diff --git a/test/llvmpasses/pipeline-o0.jl b/test/llvmpasses/pipeline-o0.jl new file mode 100644 index 0000000000000..ff9cd0aace704 --- /dev/null +++ b/test/llvmpasses/pipeline-o0.jl @@ -0,0 +1,30 @@ +# RUN: julia --startup-file=no -O0 --check-bounds=yes %s %t -O && llvm-link -S %t/* | FileCheck %s +# RUN: julia --startup-file=no -O1 --check-bounds=yes %s %t -O && llvm-link -S %t/* | FileCheck %s +# RUN: julia --startup-file=no -O2 --check-bounds=yes %s %t -O && llvm-link -S %t/* | FileCheck %s +# RUN: julia --startup-file=no -O3 --check-bounds=yes %s %t -O && llvm-link -S %t/* | FileCheck %s + +include(joinpath("..", "testhelpers", "llvmpasses.jl")) + +# CHECK-LABEL: @julia_simple +# CHECK-NOT: julia.get_pgcstack +# CHECK: asm +# CHECK-NOT: julia.gc_alloc_obj +# CHECK: ijl_gc_pool_alloc +# COM: we want something vaguely along the lines of asm load from the fs register -> allocate bytes +function simple() + Ref(0) +end + +# CHECK-LABEL: @julia_buildarray +# CHECK-NOT: julia.write_barrier +# CHECK: gc_queue_root +function buildarray() + out = [] + for i in 1:100 + push!(out, Ref(0)) + end + out +end + +emit(simple) +emit(buildarray) diff --git a/test/llvmpasses/pipeline-o2-allocs.jl b/test/llvmpasses/pipeline-o2-allocs.jl new file mode 100644 index 0000000000000..b87ce17d4bf0c --- /dev/null +++ b/test/llvmpasses/pipeline-o2-allocs.jl @@ -0,0 +1,57 @@ +# RUN: julia --startup-file=no -O2 --check-bounds=yes %s %t -O && llvm-link -S %t/* | FileCheck %s +# RUN: julia --startup-file=no -O3 --check-bounds=yes %s %t -O && llvm-link -S %t/* | FileCheck %s + +include(joinpath("..", "testhelpers", "llvmpasses.jl")) + +# CHECK-LABEL: @julia_split +# CHECK: alloc +# CHECK-NOT: alloc +# CHECK: ret +function split(maybe) + if maybe + Ref(1) + else + Ref(2) + end +end + +# CHECK-LABEL: @julia_loop_alloc +# CHECK: phi +# CHECK-NOT: phi +function loop_alloc(N) + ref = Ref(zero(typeof(N))) + N <= zero(typeof(N)) && return ref + for i in one(typeof(N)):N + ref = Ref(i) + end + ref +end + +# CHECK-LABEL: @julia_loop_const +# CHECK-NOT: br +function loop_const() + ref = Ref(0) + for i in 1:1000 + ref = Ref(0) + end + ref +end + +# CHECK-LABEL: @julia_nopreserve +# CHECK-NOT: alloc +# CHECK-NOT: julia.gc_preserve_begin +# CHECK-NOT: julia.gc_preserve_end +function nopreserve() + ref = Ref(0) + GC.@preserve ref begin + end +end + +# COM: this cordons off the atttributes/function delarations from the actual +# COM: IR that we really want to check +# CHECK: attributes + +emit(split, Bool) +emit(loop_alloc, Int64) +emit(loop_const) +emit(nopreserve) diff --git a/test/llvmpasses/pipeline-o2.jl b/test/llvmpasses/pipeline-o2.jl new file mode 100644 index 0000000000000..85f5035a3249d --- /dev/null +++ b/test/llvmpasses/pipeline-o2.jl @@ -0,0 +1,150 @@ +# RUN: julia --startup-file=no -O2 --check-bounds=yes %s %t -O && llvm-link -S %t/* | FileCheck %s --check-prefixes=ALL +# RUN: julia --startup-file=no -O3 --check-bounds=yes %s %t -O && llvm-link -S %t/* | FileCheck %s --check-prefixes=ALL + +# RUN: julia --startup-file=no -O2 --check-bounds=no %s %t -O && llvm-link -S %t/* | FileCheck %s --check-prefixes=ALL,BC_OFF +# RUN: julia --startup-file=no -O3 --check-bounds=no %s %t -O && llvm-link -S %t/* | FileCheck %s --check-prefixes=ALL,BC_OFF + +# RUN: julia --startup-file=no -O2 --check-bounds=auto %s %t -O && llvm-link -S %t/* | FileCheck %s --check-prefixes=ALL,BC_AUTO +# RUN: julia --startup-file=no -O3 --check-bounds=auto %s %t -O && llvm-link -S %t/* | FileCheck %s --check-prefixes=ALL,BC_AUTO + +include(joinpath("..", "testhelpers", "llvmpasses.jl")) + +# COM: Ensure safe iteration over one array is not boundschecked and is vectorized + +# ALL-LABEL: @julia_iterate_read +# ALL-NOT: bounds_error +# ALL: vector.body +function iterate_read(arr) + total = zero(eltype(arr)) + for i in eachindex(arr) + total += arr[i] + end + total +end + +# ALL-LABEL: @julia_iterate_write +# ALL-NOT: bounds_error +# ALL: vector.body +function iterate_write(arr, out) + for i in eachindex(arr, out) + out[i] = arr[i] + end +end + +# ALL-LABEL: @"julia_iterate_write! +# ALL-NOT: bounds_error +# ALL: vector.body +function iterate_write!(arr) + for i in eachindex(arr) + arr[i] *= 2 + end +end + +# COM: Ensure safe iteration over multiple arrays is not boundschecked and is vectorized + +# ALL-LABEL: @julia_multiiterate_read +# ALL-NOT: bounds_error +# ALL: vector.body +function multiiterate_read(arr1, arr2) + total = zero(eltype(arr1)) + for i in eachindex(arr1, arr2) + total += arr1[i] + total += arr2[i] + end + total +end + +# ALL-LABEL: @japi1_multiiterate_write +# ALL-NOT: bounds_error +# ALL: vector.body +function multiiterate_write(arr1, arr2, arr3) + for i in eachindex(arr1, arr2, arr3) + arr3[i] += arr1[i] + arr3[i] += arr2[i] + end +end + +# ALL-LABEL: @"julia_multiiterate_write! +# ALL-NOT: bounds_error +# ALL: vector.body +function multiiterate_write!(arr1, arr2) + for i in eachindex(arr1, arr2) + arr1[i] += arr2[i] + end +end + +# COM: memset checks + +# COM: INT64 +# ALL-LABEL: define nonnull {} addrspace(10)* @julia_zeros +# ALL-NOT: bounds_error +# COM: memset is not used with bounds checks on (too late in the pipeline) +# BC_OFF: llvm.memset +# BC_AUTO: llvm.memset + +# COM: INT32 +# ALL-LABEL: define nonnull {} addrspace(10)* @julia_zeros +# ALL-NOT: bounds_error +# COM: memset is not used with bounds checks on (too late in the pipeline) +# BC_OFF: llvm.memset +# BC_AUTO: llvm.memset + +# COM: INT16 +# ALL-LABEL: define nonnull {} addrspace(10)* @julia_zeros +# ALL-NOT: bounds_error +# COM: memset is not used with bounds checks on (too late in the pipeline) +# BC_OFF: llvm.memset +# BC_AUTO: llvm.memset + +# COM: check reductive indvars/vectorization + +# ALL-LABEL: @julia_sumloop +# ALL: mul +function sumloop(N) + total = zero(typeof(N)) + for i in one(typeof(N)):N + total += i + end + total +end +# ALL-LABEL: @julia_simd_sumloop +# ALL: vector.body +function simd_sumloop(N) + total = zero(typeof(N)) + @simd for i in one(typeof(N)):N + total += i + end + total +end + +# COM: check hoisting and loop deletion functionality + +# ALL-LABEL: @julia_loopedlength +# ALL-NOT: br +# ALL: ret +function loopedlength(arr) + len = length(arr) + for i in 1:length(arr) + len = length(arr) + end + len +end + +emit(iterate_read, Vector{Int64}) +emit(iterate_write, Vector{Int64}, Vector{Int64}) +emit(iterate_write!, Vector{Int64}) + +emit(multiiterate_read, Vector{Int64}, Vector{Int64}) +emit(multiiterate_write, Vector{Int64}, Vector{Int64}, Vector{Int64}) +emit(multiiterate_write!, Vector{Int64}, Vector{Int64}) + +emit(zeros, Type{Int64}, Int64) +emit(zeros, Type{Int32}, Int64) +emit(zeros, Type{Int16}, Int64) +# COM: Int8 is hardcoded to memset anyways + +emit(sumloop, Int64) +# COM: Float64 doesn't vectorize for some reason +emit(simd_sumloop, Float32) + +emit(loopedlength, Vector{Int64}) diff --git a/test/loading.jl b/test/loading.jl index 16690c6e04613..d057f0b3c3702 100644 --- a/test/loading.jl +++ b/test/loading.jl @@ -1,16 +1,18 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +original_depot_path = copy(Base.DEPOT_PATH) + using Test # Tests for @__LINE__ inside and outside of macros -@test (@__LINE__) == 6 +@test (@__LINE__) == 8 macro macro_caller_lineno() - @test 9 == (@__LINE__) != __source__.line > 12 + @test 11 == (@__LINE__) != __source__.line > 14 return __source__.line end -@test @macro_caller_lineno() == (@__LINE__) > 12 +@test @macro_caller_lineno() == (@__LINE__) > 14 # @__LINE__ in a macro expands to the location of the macrocall in the source # while __source__.line is the location of the macro caller @@ -660,7 +662,7 @@ finally Base.set_active_project(old_act_proj) popfirst!(LOAD_PATH) end -@test Base.pkgorigins[Base.PkgId(UUID("69145d58-7df6-11e8-0660-cf7622583916"), "TestPkg")].version == v"1.2.3" +@test pkgversion(TestPkg) == v"1.2.3" @testset "--project and JULIA_PROJECT paths should be absolutified" begin mktempdir() do dir; cd(dir) do @@ -930,3 +932,64 @@ end end end end + + +@testset "Loading with incomplete manifest/depot #45977" begin + mktempdir() do tmp + # Set up a stacked env. + cp(joinpath(@__DIR__, "depot"), joinpath(tmp, "depot")) + + mkdir(joinpath(tmp, "Env1")) + mkdir(joinpath(tmp, "Global")) + + for env in ["Env1", "Global"] + write(joinpath(tmp, env, "Project.toml"), """ + [deps] + Baz = "6801f525-dc68-44e8-a4e8-cabd286279e7" + """) + end + + write(joinpath(tmp, "Global", "Manifest.toml"), """ + [[Baz]] + uuid = "6801f525-dc68-44e8-a4e8-cabd286279e7" + git-tree-sha1 = "efc7e24c53d6a328011975294a2c75fed2f9800a" + """) + + # This SHA does not exist in the depot. + write(joinpath(tmp, "Env1", "Manifest.toml"), """ + [[Baz]] + uuid = "6801f525-dc68-44e8-a4e8-cabd286279e7" + git-tree-sha1 = "5f2f6e72d001b014b48b26ec462f3714c342e167" + """) + + + old_load_path = copy(LOAD_PATH) + old_depot_path = copy(DEPOT_PATH) + try + empty!(LOAD_PATH) + push!(empty!(DEPOT_PATH), joinpath(tmp, "depot")) + + push!(LOAD_PATH, joinpath(tmp, "Global")) + + pkg = Base.identify_package("Baz") + # Package in manifest in current env not present in depot + @test Base.locate_package(pkg) !== nothing + + pushfirst!(LOAD_PATH, joinpath(tmp, "Env1")) + + @test Base.locate_package(pkg) === nothing + + write(joinpath(tmp, "Env1", "Manifest.toml"), """ + """) + # Package in current env not present in manifest + pkg, env = Base.identify_package_env("Baz") + @test Base.locate_package(pkg, env) === nothing + finally + copy!(LOAD_PATH, old_load_path) + copy!(DEPOT_PATH, old_depot_path) + end + end +end + +empty!(Base.DEPOT_PATH) +append!(Base.DEPOT_PATH, original_depot_path) diff --git a/test/math.jl b/test/math.jl index 6ba40b7daa968..055f143cea39d 100644 --- a/test/math.jl +++ b/test/math.jl @@ -1280,7 +1280,7 @@ struct BadFloatWrapper <: AbstractFloat x::Float64 end -@testset "not impelemented errors" begin +@testset "not implemented errors" begin x = BadFloatWrapper(1.9) for f in (sin, cos, tan, sinh, cosh, tanh, atan, acos, asin, asinh, acosh, atanh, exp, log1p, expm1, log) #exp2, exp10 broken for now @test_throws MethodError f(x) @@ -1362,6 +1362,7 @@ end end # test for large negative exponent where error compensation matters @test 0.9999999955206014^-1.0e8 == 1.565084574870928 + @test 3e18^20 == Inf end # Test that sqrt behaves correctly and doesn't exhibit fp80 double rounding. diff --git a/test/missing.jl b/test/missing.jl index 13ed684f1fc05..474e10620732f 100644 --- a/test/missing.jl +++ b/test/missing.jl @@ -529,7 +529,7 @@ end @test mapreduce(cos, *, collect(skipmissing(A))) ≈ mapreduce(cos, *, skipmissing(A)) end - # Patterns that exercize code paths for inputs with 1 or 2 non-missing values + # Patterns that exercise code paths for inputs with 1 or 2 non-missing values @test sum(skipmissing([1, missing, missing, missing])) === 1 @test sum(skipmissing([missing, missing, missing, 1])) === 1 @test sum(skipmissing([1, missing, missing, missing, 2])) === 3 diff --git a/test/numbers.jl b/test/numbers.jl index bc838211bc698..926abf85b246d 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -103,7 +103,7 @@ end min = Top(T,Base.min) max = Top(T,Base.max) (==) = Top(T,_compare) - (===) = Top(T,Base.isequal) # we only use === to compare -0.0/0.0, `isequal` should be equalvient + (===) = Top(T,Base.isequal) # we only use === to compare -0.0/0.0, `isequal` should be equivalent @test minmax(3., 5.) == (3., 5.) @test minmax(5., 3.) == (3., 5.) @test minmax(3., NaN) ≣ (NaN, NaN) @@ -1071,6 +1071,15 @@ end @test Float64(10633823966279328163822077199654060033) == 1.063382396627933e37 #nextfloat(0x1p123) @test Float64(-10633823966279328163822077199654060032) == -1.0633823966279327e37 @test Float64(-10633823966279328163822077199654060033) == -1.063382396627933e37 + + # Test lsb/msb gaps of 54 (wont fit in 64 bit mantissa) + @test Float64(Int128(9007199254740993)) == 9.007199254740992e15 + @test Float64(UInt128(9007199254740993)) == 9.007199254740992e15 + # Test 2^104-1 and 2^104 (2^104 is cutoff for which case is run in the conversion algorithm) + @test Float64(Int128(20282409603651670423947251286015)) == 2.028240960365167e31 + @test Float64(Int128(20282409603651670423947251286016)) == 2.028240960365167e31 + @test Float64(UInt128(20282409603651670423947251286015)) == 2.028240960365167e31 + @test Float64(UInt128(20282409603651670423947251286016)) == 2.028240960365167e31 end @testset "Float vs Int128 comparisons" begin @test Int128(1e30) == 1e30 @@ -2345,12 +2354,6 @@ end end end @testset "getindex error throwing" begin - #getindex(x::Number,-1) throws BoundsError - #getindex(x::Number,0) throws BoundsError - #getindex(x::Number,2) throws BoundsError - #getindex(x::Array,-1) throws BoundsError - #getindex(x::Array,0 throws BoundsError - #getindex(x::Array,length(x::Array)+1) throws BoundsError for x in [1.23, 7, ℯ, 4//5] #[FP, Int, Irrational, Rat] @test_throws BoundsError getindex(x,-1) @test_throws BoundsError getindex(x,0) diff --git a/test/operators.jl b/test/operators.jl index cd0ca743d2cda..8192e13b73a7f 100644 --- a/test/operators.jl +++ b/test/operators.jl @@ -325,7 +325,7 @@ end @test Returns(val)(1) === val @test sprint(show, Returns(1.0)) == "Returns{Float64}(1.0)" - illtype = Vector{Core._typevar(:T, Union{}, Any)} + illtype = Vector{Core.TypeVar(:T)} @test Returns(illtype) == Returns{DataType}(illtype) end diff --git a/test/precompile.jl b/test/precompile.jl index ac2c63ff7af08..47d9a1bb7e860 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -1,5 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +original_depot_path = copy(Base.DEPOT_PATH) + using Test, Distributed, Random Foo_module = :Foo4b3a94a1a081a8cb @@ -106,16 +108,18 @@ precompile_test_harness(false) do dir write(Foo2_file, """ module $Foo2_module - export override + export override, overridenc override(x::Integer) = 2 override(x::AbstractFloat) = Float64(override(1)) + overridenc(x::Integer) = rand()+1 + overridenc(x::AbstractFloat) = Float64(overridenc(1)) end """) write(Foo_file, """ module $Foo_module import $FooBase_module, $FooBase_module.typeA - import $Foo2_module: $Foo2_module, override + import $Foo2_module: $Foo2_module, override, overridenc import $FooBase_module.hash import Test module Inner @@ -221,6 +225,8 @@ precompile_test_harness(false) do dir g() = override(1.0) Test.@test g() === 2.0 # compile this + gnc() = overridenc(1.0) + Test.@test 1 < gnc() < 5 # compile this const abigfloat_f() = big"12.34" const abigfloat_x = big"43.21" @@ -257,6 +263,8 @@ precompile_test_harness(false) do dir Foo2 = Base.require(Main, Foo2_module) @eval $Foo2.override(::Int) = 'a' @eval $Foo2.override(::Float32) = 'b' + @eval $Foo2.overridenc(::Int) = rand() + 97.0 + @eval $Foo2.overridenc(::Float32) = rand() + 100.0 Foo = Base.require(Main, Foo_module) Base.invokelatest() do # use invokelatest to see the results of loading the compile @@ -265,9 +273,13 @@ precompile_test_harness(false) do dir # Issue #21307 @test Foo.g() === 97.0 + @test 96 < Foo.gnc() < 99 @test Foo.override(1.0e0) == Float64('a') @test Foo.override(1.0f0) == 'b' @test Foo.override(UInt(1)) == 2 + @test 96 < Foo.overridenc(1.0e0) < 99 + @test 99 < Foo.overridenc(1.0f0) < 102 + @test 0 < Foo.overridenc(UInt(1)) < 3 # Issue #15722 @test Foo.abigfloat_f()::BigFloat == big"12.34" @@ -873,6 +885,152 @@ precompile_test_harness("code caching") do dir @test hasvalid(mi, world) # was compiled with the new method end +precompile_test_harness("invoke") do dir + InvokeModule = :Invoke0x030e7e97c2365aad + CallerModule = :Caller0x030e7e97c2365aad + write(joinpath(dir, "$InvokeModule.jl"), + """ + module $InvokeModule + export f, g, h, q, fnc, gnc, hnc, qnc # nc variants do not infer to a Const + export f44320, g44320 + # f is for testing invoke that occurs within a dependency + f(x::Real) = 0 + f(x::Int) = x < 5 ? 1 : invoke(f, Tuple{Real}, x) + fnc(x::Real) = rand()-1 + fnc(x::Int) = x < 5 ? rand()+1 : invoke(fnc, Tuple{Real}, x) + # g is for testing invoke that occurs from a dependent + g(x::Real) = 0 + g(x::Int) = 1 + gnc(x::Real) = rand()-1 + gnc(x::Int) = rand()+1 + # h will be entirely superseded by a new method (full invalidation) + h(x::Real) = 0 + h(x::Int) = x < 5 ? 1 : invoke(h, Tuple{Integer}, x) + hnc(x::Real) = rand()-1 + hnc(x::Int) = x < 5 ? rand()+1 : invoke(hnc, Tuple{Integer}, x) + # q will have some callers invalidated + q(x::Integer) = 0 + qnc(x::Integer) = rand()-1 + # Issue #44320 + f44320(::Int) = 1 + f44320(::Any) = 2 + g44320() = invoke(f44320, Tuple{Any}, 0) + g44320() + end + """) + write(joinpath(dir, "$CallerModule.jl"), + """ + module $CallerModule + using $InvokeModule + # involving external modules + callf(x) = f(x) + callg(x) = x < 5 ? g(x) : invoke(g, Tuple{Real}, x) + callh(x) = h(x) + callq(x) = q(x) + callqi(x) = invoke(q, Tuple{Integer}, x) + callfnc(x) = fnc(x) + callgnc(x) = x < 5 ? gnc(x) : invoke(gnc, Tuple{Real}, x) + callhnc(x) = hnc(x) + callqnc(x) = qnc(x) + callqnci(x) = invoke(qnc, Tuple{Integer}, x) + + # Purely internal + internal(x::Real) = 0 + internal(x::Int) = x < 5 ? 1 : invoke(internal, Tuple{Real}, x) + internalnc(x::Real) = rand()-1 + internalnc(x::Int) = x < 5 ? rand()+1 : invoke(internalnc, Tuple{Real}, x) + + # Issue #44320 + f44320(::Real) = 3 + + # force precompilation + begin + Base.Experimental.@force_compile + callf(3) + callg(3) + callh(3) + callq(3) + callqi(3) + callfnc(3) + callgnc(3) + callhnc(3) + callqnc(3) + callqnci(3) + internal(3) + internalnc(3) + end + + # Now that we've precompiled, invalidate with a new method that overrides the `invoke` dispatch + $InvokeModule.h(x::Integer) = -1 + $InvokeModule.hnc(x::Integer) = rand() - 20 + # ...and for q, override with a more specialized method that should leave only the invoked version still valid + $InvokeModule.q(x::Int) = -1 + $InvokeModule.qnc(x::Int) = rand()+1 + end + """) + Base.compilecache(Base.PkgId(string(CallerModule))) + @eval using $CallerModule + M = getfield(@__MODULE__, CallerModule) + + function get_method_for_type(func, @nospecialize(T)) # return the method func(::T) + for m in methods(func) + m.sig.parameters[end] === T && return m + end + error("no ::Real method found for $func") + end + function nvalid(mi::Core.MethodInstance) + isdefined(mi, :cache) || return 0 + ci = mi.cache + n = Int(ci.max_world == typemax(UInt)) + while isdefined(ci, :next) + ci = ci.next + n += ci.max_world == typemax(UInt) + end + return n + end + + for func in (M.f, M.g, M.internal, M.fnc, M.gnc, M.internalnc) + m = get_method_for_type(func, Real) + mi = m.specializations[1] + @test length(mi.backedges) == 2 + @test mi.backedges[1] === Tuple{typeof(func), Real} + @test isa(mi.backedges[2], Core.MethodInstance) + @test mi.cache.max_world == typemax(mi.cache.max_world) + end + for func in (M.q, M.qnc) + m = get_method_for_type(func, Integer) + mi = m.specializations[1] + @test length(mi.backedges) == 2 + @test mi.backedges[1] === Tuple{typeof(func), Integer} + @test isa(mi.backedges[2], Core.MethodInstance) + @test mi.cache.max_world == typemax(mi.cache.max_world) + end + + m = get_method_for_type(M.h, Real) + @test isempty(m.specializations) + m = get_method_for_type(M.hnc, Real) + @test isempty(m.specializations) + m = only(methods(M.callq)) + @test isempty(m.specializations) || nvalid(m.specializations[1]) == 0 + m = only(methods(M.callqnc)) + @test isempty(m.specializations) || nvalid(m.specializations[1]) == 0 + m = only(methods(M.callqi)) + @test m.specializations[1].specTypes == Tuple{typeof(M.callqi), Int} + m = only(methods(M.callqnci)) + @test m.specializations[1].specTypes == Tuple{typeof(M.callqnci), Int} + + m = only(methods(M.g44320)) + @test m.specializations[1].cache.max_world == typemax(UInt) + + # Precompile specific methods for arbitrary arg types + invokeme(x) = 1 + invokeme(::Int) = 2 + m_any, m_int = sort(collect(methods(invokeme)); by=m->(m.file,m.line)) + @test precompile(invokeme, (Int,), m_any) + @test m_any.specializations[1].specTypes === Tuple{typeof(invokeme), Int} + @test isempty(m_int.specializations) +end + # test --compiled-modules=no command line option precompile_test_harness("--compiled-modules=no") do dir Time_module = :Time4b3a94a1a081a8cb @@ -1069,14 +1227,22 @@ precompile_test_harness("delete_method") do dir """ module $A_module - export apc, anopc + export apc, anopc, apcnc, anopcnc + # Infer to a const apc(::Int, ::Int) = 1 apc(::Any, ::Any) = 2 anopc(::Int, ::Int) = 1 anopc(::Any, ::Any) = 2 + # Do not infer to a const + apcnc(::Int, ::Int) = rand() - 1 + apcnc(::Any, ::Any) = rand() + 1 + + anopcnc(::Int, ::Int) = rand() - 1 + anopcnc(::Any, ::Any) = rand() + 1 + end """) write(B_file, @@ -1087,19 +1253,26 @@ precompile_test_harness("delete_method") do dir bpc(x) = apc(x, x) bnopc(x) = anopc(x, x) + bpcnc(x) = apcnc(x, x) + bnopcnc(x) = anopcnc(x, x) precompile(bpc, (Int,)) precompile(bpc, (Float64,)) + precompile(bpcnc, (Int,)) + precompile(bpcnc, (Float64,)) end """) A = Base.require(Main, A_module) - for mths in (collect(methods(A.apc)), collect(methods(A.anopc))) - Base.delete_method(mths[1]) + for mths in (collect(methods(A.apc)), collect(methods(A.anopc)), collect(methods(A.apcnc)), collect(methods(A.anopcnc))) + idx = findfirst(m -> m.sig.parameters[end] === Int, mths) + Base.delete_method(mths[idx]) end B = Base.require(Main, B_module) - @test Base.invokelatest(B.bpc, 1) == Base.invokelatest(B.bpc, 1.0) == 2 - @test Base.invokelatest(B.bnopc, 1) == Base.invokelatest(B.bnopc, 1.0) == 2 + for f in (B.bpc, B.bnopc, B.bpcnc, B.bnopcnc) + @test Base.invokelatest(f, 1) > 1 + @test Base.invokelatest(f, 1.0) > 1 + end end precompile_test_harness("Issues #19030 and #25279") do load_path @@ -1290,3 +1463,30 @@ precompile_test_harness("__init__ cachepath") do load_path """) @test isa((@eval (using InitCachePath; InitCachePath)), Module) end + +# Test that precompilation can handle invalidated methods created from `precompile`, +# not via backedges. +precompile_test_harness("Issue #46558") do load_path + write(joinpath(load_path, "Foo46558.jl"), + """ + module Foo46558 + foo(x::Real) = 1 + end + """) + write(joinpath(load_path, "Bar46558.jl"), + """ + module Bar46558 + using Foo46558 + precompile(Foo46558.foo, (Int,)) + end + """) + Base.compilecache(Base.PkgId("Foo46558")) + Base.compilecache(Base.PkgId("Bar46558")) + Foo = (@eval (using Foo46558; Foo46558)) + @eval ($Foo.foo)(x::Int) = 2 + Bar = (@eval (using Bar46558; Bar46558)) + @test (@eval $Foo.foo(1)) == 2 +end + +empty!(Base.DEPOT_PATH) +append!(Base.DEPOT_PATH, original_depot_path) diff --git a/test/reduce.jl b/test/reduce.jl index 78988dbdc4225..c03013f880013 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -263,7 +263,6 @@ let x = [4,3,5,2] @test maximum(x) == 5 @test minimum(x) == 2 @test extrema(x) == (2, 5) - @test Core.Compiler.extrema(x) == (2, 5) @test maximum(abs2, x) == 25 @test minimum(abs2, x) == 4 diff --git a/test/reflection.jl b/test/reflection.jl index e28e92142e5f6..b6f8e17ab8419 100644 --- a/test/reflection.jl +++ b/test/reflection.jl @@ -202,7 +202,7 @@ end @test which(===, Tuple{Int, Int}) isa Method @test length(code_typed(===, Tuple{Int, Int})) === 1 -@test only(Base.return_types(===, Tuple{Int, Int})) === Any +@test only(Base.return_types(===, Tuple{Int, Int})) === Bool module TestingExported using Test @@ -980,8 +980,12 @@ end maybe_effectful(x::Int) = 42 maybe_effectful(x::Any) = unknown_operation() function f_no_methods end +ambig_effects_test(a::Int, b) = 1 +ambig_effects_test(a, b::Int) = 1 +ambig_effects_test(a, b) = 1 @testset "infer_effects" begin + # generic functions @test Base.infer_effects(issue41694, (Int,)) |> Core.Compiler.is_terminates @test Base.infer_effects((Int,)) do x issue41694(x) @@ -994,10 +998,17 @@ function f_no_methods end @test !Core.Compiler.is_terminates(effects) @test !Core.Compiler.is_nonoverlayed(effects) end - @test Base.infer_effects(f_no_methods) |> !Core.Compiler.is_nothrow + # should account for MethodError + @test Base.infer_effects(issue41694, (Float64,)) |> !Core.Compiler.is_nothrow # definitive dispatch error + @test Base.infer_effects(issue41694, (Integer,)) |> !Core.Compiler.is_nothrow # possible dispatch error + @test Base.infer_effects(f_no_methods) |> !Core.Compiler.is_nothrow # no possible matching methods + @test Base.infer_effects(ambig_effects_test, (Int,Int)) |> !Core.Compiler.is_nothrow # ambiguity error + @test Base.infer_effects(ambig_effects_test, (Int,Any)) |> !Core.Compiler.is_nothrow # ambiguity error # builtins @test Base.infer_effects(typeof, (Any,)) |> Core.Compiler.is_total @test Base.infer_effects(===, (Any,Any)) |> Core.Compiler.is_total @test (Base.infer_effects(setfield!, ()); true) # `builtin_effects` shouldn't throw on empty `argtypes` @test (Base.infer_effects(Core.Intrinsics.arraylen, ()); true) # `intrinsic_effects` shouldn't throw on empty `argtypes` end + +@test Base._methods_by_ftype(Tuple{}, -1, Base.get_world_counter()) == Any[] diff --git a/test/reinterpretarray.jl b/test/reinterpretarray.jl index f3f28993c313a..e9803b9bd9ceb 100644 --- a/test/reinterpretarray.jl +++ b/test/reinterpretarray.jl @@ -180,7 +180,7 @@ end else @test_throws "Parent's strides" strides(reinterpret(Int64, view(A, 1:8, viewax2))) end - # non-integer-multipled classified + # non-integer-multiplied classified if mod(step(viewax2), 3) == 0 @test check_strides(reinterpret(NTuple{3,Int16}, view(A, 2:7, viewax2))) else diff --git a/test/sets.jl b/test/sets.jl index 1a86b5abd746f..b52d813623231 100644 --- a/test/sets.jl +++ b/test/sets.jl @@ -393,9 +393,10 @@ end @test symdiff(Set([1]), BitSet()) isa Set{Int} @test symdiff(BitSet([1]), Set{Int}()) isa BitSet @test symdiff([1], BitSet()) isa Vector{Int} - # symdiff must NOT uniquify - @test symdiff([1, 2, 1]) == symdiff!([1, 2, 1]) == [2] - @test symdiff([1, 2, 1], [2, 2]) == symdiff!([1, 2, 1], [2, 2]) == [2] + #symdiff does uniquify + @test symdiff([1, 2, 1]) == symdiff!([1, 2, 1]) == [1,2] + @test symdiff([1, 2, 1], [2, 2]) == symdiff!([1, 2, 1], [2, 2]) == [1] + @test symdiff([1, 2, 1], [2, 2]) == symdiff!([1, 2, 1], [2, 2]) == [1] # Base.hasfastin @test all(Base.hasfastin, Any[Dict(1=>2), Set(1), BitSet(1), 1:9, 1:2:9, diff --git a/test/show.jl b/test/show.jl index b44ba0f84d51c..7cdcc628a7290 100644 --- a/test/show.jl +++ b/test/show.jl @@ -769,6 +769,12 @@ let repr = sprint(show, "text/html", methods(f16580)) @test occursin("f16580(x, y...; z, w, q...)", repr) end +# Just check it doesn't error +f46594(::Vararg{T, 2}) where T = 1 +let repr = sprint(show, "text/html", first(methods(f46594))) + @test occursin("f46594(::Vararg{T, 2}) where T", replace(repr, r""=>"")) +end + function triangular_methodshow(x::T1, y::T2) where {T2<:Integer, T1<:T2} end let repr = sprint(show, "text/plain", methods(triangular_methodshow)) @@ -1438,7 +1444,7 @@ struct var"#X#" end var"#f#"() = 2 struct var"%X%" end # Invalid name without '#' -# (Just to make this test more sustainable,) we don't necesssarily need to test the exact +# (Just to make this test more sustainable,) we don't necessarily need to test the exact # output format, just ensure that it prints at least the parts we expect: @test occursin(".var\"#X#\"", static_shown(var"#X#")) # Leading `.` tests it printed a module name. @test occursin(r"Set{var\"[^\"]+\"} where var\"[^\"]+\"", static_shown(Set{<:Any})) @@ -2299,6 +2305,8 @@ end @eval f1(var"a.b") = 3 @test occursin("f1(var\"a.b\")", sprint(_show, methods(f1))) + @test sprint(_show, Method[]) == "0-element Vector{Method}" + italic(s) = mime == MIME("text/html") ? "$s" : s @eval f2(; var"123") = 5 diff --git a/test/strings/basic.jl b/test/strings/basic.jl index c1f1473daa236..33c64410454ef 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -683,6 +683,7 @@ end Base.iterate(x::CharStr) = iterate(x.chars) Base.iterate(x::CharStr, i::Int) = iterate(x.chars, i) Base.lastindex(x::CharStr) = lastindex(x.chars) +Base.length(x::CharStr) = length(x.chars) @testset "cmp without UTF-8 indexing" begin # Simple case, with just ANSI Latin 1 characters @test "áB" != CharStr("áá") # returns false with bug @@ -726,6 +727,11 @@ end @test_throws ArgumentError "abc"[BitArray([true, false, true])] end +@testset "issue #46039 enhance StringIndexError display" begin + @test sprint(showerror, StringIndexError("αn", 2)) == "StringIndexError: invalid index [2], valid nearby indices [1]=>'α', [3]=>'n'" + @test sprint(showerror, StringIndexError("α\n", 2)) == "StringIndexError: invalid index [2], valid nearby indices [1]=>'α', [3]=>'\\n'" +end + @testset "concatenation" begin @test "ab" * "cd" == "abcd" @test 'a' * "bc" == "abc" diff --git a/test/strings/io.jl b/test/strings/io.jl index 91ad83b24e328..af63362db2c0d 100644 --- a/test/strings/io.jl +++ b/test/strings/io.jl @@ -190,8 +190,8 @@ end @testset "sprint with context" begin function f(io::IO) - println(io, "compact => ", get(io, :compact, false)) - println(io, "limit => ", get(io, :limit, false)) + println(io, "compact => ", get(io, :compact, false)::Bool) + println(io, "limit => ", get(io, :limit, false)::Bool) end str = sprint(f) diff --git a/test/strings/util.jl b/test/strings/util.jl index 8957513e37f25..5218310c5c1c7 100644 --- a/test/strings/util.jl +++ b/test/strings/util.jl @@ -91,6 +91,26 @@ end @test rstrip("ello", ['e','o']) == "ell" end +@testset "partition" begin + # AbstractString to partition into SubString + let v=collect(Iterators.partition("foobars",1)) + @test v==SubString{String}["f","o","o","b","a","r","s"] + end + + let v=collect(Iterators.partition("foobars",2)) + @test v==SubString{String}["fo","ob","ar","s"] + end + + for n in [7,8] + @test collect(Iterators.partition("foobars",n))[1]=="foobars" + end + + # HOWEVER enumerate explicitly slices String "atoms" so `Chars` are returned + let v=collect(Iterators.partition(enumerate("foobars"),1)) + @test v==Vector{Tuple{Int64, Char}}[[(1, 'f')],[(2, 'o')],[(3, 'o')],[(4, 'b')],[(5, 'a')],[(6, 'r')], [(7, 's')]] + end +end + @testset "rsplit/split" begin @test split("foo,bar,baz", 'x') == ["foo,bar,baz"] @test split("foo,bar,baz", ',') == ["foo","bar","baz"] diff --git a/test/subtype.jl b/test/subtype.jl index b13dcdfa7a83a..7fdf9ed1a38a0 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -1043,7 +1043,12 @@ function test_intersection() Type{Tuple{Int,T}} where T<:Integer) @testintersect(Type{<:Tuple{Any,Vararg{Any}}}, Type{Tuple{Vararg{Int,N}}} where N, - Type{Tuple{Int,Vararg{Int,N}}} where N) + !Union{}) + + @test typeintersect(Type{<:Tuple{Any,Vararg{Any}}}, Type{Tuple{Vararg{Int,N}}} where N) != Type{Tuple{Int,Vararg{Int}}} + @test_broken typeintersect(Type{<:Tuple{Any,Vararg{Any}}}, Type{Tuple{Vararg{Int,N}}} where N) == Type{Tuple{Int,Vararg{Int,N}}} where N + @test_broken typeintersect(Type{<:Tuple{Any,Vararg{Any}}}, Type{Tuple{Vararg{Int,N}}} where N) != Type{<:Tuple{Int,Vararg{Int}}} + @testintersect(Type{<:Array}, Type{AbstractArray{T}} where T, Bottom) @@ -2020,3 +2025,160 @@ end #issue #43082 struct X43082{A, I, B<:Union{Ref{I},I}}; end @testintersect(Tuple{X43082{T}, Int} where T, Tuple{X43082{Int}, Any}, Tuple{X43082{Int}, Int}) + +#issue #36443 +let C = Tuple{Val{3},Int,Int,Int}, + As = (Tuple{Val{N},Vararg{T,N}} where {T,N}, + Tuple{Val{N},Vararg{T,N}} where {N,T}), + Bs = (Tuple{Val{3},Int,Vararg{T,N}} where {T,N}, + Tuple{Val{3},Int,Vararg{T,N}} where {N,T}, + Tuple{Val{3},Int,Vararg{T}} where {T}, + Tuple{Val{3},Int,Vararg{T,2}} where {T}) + for A in As, B in Bs + @testintersect(A, B, C) + end +end + +let A = Tuple{Type{Val{N}},Tuple{Vararg{T,N}} where T} where N, + C = Tuple{Type{Val{2}},Tuple{T,T} where T} + @testintersect(A, Tuple{Type{Val{2}},Tuple{Vararg{T,N}} where T} where N, C) + @testintersect(A, Tuple{Type{Val{2}},Tuple{T,Vararg{T,N}} where T} where N, C) + @testintersect(A, Tuple{Type{Val{2}},Tuple{T,T,Vararg{T,N}} where T} where N, C) +end + +let f36443(::NTuple{N}=[(f36443,),(1,2)][2],::Val{N}=Val(2)) where{N} = 0 + @test f36443() == 0; +end + +let C = Tuple{Val{3},Int,Int,Int,Int}, + As = (Tuple{Val{N},Int,Vararg{T,N}} where {T,N}, + Tuple{Val{N},Int,Vararg{T,N}} where {N,T}), + Bs = (Tuple{Val{3},Vararg{T,N}} where {T,N}, + Tuple{Val{3},Vararg{T,N}} where {N,T}, + Tuple{Val{3},Vararg{T}} where {T}) + for A in As, B in Bs + @testintersect(A, B, C) + end +end + +#issue #37257 +let T = Tuple{Val{N}, Any, Any, Vararg{Any,N}} where N, + C = Tuple{Val{1}, Any, Any, Any} + @testintersect(T, Tuple{Val{1}, Vararg{Any}}, C) + @testintersect(T, Tuple{Val{1}, Any, Vararg{Any}}, C) + @testintersect(T, Tuple{Val{1}, Any, Any, Vararg{Any}}, C) + @testintersect(T, Tuple{Val{1}, Any, Any, Any, Vararg{Any}}, C) + @testintersect(T, Tuple{Val{1}, Any, Any, Any, Any, Vararg{Any}}, Union{}) +end + +let A = Tuple{NTuple{N,Any},Val{N}} where {N}, + C = Tuple{NTuple{4,Any},Val{4}} + @testintersect(A, Tuple{Tuple{Vararg{Any,N}},Val{4}} where {N}, C) + @testintersect(A, Tuple{Tuple{Vararg{Any}},Val{4}}, C) + @testintersect(A, Tuple{Tuple{Vararg{Any,N}} where {N},Val{4}}, C) + + @testintersect(A, Tuple{Tuple{Any,Vararg{Any,N}},Val{4}} where {N}, C) + @testintersect(A, Tuple{Tuple{Any,Vararg{Any}},Val{4}}, C) + @testintersect(A, Tuple{Tuple{Any,Vararg{Any,N}} where {N},Val{4}}, C) + + @testintersect(A, Tuple{Tuple{Any,Any,Any,Any,Any,Vararg{Any,N}},Val{4}} where {N}, Union{}) + @testintersect(A, Tuple{Tuple{Any,Any,Any,Any,Any,Vararg{Any}},Val{4}}, Union{}) + @testintersect(A, Tuple{Tuple{Any,Any,Any,Any,Any,Vararg{Any,N}} where {N},Val{4}}, Union{}) +end + +#issue #39088 +let + a() = c((1,), (1,1,1,1)) + c(d::NTuple{T}, ::NTuple{T}) where T = d + c(d::NTuple{f}, b) where f = c((d..., f), b) + j(h::NTuple{T}, ::NTuple{T} = a()) where T = nothing + @test j((1,1,1,1)) === nothing +end + +let A = Tuple{NTuple{N, Int}, NTuple{N, Int}} where N, + C = Tuple{NTuple{4, Int}, NTuple{4, Int}} + @testintersect(A, Tuple{Tuple{Int, Vararg{Any}}, NTuple{4, Int}}, C) + @testintersect(A, Tuple{Tuple{Int, Vararg{Any, N}} where {N}, NTuple{4, Int}}, C) + @testintersect(A, Tuple{Tuple{Int, Vararg{Any, N}}, NTuple{4, Int}} where {N}, C) + + Bs = (Tuple{Tuple{Int, Vararg{Any}}, Tuple{Int, Int, Vararg{Any}}}, + Tuple{Tuple{Int, Vararg{Any,N1}}, Tuple{Int, Int, Vararg{Any,N2}}} where {N1,N2}, + Tuple{Tuple{Int, Vararg{Any,N}} where {N}, Tuple{Int, Int, Vararg{Any,N}} where {N}}) + Cerr = Tuple{Tuple{Int, Vararg{Int, N}}, Tuple{Int, Int, Vararg{Int, N}}} where {N} + for B in Bs + C = typeintersect(A, B) + @test C == typeintersect(B, A) != Union{} + @test C != Cerr + # TODO: The ideal result is Tuple{Tuple{Int, Int, Vararg{Int, N}}, Tuple{Int, Int, Vararg{Int, N}}} where {N} + @test_broken C != Tuple{Tuple{Int, Vararg{Int}}, Tuple{Int, Int, Vararg{Int}}} + end +end + +let A = Pair{NTuple{N, Int}, NTuple{N, Int}} where N, + C = Pair{NTuple{4, Int}, NTuple{4, Int}} + @testintersect(A, Pair{<:Tuple{Int, Vararg{Any}}, NTuple{4, Int}}, C) + @testintersect(A, Pair{<:Tuple{Int, Vararg{Any, N}} where {N}, NTuple{4, Int}}, C) + @testintersect(A, Pair{<:Tuple{Int, Vararg{Any, N}}, NTuple{4, Int}} where {N}, C) + + Bs = (Pair{<:Tuple{Int, Vararg{Int}}, <:Tuple{Int, Int, Vararg{Int}}}, + Pair{Tuple{Int, Vararg{Int,N1}}, Tuple{Int, Int, Vararg{Int,N2}}} where {N1,N2}, + Pair{<:Tuple{Int, Vararg{Int,N}} where {N}, <:Tuple{Int, Int, Vararg{Int,N}} where {N}}) + Cerr = Pair{Tuple{Int, Vararg{Int, N}}, Tuple{Int, Int, Vararg{Int, N}}} where {N} + for B in Bs + C = typeintersect(A, B) + @test C == typeintersect(B, A) != Union{} + @test C != Cerr + @test_broken C != B + end +end + +# Example from pr#39098 +@testintersect(NTuple, Tuple{Any,Vararg}, Tuple{T, Vararg{T}} where {T}) + +let A = Pair{NTuple{N, Int}, Val{N}} where N, + Bs = (Pair{<:Tuple{Int, Vararg{Int}}, <:Val}, + Pair{Tuple{Int, Vararg{Int,N1}}, Val{N2}} where {N1,N2}) + Cerr = Pair{Tuple{Int, Vararg{Int,N}}, Val{N}} where N + for B in Bs + @testintersect(A, B, !Cerr) + @testintersect(A, B, !Union{}) + end +end + +# issue #43064 +let + env_tuple(@nospecialize(x), @nospecialize(y)) = (intersection_env(x, y)[2]...,) + all_var(x::UnionAll) = (x.var, all_var(x.body)...) + all_var(x::DataType) = () + TT0 = Tuple{Type{T},Union{Real,Missing,Nothing}} where {T} + TT1 = Union{Type{Int8},Type{Int16}} + @test env_tuple(Tuple{TT1,Missing}, TT0) === + env_tuple(Tuple{TT1,Nothing}, TT0) === + env_tuple(Tuple{TT1,Int}, TT0) === all_var(TT0) + + TT0 = Tuple{T1,T2,Union{Real,Missing,Nothing}} where {T1,T2} + TT1 = Tuple{T1,T2,Union{Real,Missing,Nothing}} where {T2,T1} + TT2 = Tuple{Union{Int,Int8},Union{Int,Int8},Int} + TT3 = Tuple{Int,Union{Int,Int8},Int} + @test env_tuple(TT2, TT0) === all_var(TT0) + @test env_tuple(TT2, TT1) === all_var(TT1) + @test env_tuple(TT3, TT0) === Base.setindex(all_var(TT0), Int, 1) + @test env_tuple(TT3, TT1) === Base.setindex(all_var(TT1), Int, 2) + + TT0 = Tuple{T1,T2,T1,Union{Real,Missing,Nothing}} where {T1,T2} + TT1 = Tuple{T1,T2,T1,Union{Real,Missing,Nothing}} where {T2,T1} + TT2 = Tuple{Int,Union{Int,Int8},Int,Int} + @test env_tuple(TT2, TT0) === Base.setindex(all_var(TT0), Int, 1) + @test env_tuple(TT2, TT1) === Base.setindex(all_var(TT1), Int, 2) +end + +#issue #46735 +T46735{B<:Real} = Pair{<:Union{B, Val{<:B}}, <:Union{AbstractMatrix{B}, AbstractMatrix{Vector{B}}}} +@testintersect(T46735{B} where {B}, T46735, !Union{}) +@testintersect(T46735{B} where {B<:Integer}, T46735, !Union{}) +S46735{B<:Val, M<:AbstractMatrix} = Tuple{<:Union{B, <:Val{<:B}},M,<:(Union{AbstractMatrix{B}, AbstractMatrix{<:Vector{<:B}}})} +@testintersect(S46735{B} where {B}, S46735, !Union{}) +@testintersect(S46735{B, M} where {B, M}, S46735, !Union{}) +A46735{B<:Val, M<:AbstractMatrix} = Tuple{<:Union{B, <:Val{<:B}},M,Union{AbstractMatrix{B}, AbstractMatrix{<:Vector{<:B}}}} +@testintersect(A46735{B} where {B}, A46735, !Union{}) +@testintersect(A46735{B, M} where {B, M}, A46735, !Union{}) diff --git a/test/testdefs.jl b/test/testdefs.jl index 1d36d8893e199..0f8ef610d02c8 100644 --- a/test/testdefs.jl +++ b/test/testdefs.jl @@ -21,7 +21,44 @@ function runtests(name, path, isolate=true; seed=nothing) res_and_time_data = @timed @testset "$name" begin # Random.seed!(nothing) will fail seed != nothing && Random.seed!(seed) + + original_depot_path = copy(Base.DEPOT_PATH) + original_load_path = copy(Base.LOAD_PATH) + original_env = copy(ENV) + Base.include(m, "$path.jl") + + if Base.DEPOT_PATH != original_depot_path + msg = "The `$(name)` test set mutated Base.DEPOT_PATH and did not restore the original values" + @error( + msg, + original_depot_path, + Base.DEPOT_PATH, + testset_name = name, + testset_path = path, + ) + error(msg) + end + if Base.LOAD_PATH != original_load_path + msg = "The `$(name)` test set mutated Base.LOAD_PATH and did not restore the original values" + @error( + msg, + original_load_path, + Base.LOAD_PATH, + testset_name = name, + testset_path = path, + ) + error(msg) + end + if copy(ENV) != original_env + msg = "The `$(name)` test set mutated ENV and did not restore the original values" + @error( + msg, + testset_name = name, + testset_path = path, + ) + error(msg) + end end rss = Sys.maxrss() #res_and_time_data[1] is the testset diff --git a/test/testhelpers/Furlongs.jl b/test/testhelpers/Furlongs.jl index 8ac22c6244cd3..15950a9f9ca4b 100644 --- a/test/testhelpers/Furlongs.jl +++ b/test/testhelpers/Furlongs.jl @@ -25,15 +25,15 @@ Base.promote_type(::Type{Furlong{p,T}}, ::Type{Furlong{p,S}}) where {p,T,S} = Furlong{p,promote_type(T,S)} # only Furlong{0} forms a ring and isa Number -Base.convert(::Type{T}, y::Number) where {T<:Furlong{0}} = T(y) +Base.convert(::Type{T}, y::Number) where {T<:Furlong{0}} = T(y)::T Base.convert(::Type{Furlong}, y::Number) = Furlong{0}(y) Base.convert(::Type{Furlong{<:Any,T}}, y::Number) where {T<:Number} = Furlong{0,T}(y) Base.convert(::Type{T}, y::Number) where {T<:Furlong} = typeassert(y, T) # throws, since cannot convert a Furlong{0} to a Furlong{p} # other Furlong{p} form a group -Base.convert(::Type{T}, y::Furlong) where {T<:Furlong{0}} = T(y) +Base.convert(::Type{T}, y::Furlong) where {T<:Furlong{0}} = T(y)::T Base.convert(::Type{Furlong}, y::Furlong) = y Base.convert(::Type{Furlong{<:Any,T}}, y::Furlong{p}) where {p,T<:Number} = Furlong{p,T}(y) -Base.convert(::Type{T}, y::Furlong) where {T<:Furlong} = T(y) +Base.convert(::Type{T}, y::Furlong) where {T<:Furlong} = T(y)::T Base.one(x::Furlong{p,T}) where {p,T} = one(T) Base.one(::Type{Furlong{p,T}}) where {p,T} = one(T) diff --git a/test/testhelpers/OffsetArrays.jl b/test/testhelpers/OffsetArrays.jl index 01b34df8e18a9..705bd07b2878c 100644 --- a/test/testhelpers/OffsetArrays.jl +++ b/test/testhelpers/OffsetArrays.jl @@ -100,7 +100,7 @@ end # function offset_coerce(::Type{Base.OneTo{T}}, r::IdOffsetRange) where T<:Integer # rc, o = offset_coerce(Base.OneTo{T}, r.parent) -# Fallback, specialze this method if `convert(I, r)` doesn't do what you need +# Fallback, specialize this method if `convert(I, r)` doesn't do what you need offset_coerce(::Type{I}, r::AbstractUnitRange) where I<:AbstractUnitRange = convert(I, r)::I, 0 diff --git a/test/worlds.jl b/test/worlds.jl index 93445e07699c0..3c60f006faef2 100644 --- a/test/worlds.jl +++ b/test/worlds.jl @@ -226,13 +226,13 @@ g38435(x) = f38435(x, x) f38435(::Int, ::Int) = 3.0 @test g38435(1) === 3.0 +# Invalidation +# ============ -## Invalidation tests - -function instance(f, types) +function method_instance(f, types=Base.default_tt(f)) m = which(f, types) inst = nothing - tt = Tuple{typeof(f), types...} + tt = Base.signature_type(f, types) specs = m.specializations if isa(specs, Nothing) elseif isa(specs, Core.SimpleVector) @@ -290,30 +290,30 @@ f35855(::Float64) = 2 applyf35855([1]) applyf35855([1.0]) applyf35855(Any[1]) -wint = worlds(instance(applyf35855, (Vector{Int},))) -wfloat = worlds(instance(applyf35855, (Vector{Float64},))) -wany2 = worlds(instance(applyf35855, (Vector{Any},))) +wint = worlds(method_instance(applyf35855, (Vector{Int},))) +wfloat = worlds(method_instance(applyf35855, (Vector{Float64},))) +wany2 = worlds(method_instance(applyf35855, (Vector{Any},))) src2 = code_typed(applyf35855, (Vector{Any},))[1] f35855(::String) = 3 applyf35855(Any[1]) -@test worlds(instance(applyf35855, (Vector{Int},))) == wint -@test worlds(instance(applyf35855, (Vector{Float64},))) == wfloat -wany3 = worlds(instance(applyf35855, (Vector{Any},))) +@test worlds(method_instance(applyf35855, (Vector{Int},))) == wint +@test worlds(method_instance(applyf35855, (Vector{Float64},))) == wfloat +wany3 = worlds(method_instance(applyf35855, (Vector{Any},))) src3 = code_typed(applyf35855, (Vector{Any},))[1] @test !(wany3 == wany2) || equal(src3, src2) # code doesn't change unless you invalidate f35855(::AbstractVector) = 4 applyf35855(Any[1]) -wany4 = worlds(instance(applyf35855, (Vector{Any},))) +wany4 = worlds(method_instance(applyf35855, (Vector{Any},))) src4 = code_typed(applyf35855, (Vector{Any},))[1] @test !(wany4 == wany3) || equal(src4, src3) # code doesn't change unless you invalidate f35855(::Dict) = 5 applyf35855(Any[1]) -wany5 = worlds(instance(applyf35855, (Vector{Any},))) +wany5 = worlds(method_instance(applyf35855, (Vector{Any},))) src5 = code_typed(applyf35855, (Vector{Any},))[1] @test (wany5 == wany4) == equal(src5, src4) f35855(::Set) = 6 # with current settings, this shouldn't invalidate applyf35855(Any[1]) -wany6 = worlds(instance(applyf35855, (Vector{Any},))) +wany6 = worlds(method_instance(applyf35855, (Vector{Any},))) src6 = code_typed(applyf35855, (Vector{Any},))[1] @test wany6 == wany5 @test equal(src6, src5) @@ -322,11 +322,11 @@ applyf35855_2(c) = f35855_2(c[1]) f35855_2(::Int) = 1 f35855_2(::Float64) = 2 applyf35855_2(Any[1]) -wany3 = worlds(instance(applyf35855_2, (Vector{Any},))) +wany3 = worlds(method_instance(applyf35855_2, (Vector{Any},))) src3 = code_typed(applyf35855_2, (Vector{Any},))[1] f35855_2(::AbstractVector) = 4 applyf35855_2(Any[1]) -wany4 = worlds(instance(applyf35855_2, (Vector{Any},))) +wany4 = worlds(method_instance(applyf35855_2, (Vector{Any},))) src4 = code_typed(applyf35855_2, (Vector{Any},))[1] @test !(wany4 == wany3) || equal(src4, src3) # code doesn't change unless you invalidate @@ -343,25 +343,60 @@ end (::Type{X})(x::Real) where {T, X<:FixedPoint35855{T}} = X(round(T, typemax(T)*x), 0) @test worlds(mi) == w -mi = instance(convert, (Type{Nothing}, String)) +mi = method_instance(convert, (Type{Nothing}, String)) w = worlds(mi) abstract type Colorant35855 end Base.convert(::Type{C}, c) where {C<:Colorant35855} = false @test worlds(mi) == w -# NamedTuple and extensions of eltype +## NamedTuple and extensions of eltype outer(anyc) = inner(anyc[]) inner(s::Union{Vector,Dict}; kw=false) = inneri(s, kwi=maximum(s), kwb=kw) inneri(s, args...; kwargs...) = inneri(IOBuffer(), s, args...; kwargs...) inneri(io::IO, s::Union{Vector,Dict}; kwi=0, kwb=false) = (print(io, first(s), " "^kwi, kwb); String(take!(io))) @test outer(Ref{Any}([1,2,3])) == "1 false" -mi = instance(Core.kwfunc(inneri), (NamedTuple{(:kwi,:kwb),TT} where TT<:Tuple{Any,Bool}, typeof(inneri), Vector{T} where T)) +mi = method_instance(Core.kwfunc(inneri), (NamedTuple{(:kwi,:kwb),TT} where TT<:Tuple{Any,Bool}, typeof(inneri), Vector{T} where T)) w = worlds(mi) abstract type Container{T} end Base.eltype(::Type{C}) where {T,C<:Container{T}} = T @test worlds(mi) == w +## invoke call + +_invoke46741(a::Int) = a > 0 ? :int : println(a) +_invoke46741(a::Integer) = a > 0 ? :integer : println(a) +invoke46741(a) = @invoke _invoke46741(a::Integer) +@test invoke46741(42) === :integer +invoke46741_world = worlds(method_instance(invoke46741, (Int,))) +_invoke46741(a::Int) = a > 0 ? :int2 : println(a) +@test invoke46741(42) === :integer +@test worlds(method_instance(invoke46741, (Int,))) == invoke46741_world +_invoke46741(a::UInt) = a > 0 ? :uint2 : println(a) +@test invoke46741(42) === :integer +@test worlds(method_instance(invoke46741, (Int,))) == invoke46741_world +_invoke46741(a::Integer) = a > 0 ? :integer2 : println(a) +@test invoke46741(42) === :integer2 +@test worlds(method_instance(invoke46741, (Int,))) ≠ invoke46741_world + +# const-prop'ed call +_invoke46741(a::Int) = a > 0 ? :int : println(a) +_invoke46741(a::Integer) = a > 0 ? :integer : println(a) +invoke46741() = @invoke _invoke46741(42::Integer) +@test invoke46741() === :integer +invoke46741_world = worlds(method_instance(invoke46741, ())) +_invoke46741(a::Int) = a > 0 ? :int2 : println(a) +@test invoke46741() === :integer +@test worlds(method_instance(invoke46741, ())) == invoke46741_world +_invoke46741(a::UInt) = a > 0 ? :uint2 : println(a) +@test invoke46741() === :integer +@test worlds(method_instance(invoke46741, ())) == invoke46741_world +_invoke46741(a::Integer) = a > 0 ? :integer2 : println(a) +@test invoke46741() === :integer2 +@test worlds(method_instance(invoke46741, ())) ≠ invoke46741_world + # invoke_in_world +# =============== + f_inworld(x) = "world one; x=$x" g_inworld(x; y) = "world one; x=$x, y=$y" wc_aiw1 = get_world_counter()