Skip to content

Commit

Permalink
post-opt: use augmented post-domtree for visit_conditional_successors
Browse files Browse the repository at this point in the history
- fixes #53613
  • Loading branch information
aviatesk committed Mar 7, 2024
1 parent 94273e6 commit b757ee6
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 36 deletions.
77 changes: 43 additions & 34 deletions base/compiler/optimize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -527,15 +527,53 @@ function any_stmt_may_throw(ir::IRCode, bb::Int)
return false
end

function visit_conditional_successors(callback, lazypostdomtree::LazyPostDomtree, ir::IRCode, bb::Int)
mutable struct LazyAugmentedDomtree
const ir::IRCode
cfg::CFG
domtree::DomTree
postdomtree::PostDomTree
LazyAugmentedDomtree(ir::IRCode) = new(ir)
end

function get!(lazyagdomtree::LazyAugmentedDomtree, sym::Symbol)
isdefined(lazyagdomtree, sym) && return getfield(lazyagdomtree, sym)
if sym === :cfg
return lazyagdomtree.cfg = construct_augmented_cfg(lazyagdomtree.ir)
elseif sym === :domtree
return lazyagdomtree.domtree = construct_domtree(get!(lazyagdomtree, :cfg))
elseif sym === :postdomtree
return lazyagdomtree.postdomtree = construct_postdomtree(get!(lazyagdomtree, :cfg))
else
error("invalid field access")
end
end

function construct_augmented_cfg(ir::IRCode)
cfg = copy(ir.cfg)
# Add a virtual basic block to represent the exit
push!(cfg.blocks, BasicBlock(StmtRange(0:-1)))
for bb = 1:(length(cfg.blocks)-1)
terminator = ir[SSAValue(last(cfg.blocks[bb].stmts))][:stmt]
if isa(terminator, ReturnNode) && isdefined(terminator, :val)
cfg_insert_edge!(cfg, bb, length(cfg.blocks))
end
end
return cfg
end

