Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Core.Compiler.BackedgeIterator #33

Merged
merged 1 commit into from
Sep 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/MethodAnalysis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@ include("backedges.jl")
if !hasmethod(==, Tuple{Core.PhiNode,Core.PhiNode})
Base.:(==)(stmt1::Core.PhiNode, stmt2::Core.PhiNode) = stmt1.edges == stmt2.edges && stmt1.values == stmt2.values
end
if isdefined(Core.Compiler, :BackedgeIterator)
getmi(mi::MethodInstance) = mi
getmi(pr::Pair{Any,MethodInstance}) = pr.second
getmi(pr::Core.Compiler.BackedgePair) = pr.caller

stdbe(::Nothing, caller::MethodInstance) = caller
stdbe(@nospecialize(invokesig), caller::MethodInstance) = Pair{Any,MethodInstance}(invokesig, caller)
stdbe(pr::Core.Compiler.BackedgePair) = stdbe(pr.sig, pr.caller)

if !hasmethod(iterate, Tuple{Core.Compiler.BackedgeIterator})
Base.iterate(iter::Core.Compiler.BackedgeIterator, state...) = Core.Compiler.iterate(iter, state...)
end
end

"""
call_type(tt)
Expand Down
22 changes: 18 additions & 4 deletions src/backedges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,31 @@ function direct_backedges(f::Union{Method,Callable}; skip::Bool=true)
elseif isa(item, MethodInstance)
callee = item::MethodInstance
if isdefined(callee, :backedges)
for caller in callee.backedges
skip && caller ∈ _skip && continue
push!(bes, callee=>caller)
end
push_unskipped_backedges!(bes, callee, skip, _skip)
end
return false
end
true
end
return bes
end
if isdefined(Core.Compiler, :BackedgeIterator)
function push_unskipped_backedges!(bes, callee, skip, _skip)
for caller in Core.Compiler.BackedgeIterator(callee.backedges)
skip && getmi(caller) ∈ _skip && continue
push!(bes, stdbe(caller.sig, callee)=>caller.caller)
end
return bes
end
else
function push_unskipped_backedges!(bes, callee, skip, _skip)
for caller in callee.backedges
skip && caller ∈ _skip && continue
push!(bes, callee=>caller)
end
return bes
end
end

"""
direct_backedges(mi::MethodInstance)
Expand Down
30 changes: 21 additions & 9 deletions src/visit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,7 @@ _visit(@nospecialize(operation), @nospecialize(x), visited::IdSet{Any}, print::B
Visit the backedges of `obj` and apply `operation` to each.
`operation` may need to be able to handle two call forms, `operation(mi)` and
`operation(sig=>mi)`, where `mi` is a `MethodInstance` and `sig` is a `Tuple`-type.
The latter arises from `MethodTable` backedges and can be ignored if `obj` does not
contain `MethodTable`s.
The latter arises from either `invoke` calls or `MethodTable` backedges.

`operation(edge)` should return `true` if the backedges of `edge` should in turn be visited,
`false` otherwise.
Expand Down Expand Up @@ -267,15 +266,28 @@ function visit_backedges(@nospecialize(operation), obj, visited::IdSet{MethodIns
visit(opwrapper, obj)
end

function _visit_backedges(@nospecialize(operation), mi::MethodInstance, visited)
mi ∈ visited && return nothing
push!(visited, mi)
if operation(mi) && isdefined(mi, :backedges)
for edge in mi.backedges
_visit_backedges(operation, edge, visited)
if isdefined(Core.Compiler, :BackedgeIterator)
function _visit_backedges(@nospecialize(operation), callee::Union{MethodInstance,Pair{Any,MethodInstance}}, visited)
getmi(callee) ∈ visited && return nothing
push!(visited, callee)
if operation(callee) && isdefined(getmi(callee), :backedges)
for be in Core.Compiler.BackedgeIterator(getmi(callee).backedges)
_visit_backedges(operation, stdbe(be), visited)
end
end
return nothing
end
else
function _visit_backedges(@nospecialize(operation), mi::MethodInstance, visited)
mi ∈ visited && return nothing
push!(visited, mi)
if operation(mi) && isdefined(mi, :backedges)
for edge in mi.backedges
_visit_backedges(operation, edge, visited)
end
end
return nothing
end
return nothing
end

function _visit_backedges(@nospecialize(operation), misig::Pair{Any,MethodInstance}, visited)
Expand Down
14 changes: 14 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ module Outer
f2(x, y::Number) = x + y

fkw(x; y=0) = 2x + y

invk(::Int) = 1
invk(::Integer) = 2
geninvk(x) = invoke(invk, Tuple{Integer}, x)
end

module One
Expand Down Expand Up @@ -266,6 +270,16 @@ end
callnocallers(x) = nocallers(x)
callnocallers(3)
@test !isempty(direct_backedges(mi))

if isdefined(Core.Compiler, :BackedgeIterator)
@test Outer.geninvk(3) == 2
m = which(Outer.invk, (Integer,))
bes = direct_backedges(m)
be = only(bes)
@test be.first.second.specTypes.parameters[2] === Int
@test be.first.first === Tuple{typeof(Main.Outer.invk), Integer}
@test be.second == methodinstance(Outer.geninvk, (Int,))
end
end

@testset "call_type" begin
Expand Down