Skip to content

Commit cf875c1

Browse files
authored
gf.c: Fix backedge de-duplication bug (#58106)
This code was checking for the old edge type (`MethodInstance`) instead of the new one (`CodeInstance`), causing duplicate non-invoke edges to accumulate in our `backedges`.
1 parent 5c6d5de commit cf875c1

File tree

3 files changed

+40
-1
lines changed

3 files changed

+40
-1
lines changed

Compiler/src/typeinfer.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,8 @@ function store_backedges(caller::CodeInstance, edges::SimpleVector)
706706
# `invoke` edge
707707
elseif isa(callee, CodeInstance)
708708
callee = get_ci_mi(callee)
709+
else
710+
callee = callee::MethodInstance
709711
end
710712
ccall(:jl_method_instance_add_backedge, Cvoid, (Any, Any, Any), callee, item, caller)
711713
i += 2

Compiler/test/invalidation.jl

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,43 @@ begin
162162
@test "42" == String(take!(GLOBAL_BUFFER))
163163
end
164164

165+
begin
166+
deduped_callee(x::Int) = @noinline rand(Int)
167+
deduped_caller1(x::Int) = @noinline deduped_callee(x)
168+
deduped_caller2(x::Int) = @noinline deduped_callee(x)
169+
170+
# run inference on both `deduped_callerx` and `deduped_callee`
171+
let (src, rt) = code_typed((Int,); interp=InvalidationTester()) do x
172+
@inline deduped_caller1(x)
173+
@inline deduped_caller2(x)
174+
end |> only
175+
@test rt === Int
176+
@test any(isinvoke(:deduped_callee), src.code)
177+
end
178+
179+
# Verify that adding the backedge again does not actually add a new backedge
180+
let mi1 = Base.method_instance(deduped_caller1, (Int,)),
181+
mi2 = Base.method_instance(deduped_caller2, (Int,)),
182+
ci1 = mi1.cache
183+
ci2 = mi2.cache
184+
185+
callee_mi = Base.method_instance(deduped_callee, (Int,))
186+
187+
# Inference should have added the callers to the callee's backedges
188+
@test ci1 in callee_mi.backedges
189+
@test ci2 in callee_mi.backedges
190+
191+
N = length(callee_mi.backedges)
192+
Core.Compiler.store_backedges(ci1, Core.svec(callee_mi))
193+
Core.Compiler.store_backedges(ci2, Core.svec(callee_mi))
194+
N′ = length(callee_mi.backedges)
195+
196+
# The number of backedges should not be affected by an additional store,
197+
# since de-duplication should have noticed the edge is already tracked
198+
@test N == N′
199+
end
200+
end
201+
165202
# we can avoid adding backedge even if the callee's return type is not the top
166203
# when the return value is not used within the caller
167204
begin take!(GLOBAL_BUFFER)

src/gf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2004,7 +2004,7 @@ JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee,
20042004
if (ciedge != (jl_value_t*)caller)
20052005
continue;
20062006
jl_value_t *invokeTypes = i > 0 ? jl_array_ptr_ref(backedges, i - 1) : NULL;
2007-
if (invokeTypes && jl_is_method_instance(invokeTypes))
2007+
if (invokeTypes && jl_is_code_instance(invokeTypes))
20082008
invokeTypes = NULL;
20092009
if ((invokesig == NULL && invokeTypes == NULL) ||
20102010
(invokesig && invokeTypes && jl_types_equal(invokesig, invokeTypes))) {

0 commit comments

Comments
 (0)