@@ -1880,43 +1880,88 @@ static bool onlyForwardsNone(SILBasicBlock *noneBB, SILBasicBlock *someBB,
1880
1880
return true ;
1881
1881
}
1882
1882
1883
- // / Check whether \p noneBB has the same ultimate successor as the successor to someBB.
1884
- // / someBB noneBB
1885
- // / \ |
1886
- // / \ ... (more bbs?)
1883
+ // / Check whether the \p someBB has only one single successor and that successor
1884
+ // / post-dominates \p noneBB.
1885
+ // /
1886
+ // / (maybe otherNoneBB)
1887
+ // / someBB noneBB /
1888
+ // / \ | v
1889
+ // / \ ... more bbs? (A)
1887
1890
// / \ /
1888
1891
// / ulimateBB
1892
+ // /
1893
+ // / This routine does not support diverging control flow in (A). This means that
1894
+ // / there must not be any loops or diamonds beginning in that region. We do
1895
+ // / support side-entrances from blocks not reachable from noneBB in order to
1896
+ // / ensure that we properly handle other failure cases where the failure case
1897
+ // / merges into .noneBB before ultimate BB.
1898
+ // /
1899
+ // / DISCUSSION: We allow this side-entrance pattern to handle iterative
1900
+ // / conditional checks which all feed the failing case through the .none
1901
+ // / path. This is a common pattern in swift code. As an example consider a
1902
+ // / switch statement with multiple pattern binding matching that use the same
1903
+ // / cleanup code upon failure.
1889
1904
static bool hasSameUltimateSuccessor (SILBasicBlock *noneBB, SILBasicBlock *someBB) {
1890
1905
// Make sure that both our some, none blocks both have single successors that
1891
1906
// are not themselves (which can happen due to single block loops).
1892
1907
auto *someSuccessorBB = someBB->getSingleSuccessorBlock ();
1893
1908
if (!someSuccessorBB || someSuccessorBB == someBB)
1894
1909
return false ;
1910
+
1895
1911
auto *noneSuccessorBB = noneBB->getSingleSuccessorBlock ();
1896
1912
if (!noneSuccessorBB || noneSuccessorBB == noneBB)
1897
1913
return false ;
1898
1914
1899
- // If we immediately find a diamond, return true. We are done.
1915
+ // If we immediately find a simple diamond, return true. We are done.
1900
1916
if (noneSuccessorBB == someSuccessorBB)
1901
1917
return true ;
1902
1918
1903
- // Otherwise, lets keep looking down the none case.
1904
- auto *next = noneSuccessorBB;
1905
- while (next != someSuccessorBB) {
1906
- noneSuccessorBB = next;
1907
- next = noneSuccessorBB->getSingleSuccessorBlock ();
1919
+ // Otherwise, lets begin a traversal along the successors of noneSuccessorBB,
1920
+ // searching for someSuccessorBB, being careful to only allow for blocks to be
1921
+ // visited once. This enables us to guarantee that there are not any loops or
1922
+ // any sub-diamonds in the part of the CFG we are traversing. This /does/
1923
+ // allow for side-entrances to the region from blocks not reachable from
1924
+ // noneSuccessorBB. See function level comment above.
1925
+ SILBasicBlock *iter = noneSuccessorBB;
1926
+ SmallPtrSet<SILBasicBlock *, 8 > visitedBlocks;
1927
+ visitedBlocks.insert (iter);
1908
1928
1909
- // If we find another single successor and it is not our own block (due to a
1910
- // self-loop), continue.
1911
- if (next && next != noneSuccessorBB)
1912
- continue ;
1929
+ do {
1930
+ // First try to grab our single successor if we have only one. If we have no
1931
+ // successor or more than one successor, bail and do not optimize.
1932
+ //
1933
+ // DISCUSSION: Trivially, if we do not have a successor, then we have
1934
+ // reached either a return/unreachable and this path will never merge with
1935
+ // the ultimate block. If we have more than one successor, then for our
1936
+ // condition to pass, we must have that both successors eventually join into
1937
+ // someSuccessorBB. But this would imply that either someSuccessorBB has
1938
+ // more than two predecessors and or that we merge the two paths before we
1939
+ // visit someSuccessorBB.
1940
+ auto *succBlock = iter->getSingleSuccessorBlock ();
1941
+ if (!succBlock)
1942
+ return false ;
1913
1943
1914
- // Otherwise, we either have multiple successors or a self-loop. We do not
1915
- // support this, return false.
1916
- return false ;
1917
- }
1944
+ // Then check if our single successor block has been visited already. If so,
1945
+ // we have some sort of loop or have some sort of merge point that is not
1946
+ // the final merge point.
1947
+ //
1948
+ // NOTE: We do not need to worry about someSuccessorBB being in
1949
+ // visitedBlocks since before we begin the loop, we check that
1950
+ // someSuccessorBB != iter and also check that in the do-while condition. So
1951
+ // we can never have visited someSuccessorBB on any previous iteration
1952
+ // meaning that the only time we can have succBlock equal to someSuccessorBB
1953
+ // is on the last iteration before we exit the loop.
1954
+ if (!visitedBlocks.insert (succBlock).second )
1955
+ return false ;
1956
+
1957
+ // Otherwise, set iter to succBlock.
1958
+ iter = succBlock;
1959
+
1960
+ // And then check if this new successor block is someSuccessorBB. If so, we
1961
+ // break and then return true since we have found our target. Otherwise, we
1962
+ // need to visit further successors, so go back around the loop.
1963
+ } while (iter != someSuccessorBB);
1918
1964
1919
- // At this point, we know that next must be someSuccessorBB.
1920
1965
return true ;
1921
1966
}
1922
1967
0 commit comments