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