blob: 5494356a60b7bdf19550c24942b62e37c9b65d23 [file] [log] [blame]
Richard Sandiford37cd6cf2013-08-23 10:27:02 +00001//===--- PartiallyInlineLibCalls.cpp - Partially inline libcalls ----------===//
Akira Hatanaka5c50a162013-06-11 22:21:44 +00002//
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//
Richard Sandiford37cd6cf2013-08-23 10:27:02 +000010// 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.
Akira Hatanaka5c50a162013-06-11 22:21:44 +000013//
14//===----------------------------------------------------------------------===//
15
Davide Italiano1021c682016-05-25 23:38:53 +000016#include "llvm/Transforms/Scalar/PartiallyInlineLibCalls.h"
Mehdi Aminib550cb12016-04-18 09:17:29 +000017#include "llvm/Analysis/TargetLibraryInfo.h"
Richard Sandiford37cd6cf2013-08-23 10:27:02 +000018#include "llvm/Analysis/TargetTransformInfo.h"
Akira Hatanaka5c50a162013-06-11 22:21:44 +000019#include "llvm/IR/IRBuilder.h"
Richard Sandiford37cd6cf2013-08-23 10:27:02 +000020#include "llvm/Transforms/Scalar.h"
Akira Hatanaka5c50a162013-06-11 22:21:44 +000021#include "llvm/Transforms/Utils/BasicBlockUtils.h"
22
23using namespace llvm;
24
Chandler Carruth964daaa2014-04-22 02:55:47 +000025#define DEBUG_TYPE "partially-inline-libcalls"
26
Andrew Kaylor50271f72016-05-03 22:32:30 +000027
Davide Italiano08713bd2016-05-20 15:43:39 +000028static bool optimizeSQRT(CallInst *Call, Function *CalledFunc,
29 BasicBlock &CurrBB, Function::iterator &BB) {
Akira Hatanaka5c50a162013-06-11 22:21:44 +000030 // 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
Peter Collingbournee52646c2014-08-01 23:21:21 +000035 // The call must have the expected result type.
36 if (!Call->getType()->isFloatingPointTy())
37 return false;
38
Akira Hatanaka5c50a162013-06-11 22:21:44 +000039 // 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.
Chandler Carruth32c52c72015-01-18 02:39:37 +000053 BasicBlock *JoinBB = llvm::SplitBlock(&CurrBB, Call->getNextNode());
Akira Hatanaka5c50a162013-06-11 22:21:44 +000054 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
Duncan P. N. Exon Smithbe4d8cb2015-10-13 19:26:58 +000079 BB = JoinBB->getIterator();
Akira Hatanaka5c50a162013-06-11 22:21:44 +000080 return true;
81}
Richard Sandiford37cd6cf2013-08-23 10:27:02 +000082
Davide Italiano1021c682016-05-25 23:38:53 +000083static bool runPartiallyInlineLibCalls(Function &F, TargetLibraryInfo *TLI,
84 const TargetTransformInfo *TTI) {
Davide Italiano08713bd2016-05-20 15:43:39 +000085 bool Changed = false;
Davide Italiano1021c682016-05-25 23:38:53 +000086
Davide Italiano08713bd2016-05-20 15:43:39 +000087 Function::iterator CurrBB;
Davide Italiano08713bd2016-05-20 15:43:39 +000088 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.
David L. Jonesd21529f2017-01-23 23:16:46 +0000101 LibFunc LF;
Davide Italiano08713bd2016-05-20 15:43:39 +0000102 if (CalledFunc->hasLocalLinkage() || !CalledFunc->hasName() ||
David L. Jonesd21529f2017-01-23 23:16:46 +0000103 !TLI->getLibFunc(CalledFunc->getName(), LF))
Davide Italiano08713bd2016-05-20 15:43:39 +0000104 continue;
105
David L. Jonesd21529f2017-01-23 23:16:46 +0000106 switch (LF) {
107 case LibFunc_sqrtf:
108 case LibFunc_sqrt:
Davide Italiano08713bd2016-05-20 15:43:39 +0000109 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
Davide Italiano1021c682016-05-25 23:38:53 +0000125PreservedAnalyses
Sean Silva36e0d012016-08-09 00:28:15 +0000126PartiallyInlineLibCallsPass::run(Function &F, FunctionAnalysisManager &AM) {
Davide Italiano1021c682016-05-25 23:38:53 +0000127 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
134namespace {
135class PartiallyInlineLibCallsLegacyPass : public FunctionPass {
136public:
137 static char ID;
138
139 PartiallyInlineLibCallsLegacyPass() : FunctionPass(ID) {
140 initializePartiallyInlineLibCallsLegacyPassPass(
141 *PassRegistry::getPassRegistry());
142 }
143
144 void getAnalysisUsage(AnalysisUsage &AU) const override {
145 AU.addRequired<TargetLibraryInfoWrapperPass>();
146 AU.addRequired<TargetTransformInfoWrapperPass>();
147 FunctionPass::getAnalysisUsage(AU);
148 }
149
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
163char PartiallyInlineLibCallsLegacyPass::ID = 0;
164INITIALIZE_PASS_BEGIN(PartiallyInlineLibCallsLegacyPass,
165 "partially-inline-libcalls",
166 "Partially inline calls to library functions", false,
167 false)
168INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
169INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
170INITIALIZE_PASS_END(PartiallyInlineLibCallsLegacyPass,
171 "partially-inline-libcalls",
172 "Partially inline calls to library functions", false, false)
173
Richard Sandiford37cd6cf2013-08-23 10:27:02 +0000174FunctionPass *llvm::createPartiallyInlineLibCallsPass() {
Davide Italiano1021c682016-05-25 23:38:53 +0000175 return new PartiallyInlineLibCallsLegacyPass();
Richard Sandiford37cd6cf2013-08-23 10:27:02 +0000176}