//===- TailRecursionElimination.cpp - Eliminate Tail Calls ----------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file transforms calls of the current function (self recursion) followed // by a return instruction with a branch to the entry of the function, creating // a loop. This pass also implements the following extensions to the basic // algorithm: // // 1. Trivial instructions between the call and return do not prevent the // transformation from taking place, though currently the analysis cannot // support moving any really useful instructions (only dead ones). // 2. This pass transforms functions that are prevented from being tail // recursive by an associative and commutative expression to use an // accumulator variable, thus compiling the typical naive factorial or // 'fib' implementation into efficient code. // 3. TRE is performed if the function returns void, if the return // returns the result returned by the call, or if the function returns a // run-time constant on all exits from the function. It is possible, though // 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 their caller stack frame, // they are marked as eligible for tail call elimination (by the code // generator). // // There are several improvements that could be made: // // 1. If the function has any alloca instructions, these instructions will be // moved out of the entry block of the function, causing them to be // evaluated each time through the tail recursion. Safely keeping allocas // in the entry block requires analysis to proves that the tail-called // function does not read or write the stack object. // 2. Tail recursion is only performed if the call immediately precedes the // return instruction. It's possible that there could be a jump between // the call and the return. // 3. There can be intervening operations between the call and the return that // prevent the TRE from occurring. For example, there could be GEP's and // stores to memory that will not be read or written by the call. This // requires some substantial analysis (such as with DSA) to prove safe to // move ahead of the call, but doing so could allow many more TREs to be // performed, for example in TreeAdd/TreeAlloc from the treeadd benchmark. // 4. The algorithm we use to detect if callees access their caller stack // frames is very primitive. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/Scalar/TailRecursionElimination.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/DomTreeUpdater.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/Loads.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/Analysis/PostDominators.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/CFG.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" usingnamespacellvm; #define DEBUG_TYPE … STATISTIC(NumEliminated, "Number of tail calls removed"); STATISTIC(NumRetDuped, "Number of return duplicated"); STATISTIC(NumAccumAdded, "Number of accumulators introduced"); /// Scan the specified function for alloca instructions. /// If it contains any dynamic allocas, returns false. static bool canTRE(Function &F) { … } namespace { struct AllocaDerivedValueTracker { … }; } static bool markTails(Function &F, OptimizationRemarkEmitter *ORE) { … } /// Return true if it is safe to move the specified /// instruction from after the call to before the call, assuming that all /// instructions between the call and this instruction are movable. /// static bool canMoveAboveCall(Instruction *I, CallInst *CI, AliasAnalysis *AA) { … } static bool canTransformAccumulatorRecursion(Instruction *I, CallInst *CI) { … } static Instruction *firstNonDbg(BasicBlock::iterator I) { … } namespace { class TailRecursionEliminator { … }; } // namespace CallInst *TailRecursionEliminator::findTRECandidate(BasicBlock *BB) { … } void TailRecursionEliminator::createTailRecurseLoopHeader(CallInst *CI) { … } void TailRecursionEliminator::insertAccumulator(Instruction *AccRecInstr) { … } // Creates a copy of contents of ByValue operand of the specified // call instruction into the newly created temporarily variable. void TailRecursionEliminator::copyByValueOperandIntoLocalTemp(CallInst *CI, int OpndIdx) { … } // Creates a copy from temporarily variable(keeping value of ByVal argument) // into the corresponding function argument location. void TailRecursionEliminator::copyLocalTempOfByValueOperandIntoArguments( CallInst *CI, int OpndIdx) { … } bool TailRecursionEliminator::eliminateCall(CallInst *CI) { … } void TailRecursionEliminator::cleanupAndFinalize() { … } bool TailRecursionEliminator::processBlock(BasicBlock &BB) { … } bool TailRecursionEliminator::eliminate(Function &F, const TargetTransformInfo *TTI, AliasAnalysis *AA, OptimizationRemarkEmitter *ORE, DomTreeUpdater &DTU) { … } namespace { struct TailCallElim : public FunctionPass { … }; } char TailCallElim::ID = …; INITIALIZE_PASS_BEGIN(TailCallElim, "tailcallelim", "Tail Call Elimination", false, false) INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass) INITIALIZE_PASS_END(TailCallElim, "tailcallelim", "Tail Call Elimination", false, false) // Public interface to the TailCallElimination pass FunctionPass *llvm::createTailCallEliminationPass() { … } PreservedAnalyses TailCallElimPass::run(Function &F, FunctionAnalysisManager &AM) { … }