fix: preserve shared if branch targets - #2936
Conversation
Keep branch blocks with external predecessors inside the current if unless sibling fall-through proves they are the continuation. Reject out-block candidates beyond an active enclosing region exit. Add switch and non-switch regression coverage for shared branch targets.
|
More detail on the failure mode and why the fix is intentionally not switch-specific. Failure modeThe original reproducer has a block that is a legitimate branch target of an inner For the inner Previously, That is too strong for shared CFG targets. In the example, the external predecessor makes
into the equivalent of: which makes Why this does not special-case switchesA first narrow fix could ignore an external predecessor when it is a The same invalid promotion can occur when the external predecessor comes from another The relevant property is instead whether the sibling branch proves that the candidate is actually a continuation. The new logic only promotes a shared branch when all non-terminating, non-back-edge sibling paths stay in the current dominated scope until they reach that branch. A return/throw-style terminal path is allowed to end without reaching it. In other words, an external incoming edge no longer means "this must be the continuation". Promotion requires positive CFG evidence that it is safe to execute the candidate after the reconstructed Enclosing-region exit caseThere is a second related failure mode when The patch rejects such Semantic invariantThe transformation should preserve this invariant: Equivalently, code emitted after a reconstructed Regression coverageTwo minimized smali regressions are included:
Validation on the branch: Relation to #2909#2909 is related because it also produces an incorrect This PR fixes shared branch ownership/continuation and enclosing-scope validation; it does not fix the partial-merge selection in #2909, so I have intentionally not marked #2909 as fixed by this change. |
Description
Fix
IfRegionMakermoving shared branch targets outside anifwhen those blocks also have incoming edges from an enclosing control-flow structure.The branch check now:
ifcontinuation when sibling fall-through paths prove it is the continuation;findOutBlock()candidates beyond an active enclosing region exit.Adds regression coverage for shared branch targets both with and without a switch.
A related but different region-making issue is tracked in #2909; its secondary-break CFG is not fixed by this change.
Validation
./gradlew clean build dist --no-daemon