@@ -43,16 +43,21 @@ following meanings:
43
43
except that it may access or modify mutable memory pointed to by its call arguments.
44
44
This may later be refined to `ALWAYS_TRUE` in a case when call arguments are known to be immutable.
45
45
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).
51
48
* `ALWAYS_FALSE`: this method may execute undefined behavior.
52
49
* `NOUB_IF_NOINBOUNDS`: this method is guaranteed to not execute any undefined behavior
53
50
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.
56
61
57
62
Note that the representations above are just internal implementation details and thus likely
58
63
to 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
94
99
- `+u` (green): `true`
95
100
- `-u` (red): `false`
96
101
- `?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`
99
106
"""
100
107
struct Effects
101
108
consistent:: UInt8
@@ -105,7 +112,7 @@ struct Effects
105
112
notaskstate:: Bool
106
113
inaccessiblememonly:: UInt8
107
114
noub:: UInt8
108
- nonoverlayed:: Bool
115
+ nonoverlayed:: UInt8
109
116
function Effects (
110
117
consistent:: UInt8 ,
111
118
effect_free:: UInt8 ,
@@ -114,7 +121,7 @@ struct Effects
114
121
notaskstate:: Bool ,
115
122
inaccessiblememonly:: UInt8 ,
116
123
noub:: UInt8 ,
117
- nonoverlayed:: Bool )
124
+ nonoverlayed:: UInt8 )
118
125
return new (
119
126
consistent,
120
127
effect_free,
@@ -150,10 +157,13 @@ const INACCESSIBLEMEM_OR_ARGMEMONLY = 0x01 << 1
150
157
# :noub bits
151
158
const NOUB_IF_NOINBOUNDS = 0x01 << 1
152
159
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
157
167
158
168
function Effects (effects:: Effects = _EFFECTS_UNKNOWN;
159
169
consistent:: UInt8 = effects. consistent,
@@ -163,7 +173,7 @@ function Effects(effects::Effects = _EFFECTS_UNKNOWN;
163
173
notaskstate:: Bool = effects. notaskstate,
164
174
inaccessiblememonly:: UInt8 = effects. inaccessiblememonly,
165
175
noub:: UInt8 = effects. noub,
166
- nonoverlayed:: Bool = effects. nonoverlayed)
176
+ nonoverlayed:: UInt8 = effects. nonoverlayed)
167
177
return Effects (
168
178
consistent,
169
179
effect_free,
@@ -229,8 +239,11 @@ function is_better_effects(new::Effects, old::Effects)
229
239
elseif new. noub != old. noub
230
240
return false
231
241
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
234
247
elseif new. nonoverlayed != old. nonoverlayed
235
248
return false
236
249
end
@@ -265,7 +278,7 @@ is_notaskstate(effects::Effects) = effects.notaskstate
265
278
is_inaccessiblememonly (effects:: Effects ) = effects. inaccessiblememonly === ALWAYS_TRUE
266
279
is_noub (effects:: Effects ) = effects. noub === ALWAYS_TRUE
267
280
is_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
269
282
270
283
# implies `is_notaskstate` & `is_inaccessiblememonly`, but not explicitly checked here
271
284
is_foldable (effects:: Effects ) =
@@ -295,6 +308,8 @@ is_effect_free_if_inaccessiblememonly(effects::Effects) = !iszero(effects.effect
295
308
296
309
is_inaccessiblemem_or_argmemonly (effects:: Effects ) = effects. inaccessiblememonly === INACCESSIBLEMEM_OR_ARGMEMONLY
297
310
311
+ is_consistent_overlay (effects:: Effects ) = effects. nonoverlayed === CONSISTENT_OVERLAY
312
+
298
313
function encode_effects (e:: Effects )
299
314
return ((e. consistent % UInt32) << 0 ) |
300
315
((e. effect_free % UInt32) << 3 ) |
@@ -315,7 +330,7 @@ function decode_effects(e::UInt32)
315
330
_Bool ((e >> 7 ) & 0x01 ),
316
331
UInt8 ((e >> 8 ) & 0x03 ),
317
332
UInt8 ((e >> 10 ) & 0x03 ),
318
- _Bool ((e >> 12 ) & 0x01 ))
333
+ UInt8 ((e >> 12 ) & 0x03 ))
319
334
end
320
335
321
336
function encode_effects_override (eo:: EffectsOverride )
@@ -329,6 +344,7 @@ function encode_effects_override(eo::EffectsOverride)
329
344
eo. inaccessiblememonly && (e |= (0x0001 << 6 ))
330
345
eo. noub && (e |= (0x0001 << 7 ))
331
346
eo. noub_if_noinbounds && (e |= (0x0001 << 8 ))
347
+ eo. consistent_overlay && (e |= (0x0001 << 9 ))
332
348
return e
333
349
end
334
350
@@ -342,7 +358,8 @@ function decode_effects_override(e::UInt16)
342
358
! iszero (e & (0x0001 << 5 )),
343
359
! iszero (e & (0x0001 << 6 )),
344
360
! iszero (e & (0x0001 << 7 )),
345
- ! iszero (e & (0x0001 << 8 )))
361
+ ! iszero (e & (0x0001 << 8 )),
362
+ ! iszero (e & (0x0001 << 9 )))
346
363
end
347
364
348
365
decode_statement_effects_override (ssaflag:: UInt32 ) =
0 commit comments