Skip to content

Commit 0778175

Browse files
committed
effects: allow override of :nonoverlayed effect bit
Certain external `AbstractInterpreters`, such as GPUCompiler.jl, have long sought the ability to allow concrete evaluation for specific overlay-ed methods to achieve optimal inference accuracy. This is currently not permitted, although it should be safe when an overlay-ed method has the same semantics as the original method, and its result can be safely replaced with the result of the original method. Refer to JuliaGPU/GPUCompiler.jl#384 for more examples. To address this issue, this commit introduces the capability to override the `:nonoverlayed` effect bit using `@assume_effects`. With the enhancements in PR #51078, this override behaves similarly to other effect bits. Consequently, external `AbstractInterpreters` can utilize this feature to permit concrete evaluation for annotated overlay-ed methods, e.g. ```julia @overlay OVERLAY_MT Base.@assume_effects :nonoverlayed f(x) = [...] ``` However, it now seems awkward to annotate a method with `Base.@assume_effects :nonoverlayed` when it is actually marked with `@overlay`. A more intuitive terminology, like `native_executable`, might be more appropriate for renaming the `:nonoverlayed` effect bit.
1 parent 00b5060 commit 0778175

File tree

13 files changed

+116
-66
lines changed

13 files changed

+116
-66
lines changed

base/boot.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,8 @@ macro _foldable_meta()
464464
#=:terminates_locally=#false,
465465
#=:notaskstate=#false,
466466
#=:inaccessiblememonly=#false,
467-
#=:noub=#true))
467+
#=:noub=#true,
468+
#=:nonoverlayed=#false))
468469
end
469470

470471
const NTuple{N,T} = Tuple{Vararg{T,N}}

base/c.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,6 @@ macro ccall(expr)
715715
return ccall_macro_lower(:ccall, ccall_macro_parse(expr)...)
716716
end
717717

718-
macro ccall_effects(effects::UInt8, expr)
718+
macro ccall_effects(effects::UInt32, expr)
719719
return ccall_macro_lower((:ccall, effects), ccall_macro_parse(expr)...)
720720
end

