[llvm-commits] CVS: llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp

Chris Lattner lattner at cs.uiuc.edu
Sat Sep 20 00:04:13 PDT 2003


Changes in directory llvm/lib/Transforms/Scalar:

TailRecursionElimination.cpp added (r1.1)

---
Log message:

New transformation: tail recursion elimination


---
Diffs of the changes:

Index: llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
diff -c /dev/null llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp:1.1
*** /dev/null	Sat Sep 20 00:03:41 2003
--- llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp	Sat Sep 20 00:03:31 2003
***************
*** 0 ****
--- 1,96 ----
+ //===- TailRecursionElimination.cpp - Eliminate Tail Calls ----------------===//
+ //
+ // This file implements tail recursion elimination.
+ //
+ // Caveats: The algorithm implemented is trivially simple.  There are several
+ // improvements that could be made:
+ //
+ //  1. If the function has any alloca instructions, these instructions will not
+ //     remain in the entry block of the function.  Doing this requires analysis
+ //     to prove that the alloca is not reachable by the recursively invoked
+ //     function call.
+ //  2. Tail recursion is only performed if the call immediately preceeds the
+ //     return instruction.  Would it be useful to generalize this somehow?
+ //  3. TRE is only performed if the function returns void or if the return
+ //     returns the result returned by the call.  It is possible, but unlikely,
+ //     that the return returns something else (like constant 0), and can still
+ //     be TRE'd.  It can be TRE'd if ALL OTHER return instructions in the
+ //     function return the exact same value.
+ //
+ //===----------------------------------------------------------------------===//
+ 
+ #include "llvm/DerivedTypes.h"
+ #include "llvm/Function.h"
+ #include "llvm/Instructions.h"
+ #include "llvm/Pass.h"
+ #include "Support/Statistic.h"
+ 
+ namespace {
+   Statistic<> NumEliminated("tailcallelim", "Number of tail calls removed");
+ 
+   struct TailCallElim : public FunctionPass {
+     virtual bool runOnFunction(Function &F);
+   };
+   RegisterOpt<TailCallElim> X("tailcallelim", "Tail Call Elimination");
+ }
+ 
+ 
+ bool TailCallElim::runOnFunction(Function &F) {
+   // If this function is a varargs function, we won't be able to PHI the args
+   // right, so don't even try to convert it...
+   if (F.getFunctionType()->isVarArg()) return false;
+ 
+   BasicBlock *OldEntry = 0;
+   std::vector<PHINode*> ArgumentPHIs;
+   bool MadeChange = false;
+ 
+   // Loop over the function, looking for any returning blocks...
+   for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
+     if (ReturnInst *Ret = dyn_cast<ReturnInst>(BB->getTerminator()))
+       if (Ret != BB->begin())
+         if (CallInst *CI = dyn_cast<CallInst>(Ret->getPrev()))
+           // Make sure the tail call is to the current function, and that the
+           // return either returns void or returns the value computed by the
+           // call.
+           if (CI->getCalledFunction() == &F &&
+               (Ret->getNumOperands() == 0 || Ret->getReturnValue() == CI)) {
+             // Ohh, it looks like we found a tail call, is this the first?
+             if (!OldEntry) {
+               // Ok, so this is the first tail call we have found in this
+               // function.  Insert a new entry block into the function, allowing
+               // us to branch back to the old entry block.
+               OldEntry = &F.getEntryNode();
+               BasicBlock *NewEntry = new BasicBlock("tailrecurse", OldEntry);
+               NewEntry->getInstList().push_back(new BranchInst(OldEntry));
+               
+               // Now that we have created a new block, which jumps to the entry
+               // block, insert a PHI node for each argument of the function.
+               // For now, we initialize each PHI to only have the real arguments
+               // which are passed in.
+               Instruction *InsertPos = OldEntry->begin();
+               for (Function::aiterator I = F.abegin(), E = F.aend(); I!=E; ++I){
+                 PHINode *PN = new PHINode(I->getType(), I->getName()+".tr",
+                                           InsertPos);
+                 PN->addIncoming(I, NewEntry);
+                 ArgumentPHIs.push_back(PN);
+               }
+             }
+             
+             // Ok, now that we know we have a pseudo-entry block WITH all of the
+             // required PHI nodes, add entries into the PHI node for the actual
+             // parameters passed into the tail-recursive call.
+             for (unsigned i = 0, e = CI->getNumOperands()-1; i != e; ++i)
+               ArgumentPHIs[i]->addIncoming(CI->getOperand(i+1), BB);
+ 
+             // Now that all of the PHI nodes are in place, remove the call and
+             // ret instructions, replacing them with an unconditional branch.
+             new BranchInst(OldEntry, CI);
+             BB->getInstList().pop_back();  // Remove return.
+             BB->getInstList().pop_back();  // Remove call.
+             MadeChange = true;
+             NumEliminated++;
+           }
+   
+   return MadeChange;
+ }
+ 





More information about the llvm-commits mailing list