Skip to content

Commit b208ee9

Browse files
aviateskstevengj
authored andcommitted
Compiler.jl: use Base.[all|any] instead of Compiler's own versions (#56851)
The current `Compiler` defines its own versions of `all` and `any`, which are separate generic functions from `Base.[all|any]`: https://github.com/JuliaLang/julia/blob/2ed1a411e0a080f3107e75bb65105a15a0533a90/Compiler/src/utilities.jl#L15-L32 On the other hand, at the point where `Base.Compiler` is bootstrapped, only a subset of `Base.[all|any]` are defined, specifically those related to `Tuple`: https://github.com/JuliaLang/julia/blob/2ed1a411e0a080f3107e75bb65105a15a0533a90/base/tuple.jl#L657-L668. Consequently, in the type inference world, functions like `Base.all(::Generator)` are unavailable. If `Base.Compiler` attempts to perform operations such as `::BitSet ⊆ ::BitSet` (which internally uses `Base.[all|any]`), a world age error occurs (while `Compiler.[all|any]` can handle these operations, `::BitSet ⊆ ::BitSet` uses `Base.[all|any]`, leading to this issue) To resolve this problem, this commit removes the custom `Compiler` versions of `[all|any]` and switches to using the Base versions. One concern is that the previous `Compiler` versions of `[all|any]` utilized `@nospecialize`. That annotation was introduced a long time ago to prevent over-specialization, but it is questionable whether it is still effective with the current compiler implementation. The results of the nanosoldier benchmarks conducted below also seem to confirm that the `@nospecialize`s are no longer necessary for those functions.
1 parent 7766adc commit b208ee9

File tree

5 files changed

+260
-276
lines changed

5 files changed

+260
-276
lines changed