base/compiler/abstractinterpretation.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2557,7 +2557,7 @@ function abstract_eval_foreigncall(interp::AbstractInterpreter, e::Expr, vtypes:
25572557
abstract_eval_value(interp, x, vtypes, sv)
25582558
end
25592559
cconv = e.args[5]
2560-
if isa(cconv, QuoteNode) && (v = cconv.value; isa(v, Tuple{Symbol, UInt8}))
2560+
if isa(cconv, QuoteNode) && (v = cconv.value; isa(v, Tuple{Symbol, UInt32}))
25612561
override = decode_effects_override(v[2])
25622562
effects = Effects(effects;
25632563
consistent = override.consistent ? ALWAYS_TRUE : effects.consistent,

base/compiler/effects.jl

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -258,29 +258,32 @@ struct EffectsOverride
258258
notaskstate::Bool
259259
inaccessiblememonly::Bool
260260
noub::Bool
261+
nonoverlayed::Bool
261262
end
262263

263264
function encode_effects_override(eo::EffectsOverride)
264-
e = 0x00
265-
eo.consistent && (e |= (0x01 << 0))
266-
eo.effect_free && (e |= (0x01 << 1))
267-
eo.nothrow && (e |= (0x01 << 2))
268-
eo.terminates_globally && (e |= (0x01 << 3))
269-
eo.terminates_locally && (e |= (0x01 << 4))
270-
eo.notaskstate && (e |= (0x01 << 5))
271-
eo.inaccessiblememonly && (e |= (0x01 << 6))
272-
eo.noub && (e |= (0x01 << 7))
265+
e = zero(UInt32)
266+
eo.consistent && (e |= (1 << 0) % UInt32)
267+
eo.effect_free && (e |= (1 << 1) % UInt32)
268+
eo.nothrow && (e |= (1 << 2) % UInt32)
269+
eo.terminates_globally && (e |= (1 << 3) % UInt32)
270+
eo.terminates_locally && (e |= (1 << 4) % UInt32)
271+
eo.notaskstate && (e |= (1 << 5) % UInt32)
272+
eo.inaccessiblememonly && (e |= (1 << 6) % UInt32)
273+
eo.noub && (e |= (1 << 7) % UInt32)
274+
eo.nonoverlayed && (e |= (1 << 8) % UInt32)
273275
return e
274276
end
275277

276-
function decode_effects_override(e::UInt8)
278+
function decode_effects_override(e::UInt32)
277279
return EffectsOverride(
278-
(e & (0x01 << 0)) != 0x00,
279-
(e & (0x01 << 1)) != 0x00,
280-
(e & (0x01 << 2)) != 0x00,
281-
(e & (0x01 << 3)) != 0x00,
282-
(e & (0x01 << 4)) != 0x00,
283-
(e & (0x01 << 5)) != 0x00,
284-
(e & (0x01 << 6)) != 0x00,
285-
(e & (0x01 << 7)) != 0x00)
280+
!iszero(e & (1 << 0)),
281+
!iszero(e & (1 << 1)),
282+
!iszero(e & (1 << 2)),
283+
!iszero(e & (1 << 3)),
284+
!iszero(e & (1 << 4)),
285+
!iszero(e & (1 << 5)),
286+
!iszero(e & (1 << 6)),
287+
!iszero(e & (1 << 7)),
288+
!iszero(e & (1 << 8)))
286289
end

base/compiler/typeinfer.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,9 @@ function adjust_effects(sv::InferenceState)
500500
if is_effect_overridden(override, :noub)
501501
ipo_effects = Effects(ipo_effects; noub=true)
502502
end
503+
if is_effect_overridden(override, :nonoverlayed)
504+
ipo_effects = Effects(ipo_effects; nonoverlayed=true)
505+
end
503506
end
504507

505508
return ipo_effects

base/essentials.jl

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,8 @@ macro _total_meta()
209209
#=:terminates_locally=#false,
210210
#=:notaskstate=#true,
211211
#=:inaccessiblememonly=#true,
212-
#=:noub=#true))
212+
#=:noub=#true,
213+
#=:nonoverlayed=#false))
213214
end
214215
# can be used in place of `@assume_effects :foldable` (supposed to be used for bootstrapping)
215216
macro _foldable_meta()
@@ -221,7 +222,8 @@ macro _foldable_meta()
221222
#=:terminates_locally=#false,
222223
#=:notaskstate=#false,
223224
#=:inaccessiblememonly=#true,
224-
#=:noub=#true))
225+
#=:noub=#true,
226+
#=:nonoverlayed=#false))
225227
end
226228
# can be used in place of `@assume_effects :nothrow` (supposed to be used for bootstrapping)
227229
macro _nothrow_meta()
@@ -233,7 +235,8 @@ macro _nothrow_meta()
233235
#=:terminates_locally=#false,
234236
#=:notaskstate=#false,
235237
#=:inaccessiblememonly=#false,
236-
#=:noub=#false))
238+
#=:noub=#false,
239+
#=:nonoverlayed=#false))
237240
end
238241
# can be used in place of `@assume_effects :terminates_locally` (supposed to be used for bootstrapping)
239242
macro _terminates_locally_meta()
@@ -245,7 +248,8 @@ macro _terminates_locally_meta()
245248
#=:terminates_locally=#true,
246249
#=:notaskstate=#false,
247250
#=:inaccessiblememonly=#false,
248-
#=:noub=#false))
251+
#=:noub=#false,
252+
#=:nonoverlayed=#false))
249253
end
250254
# can be used in place of `@assume_effects :effect_free :terminates_locally` (supposed to be used for bootstrapping)
251255
macro _effect_free_terminates_locally_meta()
@@ -257,7 +261,8 @@ macro _effect_free_terminates_locally_meta()
257261
#=:terminates_locally=#true,
258262
#=:notaskstate=#false,
259263
#=:inaccessiblememonly=#false,
260-
#=:noub=#false))
264+
#=:noub=#false,
265+
#=:nonoverlayed=#false))
261266
end
262267

263268
# another version of inlining that propagates an inbounds context

base/expr.jl

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -714,8 +714,9 @@ macro assume_effects(args...)
714714
ex = nothing
715715
idx = length(args)
716716
end
717-
(consistent, effect_free, nothrow, terminates_globally, terminates_locally, notaskstate, inaccessiblememonly, noub) =
718-
(false, false, false, false, false, false, false, false, false)
717+
(consistent, effect_free, nothrow, terminates_globally, terminates_locally,
718+
notaskstate, inaccessiblememonly, noub, nonoverlayed) =
719+
(false, false, false, false, false, false, false, false, false, false)
719720
for org_setting in args[1:idx]
720721
(setting, val) = compute_assumed_setting(org_setting)
721722
if setting === :consistent
@@ -734,6 +735,8 @@ macro assume_effects(args...)
734735
inaccessiblememonly = val
735736
elseif setting === :noub
736737
noub = val
738+
elseif setting === :nonoverlayed
739+
nonoverlayed = val
737740
elseif setting === :foldable
738741
consistent = effect_free = terminates_globally = noub = val
739742
elseif setting === :removable
@@ -746,15 +749,18 @@ macro assume_effects(args...)
746749
end
747750
if is_function_def(inner)
748751
return esc(pushmeta!(ex, :purity,
749-
consistent, effect_free, nothrow, terminates_globally, terminates_locally, notaskstate, inaccessiblememonly, noub))
752+
consistent, effect_free, nothrow, terminates_globally, terminates_locally,
753+
notaskstate, inaccessiblememonly, noub, nonoverlayed))
750754
elseif isexpr(ex, :macrocall) && ex.args[1] === Symbol("@ccall")
751755
ex.args[1] = GlobalRef(Base, Symbol("@ccall_effects"))
752756
insert!(ex.args, 3, Core.Compiler.encode_effects_override(Core.Compiler.EffectsOverride(
753-
consistent, effect_free, nothrow, terminates_globally, terminates_locally, notaskstate, inaccessiblememonly, noub)))
757+
consistent, effect_free, nothrow, terminates_globally, terminates_locally,
758+
notaskstate, inaccessiblememonly, noub, nonoverlayed)))
754759
return esc(ex)
755760
else # anonymous function case
756761
return Expr(:meta, Expr(:purity,
757-
consistent, effect_free, nothrow, terminates_globally, terminates_locally, notaskstate, inaccessiblememonly, noub))
762+
consistent, effect_free, nothrow, terminates_globally, terminates_locally,
763+
notaskstate, inaccessiblememonly, noub, nonoverlayed))
758764
end
759765
end
760766

