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 
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   // Do the following transformation:
36   //
37   // (before)
38   // dst = sqrt(src)
39   //
40   // (after)
41   // v0 = sqrt_noreadmem(src) # native sqrt instruction.
42   // if (v0 is a NaN)
43   //   v1 = sqrt(src)         # library call.
44   // dst = phi(v0, v1)
45   //
46 
47   // Move all instructions following Call to newly created block JoinBB.
48   // Create phi and replace all uses.
49   BasicBlock *JoinBB = llvm::SplitBlock(&CurrBB, Call->getNextNode());
50   IRBuilder<> Builder(JoinBB, JoinBB->begin());
51   PHINode *Phi = Builder.CreatePHI(Call->getType(), 2);
52   Call->replaceAllUsesWith(Phi);
53 
54   // Create basic block LibCallBB and insert a call to library function sqrt.
55   BasicBlock *LibCallBB = BasicBlock::Create(CurrBB.getContext(), "call.sqrt",
56                                              CurrBB.getParent(), JoinBB);
57   Builder.SetInsertPoint(LibCallBB);
58   Instruction *LibCall = Call->clone();
59   Builder.Insert(LibCall);
60   Builder.CreateBr(JoinBB);
61 
62   // Add attribute "readnone" so that backend can use a native sqrt instruction
63   // for this call. Insert a FP compare instruction and a conditional branch
64   // at the end of CurrBB.
65   Call->addAttribute(AttributeList::FunctionIndex, Attribute::ReadNone);
66   CurrBB.getTerminator()->eraseFromParent();
67   Builder.SetInsertPoint(&CurrBB);
68   Value *FCmp = Builder.CreateFCmpOEQ(Call, Call);
69   Builder.CreateCondBr(FCmp, JoinBB, LibCallBB);
70 
71   // Add phi operands.
72   Phi->addIncoming(Call, &CurrBB);
73   Phi->addIncoming(LibCall, LibCallBB);
74 
75   BB = JoinBB->getIterator();
76   return true;
77 }
78 
79 static bool runPartiallyInlineLibCalls(Function &F, TargetLibraryInfo *TLI,
80                                        const TargetTransformInfo *TTI) {
81   bool Changed = false;
82 
83   Function::iterator CurrBB;
84   for (Function::iterator BB = F.begin(), BE = F.end(); BB != BE;) {
85     CurrBB = BB++;
86 
87     for (BasicBlock::iterator II = CurrBB->begin(), IE = CurrBB->end();
88          II != IE; ++II) {
89       CallInst *Call = dyn_cast<CallInst>(&*II);
90       Function *CalledFunc;
91 
92       if (!Call || !(CalledFunc = Call->getCalledFunction()))
93         continue;
94 
95       if (Call->isNoBuiltin())
96         continue;
97 
98       // Skip if function either has local linkage or is not a known library
99       // function.
100       LibFunc LF;
101       if (CalledFunc->hasLocalLinkage() ||
102           !TLI->getLibFunc(*CalledFunc, LF) || !TLI->has(LF))
103         continue;
104 
105       switch (LF) {
106       case LibFunc_sqrtf:
107       case LibFunc_sqrt:
108         if (TTI->haveFastSqrt(Call->getType()) &&
109             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 
124 PreservedAnalyses
125 PartiallyInlineLibCallsPass::run(Function &F, FunctionAnalysisManager &AM) {
126   auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
127   auto &TTI = AM.getResult<TargetIRAnalysis>(F);
128   if (!runPartiallyInlineLibCalls(F, &TLI, &TTI))
129     return PreservedAnalyses::all();
130   return PreservedAnalyses::none();
131 }
132 
133 namespace {
134 class PartiallyInlineLibCallsLegacyPass : public FunctionPass {
135 public:
136   static char ID;
137 
138   PartiallyInlineLibCallsLegacyPass() : FunctionPass(ID) {
139     initializePartiallyInlineLibCallsLegacyPassPass(
140         *PassRegistry::getPassRegistry());
141   }
142 
143   void getAnalysisUsage(AnalysisUsage &AU) const override {
144     AU.addRequired<TargetLibraryInfoWrapperPass>();
145     AU.addRequired<TargetTransformInfoWrapperPass>();
146     FunctionPass::getAnalysisUsage(AU);
147   }
148 
149   bool runOnFunction(Function &F) override {
150     if (skipFunction(F))
151       return false;
152 
153     TargetLibraryInfo *TLI =
154         &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
155     const TargetTransformInfo *TTI =
156         &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
157     return runPartiallyInlineLibCalls(F, TLI, TTI);
158   }
159 };
160 }
161 
162 char PartiallyInlineLibCallsLegacyPass::ID = 0;
163 INITIALIZE_PASS_BEGIN(PartiallyInlineLibCallsLegacyPass,
164                       "partially-inline-libcalls",
165                       "Partially inline calls to library functions", false,
166                       false)
167 INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
168 INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
169 INITIALIZE_PASS_END(PartiallyInlineLibCallsLegacyPass,
170                     "partially-inline-libcalls",
171                     "Partially inline calls to library functions", false, false)
172 
173 FunctionPass *llvm::createPartiallyInlineLibCallsPass() {
174   return new PartiallyInlineLibCallsLegacyPass();
175 }
176