1//===---- MipsOptimizeMathLibCalls.cpp - Optimize math lib calls.      ----===//
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 does an IR transformation which enables the backend to emit native
11// math instructions.
12//
13//===----------------------------------------------------------------------===//
14
15#include "MipsTargetMachine.h"
16#include "llvm/IR/IRBuilder.h"
17#include "llvm/IR/Intrinsics.h"
18#include "llvm/Pass.h"
19#include "llvm/Support/CommandLine.h"
20#include "llvm/Target/TargetLibraryInfo.h"
21#include "llvm/Transforms/Utils/BasicBlockUtils.h"
22
23using namespace llvm;
24
25static cl::opt<bool> DisableOpt("disable-mips-math-optimization",
26                                cl::init(false),
27                                cl::desc("MIPS: Disable math lib call "
28                                         "optimization."), cl::Hidden);
29
30namespace {
31  class MipsOptimizeMathLibCalls : public FunctionPass {
32  public:
33    static char ID;
34
35    MipsOptimizeMathLibCalls(MipsTargetMachine &TM_) :
36      FunctionPass(ID), TM(TM_) {}
37
38    virtual const char *getPassName() const {
39      return "MIPS: Optimize calls to math library functions.";
40    }
41
42    virtual void getAnalysisUsage(AnalysisUsage &AU) const;
43
44    virtual bool runOnFunction(Function &F);
45
46  private:
47    /// Optimize calls to sqrt.
48    bool optimizeSQRT(CallInst *Call, Function *CalledFunc,
49                      BasicBlock &CurrBB,
50                      Function::iterator &BB);
51
52    const TargetMachine &TM;
53  };
54
55  char MipsOptimizeMathLibCalls::ID = 0;
56}
57
58FunctionPass *llvm::createMipsOptimizeMathLibCalls(MipsTargetMachine &TM) {
59  return new MipsOptimizeMathLibCalls(TM);
60}
61
62void MipsOptimizeMathLibCalls::getAnalysisUsage(AnalysisUsage &AU) const {
63  AU.addRequired<TargetLibraryInfo>();
64  FunctionPass::getAnalysisUsage(AU);
65}
66
67bool MipsOptimizeMathLibCalls::runOnFunction(Function &F) {
68  if (DisableOpt)
69    return false;
70
71  const MipsSubtarget &Subtarget = TM.getSubtarget<MipsSubtarget>();
72
73  if (Subtarget.inMips16Mode())
74    return false;
75
76  bool Changed = false;
77  Function::iterator CurrBB;
78  const TargetLibraryInfo *LibInfo = &getAnalysis<TargetLibraryInfo>();
79
80  for (Function::iterator BB = F.begin(), BE = F.end(); BB != BE;) {
81    CurrBB = BB++;
82
83    for (BasicBlock::iterator II = CurrBB->begin(), IE = CurrBB->end();
84         II != IE; ++II) {
85      CallInst *Call = dyn_cast<CallInst>(&*II);
86      Function *CalledFunc;
87
88      if (!Call || !(CalledFunc = Call->getCalledFunction()))
89        continue;
90
91      LibFunc::Func LibFunc;
92      Attribute A = CalledFunc->getAttributes()
93        .getAttribute(AttributeSet::FunctionIndex, "use-soft-float");
94
95      // Skip if function has "use-soft-float" attribute.
96      if ((A.isStringAttribute() && (A.getValueAsString() == "true")) ||
97          TM.Options.UseSoftFloat)
98        continue;
99
100      // Skip if function either has local linkage or is not a known library
101      // function.
102      if (CalledFunc->hasLocalLinkage() || !CalledFunc->hasName() ||
103          !LibInfo->getLibFunc(CalledFunc->getName(), LibFunc))
104        continue;
105
106      switch (LibFunc) {
107      case LibFunc::sqrtf:
108      case LibFunc::sqrt:
109        if (optimizeSQRT(Call, CalledFunc, *CurrBB, BB))
110          break;
111        continue;
112      default:
113        continue;
114      }
115
116      Changed = true;
117      break;
118    }
119  }
120
121  return Changed;
122}
123
124bool MipsOptimizeMathLibCalls::optimizeSQRT(CallInst *Call,
125                                            Function *CalledFunc,
126                                            BasicBlock &CurrBB,
127                                            Function::iterator &BB) {
128  // There is no need to change the IR, since backend will emit sqrt
129  // instruction if the call has already been marked read-only.
130  if (Call->onlyReadsMemory())
131    return false;
132
133  // Do the following transformation:
134  //
135  // (before)
136  // dst = sqrt(src)
137  //
138  // (after)
139  // v0 = sqrt_noreadmem(src) # native sqrt instruction.
140  // if (v0 is a NaN)
141  //   v1 = sqrt(src)         # library call.
142  // dst = phi(v0, v1)
143  //
144
145  // Move all instructions following Call to newly created block JoinBB.
146  // Create phi and replace all uses.
147  BasicBlock *JoinBB = llvm::SplitBlock(&CurrBB, Call->getNextNode(), this);
148  IRBuilder<> Builder(JoinBB, JoinBB->begin());
149  PHINode *Phi = Builder.CreatePHI(Call->getType(), 2);
150  Call->replaceAllUsesWith(Phi);
151
152  // Create basic block LibCallBB and insert a call to library function sqrt.
153  BasicBlock *LibCallBB = BasicBlock::Create(CurrBB.getContext(), "call.sqrt",
154                                             CurrBB.getParent(), JoinBB);
155  Builder.SetInsertPoint(LibCallBB);
156  Instruction *LibCall = Call->clone();
157  Builder.Insert(LibCall);
158  Builder.CreateBr(JoinBB);
159
160  // Add attribute "readnone" so that backend can use a native sqrt instruction
161  // for this call. Insert a FP compare instruction and a conditional branch
162  // at the end of CurrBB.
163  Call->addAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone);
164  CurrBB.getTerminator()->eraseFromParent();
165  Builder.SetInsertPoint(&CurrBB);
166  Value *FCmp = Builder.CreateFCmpOEQ(Call, Call);
167  Builder.CreateCondBr(FCmp, JoinBB, LibCallBB);
168
169  // Add phi operands.
170  Phi->addIncoming(Call, &CurrBB);
171  Phi->addIncoming(LibCall, LibCallBB);
172
173  BB = JoinBB;
174  return true;
175}
176