base/strings/string.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,11 @@ end
8787

8888
# This is @assume_effects :effect_free :nothrow :terminates_globally @ccall jl_alloc_string(n::Csize_t)::Ref{String},
8989
# but the macro is not available at this time in bootstrap, so we write it manually.
90-
@eval _string_n(n::Integer) = $(Expr(:foreigncall, QuoteNode(:jl_alloc_string), Ref{String}, Expr(:call, Expr(:core, :svec), :Csize_t), 1, QuoteNode((:ccall,0xe)), :(convert(Csize_t, n))))
90+
@eval function _string_n(n::Integer)
91+
return $(Expr(:foreigncall, QuoteNode(:jl_alloc_string), Ref{String},
92+
Expr(:call, Expr(:core, :svec), :Csize_t), 1, QuoteNode((:ccall, 0x0000000e)),
93+
:(convert(Csize_t, n))))
94+
end
9195

9296
"""
9397
String(s::AbstractString)

src/jltypes.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3005,7 +3005,7 @@ void jl_init_types(void) JL_GC_DISABLED
30053005
jl_bool_type,
30063006
jl_uint8_type,
30073007
jl_uint8_type,
3008-
jl_uint8_type,
3008+
jl_uint32_type,
30093009
jl_uint16_type),
30103010
jl_emptysvec,
30113011
0, 1, 22);
@@ -3074,7 +3074,7 @@ void jl_init_types(void) JL_GC_DISABLED
30743074
jl_bool_type,
30753075
jl_uint8_type,
30763076
jl_uint8_type,
3077-
jl_uint8_type),
3077+
jl_uint32_type),
30783078
jl_emptysvec,
30793079
0, 1, 10);
30803080
//const static uint32_t method_constfields[1] = { 0x03fc065f }; // (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<6)|(1<<9)|(1<<10)|(1<<18)|(1<<19)|(1<<20)|(1<<21)|(1<<22)|(1<<23)|(1<<24)|(1<<25);

src/julia.h

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,9 @@ typedef union __jl_purity_overrides_t {
269269
uint8_t ipo_notaskstate : 1;
270270
uint8_t ipo_inaccessiblememonly : 1;
271271
uint8_t ipo_noub : 1;
272+
uint8_t ipo_nonoverlayed : 1;
272273
} overrides;
273-
uint8_t bits;
274+
uint32_t bits;
274275
} _jl_purity_overrides_t;
275276

276277
// This type describes a single function body
@@ -428,22 +429,24 @@ typedef struct _jl_code_instance_t {
428429
// see also encode_effects() and decode_effects() in `base/compiler/effects.jl`,
429430
uint32_t ipo_purity_bits;
430431
// ipo_purity_flags:
431-
// uint8_t ipo_consistent : 2;
432+
// uint8_t ipo_consistent : 3;
432433
// uint8_t ipo_effect_free : 2;
433-
// uint8_t ipo_nothrow : 2;
434-
// uint8_t ipo_terminates : 2;
435-
// uint8_t ipo_nonoverlayed : 1;
434+
// uint8_t ipo_nothrow : 1;
435+
// uint8_t ipo_terminates : 1;
436436
// uint8_t ipo_notaskstate : 2;
437437
// uint8_t ipo_inaccessiblememonly : 2;
438+
// uint8_t ipo_nonoverlayed : 1;
439+
// uint8_t ipo_noinbounds : 1;
438440
_Atomic(uint32_t) purity_bits;
439441
// purity_flags:
440-
// uint8_t consistent : 2;
441-
// uint8_t effect_free : 2;
442-
// uint8_t nothrow : 2;
443-
// uint8_t terminates : 2;
444-
// uint8_t nonoverlayed : 1;
445-
// uint8_t notaskstate : 2;
446-
// uint8_t inaccessiblememonly : 2;
442+
// uint8_t ipo_consistent : 3;
443+
// uint8_t ipo_effect_free : 2;
444+
// uint8_t ipo_nothrow : 1;
445+
// uint8_t ipo_terminates : 1;
446+
// uint8_t ipo_notaskstate : 2;
447+
// uint8_t ipo_inaccessiblememonly : 2;
448+
// uint8_t ipo_nonoverlayed : 1;
449+
// uint8_t ipo_noinbounds : 1;
447450
jl_value_t *argescapes; // escape information of call arguments
448451

449452
// compilation state cache

src/method.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ static jl_value_t *resolve_globals(jl_value_t *expr, jl_module_t *module, jl_sve
192192
jl_error("In ccall calling convention, expected two argument tuple or symbol.");
193193
}
194194
JL_TYPECHK(ccall method definition, symbol, jl_get_nth_field(cc, 0));
195-
JL_TYPECHK(ccall method definition, uint8, jl_get_nth_field(cc, 1));
195+
JL_TYPECHK(ccall method definition, uint32, jl_get_nth_field(cc, 1));
196196
}
197197
jl_exprargset(e, 0, resolve_globals(jl_exprarg(e, 0), module, sparam_vals, binding_effects, 1));
198198
i++;
@@ -328,7 +328,7 @@ static void jl_code_info_set_ir(jl_code_info_t *li, jl_expr_t *ir)
328328
else if (ma == (jl_value_t*)jl_no_constprop_sym)
329329
li->constprop = 2;
330330
else if (jl_is_expr(ma) && ((jl_expr_t*)ma)->head == jl_purity_sym) {
331-
if (jl_expr_nargs(ma) == 8) {
331+
if (jl_expr_nargs(ma) == 9) {
332332
li->purity.overrides.ipo_consistent = jl_unbox_bool(jl_exprarg(ma, 0));
333333
li->purity.overrides.ipo_effect_free = jl_unbox_bool(jl_exprarg(ma, 1));
334334
li->purity.overrides.ipo_nothrow = jl_unbox_bool(jl_exprarg(ma, 2));
@@ -337,6 +337,7 @@ static void jl_code_info_set_ir(jl_code_info_t *li, jl_expr_t *ir)
337337
li->purity.overrides.ipo_notaskstate = jl_unbox_bool(jl_exprarg(ma, 5));
338338
li->purity.overrides.ipo_inaccessiblememonly = jl_unbox_bool(jl_exprarg(ma, 6));
339339
li->purity.overrides.ipo_noub = jl_unbox_bool(jl_exprarg(ma, 7));
340+
li->purity.overrides.ipo_nonoverlayed = jl_unbox_bool(jl_exprarg(ma, 8));
340341
}
341342
}
342343
else

stdlib/Serialization/src/Serialization.jl

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ const TAGS = Any[
8080
const NTAGS = length(TAGS)
8181
@assert NTAGS == 255
8282

83-
const ser_version = 24 # do not make changes without bumping the version #!
83+
const ser_version = 25 # do not make changes without bumping the version #!
8484

8585
format_version(::AbstractSerializer) = ser_version
8686
format_version(s::Serializer) = s.version
@@ -1028,7 +1028,8 @@ function deserialize(s::AbstractSerializer, ::Type{Method})
10281028
isva = deserialize(s)::Bool
10291029
is_for_opaque_closure = false
10301030
nospecializeinfer = false
1031-
constprop = purity = 0x00
1031+
constprop = 0x00
1032+
purity = format_version(s) >= 25 ? zero(UInt32) : 0x00
10321033
template_or_is_opaque = deserialize(s)
10331034
if isa(template_or_is_opaque, Bool)
10341035
is_for_opaque_closure = template_or_is_opaque
@@ -1039,7 +1040,7 @@ function deserialize(s::AbstractSerializer, ::Type{Method})
10391040
constprop = deserialize(s)::UInt8
10401041
end
10411042
if format_version(s) >= 17
1042-
purity = deserialize(s)::UInt8
1043+
purity = deserialize(s)::(format_version(s) >= 25 ? UInt32 : UInt8)
10431044
end
10441045
template = deserialize(s)
10451046
else
@@ -1211,7 +1212,7 @@ function deserialize(s::AbstractSerializer, ::Type{CodeInfo})
12111212
ci.constprop = deserialize(s)::UInt8
12121213
end
12131214
if format_version(s) >= 17
1214-
ci.purity = deserialize(s)::UInt8
1215+
ci.purity = deserialize(s)::(format_version(s) >= 25 ? UInt32 : UInt8)
12151216
end
12161217
if format_version(s) >= 22
12171218
ci.inlining_cost = deserialize(s)::UInt16

0 commit comments

Comments
 (0)