Home | History | Annotate | Download | only in Scalar
      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/Analysis/TargetLibraryInfo.h"
     22 #include "llvm/Transforms/Scalar.h"
     23 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
     24 
     25 using namespace llvm;
     26 
     27 #define DEBUG_TYPE "partially-inline-libcalls"
     28 
     29 namespace {
     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 
     51 INITIALIZE_PASS(PartiallyInlineLibCalls, "partially-inline-libcalls",
     52                 "Partially inline calls to library functions", false, false)
     53 
     54 void PartiallyInlineLibCalls::getAnalysisUsage(AnalysisUsage &AU) const {
     55   AU.addRequired<TargetLibraryInfoWrapperPass>();
     56   AU.addRequired<TargetTransformInfoWrapperPass>();
     57   FunctionPass::getAnalysisUsage(AU);
     58 }
     59 
     60 bool PartiallyInlineLibCalls::runOnFunction(Function &F) {
     61   bool Changed = false;
     62   Function::iterator CurrBB;
     63   TargetLibraryInfo *TLI =
     64       &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
     65   const TargetTransformInfo *TTI =
     66       &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
     67   for (Function::iterator BB = F.begin(), BE = F.end(); BB != BE;) {
     68     CurrBB = BB++;
     69 
     70     for (BasicBlock::iterator II = CurrBB->begin(), IE = CurrBB->end();
     71          II != IE; ++II) {
     72       CallInst *Call = dyn_cast<CallInst>(&*II);
     73       Function *CalledFunc;
     74 
     75       if (!Call || !(CalledFunc = Call->getCalledFunction()))
     76         continue;
     77 
     78       // Skip if function either has local linkage or is not a known library
     79       // function.
     80       LibFunc::Func LibFunc;
     81       if (CalledFunc->hasLocalLinkage() || !CalledFunc->hasName() ||
     82           !TLI->getLibFunc(CalledFunc->getName(), LibFunc))
     83         continue;
     84 
     85       switch (LibFunc) {
     86       case LibFunc::sqrtf:
     87       case LibFunc::sqrt:
     88         if (TTI->haveFastSqrt(Call->getType()) &&
     89             optimizeSQRT(Call, CalledFunc, *CurrBB, BB))
     90           break;
     91         continue;
     92       default:
     93         continue;
     94       }
     95 
     96       Changed = true;
     97       break;
     98     }
     99   }
    100 
    101   return Changed;
    102 }
    103 
    104 bool PartiallyInlineLibCalls::optimizeSQRT(CallInst *Call,
    105                                            Function *CalledFunc,
    106                                            BasicBlock &CurrBB,
    107                                            Function::iterator &BB) {
    108   // There is no need to change the IR, since backend will emit sqrt
    109   // instruction if the call has already been marked read-only.
    110   if (Call->onlyReadsMemory())
    111     return false;
    112 
    113   // The call must have the expected result type.
    114   if (!Call->getType()->isFloatingPointTy())
    115     return false;
    116 
    117   // Do the following transformation:
    118   //
    119   // (before)
    120   // dst = sqrt(src)
    121   //
    122   // (after)
    123   // v0 = sqrt_noreadmem(src) # native sqrt instruction.
    124   // if (v0 is a NaN)
    125   //   v1 = sqrt(src)         # library call.
    126   // dst = phi(v0, v1)
    127   //
    128 
    129   // Move all instructions following Call to newly created block JoinBB.
    130   // Create phi and replace all uses.
    131   BasicBlock *JoinBB = llvm::SplitBlock(&CurrBB, Call->getNextNode());
    132   IRBuilder<> Builder(JoinBB, JoinBB->begin());
    133   PHINode *Phi = Builder.CreatePHI(Call->getType(), 2);
    134   Call->replaceAllUsesWith(Phi);
    135 
    136   // Create basic block LibCallBB and insert a call to library function sqrt.
    137   BasicBlock *LibCallBB = BasicBlock::Create(CurrBB.getContext(), "call.sqrt",
    138                                              CurrBB.getParent(), JoinBB);
    139   Builder.SetInsertPoint(LibCallBB);
    140   Instruction *LibCall = Call->clone();
    141   Builder.Insert(LibCall);
    142   Builder.CreateBr(JoinBB);
    143 
    144   // Add attribute "readnone" so that backend can use a native sqrt instruction
    145   // for this call. Insert a FP compare instruction and a conditional branch
    146   // at the end of CurrBB.
    147   Call->addAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone);
    148   CurrBB.getTerminator()->eraseFromParent();
    149   Builder.SetInsertPoint(&CurrBB);
    150   Value *FCmp = Builder.CreateFCmpOEQ(Call, Call);
    151   Builder.CreateCondBr(FCmp, JoinBB, LibCallBB);
    152 
    153   // Add phi operands.
    154   Phi->addIncoming(Call, &CurrBB);
    155   Phi->addIncoming(LibCall, LibCallBB);
    156 
    157   BB = JoinBB->getIterator();
    158   return true;
    159 }
    160 
    161 FunctionPass *llvm::createPartiallyInlineLibCallsPass() {
    162   return new PartiallyInlineLibCalls();
    163 }
    164