blob: f0c5ba73b917f4bca185133131e3746b73849f4e [file] [log] [blame]
Chris Lattner2240d2b2003-09-20 05:03:31 +00001//===- TailRecursionElimination.cpp - Eliminate Tail Calls ----------------===//
2//
3// This file implements tail recursion elimination.
4//
5// Caveats: The algorithm implemented is trivially simple. There are several
6// improvements that could be made:
7//
8// 1. If the function has any alloca instructions, these instructions will not
9// remain in the entry block of the function. Doing this requires analysis
10// to prove that the alloca is not reachable by the recursively invoked
11// function call.
12// 2. Tail recursion is only performed if the call immediately preceeds the
13// return instruction. Would it be useful to generalize this somehow?
14// 3. TRE is only performed if the function returns void or if the return
15// returns the result returned by the call. It is possible, but unlikely,
16// that the return returns something else (like constant 0), and can still
17// be TRE'd. It can be TRE'd if ALL OTHER return instructions in the
18// function return the exact same value.
19//
20//===----------------------------------------------------------------------===//
21
22#include "llvm/DerivedTypes.h"
23#include "llvm/Function.h"
24#include "llvm/Instructions.h"
25#include "llvm/Pass.h"
26#include "Support/Statistic.h"
27
28namespace {
29 Statistic<> NumEliminated("tailcallelim", "Number of tail calls removed");
30
31 struct TailCallElim : public FunctionPass {
32 virtual bool runOnFunction(Function &F);
33 };
34 RegisterOpt<TailCallElim> X("tailcallelim", "Tail Call Elimination");
35}
36
37
38bool TailCallElim::runOnFunction(Function &F) {
39 // If this function is a varargs function, we won't be able to PHI the args
40 // right, so don't even try to convert it...
41 if (F.getFunctionType()->isVarArg()) return false;
42
43 BasicBlock *OldEntry = 0;
44 std::vector<PHINode*> ArgumentPHIs;
45 bool MadeChange = false;
46
47 // Loop over the function, looking for any returning blocks...
48 for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
49 if (ReturnInst *Ret = dyn_cast<ReturnInst>(BB->getTerminator()))
50 if (Ret != BB->begin())
51 if (CallInst *CI = dyn_cast<CallInst>(Ret->getPrev()))
52 // Make sure the tail call is to the current function, and that the
53 // return either returns void or returns the value computed by the
54 // call.
55 if (CI->getCalledFunction() == &F &&
56 (Ret->getNumOperands() == 0 || Ret->getReturnValue() == CI)) {
57 // Ohh, it looks like we found a tail call, is this the first?
58 if (!OldEntry) {
59 // Ok, so this is the first tail call we have found in this
60 // function. Insert a new entry block into the function, allowing
61 // us to branch back to the old entry block.
62 OldEntry = &F.getEntryNode();
63 BasicBlock *NewEntry = new BasicBlock("tailrecurse", OldEntry);
64 NewEntry->getInstList().push_back(new BranchInst(OldEntry));
65
66 // Now that we have created a new block, which jumps to the entry
67 // block, insert a PHI node for each argument of the function.
68 // For now, we initialize each PHI to only have the real arguments
69 // which are passed in.
70 Instruction *InsertPos = OldEntry->begin();
71 for (Function::aiterator I = F.abegin(), E = F.aend(); I!=E; ++I){
72 PHINode *PN = new PHINode(I->getType(), I->getName()+".tr",
73 InsertPos);
74 PN->addIncoming(I, NewEntry);
75 ArgumentPHIs.push_back(PN);
76 }
77 }
78
79 // Ok, now that we know we have a pseudo-entry block WITH all of the
80 // required PHI nodes, add entries into the PHI node for the actual
81 // parameters passed into the tail-recursive call.
82 for (unsigned i = 0, e = CI->getNumOperands()-1; i != e; ++i)
83 ArgumentPHIs[i]->addIncoming(CI->getOperand(i+1), BB);
84
85 // Now that all of the PHI nodes are in place, remove the call and
86 // ret instructions, replacing them with an unconditional branch.
87 new BranchInst(OldEntry, CI);
88 BB->getInstList().pop_back(); // Remove return.
89 BB->getInstList().pop_back(); // Remove call.
90 MadeChange = true;
91 NumEliminated++;
92 }
93
94 return MadeChange;
95}
96