[PATCH] D26299: Improving the efficiency of the Loop Unswitching pass

Abhilash Bhandari via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 4 11:07:28 PDT 2016


Abhilash created this revision.
Abhilash added reviewers: hfinkel, lattner, atrick.
Abhilash added a subscriber: llvm-commits.
Abhilash set the repository for this revision to rL LLVM.
Herald added a subscriber: mzolotukhin.

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:

1. Condition at line 2 is true and Condition at line 4 is true.
2. Condition at line 2 is true and Condition at line 4 is false.
3. Condition at line 2 is false and Condition at line 4 is true.
4. 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:

1. Condition at line 2 is true.
2. Condition at line 2 is false and Condition at line 4 is true.
3. 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:

1. Eliminating unreachable branches so that many other branches are unswitched out of their enclosing loops (probably, better code).
2. Difficult to handle in the existing CFG Simplification Pass.


Repository:
  rL LLVM

https://reviews.llvm.org/D26299

Files:
  lib/Transforms/Scalar/LoopUnswitch.cpp


Index: lib/Transforms/Scalar/LoopUnswitch.cpp
===================================================================
--- lib/Transforms/Scalar/LoopUnswitch.cpp
+++ lib/Transforms/Scalar/LoopUnswitch.cpp
@@ -593,6 +593,45 @@
       continue;
 
     if (BranchInst *BI = dyn_cast<BranchInst>(TI)) {
+     /*
+      * Some branches may be rendered unreachable because of previous unswitching.
+      * Unswitch only those branches that are reachable.
+      */
+      auto *Node = DT->getNode(*I)->getIDom();
+      BasicBlock *DomBB = Node->getBlock();
+      bool isUnreachable = false;
+      while (currentLoop->contains(DomBB)) {
+          BranchInst *BI = dyn_cast<BranchInst> (DomBB->getTerminator());
+
+          if (BI && BI->isConditional()) {
+             Value *Cond = BI->getCondition();
+             BasicBlock *Succ = NULL;
+             if (Cond == ConstantInt::getTrue(Cond->getContext())) {
+                Succ = BI->getSuccessor(1);
+             } else if (Cond == ConstantInt::getFalse(Cond->getContext())){
+                Succ = BI->getSuccessor(0);
+             }
+
+             if (Succ) {
+                BasicBlockEdge UnreachableEdge (BI->getParent(), Succ);
+                if (DT->dominates(UnreachableEdge, *I)) {
+                   isUnreachable = true;
+                   break;
+                }
+             }
+          }
+
+          if (isUnreachable) break;
+
+          Node = DT->getNode(DomBB)->getIDom();
+          DomBB = Node->getBlock();
+      }
+
+      if (isUnreachable) {
+        DEBUG (dbgs() << "Unreachable branch: " << *TI << " in Function " << (*I)->getParent()->getName() << "\n");
+        continue;
+      }
+
       // If this isn't branching on an invariant condition, we can't unswitch
       // it.
       if (BI->isConditional()) {


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D26299.76914.patch
Type: text/x-patch
Size: 1807 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20161104/31adc4eb/attachment.bin>


More information about the llvm-commits mailing list