diff --git a/base/compiler/optimize.jl b/base/compiler/optimize.jl index d3c680f9308d3b..16157817276692 100644 --- a/base/compiler/optimize.jl +++ b/base/compiler/optimize.jl @@ -531,17 +531,22 @@ function any_stmt_may_throw(ir::IRCode, bb::Int) return false end -function conditional_successors_may_throw(lazypostdomtree::LazyPostDomtree, ir::IRCode, bb::Int) +function visit_conditional_successors(callback, lazypostdomtree::LazyPostDomtree, ir::IRCode, bb::Int) visited = BitSet((bb,)) worklist = Int[bb] while !isempty(worklist) - thisbb = pop!(worklist) + thisbb = popfirst!(worklist) for succ in ir.cfg.blocks[thisbb].succs succ in visited && continue push!(visited, succ) - postdominates(get!(lazypostdomtree), succ, thisbb) && continue - any_stmt_may_throw(ir, succ) && return true - push!(worklist, succ) + if postdominates(get!(lazypostdomtree), succ, bb) + # this successor is not conditional, so no need to visit it further + continue + elseif callback(succ) + return true + else + push!(worklist, succ) + end end end return false @@ -833,8 +838,10 @@ function ((; sv)::ScanStmt)(inst::Instruction, lstmt::Int, bb::Int) # inconsistent region. if !sv.result.ipo_effects.terminates sv.all_retpaths_consistent = false - elseif conditional_successors_may_throw(sv.lazypostdomtree, sv.ir, bb) - # Check if there are potential throws that require + elseif visit_conditional_successors(sv.lazypostdomtree, 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) diff --git a/test/compiler/effects.jl b/test/compiler/effects.jl index f5ecb8a0d347cc..fa70c8de9d8538 100644 --- a/test/compiler/effects.jl +++ b/test/compiler/effects.jl @@ -1382,3 +1382,8 @@ let; Base.Experimental.@force_compile; func52843(); end # pointerref nothrow for invalid pointer @test !Core.Compiler.intrinsic_nothrow(Core.Intrinsics.pointerref, Any[Type{Ptr{Vector{Int64}}}, Int, Int]) @test !Core.Compiler.intrinsic_nothrow(Core.Intrinsics.pointerref, Any[Type{Ptr{T}} where T, Int, Int]) + +# post-opt :consistent-cy analysis correctness +# 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))) diff --git a/test/compiler/ssair.jl b/test/compiler/ssair.jl index 3a90ee6308d538..0a53dec80f7326 100644 --- a/test/compiler/ssair.jl +++ b/test/compiler/ssair.jl @@ -238,6 +238,35 @@ let ci = code_lowered(()->@isdefined(_not_def_37919_), ())[1] @test Core.Compiler.verify_ir(ir) === nothing end +let code = Any[ + # block 1 + GotoIfNot(Argument(2), 4), + # block 2 + GotoNode(3), + # block 3 + Expr(:call, throw, "potential throw"), + # block 4 + Expr(:call, Core.Intrinsics.add_int, Argument(3), Argument(4)), + GotoNode(6), + # block 5 + 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 + push!(visited, succ) + return false + end + @test 2 ∈ visited + @test 3 ∈ visited + @test 4 ∉ visited + @test 5 ∉ visited + oc = Core.OpaqueClosure(ir) + @test oc(false, 1, 1) == 2 + @test_throws "potential throw" oc(true, 1, 1) +end + # Test dynamic update of domtree with edge insertions and deletions in the # following CFG: #