Splitting critical edges for indirect branches the SplitIndirectBrCriticalEdges() function may break branch probabilities if target basic block happens to have unset a probability for any of its successors. That is because in such cases the getEdgeProbability(Target) function returns probability 1/NumOfSuccessors and it is called after Target was split (thus Target has a single successor). As the result the correspondent successor of the split block gets probability 100% but 1/NumOfSuccessors is expected (or better be left unset).
Details
Diff Detail
Event Timeline
Why considering the cases where "target basic block happens to have unset a probability for any of its successors" specifically?
Does the new test TEST(BasicBlockUtils, SplitIndirectBrCriticalEdge) fail before the change in BreakCriticalEdges.cpp (where the target block doesn't seem to have an unset successor)?
Functionally the change looks ok.
I think we should improve current API of BP (not in this change though) because it's easy to break invariant that sum of all probabilities is 1.
We better disallow cases when only part of edges have probability set and others unset. 1/NumSuccesors will likely be incorrect value in most cases with uneven distribution.
llvm/unittests/Transforms/Utils/BasicBlockUtilsTest.cpp | ||
---|---|---|
146 | ok. but this will look different from the other test cases |
What happens in the newly added test seems that none of the successor probabilities are ever set (BranchProbabilityInfo::Probs is empty throughout). The thing is that BPI does not internally store the edge probabilities unless they are non-default, unevenly-split ones (1/NumOfSuccessors) and relies on the real-time state of the blocks/CFG for default cases, which is likely different from what the author of SplitIndirectBrCriticalEdges expected. In contrast, BFI stores the block frequencies at the time it was calculated, which stays there after the blocks/CFG are modified. When the block "bb1" gets split, the number of its successors goes from two (50% each) to one (100%). Then, this 100% probability incorrectly gets copied to each of the two successors of the new block.
Can you clang-format this code (as the lint check)?