Skip to content

Commit

Permalink
Merge branch 'master' into jishnub/copyto_subarray_linear
Browse files Browse the repository at this point in the history
  • Loading branch information
LilithHafner authored Dec 2, 2024
2 parents beea81c + ea42112 commit 0945185
Show file tree
Hide file tree
Showing 46 changed files with 634 additions and 384 deletions.
57 changes: 34 additions & 23 deletions Compiler/src/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -856,8 +856,7 @@ end

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

struct ConstCallResult
Expand Down Expand Up @@ -2218,34 +2217,46 @@ function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::Stmt
ft′ = argtype_by_index(argtypes, 2)
ft = widenconst(ft′)
ft === Bottom && return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo()))
(types, isexact, isconcrete, istype) = instanceof_tfunc(argtype_by_index(argtypes, 3), false)
isexact || return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
unwrapped = unwrap_unionall(types)
types === Bottom && return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo()))
if !(unwrapped isa DataType && unwrapped.name === Tuple.name)
return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo()))
end
argtype = argtypes_to_type(argtype_tail(argtypes, 4))
nargtype = typeintersect(types, argtype)
nargtype === Bottom && return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo()))
nargtype isa DataType || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # other cases are not implemented below
isdispatchelem(ft) || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below
ft = ft::DataType
lookupsig = rewrap_unionall(Tuple{ft, unwrapped.parameters...}, types)::Type
nargtype = Tuple{ft, nargtype.parameters...}
argtype = Tuple{ft, argtype.parameters...}
matched, valid_worlds = findsup(lookupsig, method_table(interp))
matched === nothing && return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
update_valid_age!(sv, valid_worlds)
method = matched.method
types = argtype_by_index(argtypes, 3)
if types isa Const && types.val isa Method
method = types.val::Method
types = method # argument value
lookupsig = method.sig # edge kind
argtype = argtypes_to_type(pushfirst!(argtype_tail(argtypes, 4), ft))
nargtype = typeintersect(lookupsig, argtype)
nargtype === Bottom && return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo()))
nargtype isa DataType || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # other cases are not implemented below
else
widenconst(types) >: Method && return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
(types, isexact, isconcrete, istype) = instanceof_tfunc(argtype_by_index(argtypes, 3), false)
isexact || return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
unwrapped = unwrap_unionall(types)
types === Bottom && return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo()))
if !(unwrapped isa DataType && unwrapped.name === Tuple.name)
return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo()))
end
argtype = argtypes_to_type(argtype_tail(argtypes, 4))
nargtype = typeintersect(types, argtype)
nargtype === Bottom && return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo()))
nargtype isa DataType || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # other cases are not implemented below
isdispatchelem(ft) || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below
ft = ft::DataType
lookupsig = rewrap_unionall(Tuple{ft, unwrapped.parameters...}, types)::Type
nargtype = Tuple{ft, nargtype.parameters...}
argtype = Tuple{ft, argtype.parameters...}
matched, valid_worlds = findsup(lookupsig, method_table(interp))
matched === nothing && return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
update_valid_age!(sv, valid_worlds)
method = matched.method
end
tienv = ccall(:jl_type_intersection_with_env, Any, (Any, Any), nargtype, method.sig)::SimpleVector
ti = tienv[1]
env = tienv[2]::SimpleVector
mresult = abstract_call_method(interp, method, ti, env, false, si, sv)::Future
match = MethodMatch(ti, env, method, argtype <: method.sig)
ft′_box = Core.Box(ft′)
lookupsig_box = Core.Box(lookupsig)
invokecall = InvokeCall(types, lookupsig)
invokecall = InvokeCall(types)
return Future{CallMeta}(mresult, interp, sv) do result, interp, sv
(; rt, exct, effects, edge, volatile_inf_result) = result
local ft′ = ft′_box.contents
Expand Down
2 changes: 1 addition & 1 deletion Compiler/src/abstractlattice.jl
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ end
if isa(t, Const)
# don't consider mutable values useful constants
val = t.val
return isa(val, Symbol) || isa(val, Type) || !ismutable(val)
return isa(val, Symbol) || isa(val, Type) || isa(val, Method) || !ismutable(val)
end
isa(t, PartialTypeVar) && return false # this isn't forwardable
return is_const_prop_profitable_arg(widenlattice(𝕃), t)
Expand Down
6 changes: 4 additions & 2 deletions Compiler/src/ssair/irinterp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,10 @@ function process_terminator!(@nospecialize(stmt), bb::Int, bb_ip::BitSetBoundedM
return backedge
elseif isa(stmt, EnterNode)
dest = stmt.catch_dest
@assert dest > bb
push!(bb_ip, dest)
if dest 0
@assert dest > bb
push!(bb_ip, dest)
end
push!(bb_ip, bb+1)
return false
else
Expand Down
6 changes: 4 additions & 2 deletions Compiler/src/ssair/passes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2393,8 +2393,10 @@ function cfg_simplify!(ir::IRCode)
end
elseif isa(terminator, EnterNode)
catchbb = terminator.catch_dest
if bb_rename_succ[catchbb] == 0
push!(worklist, catchbb)
if catchbb 0
if bb_rename_succ[catchbb] == 0
push!(worklist, catchbb)
end
end
elseif isa(terminator, GotoNode) || isa(terminator, ReturnNode)
# No implicit fall through. Schedule from work list.
Expand Down
4 changes: 2 additions & 2 deletions Compiler/src/utilities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ function count_const_size(@nospecialize(x), count_self::Bool = true)
# No definite size
(isa(x, GenericMemory) || isa(x, String) || isa(x, SimpleVector)) &&
return MAX_INLINE_CONST_SIZE + 1
if isa(x, Module)
# We allow modules, because we already assume they are externally
if isa(x, Module) || isa(x, Method)
# We allow modules and methods, because we already assume they are externally
# rooted, so we count their contents as 0 size.
return sizeof(Ptr{Cvoid})
end
Expand Down
29 changes: 28 additions & 1 deletion Compiler/test/irpasses.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1816,7 +1816,34 @@ function f53521()
end
end
end
@test code_typed(f53521)[1][2] === Nothing
let (ir,rt) = only(Base.code_ircode(f53521, ()))
@test rt == Nothing
Compiler.verify_ir(ir)
Compiler.cfg_simplify!(ir)
Compiler.verify_ir(ir)
end

Base.@assume_effects :foldable Base.@constprop :aggressive function f53521(x::Int, ::Int)
VALUE = ScopedValue(x)
@with VALUE => 2 begin
for i = 1
@with VALUE => 3 begin
local v
try
v = sin(VALUE[])
catch
v = nothing
end
return v
end
end
end
end
let (ir,rt) = only(Base.code_ircode((Int,)) do y
f53521(1, y)
end)
@test rt == Union{Nothing,Float64}
end

# Test that adce_pass! sets Refined on PhiNode values
let code = Any[
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ New library features
* `Base.require_one_based_indexing` and `Base.has_offset_axes` are now public ([#56196])
* New `ltruncate`, `rtruncate` and `ctruncate` functions for truncating strings to text width, accounting for char widths ([#55351])
* `isless` (and thus `cmp`, sorting, etc.) is now supported for zero-dimensional `AbstractArray`s ([#55772])
* `invoke` now supports passing a Method instead of a type signature making this interface somewhat more flexible for certain uncommon use cases ([#56692]).

Standard library changes
------------------------
Expand Down
2 changes: 1 addition & 1 deletion base/cmd.jl
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ end
"""
@cmd str
Similar to `cmd`, generate a `Cmd` from the `str` string which represents the shell command(s) to be executed.
Similar to ``` `str` ```, generate a `Cmd` from the `str` string which represents the shell command(s) to be executed.
The [`Cmd`](@ref) object can be run as a process and can outlive the spawning julia process (see `Cmd` for more).
# Examples
Expand Down
15 changes: 13 additions & 2 deletions base/docs/basedocs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2030,21 +2030,32 @@ applicable

"""
invoke(f, argtypes::Type, args...; kwargs...)
invoke(f, argtypes::Method, args...; kwargs...)
Invoke a method for the given generic function `f` matching the specified types `argtypes` on the
specified arguments `args` and passing the keyword arguments `kwargs`. The arguments `args` must
conform with the specified types in `argtypes`, i.e. conversion is not automatically performed.
This method allows invoking a method other than the most specific matching method, which is useful
when the behavior of a more general definition is explicitly needed (often as part of the
implementation of a more specific method of the same function).
implementation of a more specific method of the same function). However, because this means
the runtime must do more work, `invoke` is generally also slower--sometimes significantly
so--than doing normal dispatch with a regular call.
Be careful when using `invoke` for functions that you don't write. What definition is used
Be careful when using `invoke` for functions that you don't write. What definition is used
for given `argtypes` is an implementation detail unless the function is explicitly states
that calling with certain `argtypes` is a part of public API. For example, the change
between `f1` and `f2` in the example below is usually considered compatible because the
change is invisible by the caller with a normal (non-`invoke`) call. However, the change is
visible if you use `invoke`.
# Passing a `Method` instead of a signature
The `argtypes` argument may be a `Method`, in which case the ordinary method table lookup is
bypassed entirely and the given method is invoked directly. Needing this feature is uncommon.
Note in particular that the specified `Method` may be entirely unreachable from ordinary dispatch
(or ordinary invoke), e.g. because it was replaced or fully covered by more specific methods.
If the method is part of the ordinary method table, this call behaves similar
to `invoke(f, method.sig, args...)`.
# Examples
```jldoctest
julia> f(x::Real) = x^2;
Expand Down
9 changes: 9 additions & 0 deletions base/experimental.jl
Original file line number Diff line number Diff line change
Expand Up @@ -494,4 +494,13 @@ function entrypoint(@nospecialize(argt::Type))
nothing
end

"""
Base.Experimental.disable_new_worlds()
Mark that no new worlds (methods additions, deletions, etc) are permitted to be created at
any future time, allowing for lower latencies for some operations and slightly lower memory
usage, by eliminating the tracking of those possible invalidation.
"""
disable_new_worlds() = ccall(:jl_disable_new_worlds, Cvoid, ())

end
3 changes: 2 additions & 1 deletion base/intfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1205,6 +1205,8 @@ julia> binomial(-5, 3)
# External links
* [Binomial coefficient](https://en.wikipedia.org/wiki/Binomial_coefficient) on Wikipedia.
"""
binomial(n::Integer, k::Integer) = binomial(promote(n, k)...)

Base.@assume_effects :terminates_locally function binomial(n::T, k::T) where T<:Integer
n0, k0 = n, k
k < 0 && return zero(T)
Expand Down Expand Up @@ -1233,7 +1235,6 @@ Base.@assume_effects :terminates_locally function binomial(n::T, k::T) where T<:
end
copysign(x, sgn)
end
binomial(n::Integer, k::Integer) = binomial(promote(n, k)...)

"""
binomial(x::Number, k::Integer)
Expand Down
9 changes: 7 additions & 2 deletions base/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1587,9 +1587,14 @@ function run_extension_callbacks(extid::ExtensionId)
true
catch
# Try to continue loading if loading an extension errors
errs = current_exceptions()
@error "Error during loading of extension $(extid.id.name) of $(extid.parentid.name), \
if JLOptions().incremental != 0
# during incremental precompilation, this should be fail-fast
rethrow()
else
errs = current_exceptions()
@error "Error during loading of extension $(extid.id.name) of $(extid.parentid.name), \
use `Base.retry_load_extensions()` to retry." exception=errs
end
false
finally
global loading_extension = false
Expand Down
61 changes: 41 additions & 20 deletions base/sort.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1475,21 +1475,15 @@ InitialOptimizations(next) = SubArrayOptimization(
Small{10}(
IEEEFloatOptimization(
next)))))
"""
DEFAULT_STABLE

The default sorting algorithm.
This algorithm is guaranteed to be stable (i.e. it will not reorder elements that compare
equal). It makes an effort to be fast for most inputs.
The algorithms used by `DEFAULT_STABLE` are an implementation detail. See extended help
for the current dispatch system.
"""
struct DefaultStable <: Algorithm end
# Extended Help
`DefaultStable` is an algorithm which indicates that a fast, general purpose sorting
algorithm should be used, but does not specify exactly which algorithm.
`DEFAULT_STABLE` is composed of two parts: the [`InitialOptimizations`](@ref) and a hybrid
of Radix, Insertion, Counting, Quick sorts.
Currently, it is composed of two parts: the [`InitialOptimizations`](@ref) and a hybrid of
Radix, Insertion, Counting, Quick sorts.
We begin with MissingOptimization because it has no runtime cost when it is not
triggered and can enable other optimizations to be applied later. For example,
Expand Down Expand Up @@ -1549,7 +1543,39 @@ stage.
Finally, if the input has length less than 80, we dispatch to [`InsertionSort`](@ref) and
otherwise we dispatch to [`ScratchQuickSort`](@ref).
"""
const DEFAULT_STABLE = InitialOptimizations(
struct DefaultStable <: Algorithm end

"""
DEFAULT_STABLE
The default sorting algorithm.
This algorithm is guaranteed to be stable (i.e. it will not reorder elements that compare
equal). It makes an effort to be fast for most inputs.
The algorithms used by `DEFAULT_STABLE` are an implementation detail. See the docstring
of `Base.Sort.DefaultStable` for the current dispatch system.
"""
const DEFAULT_STABLE = DefaultStable()

"""
DefaultUnstable <: Algorithm
Like [`DefaultStable`](@ref), but does not guarantee stability.
"""
struct DefaultUnstable <: Algorithm end

"""
DEFAULT_UNSTABLE
An efficient sorting algorithm which may or may not be stable.
The algorithms used by `DEFAULT_UNSTABLE` are an implementation detail. They are currently
the same as those used by [`DEFAULT_STABLE`](@ref), but this is subject to change in future.
"""
const DEFAULT_UNSTABLE = DefaultUnstable()

const _DEFAULT_ALGORITHMS_FOR_VECTORS = InitialOptimizations(
IsUIntMappable(
Small{40}(
CheckSorted(
Expand All @@ -1560,15 +1586,10 @@ const DEFAULT_STABLE = InitialOptimizations(
ScratchQuickSort())))))),
StableCheckSorted(
ScratchQuickSort())))
"""
DEFAULT_UNSTABLE

An efficient sorting algorithm.
_sort!(v::AbstractVector, ::Union{DefaultStable, DefaultUnstable}, o::Ordering, kw) =
_sort!(v, _DEFAULT_ALGORITHMS_FOR_VECTORS, o, kw)

The algorithms used by `DEFAULT_UNSTABLE` are an implementation detail. They are currently
the same as those used by [`DEFAULT_STABLE`](@ref), but this is subject to change in future.
"""
const DEFAULT_UNSTABLE = DEFAULT_STABLE
const SMALL_THRESHOLD = 20

function Base.show(io::IO, alg::Algorithm)
Expand Down
6 changes: 6 additions & 0 deletions base/strings/unicode.jl
Original file line number Diff line number Diff line change
Expand Up @@ -534,11 +534,17 @@ iscntrl(c::AbstractChar) = c <= '\x1f' || '\x7f' <= c <= '\u9f'
Tests whether a character belongs to the Unicode general category Punctuation, i.e. a
character whose category code begins with 'P'.
!!! note
This behavior is different from the `ispunct` function in C.
# Examples
```jldoctest
julia> ispunct('α')
false
julia> ispunct('=')
false
julia> ispunct('/')
true
Expand Down
2 changes: 2 additions & 0 deletions base/threadingconstructs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
export threadid, nthreads, @threads, @spawn,
threadpool, nthreadpools

public Condition

"""
Threads.threadid([t::Task]) -> Int
Expand Down
Loading

0 comments on commit 0945185

Please sign in to comment.