Compiler/src/Compiler.jl

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -41,36 +41,36 @@ ccall(:jl_set_module_uuid, Cvoid, (Any, NTuple{2, UInt64}), Compiler,
4141

4242
using Core.Intrinsics, Core.IR
4343

44-
import Core: print, println, show, write, unsafe_write,
45-
_apply_iterate, svec, apply_type, Builtin, IntrinsicFunction,
46-
MethodInstance, CodeInstance, MethodTable, MethodMatch, PartialOpaque,
47-
TypeofVararg, Core, SimpleVector, donotdelete, compilerbarrier,
48-
memoryref_isassigned, memoryrefnew, memoryrefoffset, memoryrefget,
49-
memoryrefset!, typename
44+
using Core: Builtin, CodeInstance, IntrinsicFunction, MethodInstance, MethodMatch,
45+
MethodTable, PartialOpaque, SimpleVector, TypeofVararg,
46+
_apply_iterate, apply_type, compilerbarrier, donotdelete, memoryref_isassigned,
47+
memoryrefget, memoryrefnew, memoryrefoffset, memoryrefset!, print, println, show, svec,
48+
typename, unsafe_write, write
5049

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

7575
const getproperty = Core.getfield
7676
const setproperty! = Core.setfield!

Compiler/src/utilities.jl

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,6 @@ if !@isdefined(var"@timeit")
1212
end
1313
end
1414

15-
# avoid cycle due to over-specializing `any` when used by inference
16-
function _any(@nospecialize(f), a)
17-
for x in a
18-
f(x) && return true
19-
end
20-
return false
21-
end
22-
any(@nospecialize(f), itr) = _any(f, itr)
23-
any(itr) = _any(identity, itr)
24-
25-
function _all(@nospecialize(f), a)
26-
for x in a
27-
f(x) || return false
28-
end
29-
return true
30-
end
31-
all(@nospecialize(f), itr) = _all(f, itr)
32-
all(itr) = _all(identity, itr)
33-
3415
function contains_is(itr, @nospecialize(x))
3516
for y in itr
3617
if y === x

base/Base_compiler.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,8 @@ using .Iterators: Flatten, Filter, product # for generators
249249
using .Iterators: Stateful # compat (was formerly used in reinterpretarray.jl)
250250
include("namedtuple.jl")
251251

252+
include("anyall.jl")
253+
252254
include("ordering.jl")
253255
using .Order
254256

base/anyall.jl

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
# This file is a part of Julia. License is MIT: https://julialang.org/license
2+
3+
## all & any
4+
5+
"""
6+
any(itr) -> Bool
7+
8+
Test whether any elements of a boolean collection are `true`, returning `true` as
9+
soon as the first `true` value in `itr` is encountered (short-circuiting). To
10+
short-circuit on `false`, use [`all`](@ref).
11+
12+
If the input contains [`missing`](@ref) values, return `missing` if all non-missing
13+
values are `false` (or equivalently, if the input contains no `true` value), following
14+
[three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic).
15+
16+
See also: [`all`](@ref), [`count`](@ref), [`sum`](@ref), [`|`](@ref), [`||`](@ref).
17+
18+
# Examples
19+
```jldoctest
20+
julia> a = [true,false,false,true]
21+
4-element Vector{Bool}:
22+
1
23+
0
24+
0
25+
1
26+
27+
julia> any(a)
28+
true
29+
30+
julia> any((println(i); v) for (i, v) in enumerate(a))
31+
1
32+
true
33+
34+
julia> any([missing, true])
35+
true
36+
37+
julia> any([false, missing])
38+
missing
39+
```
40+
"""
41+
any(itr) = any(identity, itr)
42+
43+
"""
44+
all(itr) -> Bool
45+
46+
Test whether all elements of a boolean collection are `true`, returning `false` as
47+
soon as the first `false` value in `itr` is encountered (short-circuiting). To
48+
short-circuit on `true`, use [`any`](@ref).
49+
50+
If the input contains [`missing`](@ref) values, return `missing` if all non-missing
51+
values are `true` (or equivalently, if the input contains no `false` value), following
52+
[three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic).
53+
54+
See also: [`all!`](@ref), [`any`](@ref), [`count`](@ref), [`&`](@ref), [`&&`](@ref), [`allunique`](@ref).
55+
56+
# Examples
57+
```jldoctest
58+
julia> a = [true,false,false,true]
59+
4-element Vector{Bool}:
60+
1
61+
0
62+
0
63+
1
64+
65+
julia> all(a)
66+
false
67+
68+
julia> all((println(i); v) for (i, v) in enumerate(a))
69+
1
70+
2
71+
false
72+
73+
julia> all([missing, false])
74+
false
75+
76+
julia> all([true, missing])
77+
missing
78+
```
79+
"""
80+
all(itr) = all(identity, itr)
81+
82+
"""
83+
any(p, itr) -> Bool
84+
85+
Determine whether predicate `p` returns `true` for any elements of `itr`, returning
86+
`true` as soon as the first item in `itr` for which `p` returns `true` is encountered
87+
(short-circuiting). To short-circuit on `false`, use [`all`](@ref).
88+
89+
If the input contains [`missing`](@ref) values, return `missing` if all non-missing
90+
values are `false` (or equivalently, if the input contains no `true` value), following
91+
[three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic).
92+
93+
# Examples
94+
```jldoctest
95+
julia> any(i->(4<=i<=6), [3,5,7])
96+
true
97+
98+
julia> any(i -> (println(i); i > 3), 1:10)
99+
1
100+
2
101+
3
102+
4
103+
true
104+
105+
julia> any(i -> i > 0, [1, missing])
106+
true
107+
108+
julia> any(i -> i > 0, [-1, missing])
109+
missing
110+
111+
julia> any(i -> i > 0, [-1, 0])
112+
false
113+
```
114+
"""
115+
any(f, itr) = _any(f, itr, :)
116+
117+
for ItrT = (Tuple,Any)
118+
# define a generic method and a specialized version for `Tuple`,
119+
# whose method bodies are identical, while giving better effects to the later
120+
@eval function _any(f, itr::$ItrT, ::Colon)
121+
$(ItrT === Tuple ? :(@_terminates_locally_meta) : :nothing)
122+
anymissing = false
123+
for x in itr
124+
v = f(x)
125+
if ismissing(v)
126+
anymissing = true
127+
else
128+
v && return true
129+
end
130+
end
131+
return anymissing ? missing : false
132+
end
133+
end
134+
135+
# Specialized versions of any(f, ::Tuple)
136+
# We fall back to the for loop implementation all elements have the same type or
137+
# if the tuple is too large.
138+
function any(f, itr::Tuple)
139+
if itr isa NTuple || length(itr) > 32
140+
return _any(f, itr, :)
141+
end
142+
_any_tuple(f, false, itr...)
143+
end
144+
145+
@inline function _any_tuple(f, anymissing, x, rest...)
146+
v = f(x)
147+
if ismissing(v)
148+
anymissing = true
149+
elseif v
150+
return true
151+
end
152+
return _any_tuple(f, anymissing, rest...)
153+
end
154+
@inline _any_tuple(f, anymissing) = anymissing ? missing : false
155+
156+
"""
157+
all(p, itr) -> Bool
158+
159+
Determine whether predicate `p` returns `true` for all elements of `itr`, returning
160+
`false` as soon as the first item in `itr` for which `p` returns `false` is encountered
161+
(short-circuiting). To short-circuit on `true`, use [`any`](@ref).
162+
163+
If the input contains [`missing`](@ref) values, return `missing` if all non-missing
164+
values are `true` (or equivalently, if the input contains no `false` value), following
165+
[three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic).
166+
167+
# Examples
168+
```jldoctest
169+
julia> all(i->(4<=i<=6), [4,5,6])
170+
true
171+
172+
julia> all(i -> (println(i); i < 3), 1:10)
173+
1
174+
2
175+
3
176+
false
177+
178+
julia> all(i -> i > 0, [1, missing])
179+
missing
180+
181+
julia> all(i -> i > 0, [-1, missing])
182+
false
183+
184+
julia> all(i -> i > 0, [1, 2])
185+
true
186+
```
187+
"""
188+
all(f, itr) = _all(f, itr, :)
189+
190+
for ItrT = (Tuple,Any)
191+
# define a generic method and a specialized version for `Tuple`,
192+
# whose method bodies are identical, while giving better effects to the later
193+
@eval function _all(f, itr::$ItrT, ::Colon)
194+
$(ItrT === Tuple ? :(@_terminates_locally_meta) : :nothing)
195+
anymissing = false
196+
for x in itr
197+
v = f(x)
198+
if ismissing(v)
199+
anymissing = true
200+
else
201+
v || return false
202+
end
203+
end
204+
return anymissing ? missing : true
205+
end
206+
end
207+
208+
# Specialized versions of all(f, ::Tuple),
209+
# This is similar to any(f, ::Tuple) defined above.
210+
function all(f, itr::Tuple)
211+
if itr isa NTuple || length(itr) > 32
212+
return _all(f, itr, :)
213+
end
214+
_all_tuple(f, false, itr...)
215+
end
216+
217+
@inline function _all_tuple(f, anymissing, x, rest...)
218+
v = f(x)
219+
if ismissing(v)
220+
anymissing = true
221+
# this syntax allows throwing a TypeError for non-Bool, for consistency with any
222+
elseif v
223+
nothing
224+
else
225+
return false
226+
end
227+
return _all_tuple(f, anymissing, rest...)
228+
end
229+
@inline _all_tuple(f, anymissing) = anymissing ? missing : true
230+
231+
all(::Tuple{Missing}) = missing

0 commit comments

Comments
 (0)