1 //===--- PartiallyInlineLibCalls.cpp - Partially inline libcalls ----------===// 2 // 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 // 10 // 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. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "llvm/Transforms/Scalar/PartiallyInlineLibCalls.h" 17 #include "llvm/Analysis/TargetLibraryInfo.h" 18 #include "llvm/Analysis/TargetTransformInfo.h" 19 #include "llvm/IR/IRBuilder.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 28 static bool optimizeSQRT(CallInst *Call, Function *CalledFunc, 29 BasicBlock &CurrBB, Function::iterator &BB) { 30 // 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 35 // The call must have the expected result type. 36 if (!Call->getType()->isFloatingPointTy()) 37 return false; 38 39 // 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. 53 BasicBlock *JoinBB = llvm::SplitBlock(&CurrBB, Call->getNextNode()); 54 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 79 BB = JoinBB->getIterator(); 80 return true; 81 } 82 83 static bool runPartiallyInlineLibCalls(Function &F, TargetLibraryInfo *TLI, 84 const TargetTransformInfo *TTI) { 85 bool Changed = false; 86 87 Function::iterator CurrBB; 88 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. 101 LibFunc::Func LibFunc; 102 if (CalledFunc->hasLocalLinkage() || !CalledFunc->hasName() || 103 !TLI->getLibFunc(CalledFunc->getName(), LibFunc)) 104 continue; 105 106 switch (LibFunc) { 107 case LibFunc::sqrtf: 108 case LibFunc::sqrt: 109 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 125 PreservedAnalyses 126 PartiallyInlineLibCallsPass::run(Function &F, AnalysisManager<Function> &AM) { 127 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 134 namespace { 135 class PartiallyInlineLibCallsLegacyPass : public FunctionPass { 136 public: 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 163 char PartiallyInlineLibCallsLegacyPass::ID = 0; 164 INITIALIZE_PASS_BEGIN(PartiallyInlineLibCallsLegacyPass, 165 "partially-inline-libcalls", 166 "Partially inline calls to library functions", false, 167 false) 168 INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) 169 INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) 170 INITIALIZE_PASS_END(PartiallyInlineLibCallsLegacyPass, 171 "partially-inline-libcalls", 172 "Partially inline calls to library functions", false, false) 173 174 FunctionPass *llvm::createPartiallyInlineLibCallsPass() { 175 return new PartiallyInlineLibCallsLegacyPass(); 176 } 177