{F2564183}The existing Loop Unswitching Pass generates an exponential number of loops with respect to the number of unswitched branches.
For any loop, the number of generated loops are n^2 where n is the number of unswitched branches.
The exponential nature of the transformation is an obstacle in generating better unswitched code.
Consider the following testcase:
1: for(int i=0;i<100;i++){
2: if (m)
3: a[i]*=2;
4: else if (n)
5: a[i]*=3;
6:
7: a[i]*=4;
8: }
m and n are loop invariants.
The existing algorithm generates 4 unswitched loops for the following cases:
- Condition at line 2 is true and Condition at line 4 is true.
- Condition at line 2 is true and Condition at line 4 is false.
- Condition at line 2 is false and Condition at line 4 is true.
- Condition at line 2 is false and Condition at line 4 is false.
However, due to the very nature of the else-if chain, there exists a control dependency between Conditions at line 2 and 4. When the Condition at line 2 is true, the Condition at line 4 is never taken and hence the outcome of the Condition at line 4 is irrelevant (don't care scenario), in this case.
This has not been accounted for, in the existing infrastructure. Currently, two similar loops are generated for cases 1 and 2 leading to redundancy and inefficiency.
It is sufficient, if we handle the following three cases:
- Condition at line 2 is true.
- Condition at line 2 is false and Condition at line 4 is true.
- Condition at line 2 is false and Condition at line 4 is false.
One of the possible solutions, is to find the unreachable branches and eliminate them before unswitching.
The attached patch has the solution implemented in the Loop Unswitching Pass. The choice of this solution (among other possible solutions) is for the following reasons:
- Eliminating unreachable branches so that many other branches are unswitched out of their enclosing loops (probably, better code).
- Difficult to handle in the existing CFG Simplification Pass.
Please rename this function, as the name is to generic now, and LLVM already uses term unreachable with another meaning. Here the block is rendered unreachable because we unswitched some conditional branches - we should somehow reflect that in the name (I don't have good suggestions though :) ).