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