Commits

Michael Gottesman committed 5fe0b8b34c3
[loop-arc] Fix a bug in how we process successors and fix the resulting performance issue that resulted. Previously we represented all successors in a list where each successor was represented by a SuccessorID. A SuccessorID is essentially an unsigned int that stores some flags in the lower bits of the integer. The two flags are: 1. IsDead, 2. IsNonLocal (where non local means that it is a loop exit edge). When the IsNonLocal flag is not set, the integer that is actually stored represents the ID of the successor region. If the IsNonLocal flag is set, then the integer represents the index in the parent region's successor list of the actual loop exit successor. The bug I mentioned was that we were not being careful enough in the replacement code to distinguish in between successors that were loop exit successors and those that were not. This could cause us to replace a loop exit successor whose integer value was the same as the index of a non-loop exit successor with the non-loop exit successor. This then would cause us to miscompile and or introduce duplicate values into the successor list. Luckily an assert I added caught the latter condition. After I fixed this problem, an interesting performance issue was exposed. I had assumed when using a list that I would never have more than 10-20 successors (in general a reasonable assumption). But introducing loop exit successors adds in an interesting wrinkle, namely every block with an unreachable terminator will result in a successor edge. This makes just iterating over a uniqued list really slow. I solved the issue by writing a new data structure called BlotSetVector. The interesting thing about BlotSetVector is that all operations preserve index offsets. This means that if one erases a value, all other values in the set vector are not moved around in the internal vector. This is important since a loop exit edge needs to refer to an invariant offset in the parent region's successor array since we do not want to have to go through and update large amounts of unrelated edges every time we erase an edge. In terms of a test case, this invariant was impossible for me to reproduce since it is sensitive to the order of successors. Even dumping the file and running the analysis would not catch it. After 2 days of trying to make a test case I gave up. But I filed rdar://23228299 to verify that sil-opt can round trip in memory ordering of various items such as use lists, successors, predecessors, block ordering, function ordering, etc. rdar://22238658 Swift SVN r32839