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

Fix handling of virtual exit node in PostDomTree #53739

Merged
merged 1 commit into from
Mar 19, 2024

Conversation

topolarity
Copy link
Member

@topolarity topolarity commented Mar 14, 2024

This is an alternative to #53642

The dom_edges() for an exit block in the CFG are empty when computing the PostDomTree so the loop below this may not actually run. In that case, the right semidominator is the ancestor from the DFSTree, which is the "virtual" -1 block.

This resolves half of the issue in #53613:

julia> let code = Any[
               # block 1
               GotoIfNot(Argument(2), 3),
               # block 2
               ReturnNode(Argument(3)),
               # block 3 (we should visit this block)
               Expr(:call, throw, "potential throw"),
               ReturnNode(), # unreachable
           ]
           ir = make_ircode(code; slottypes=Any[Any,Bool,Bool])
           visited = BitSet()
           @test !Core.Compiler.visit_conditional_successors(CC.LazyPostDomtree(ir), ir, #=bb=#1) do succ::Int
               push!(visited, succ)
               return false
           end
           @test 2  visited
           @test 3  visited
       end
Test Passed

This needs some tests (esp. since I don't think we have any DomTree tests at all right now), but otherwise should be good to go.

@topolarity topolarity requested a review from aviatesk March 14, 2024 22:50
The `dom_edges()` for an exit block in the CFG are empty when computing
the PostDomTree, although the algorithm is supposed to treat this as
being dominated by a "virtual" -1 node (which is already included in the
DFSTree). As a result, we can't rely on the loop below this code to
initialize the semi-dominator correctly for us.
Copy link
Member

@aviatesk aviatesk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this change fixes the problem #53739 tried to fix with the augmented control-flow graph right at its root. If you're up for it, switching the base branch to #53739 could let us use the test cases from there to check this fix. Though, having more direct test cases could be even better, but not necessary if we use test cases from #53739.

@aviatesk aviatesk marked this pull request as ready for review March 15, 2024 16:54
@aviatesk aviatesk force-pushed the ct/fix-postdomtree branch from 4ff4981 to c860691 Compare March 16, 2024 15:34
aviatesk added a commit that referenced this pull request Mar 16, 2024
@aviatesk
Copy link
Member

I confirm this PR passes all the test cases added in #53642.

@aviatesk aviatesk added compiler:optimizer Optimization passes (mostly in base/compiler/ssair/) merge me PR is reviewed. Merge when all tests are passing labels Mar 16, 2024
@aviatesk aviatesk merged commit 2775c9a into JuliaLang:master Mar 19, 2024
7 of 9 checks passed
aviatesk added a commit that referenced this pull request Mar 19, 2024
aviatesk added a commit that referenced this pull request Mar 19, 2024
This commit was initially crafted to fix an issue with post-opt analysis
that came to light in #53613, planning to solve it by
incorporating an augmented CFG directly into the post-opt analysis. But,
with the issue now sorted out by #53739, this commit
shifted focus to just adding test cases.

=== The original commit message ===

post-opt: use augmented post-domtree for `visit_conditional_successors`

This commit fixes the first problem that was found while digging into
#53613. It turns out that the post-domtree constructed
from regular `IRCode` doesn't work for visiting conditional successors
for post-opt analysis in cases like:
```julia
julia> let code = Any[
               # block 1
               GotoIfNot(Argument(2), 3),
               # block 2
               ReturnNode(Argument(3)),
               # block 3 (we should visit this block)
               Expr(:call, throw, "potential throw"),
               ReturnNode(), # unreachable
           ]
           ir = make_ircode(code; slottypes=Any[Any,Bool,Bool])
           visited = BitSet()
           @test !Core.Compiler.visit_conditional_successors(CC.LazyPostDomtree(ir), ir, #=bb=#1) do succ::Int
               push!(visited, succ)
               return false
           end
           @test 2 ∉ visited
           @test 3 ∈ visited
       end
Test Failed at REPL[14]:16
  Expression: 2 ∉ visited
   Evaluated: 2 ∉ BitSet([2])
```

This might mean that we need to fix on the `postdominates` end, but for
now, this commit tries to get around it by using the augmented post
domtree in `visit_conditional_successors`, while also enforcing the
augmented control flow graph (`construct_augmented_cfg`) to have a
single exit node really. Since the augmented post domtree is now
enforced to have a single return, we can keep using the current
`postdominates` to fix the issue.

However, this commit isn't enough to fix the NeuralNetworkReachability
segfault as reported in #53613, and we need to tackle the second issue
reported there too (#53613 (comment)).
@IanButterworth IanButterworth removed the merge me PR is reviewed. Merge when all tests are passing label Apr 5, 2024
@aviatesk aviatesk mentioned this pull request Apr 23, 2024
59 tasks
aviatesk pushed a commit that referenced this pull request Apr 23, 2024
This is an alternative to #53642

The `dom_edges()` for an exit block in the CFG are empty when computing
the PostDomTree so the loop below this may not actually run. In that
case, the right semidominator is the ancestor from the DFSTree, which is
the "virtual" -1 block.

This resolves half of the issue in
#53613:
```julia
julia> let code = Any[
               # block 1
               GotoIfNot(Argument(2), 3),
               # block 2
               ReturnNode(Argument(3)),
               # block 3 (we should visit this block)
               Expr(:call, throw, "potential throw"),
               ReturnNode(), # unreachable
           ]
           ir = make_ircode(code; slottypes=Any[Any,Bool,Bool])
           visited = BitSet()
           @test !Core.Compiler.visit_conditional_successors(CC.LazyPostDomtree(ir), ir, #=bb=#1) do succ::Int
               push!(visited, succ)
               return false
           end
           @test 2 ∈ visited
           @test 3 ∈ visited
       end
Test Passed
```

This needs some tests (esp. since I don't think we have any DomTree
tests at all right now), but otherwise should be good to go.
@topolarity topolarity added the backport 1.10 Change should be backported to the 1.10 release label Oct 30, 2024
topolarity added a commit that referenced this pull request Oct 30, 2024
This is an alternative to #53642

The `dom_edges()` for an exit block in the CFG are empty when computing
the PostDomTree so the loop below this may not actually run. In that
case, the right semidominator is the ancestor from the DFSTree, which is
the "virtual" -1 block.

This resolves half of the issue in
#53613:
```julia
julia> let code = Any[
               # block 1
               GotoIfNot(Argument(2), 3),
               # block 2
               ReturnNode(Argument(3)),
               # block 3 (we should visit this block)
               Expr(:call, throw, "potential throw"),
               ReturnNode(), # unreachable
           ]
           ir = make_ircode(code; slottypes=Any[Any,Bool,Bool])
           visited = BitSet()
           @test !Core.Compiler.visit_conditional_successors(CC.LazyPostDomtree(ir), ir, #=bb=#1) do succ::Int
               push!(visited, succ)
               return false
           end
           @test 2 ∈ visited
           @test 3 ∈ visited
       end
Test Passed
```

This needs some tests (esp. since I don't think we have any DomTree
tests at all right now), but otherwise should be good to go.
@topolarity topolarity removed the backport 1.10 Change should be backported to the 1.10 release label Oct 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler:optimizer Optimization passes (mostly in base/compiler/ssair/)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants