1 //===--- PartiallyInlineLibCalls.cpp - Partially inline libcalls ----------===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 // 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. 12 // 13 //===----------------------------------------------------------------------===// 14 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" 25 26 using namespace llvm; 27 28 #define DEBUG_TYPE "partially-inline-libcalls" 29 30 DEBUG_COUNTER(PILCounter, "partially-inline-libcalls-transform", 31 "Controls transformations in partially-inline-libcalls"); 32 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()) 39 return false; 40 41 if (!DebugCounter::shouldExecute(PILCounter)) 42 return false; 43 44 // Do the following transformation: 45 // 46 // (before) 47 // dst = sqrt(src) 48 // 49 // (after) 50 // v0 = sqrt_noreadmem(src) # native sqrt instruction. 51 // [if (v0 is a NaN) || if (src < 0)] 52 // v1 = sqrt(src) # library call. 53 // dst = phi(v0, v1) 54 // 55 56 Type *Ty = Call->getType(); 57 IRBuilder<> Builder(Call->getNextNode()); 58 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); 64 65 auto *CurrBBTerm = cast<BranchInst>(CurrBB.getTerminator()); 66 // We want an 'else' block though, not a 'then' block. 67 cast<BranchInst>(CurrBBTerm)->swapSuccessors(); 68 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); 75 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); 82 83 // Add attribute "readnone" so that backend can use a native sqrt instruction 84 // for this call. 85 Call->addAttribute(AttributeList::FunctionIndex, Attribute::ReadNone); 86 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); 94 95 // Add phi operands. 96 Phi->addIncoming(Call, &CurrBB); 97 Phi->addIncoming(LibCall, LibCallBB); 98 99 BB = JoinBB->getIterator(); 100 return true; 101 } 102 103 static bool runPartiallyInlineLibCalls(Function &F, TargetLibraryInfo *TLI, 104 const TargetTransformInfo *TTI, 105 DominatorTree *DT) { 106 Optional<DomTreeUpdater> DTU; 107 if (DT) 108 DTU.emplace(DT, DomTreeUpdater::UpdateStrategy::Lazy); 109 110 bool Changed = false; 111 112 Function::iterator CurrBB; 113 for (Function::iterator BB = F.begin(), BE = F.end(); BB != BE;) { 114 CurrBB = BB++; 115 116 for (BasicBlock::iterator II = CurrBB->begin(), IE = CurrBB->end(); 117 II != IE; ++II) { 118 CallInst *Call = dyn_cast<CallInst>(&*II); 119 Function *CalledFunc; 120 121 if (!Call || !(CalledFunc = Call->getCalledFunction())) 122 continue; 123 124 if (Call->isNoBuiltin() || Call->isStrictFP()) 125 continue; 126 127 // Skip if function either has local linkage or is not a known library 128 // function. 129 LibFunc LF; 130 if (CalledFunc->hasLocalLinkage() || 131 !TLI->getLibFunc(*CalledFunc, LF) || !TLI->has(LF)) 132 continue; 133 134 switch (LF) { 135 case LibFunc_sqrtf: 136 case LibFunc_sqrt: 137 if (TTI->haveFastSqrt(Call->getType()) && 138 optimizeSQRT(Call, CalledFunc, *CurrBB, BB, TTI, 139 DTU.hasValue() ? DTU.getPointer() : nullptr)) 140 break; 141 continue; 142 default: 143 continue; 144 } 145 146 Changed = true; 147 break; 148 } 149 } 150 151 return Changed; 152 } 153 154 PreservedAnalyses 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>(); 163 return PA; 164 } 165 166 namespace { 167 class PartiallyInlineLibCallsLegacyPass : public FunctionPass { 168 public: 169 static char ID; 170 171 PartiallyInlineLibCallsLegacyPass() : FunctionPass(ID) { 172 initializePartiallyInlineLibCallsLegacyPassPass( 173 *PassRegistry::getPassRegistry()); 174 } 175 176 void getAnalysisUsage(AnalysisUsage &AU) const override { 177 AU.addRequired<TargetLibraryInfoWrapperPass>(); 178 AU.addRequired<TargetTransformInfoWrapperPass>(); 179 AU.addPreserved<DominatorTreeWrapperPass>(); 180 FunctionPass::getAnalysisUsage(AU); 181 } 182 183 bool runOnFunction(Function &F) override { 184 if (skipFunction(F)) 185 return false; 186 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); 195 } 196 }; 197 } 198 199 char PartiallyInlineLibCallsLegacyPass::ID = 0; 200 INITIALIZE_PASS_BEGIN(PartiallyInlineLibCallsLegacyPass, 201 "partially-inline-libcalls", 202 "Partially inline calls to library functions", false, 203 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) 210 211 FunctionPass *llvm::createPartiallyInlineLibCallsPass() { 212 return new PartiallyInlineLibCallsLegacyPass(); 213 } 214