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