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