@@ -43,16 +43,21 @@ following meanings:
4343 except that it may access or modify mutable memory pointed to by its call arguments.
4444 This may later be refined to `ALWAYS_TRUE` in a case when call arguments are known to be immutable.
4545 This state corresponds to LLVM's `inaccessiblemem_or_argmemonly` function attribute.
46- - `noub::UInt8`: indicates that the method will not execute any undefined behavior (for any input).
47- Note that undefined behavior may technically cause the method to violate any other effect
48- assertions (such as `:consistent` or `:effect_free`) as well, but we do not model this,
49- and they assume the absence of undefined behavior.
50- * `ALWAYS_TRUE`: this method is guaranteed to not execute any undefined behavior.
46+ - `noub::UInt8`:
47+ * `ALWAYS_TRUE`: this method is guaranteed to not execute any undefined behavior (for any input).
5148 * `ALWAYS_FALSE`: this method may execute undefined behavior.
5249 * `NOUB_IF_NOINBOUNDS`: this method is guaranteed to not execute any undefined behavior
5350 if the caller does not set nor propagate the `@inbounds` context.
54- - `nonoverlayed::Bool`: indicates that any methods that may be called within this method
55- are not defined in an [overlayed method table](@ref OverlayMethodTable).
51+ Note that undefined behavior may technically cause the method to violate any other effect
52+ assertions (such as `:consistent` or `:effect_free`) as well, but we do not model this,
53+ and they assume the absence of undefined behavior.
54+ - `nonoverlayed::UInt8`:
55+ * `ALWAYS_TRUE`: this method is guaranteed to not invoke any methods that defined in an
56+ [overlayed method table](@ref OverlayMethodTable).
57+ * `CONSISTENT_OVERLAY`: this method may invoke overlayed methods, but all such overlayed
58+ methods are `:consistent` with their non-overlayed original counterparts
59+ (see [`Base.@assume_effects`](@ref) for the exact definition of `:consistenct`-cy).
60+ * `ALWAYS_FALSE`: this method may invoke overlayed methods.
5661
5762Note that the representations above are just internal implementation details and thus likely
5863to change in the future. See [`Base.@assume_effects`](@ref) for more detailed explanation
@@ -94,8 +99,10 @@ The output represents the state of different effect properties in the following
9499 - `+u` (green): `true`
95100 - `-u` (red): `false`
96101 - `?u` (yellow): `NOUB_IF_NOINBOUNDS`
97-
98- Additionally, if the `nonoverlayed` property is false, a red prime symbol (′) is displayed after the tuple.
102+ 8. `:nonoverlayed` (`o`):
103+ - `+o` (green): `ALWAYS_TRUE`
104+ - `-o` (red): `ALWAYS_FALSE`
105+ - `?o` (yellow): `CONSISTENT_OVERLAY`
99106"""
100107struct Effects
101108 consistent:: UInt8
@@ -105,7 +112,7 @@ struct Effects
105112 notaskstate:: Bool
106113 inaccessiblememonly:: UInt8
107114 noub:: UInt8
108- nonoverlayed:: Bool
115+ nonoverlayed:: UInt8
109116 function Effects (
110117 consistent:: UInt8 ,
111118 effect_free:: UInt8 ,
@@ -114,7 +121,7 @@ struct Effects
114121 notaskstate:: Bool ,
115122 inaccessiblememonly:: UInt8 ,
116123 noub:: UInt8 ,
117- nonoverlayed:: Bool )
124+ nonoverlayed:: UInt8 )
118125 return new (
119126 consistent,
120127 effect_free,
@@ -150,10 +157,13 @@ const INACCESSIBLEMEM_OR_ARGMEMONLY = 0x01 << 1
150157# :noub bits
151158const NOUB_IF_NOINBOUNDS = 0x01 << 1
152159
153- const EFFECTS_TOTAL = Effects (ALWAYS_TRUE, ALWAYS_TRUE, true , true , true , ALWAYS_TRUE, ALWAYS_TRUE, true )
154- const EFFECTS_THROWS = Effects (ALWAYS_TRUE, ALWAYS_TRUE, false , true , true , ALWAYS_TRUE, ALWAYS_TRUE, true )
155- const EFFECTS_UNKNOWN = Effects (ALWAYS_FALSE, ALWAYS_FALSE, false , false , false , ALWAYS_FALSE, ALWAYS_FALSE, true ) # unknown mostly, but it's not overlayed at least (e.g. it's not a call)
156- const _EFFECTS_UNKNOWN = Effects (ALWAYS_FALSE, ALWAYS_FALSE, false , false , false , ALWAYS_FALSE, ALWAYS_FALSE, false ) # unknown really
160+ # :nonoverlayed bits
161+ const CONSISTENT_OVERLAY = 0x01 << 1
162+
163+ const EFFECTS_TOTAL = Effects (ALWAYS_TRUE, ALWAYS_TRUE, true , true , true , ALWAYS_TRUE, ALWAYS_TRUE, ALWAYS_TRUE)
164+ const EFFECTS_THROWS = Effects (ALWAYS_TRUE, ALWAYS_TRUE, false , true , true , ALWAYS_TRUE, ALWAYS_TRUE, ALWAYS_TRUE)
165+ const EFFECTS_UNKNOWN = Effects (ALWAYS_FALSE, ALWAYS_FALSE, false , false , false , ALWAYS_FALSE, ALWAYS_FALSE, ALWAYS_TRUE) # unknown mostly, but it's not overlayed at least (e.g. it's not a call)
166+ const _EFFECTS_UNKNOWN = Effects (ALWAYS_FALSE, ALWAYS_FALSE, false , false , false , ALWAYS_FALSE, ALWAYS_FALSE, ALWAYS_FALSE) # unknown really
157167
158168function Effects (effects:: Effects = _EFFECTS_UNKNOWN;
159169 consistent:: UInt8 = effects. consistent,
@@ -163,7 +173,7 @@ function Effects(effects::Effects = _EFFECTS_UNKNOWN;
163173 notaskstate:: Bool = effects. notaskstate,
164174 inaccessiblememonly:: UInt8 = effects. inaccessiblememonly,
165175 noub:: UInt8 = effects. noub,
166- nonoverlayed:: Bool = effects. nonoverlayed)
176+ nonoverlayed:: UInt8 = effects. nonoverlayed)
167177 return Effects (
168178 consistent,
169179 effect_free,
@@ -229,8 +239,11 @@ function is_better_effects(new::Effects, old::Effects)
229239 elseif new. noub != old. noub
230240 return false
231241 end
232- if new. nonoverlayed
233- any_improved |= ! old. nonoverlayed
242+ if new. nonoverlayed == ALWAYS_TRUE
243+ any_improved |= old. nonoverlayed != ALWAYS_TRUE
244+ elseif new. nonoverlayed == CONSISTENT_OVERLAY
245+ old. nonoverlayed == ALWAYS_TRUE && return false
246+ any_improved |= old. nonoverlayed != CONSISTENT_OVERLAY
234247 elseif new. nonoverlayed != old. nonoverlayed
235248 return false
236249 end
@@ -265,7 +278,7 @@ is_notaskstate(effects::Effects) = effects.notaskstate
265278is_inaccessiblememonly (effects:: Effects ) = effects. inaccessiblememonly === ALWAYS_TRUE
266279is_noub (effects:: Effects ) = effects. noub === ALWAYS_TRUE
267280is_noub_if_noinbounds (effects:: Effects ) = effects. noub === NOUB_IF_NOINBOUNDS
268- is_nonoverlayed (effects:: Effects ) = effects. nonoverlayed
281+ is_nonoverlayed (effects:: Effects ) = effects. nonoverlayed === ALWAYS_TRUE
269282
270283# implies `is_notaskstate` & `is_inaccessiblememonly`, but not explicitly checked here
271284is_foldable (effects:: Effects ) =
@@ -295,6 +308,8 @@ is_effect_free_if_inaccessiblememonly(effects::Effects) = !iszero(effects.effect
295308
296309is_inaccessiblemem_or_argmemonly (effects:: Effects ) = effects. inaccessiblememonly === INACCESSIBLEMEM_OR_ARGMEMONLY
297310
311+ is_consistent_overlay (effects:: Effects ) = effects. nonoverlayed === CONSISTENT_OVERLAY
312+
298313function encode_effects (e:: Effects )
299314 return ((e. consistent % UInt32) << 0 ) |
300315 ((e. effect_free % UInt32) << 3 ) |
@@ -315,7 +330,7 @@ function decode_effects(e::UInt32)
315330 _Bool ((e >> 7 ) & 0x01 ),
316331 UInt8 ((e >> 8 ) & 0x03 ),
317332 UInt8 ((e >> 10 ) & 0x03 ),
318- _Bool ((e >> 12 ) & 0x01 ))
333+ UInt8 ((e >> 12 ) & 0x03 ))
319334end
320335
321336function encode_effects_override (eo:: EffectsOverride )
@@ -329,6 +344,7 @@ function encode_effects_override(eo::EffectsOverride)
329344 eo. inaccessiblememonly && (e |= (0x0001 << 6 ))
330345 eo. noub && (e |= (0x0001 << 7 ))
331346 eo. noub_if_noinbounds && (e |= (0x0001 << 8 ))
347+ eo. consistent_overlay && (e |= (0x0001 << 9 ))
332348 return e
333349end
334350
@@ -342,7 +358,8 @@ function decode_effects_override(e::UInt16)
342358 ! iszero (e & (0x0001 << 5 )),
343359 ! iszero (e & (0x0001 << 6 )),
344360 ! iszero (e & (0x0001 << 7 )),
345- ! iszero (e & (0x0001 << 8 )))
361+ ! iszero (e & (0x0001 << 8 )),
362+ ! iszero (e & (0x0001 << 9 )))
346363end
347364
348365decode_statement_effects_override (ssaflag:: UInt32 ) =
0 commit comments