From a2b09656131ab42483057d74128ee3cc43a9dfa2 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Sat, 7 Nov 2009 07:10:01 +0000 Subject: [PATCH] Dust off tail recursion elimination. Fix a fixme by applying CaptureTracking and add a .ll to demo the new capability. llvm-svn: 86349 --- .../Scalar/TailRecursionElimination.cpp | 29 +++++-------------- test/Transforms/TailCallElim/nocapture.ll | 24 +++++++++++++++ 2 files changed, 32 insertions(+), 21 deletions(-) create mode 100644 test/Transforms/TailCallElim/nocapture.ll diff --git a/lib/Transforms/Scalar/TailRecursionElimination.cpp b/lib/Transforms/Scalar/TailRecursionElimination.cpp index b56e17040db..1b8ed4127c4 100644 --- a/lib/Transforms/Scalar/TailRecursionElimination.cpp +++ b/lib/Transforms/Scalar/TailRecursionElimination.cpp @@ -25,7 +25,7 @@ // 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. -// 4. If it can prove that callees do not access theier caller stack frame, +// 4. If it can prove that callees do not access their caller stack frame, // they are marked as eligible for tail call elimination (by the code // generator). // @@ -58,6 +58,7 @@ #include "llvm/Function.h" #include "llvm/Instructions.h" #include "llvm/Pass.h" +#include "llvm/Analysis/CaptureTracking.h" #include "llvm/Support/CFG.h" #include "llvm/ADT/Statistic.h" using namespace llvm; @@ -75,7 +76,7 @@ namespace { private: bool ProcessReturningBlock(ReturnInst *RI, BasicBlock *&OldEntry, bool &TailCallsAreMarkedTail, - std::vector &ArgumentPHIs, + SmallVector &ArgumentPHIs, bool CannotTailCallElimCallsMarkedTail); bool CanMoveAboveCall(Instruction *I, CallInst *CI); Value *CanTransformAccumulatorRecursion(Instruction *I, CallInst *CI); @@ -90,17 +91,7 @@ FunctionPass *llvm::createTailCallEliminationPass() { return new TailCallElim(); } - -/// AllocaMightEscapeToCalls - Return true if this alloca may be accessed by -/// callees of this function. We only do very simple analysis right now, this -/// could be expanded in the future to use mod/ref information for particular -/// call sites if desired. -static bool AllocaMightEscapeToCalls(AllocaInst *AI) { - // FIXME: do simple 'address taken' analysis. - return true; -} - -/// FunctionContainsAllocas - Scan the specified basic block for alloca +/// CheckForEscapingAllocas - Scan the specified basic block for alloca /// instructions. If it contains any that might be accessed by calls, return /// true. static bool CheckForEscapingAllocas(BasicBlock *BB, @@ -108,7 +99,7 @@ static bool CheckForEscapingAllocas(BasicBlock *BB, bool RetVal = false; for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) if (AllocaInst *AI = dyn_cast(I)) { - RetVal |= AllocaMightEscapeToCalls(AI); + RetVal |= PointerMayBeCaptured(AI, true); // If this alloca is in the body of the function, or if it is a variable // sized allocation, we cannot tail call eliminate calls marked 'tail' @@ -127,7 +118,7 @@ bool TailCallElim::runOnFunction(Function &F) { BasicBlock *OldEntry = 0; bool TailCallsAreMarkedTail = false; - std::vector ArgumentPHIs; + SmallVector ArgumentPHIs; bool MadeChange = false; bool FunctionContainsEscapingAllocas = false; @@ -204,7 +195,7 @@ bool TailCallElim::CanMoveAboveCall(Instruction *I, CallInst *CI) { if (I->mayHaveSideEffects()) // This also handles volatile loads. return false; - if (LoadInst* L = dyn_cast(I)) { + if (LoadInst *L = dyn_cast(I)) { // Loads may always be moved above calls without side effects. if (CI->mayHaveSideEffects()) { // Non-volatile loads may be moved above a call with side effects if it @@ -265,10 +256,6 @@ static Value *getCommonReturnValue(ReturnInst *TheRI, CallInst *CI) { Function *F = TheRI->getParent()->getParent(); Value *ReturnedValue = 0; - // TODO: Handle multiple value ret instructions; - if (isa(F->getReturnType())) - return 0; - for (Function::iterator BBI = F->begin(), E = F->end(); BBI != E; ++BBI) if (ReturnInst *RI = dyn_cast(BBI->getTerminator())) if (RI != TheRI) { @@ -315,7 +302,7 @@ Value *TailCallElim::CanTransformAccumulatorRecursion(Instruction *I, bool TailCallElim::ProcessReturningBlock(ReturnInst *Ret, BasicBlock *&OldEntry, bool &TailCallsAreMarkedTail, - std::vector &ArgumentPHIs, + SmallVector &ArgumentPHIs, bool CannotTailCallElimCallsMarkedTail) { BasicBlock *BB = Ret->getParent(); Function *F = BB->getParent(); diff --git a/test/Transforms/TailCallElim/nocapture.ll b/test/Transforms/TailCallElim/nocapture.ll new file mode 100644 index 00000000000..92dc374a93c --- /dev/null +++ b/test/Transforms/TailCallElim/nocapture.ll @@ -0,0 +1,24 @@ +; RUN: opt %s -tailcallelim -S | FileCheck %s + +declare void @use(i8* nocapture, i8* nocapture) + +define i8* @foo(i8* nocapture %A, i1 %cond) { +; CHECK: tailrecurse: +; CHECK: %A.tr = phi i8* [ %A, %0 ], [ %B, %cond_true ] +; CHECK: %cond.tr = phi i1 [ %cond, %0 ], [ false, %cond_true ] + %B = alloca i8 +; CHECK: %B = alloca i8 + br i1 %cond, label %cond_true, label %cond_false +; CHECK: br i1 %cond.tr, label %cond_true, label %cond_false +cond_true: +; CHECK: cond_true: +; CHECK: br label %tailrecurse + call i8* @foo(i8* %B, i1 false) + ret i8* null +cond_false: +; CHECK: cond_false + call void @use(i8* %A, i8* %B) +; CHECK: tail call void @use(i8* %A.tr, i8* %B) + ret i8* null +; CHECK: ret i8* null +}