Skip to content

Commit b7ac60a

Browse files
committed
inference: follow up #54323, override ssaflags with new cycle effects
#54323 ensures that all frames within a cycle have the same, cycle valid effects. However, `src.ssaflags` is calculated using partial effects, so when the effects of a `frame` within the cycle are updated, there would be an inconsistency between `frame.ipo_effects` and `frame.src.ssaflags`. Due to this inconsistency, #54323 breaks the test cases from #51092, when backported to v1.11. On the surface this is because #52999 hasn't been backported to v1.11, but the fundamental issue lies in this inconsistency between cycle effects and `ssaflags`. This commit uses a somewhat hacky approach to resolve this. It identifies statements involved in the cycle comparing `stmt_edges` to `callers_in_cycle`, and updates `ssaflags` according to new cycle valid effects if necessary. This resolves the issue, but ideally, it should be implemented more safely with the new `edges` format that will be implemented in the future. For now, this approach should be okay.
1 parent fc6acc7 commit b7ac60a

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

base/compiler/typeinfer.jl

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,11 +231,46 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState)
231231
return nothing
232232
end
233233

234+
# override statement flags for a frame within the cycle so that they are consistent with
235+
# the new effects that are valid for the cycle
236+
function cycle_ssaflags!(sv::InferenceState, callers_in_cycle::Vector{InferenceState},
237+
cycle_effects::Effects)
238+
new_flags = flags_for_effects(cycle_effects)
239+
old_currpc = sv.currpc
240+
for i = 1:length(sv.src.ssaflags)
241+
edges = sv.stmt_edges[i]
242+
edges === nothing && continue
243+
if any(callers_in_cycle) do caller::InferenceState
244+
mi = caller.linfo
245+
for edge in edges
246+
edge isa MethodInstance || continue
247+
if edge === mi
248+
return true
249+
end
250+
end
251+
return false
252+
end
253+
sv.currpc = i
254+
set_curr_ssaflag!(sv, new_flags)
255+
end
256+
end
257+
sv.currpc = old_currpc
258+
return nothing
259+
end
260+
234261
function _typeinf(interp::AbstractInterpreter, frame::InferenceState)
235262
typeinf_nocycle(interp, frame) || return false # frame is now part of a higher cycle
236263
# with no active ip's, frame is done
237264
frames = frame.callers_in_cycle
238-
isempty(frames) && push!(frames, frame)
265+
if isempty(frames)
266+
push!(frames, frame)
267+
has_cycle = false
268+
elseif length(frames) == 1
269+
@assert frames[1] === frame "invalid callers_in_cycle"
270+
has_cycle = false
271+
else
272+
has_cycle = true
273+
end
239274
cycle_valid_worlds = WorldRange()
240275
cycle_effects = EFFECTS_TOTAL
241276
for caller in frames
@@ -251,6 +286,7 @@ function _typeinf(interp::AbstractInterpreter, frame::InferenceState)
251286
for caller in frames
252287
caller.valid_worlds = cycle_valid_worlds
253288
caller.ipo_effects = cycle_effects
289+
has_cycle && cycle_ssaflags!(caller, frames, cycle_effects)
254290
finish(caller, caller.interp)
255291
end
256292
for caller in frames

test/compiler/inference.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5291,6 +5291,15 @@ end
52915291
foo51090(b) = return bar51090(b)
52925292
@test !fully_eliminated(foo51090, (Int,))
52935293

5294+
Base.@assume_effects :terminates_globally @noinline function bar51090_terminates(b)
5295+
b == 0 && return
5296+
r = foo51090_terminates(b - 1)
5297+
Base.donotdelete(b)
5298+
return r
5299+
end
5300+
foo51090_terminates(b) = return bar51090_terminates(b)
5301+
@test !fully_eliminated(foo51090_terminates, (Int,))
5302+
52945303
# exploit throwness from concrete eval for intrinsics
52955304
@test Base.return_types() do
52965305
Base.or_int(true, 1)

0 commit comments

Comments
 (0)