1 //===--- PartiallyInlineLibCalls.cpp - Partially inline libcalls ----------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This pass tries to partially inline the fast path of well-known library
10 // functions, such as using square-root instructions for cases where sqrt()
11 // does not need to set errno.
13 //===----------------------------------------------------------------------===//
15 #include "llvm/Transforms/Scalar/PartiallyInlineLibCalls.h"
16 #include "llvm/Analysis/DomTreeUpdater.h"
17 #include "llvm/Analysis/TargetLibraryInfo.h"
18 #include "llvm/Analysis/TargetTransformInfo.h"
19 #include "llvm/IR/Dominators.h"
20 #include "llvm/IR/IRBuilder.h"
21 #include "llvm/InitializePasses.h"
22 #include "llvm/Support/DebugCounter.h"
23 #include "llvm/Transforms/Scalar.h"
24 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
28 #define DEBUG_TYPE "partially-inline-libcalls"
30 DEBUG_COUNTER(PILCounter
, "partially-inline-libcalls-transform",
31 "Controls transformations in partially-inline-libcalls");
33 static bool optimizeSQRT(CallInst
*Call
, Function
*CalledFunc
,
34 BasicBlock
&CurrBB
, Function::iterator
&BB
,
35 const TargetTransformInfo
*TTI
, DomTreeUpdater
*DTU
) {
36 // There is no need to change the IR, since backend will emit sqrt
37 // instruction if the call has already been marked read-only.
38 if (Call
->onlyReadsMemory())
41 if (!DebugCounter::shouldExecute(PILCounter
))
44 // Do the following transformation:
50 // v0 = sqrt_noreadmem(src) # native sqrt instruction.
51 // [if (v0 is a NaN) || if (src < 0)]
52 // v1 = sqrt(src) # library call.
56 Type
*Ty
= Call
->getType();
57 IRBuilder
<> Builder(Call
->getNextNode());
59 // Split CurrBB right after the call, create a 'then' block (that branches
60 // back to split-off tail of CurrBB) into which we'll insert a libcall.
61 Instruction
*LibCallTerm
= SplitBlockAndInsertIfThen(
62 Builder
.getTrue(), Call
->getNextNode(), /*Unreachable=*/false,
63 /*BranchWeights*/ nullptr, DTU
);
65 auto *CurrBBTerm
= cast
<BranchInst
>(CurrBB
.getTerminator());
66 // We want an 'else' block though, not a 'then' block.
67 cast
<BranchInst
>(CurrBBTerm
)->swapSuccessors();
69 // Create phi that will merge results of either sqrt and replace all uses.
70 BasicBlock
*JoinBB
= LibCallTerm
->getSuccessor(0);
71 JoinBB
->setName(CurrBB
.getName() + ".split");
72 Builder
.SetInsertPoint(JoinBB
, JoinBB
->begin());
73 PHINode
*Phi
= Builder
.CreatePHI(Ty
, 2);
74 Call
->replaceAllUsesWith(Phi
);
76 // Finally, insert the libcall into 'else' block.
77 BasicBlock
*LibCallBB
= LibCallTerm
->getParent();
78 LibCallBB
->setName("call.sqrt");
79 Builder
.SetInsertPoint(LibCallTerm
);
80 Instruction
*LibCall
= Call
->clone();
81 Builder
.Insert(LibCall
);
83 // Add attribute "readnone" so that backend can use a native sqrt instruction
85 Call
->addFnAttr(Attribute::ReadNone
);
87 // Insert a FP compare instruction and use it as the CurrBB branch condition.
88 Builder
.SetInsertPoint(CurrBBTerm
);
89 Value
*FCmp
= TTI
->isFCmpOrdCheaperThanFCmpZero(Ty
)
90 ? Builder
.CreateFCmpORD(Call
, Call
)
91 : Builder
.CreateFCmpOGE(Call
->getOperand(0),
92 ConstantFP::get(Ty
, 0.0));
93 CurrBBTerm
->setCondition(FCmp
);
96 Phi
->addIncoming(Call
, &CurrBB
);
97 Phi
->addIncoming(LibCall
, LibCallBB
);
99 BB
= JoinBB
->getIterator();
103 static bool runPartiallyInlineLibCalls(Function
&F
, TargetLibraryInfo
*TLI
,
104 const TargetTransformInfo
*TTI
,
106 Optional
<DomTreeUpdater
> DTU
;
108 DTU
.emplace(DT
, DomTreeUpdater::UpdateStrategy::Lazy
);
110 bool Changed
= false;
112 Function::iterator CurrBB
;
113 for (Function::iterator BB
= F
.begin(), BE
= F
.end(); BB
!= BE
;) {
116 for (BasicBlock::iterator II
= CurrBB
->begin(), IE
= CurrBB
->end();
118 CallInst
*Call
= dyn_cast
<CallInst
>(&*II
);
119 Function
*CalledFunc
;
121 if (!Call
|| !(CalledFunc
= Call
->getCalledFunction()))
124 if (Call
->isNoBuiltin() || Call
->isStrictFP())
127 // Skip if function either has local linkage or is not a known library
130 if (CalledFunc
->hasLocalLinkage() ||
131 !TLI
->getLibFunc(*CalledFunc
, LF
) || !TLI
->has(LF
))
137 if (TTI
->haveFastSqrt(Call
->getType()) &&
138 optimizeSQRT(Call
, CalledFunc
, *CurrBB
, BB
, TTI
,
139 DTU
.hasValue() ? DTU
.getPointer() : nullptr))
155 PartiallyInlineLibCallsPass::run(Function
&F
, FunctionAnalysisManager
&AM
) {
156 auto &TLI
= AM
.getResult
<TargetLibraryAnalysis
>(F
);
157 auto &TTI
= AM
.getResult
<TargetIRAnalysis
>(F
);
158 auto *DT
= AM
.getCachedResult
<DominatorTreeAnalysis
>(F
);
159 if (!runPartiallyInlineLibCalls(F
, &TLI
, &TTI
, DT
))
160 return PreservedAnalyses::all();
161 PreservedAnalyses PA
;
162 PA
.preserve
<DominatorTreeAnalysis
>();
167 class PartiallyInlineLibCallsLegacyPass
: public FunctionPass
{
171 PartiallyInlineLibCallsLegacyPass() : FunctionPass(ID
) {
172 initializePartiallyInlineLibCallsLegacyPassPass(
173 *PassRegistry::getPassRegistry());
176 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
177 AU
.addRequired
<TargetLibraryInfoWrapperPass
>();
178 AU
.addRequired
<TargetTransformInfoWrapperPass
>();
179 AU
.addPreserved
<DominatorTreeWrapperPass
>();
180 FunctionPass::getAnalysisUsage(AU
);
183 bool runOnFunction(Function
&F
) override
{
187 TargetLibraryInfo
*TLI
=
188 &getAnalysis
<TargetLibraryInfoWrapperPass
>().getTLI(F
);
189 const TargetTransformInfo
*TTI
=
190 &getAnalysis
<TargetTransformInfoWrapperPass
>().getTTI(F
);
191 DominatorTree
*DT
= nullptr;
192 if (auto *DTWP
= getAnalysisIfAvailable
<DominatorTreeWrapperPass
>())
193 DT
= &DTWP
->getDomTree();
194 return runPartiallyInlineLibCalls(F
, TLI
, TTI
, DT
);
199 char PartiallyInlineLibCallsLegacyPass::ID
= 0;
200 INITIALIZE_PASS_BEGIN(PartiallyInlineLibCallsLegacyPass
,
201 "partially-inline-libcalls",
202 "Partially inline calls to library functions", false,
204 INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass
)
205 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass
)
206 INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass
)
207 INITIALIZE_PASS_END(PartiallyInlineLibCallsLegacyPass
,
208 "partially-inline-libcalls",
209 "Partially inline calls to library functions", false, false)
211 FunctionPass
*llvm::createPartiallyInlineLibCallsPass() {
212 return new PartiallyInlineLibCallsLegacyPass();