forked from OSchip/llvm-project
parent
3e96a709f1
commit
59fe82f4ce
|
@ -0,0 +1,66 @@
|
|||
//===---- TailRecursionElimination.h ----------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TRANSFORMS_SCALAR_TAILRECURSIONELIMINATION_H
|
||||
#define LLVM_TRANSFORMS_SCALAR_TAILRECURSIONELIMINATION_H
|
||||
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
struct TailCallElimPass : PassInfoMixin<TailCallElimPass> {
|
||||
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LLVM_TRANSFORMS_SCALAR_TAILRECURSIONELIMINATION_H
|
|
@ -98,6 +98,7 @@
|
|||
#include "llvm/Transforms/Scalar/SROA.h"
|
||||
#include "llvm/Transforms/Scalar/SimplifyCFG.h"
|
||||
#include "llvm/Transforms/Scalar/Sink.h"
|
||||
#include "llvm/Transforms/Scalar/TailRecursionElimination.h"
|
||||
#include "llvm/Transforms/Utils/AddDiscriminators.h"
|
||||
#include "llvm/Transforms/Utils/LCSSA.h"
|
||||
#include "llvm/Transforms/Utils/Mem2Reg.h"
|
||||
|
|
|
@ -163,6 +163,7 @@ FUNCTION_PASS("simplify-cfg", SimplifyCFGPass())
|
|||
FUNCTION_PASS("sink", SinkingPass())
|
||||
FUNCTION_PASS("slp-vectorizer", SLPVectorizerPass())
|
||||
FUNCTION_PASS("sroa", SROA())
|
||||
FUNCTION_PASS("tailcallelim", TailCallElimPass())
|
||||
FUNCTION_PASS("verify", VerifierPass())
|
||||
FUNCTION_PASS("verify<domtree>", DominatorTreeVerifierPass())
|
||||
FUNCTION_PASS("verify<memoryssa>", MemorySSAVerifierPass())
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Transforms/Scalar/TailRecursionElimination.h"
|
||||
#include "llvm/Transforms/Scalar.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
|
@ -731,6 +732,9 @@ static bool processReturningBlock(ReturnInst *Ret, BasicBlock *&OldEntry,
|
|||
}
|
||||
|
||||
static bool eliminateTailRecursion(Function &F, const TargetTransformInfo *TTI) {
|
||||
if (F.getFnAttribute("disable-tail-calls").getValueAsString() == "true")
|
||||
return false;
|
||||
|
||||
bool MadeChange = false;
|
||||
bool AllCallsAreTailCalls = false;
|
||||
MadeChange |= markTails(F, AllCallsAreTailCalls);
|
||||
|
@ -800,8 +804,7 @@ struct TailCallElim : public FunctionPass {
|
|||
}
|
||||
|
||||
bool runOnFunction(Function &F) override {
|
||||
if (skipFunction(F) ||
|
||||
F.getFnAttribute("disable-tail-calls").getValueAsString() == "true")
|
||||
if (skipFunction(F))
|
||||
return false;
|
||||
|
||||
return eliminateTailRecursion(
|
||||
|
@ -821,3 +824,17 @@ INITIALIZE_PASS_END(TailCallElim, "tailcallelim", "Tail Call Elimination",
|
|||
FunctionPass *llvm::createTailCallEliminationPass() {
|
||||
return new TailCallElim();
|
||||
}
|
||||
|
||||
PreservedAnalyses TailCallElimPass::run(Function &F,
|
||||
FunctionAnalysisManager &AM) {
|
||||
|
||||
TargetTransformInfo &TTI = AM.getResult<TargetIRAnalysis>(F);
|
||||
|
||||
bool Changed = eliminateTailRecursion(F, &TTI);
|
||||
|
||||
if (!Changed)
|
||||
return PreservedAnalyses::all();
|
||||
PreservedAnalyses PA;
|
||||
PA.preserve<GlobalsAA>();
|
||||
return PA;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
; RUN: opt < %s -tailcallelim -S | FileCheck %s
|
||||
; RUN: opt < %s -passes=tailcallelim -S | FileCheck %s
|
||||
|
||||
define i32 @test1_factorial(i32 %x) {
|
||||
entry:
|
||||
|
|
Loading…
Reference in New Issue