visit_conditional_successors(callback, ir::IRCode, bb::Int) =
visit_conditional_successors(callback, construct_postdomtree(construct_augmented_cfg(ir)), ir, bb)
visit_conditional_successors(callback, lazyagdomtree::LazyAugmentedDomtree, ir::IRCode, bb::Int) =
visit_conditional_successors(callback, get!(lazyagdomtree, :postdomtree), ir, bb)
function visit_conditional_successors(callback, postdomtree::PostDomTree, ir::IRCode, bb::Int)
visited = BitSet((bb,))
worklist = Int[bb]
while !isempty(worklist)
thisbb = popfirst!(worklist)
for succ in ir.cfg.blocks[thisbb].succs
succ in visited && continue
push!(visited, succ)
if postdominates(get!(lazypostdomtree), succ, bb)
if postdominates(postdomtree, succ, bb)
# this successor is not conditional, so no need to visit it further
continue
elseif callback(succ)
Expand All @@ -548,39 +586,11 @@ function visit_conditional_successors(callback, lazypostdomtree::LazyPostDomtree
return false
end

struct AugmentedDomtree
cfg::CFG
domtree::DomTree
end

mutable struct LazyAugmentedDomtree
const ir::IRCode
agdomtree::AugmentedDomtree
LazyAugmentedDomtree(ir::IRCode) = new(ir)
end

function get!(lazyagdomtree::LazyAugmentedDomtree)
isdefined(lazyagdomtree, :agdomtree) && return lazyagdomtree.agdomtree
ir = lazyagdomtree.ir
cfg = copy(ir.cfg)
# Add a virtual basic block to represent the exit
push!(cfg.blocks, BasicBlock(StmtRange(0:-1)))
for bb = 1:(length(cfg.blocks)-1)
terminator = ir[SSAValue(last(cfg.blocks[bb].stmts))][:stmt]
if isa(terminator, ReturnNode) && isdefined(terminator, :val)
cfg_insert_edge!(cfg, bb, length(cfg.blocks))
end
end
domtree = construct_domtree(cfg)
return lazyagdomtree.agdomtree = AugmentedDomtree(cfg, domtree)
end

mutable struct PostOptAnalysisState
const result::InferenceResult
const ir::IRCode
const inconsistent::BitSetBoundedMinPrioritySet
const tpdum::TwoPhaseDefUseMap
const lazypostdomtree::LazyPostDomtree
const lazyagdomtree::LazyAugmentedDomtree
const ea_analysis_pending::Vector{Int}
all_retpaths_consistent::Bool
Expand All @@ -592,9 +602,8 @@ mutable struct PostOptAnalysisState
function PostOptAnalysisState(result::InferenceResult, ir::IRCode)
inconsistent = BitSetBoundedMinPrioritySet(length(ir.stmts))
tpdum = TwoPhaseDefUseMap(length(ir.stmts))
lazypostdomtree = LazyPostDomtree(ir)
lazyagdomtree = LazyAugmentedDomtree(ir)
return new(result, ir, inconsistent, tpdum, lazypostdomtree, lazyagdomtree, Int[],
return new(result, ir, inconsistent, tpdum, lazyagdomtree, Int[],
true, true, nothing, true, true, false)
end
end
Expand Down Expand Up @@ -834,13 +843,13 @@ function ((; sv)::ScanStmt)(inst::Instruction, lstmt::Int, bb::Int)
# inconsistent region.
if !sv.result.ipo_effects.terminates
sv.all_retpaths_consistent = false
elseif visit_conditional_successors(sv.lazypostdomtree, sv.ir, bb) do succ::Int
elseif visit_conditional_successors(sv.lazyagdomtree, sv.ir, bb) do succ::Int
return any_stmt_may_throw(sv.ir, succ)
end
# check if this `GotoIfNot` leads to conditional throws, which taints consistency
sv.all_retpaths_consistent = false
else
(; cfg, domtree) = get!(sv.lazyagdomtree)
cfg, domtree = get!(sv.lazyagdomtree, :cfg), get!(sv.lazyagdomtree, :domtree)
for succ in iterated_dominance_frontier(cfg, BlockLiveness(sv.ir.cfg.blocks[bb].succs, nothing), domtree)
if succ == length(cfg.blocks)
# Phi node in the virtual exit -> We have a conditional
Expand Down
10 changes: 10 additions & 0 deletions test/compiler/effects.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1387,3 +1387,13 @@ let; Base.Experimental.@force_compile; func52843(); end
# https://github.com/JuliaLang/julia/issues/53508
@test !Core.Compiler.is_consistent(Base.infer_effects(getindex, (UnitRange{Int},Int)))
@test !Core.Compiler.is_consistent(Base.infer_effects(getindex, (Base.OneTo{Int},Int)))

@noinline f53613() = @assert isdefined(@__MODULE__, :v53613)
g53613() = f53613()
@test !Core.Compiler.is_consistent(Base.infer_effects(f53613))
@test_broken !Core.Compiler.is_consistent(Base.infer_effects(g53613))
@test_throws AssertionError f53613()
@test_throws AssertionError g53613()
global v53613 = nothing
@test f53613() === nothing
@test g53613() === nothing
3 changes: 1 addition & 2 deletions test/compiler/ssair.jl
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,8 @@ let code = Any[
ReturnNode(SSAValue(4))
]
ir = make_ircode(code; slottypes=Any[Any,Bool,Int,Int])
lazypostdomtree = Core.Compiler.LazyPostDomtree(ir)
visited = BitSet()
@test !Core.Compiler.visit_conditional_successors(lazypostdomtree, ir, #=bb=#1) do succ::Int
@test !Core.Compiler.visit_conditional_successors(ir, #=bb=#1) do succ::Int
push!(visited, succ)
return false
end
Expand Down

0 comments on commit b757ee6

Please sign in to comment.