PartiallyInlineLibCalls.cpp revision 37ed9c199ca639565f6ce88105f9e39e898d82d0
1//===--- PartiallyInlineLibCalls.cpp - Partially inline libcalls ----------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This pass tries to partially inline the fast path of well-known library
11// functions, such as using square-root instructions for cases where sqrt()
12// does not need to set errno.
13//
14//===----------------------------------------------------------------------===//
15
16#include "llvm/Analysis/TargetTransformInfo.h"
17#include "llvm/IR/IRBuilder.h"
18#include "llvm/IR/Intrinsics.h"
19#include "llvm/Pass.h"
20#include "llvm/Support/CommandLine.h"
21#include "llvm/Target/TargetLibraryInfo.h"
22#include "llvm/Transforms/Scalar.h"
23#include "llvm/Transforms/Utils/BasicBlockUtils.h"
24
25using namespace llvm;
26
27#define DEBUG_TYPE "partially-inline-libcalls"
28
29namespace {
30  class PartiallyInlineLibCalls : public FunctionPass {
31  public:
32    static char ID;
33
34    PartiallyInlineLibCalls() :
35      FunctionPass(ID) {
36      initializePartiallyInlineLibCallsPass(*PassRegistry::getPassRegistry());
37    }
38
39    void getAnalysisUsage(AnalysisUsage &AU) const override;
40    bool runOnFunction(Function &F) override;
41
42  private:
43    /// Optimize calls to sqrt.
44    bool optimizeSQRT(CallInst *Call, Function *CalledFunc,
45                      BasicBlock &CurrBB, Function::iterator &BB);
46  };
47
48  char PartiallyInlineLibCalls::ID = 0;
49}
50
51INITIALIZE_PASS(PartiallyInlineLibCalls, "partially-inline-libcalls",
52                "Partially inline calls to library functions", false, false)
53
54void PartiallyInlineLibCalls::getAnalysisUsage(AnalysisUsage &AU) const {
55  AU.addRequired<TargetLibraryInfo>();
56  AU.addRequired<TargetTransformInfo>();
57  FunctionPass::getAnalysisUsage(AU);
58}
59
60bool PartiallyInlineLibCalls::runOnFunction(Function &F) {
61  bool Changed = false;
62  Function::iterator CurrBB;
63  TargetLibraryInfo *TLI = &getAnalysis<TargetLibraryInfo>();
64  const TargetTransformInfo *TTI = &getAnalysis<TargetTransformInfo>();
65  for (Function::iterator BB = F.begin(), BE = F.end(); BB != BE;) {
66    CurrBB = BB++;
67
68    for (BasicBlock::iterator II = CurrBB->begin(), IE = CurrBB->end();
69         II != IE; ++II) {
70      CallInst *Call = dyn_cast<CallInst>(&*II);
71      Function *CalledFunc;
72
73      if (!Call || !(CalledFunc = Call->getCalledFunction()))
74        continue;
75
76      // Skip if function either has local linkage or is not a known library
77      // function.
78      LibFunc::Func LibFunc;
79      if (CalledFunc->hasLocalLinkage() || !CalledFunc->hasName() ||
80          !TLI->getLibFunc(CalledFunc->getName(), LibFunc))
81        continue;
82
83      switch (LibFunc) {
84      case LibFunc::sqrtf:
85      case LibFunc::sqrt:
86        if (TTI->haveFastSqrt(Call->getType()) &&
87            optimizeSQRT(Call, CalledFunc, *CurrBB, BB))
88          break;
89        continue;
90      default:
91        continue;
92      }
93
94      Changed = true;
95      break;
96    }
97  }
98
99  return Changed;
100}
101
102bool PartiallyInlineLibCalls::optimizeSQRT(CallInst *Call,
103                                           Function *CalledFunc,
104                                           BasicBlock &CurrBB,
105                                           Function::iterator &BB) {
106  // There is no need to change the IR, since backend will emit sqrt
107  // instruction if the call has already been marked read-only.
108  if (Call->onlyReadsMemory())
109    return false;
110
111  // The call must have the expected result type.
112  if (!Call->getType()->isFloatingPointTy())
113    return false;
114
115  // Do the following transformation:
116  //
117  // (before)
118  // dst = sqrt(src)
119  //
120  // (after)
121  // v0 = sqrt_noreadmem(src) # native sqrt instruction.
122  // if (v0 is a NaN)
123  //   v1 = sqrt(src)         # library call.
124  // dst = phi(v0, v1)
125  //
126
127  // Move all instructions following Call to newly created block JoinBB.
128  // Create phi and replace all uses.
129  BasicBlock *JoinBB = llvm::SplitBlock(&CurrBB, Call->getNextNode(), this);
130  IRBuilder<> Builder(JoinBB, JoinBB->begin());
131  PHINode *Phi = Builder.CreatePHI(Call->getType(), 2);
132  Call->replaceAllUsesWith(Phi);
133
134  // Create basic block LibCallBB and insert a call to library function sqrt.
135  BasicBlock *LibCallBB = BasicBlock::Create(CurrBB.getContext(), "call.sqrt",
136                                             CurrBB.getParent(), JoinBB);
137  Builder.SetInsertPoint(LibCallBB);
138  Instruction *LibCall = Call->clone();
139  Builder.Insert(LibCall);
140  Builder.CreateBr(JoinBB);
141
142  // Add attribute "readnone" so that backend can use a native sqrt instruction
143  // for this call. Insert a FP compare instruction and a conditional branch
144  // at the end of CurrBB.
145  Call->addAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone);
146  CurrBB.getTerminator()->eraseFromParent();
147  Builder.SetInsertPoint(&CurrBB);
148  Value *FCmp = Builder.CreateFCmpOEQ(Call, Call);
149  Builder.CreateCondBr(FCmp, JoinBB, LibCallBB);
150
151  // Add phi operands.
152  Phi->addIncoming(Call, &CurrBB);
153  Phi->addIncoming(LibCall, LibCallBB);
154
155  BB = JoinBB;
156  return true;
157}
158
159FunctionPass *llvm::createPartiallyInlineLibCallsPass() {
160  return new PartiallyInlineLibCalls();
161}
162