PartiallyInlineLibCalls.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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. #include "llvm/Transforms/Scalar/PartiallyInlineLibCalls.h"
  15. #include "llvm/Analysis/DomTreeUpdater.h"
  16. #include "llvm/Analysis/TargetLibraryInfo.h"
  17. #include "llvm/Analysis/TargetTransformInfo.h"
  18. #include "llvm/IR/Dominators.h"
  19. #include "llvm/IR/IRBuilder.h"
  20. #include "llvm/InitializePasses.h"
  21. #include "llvm/Support/DebugCounter.h"
  22. #include "llvm/Transforms/Scalar.h"
  23. #include "llvm/Transforms/Utils/BasicBlockUtils.h"
  24. using namespace llvm;
  25. #define DEBUG_TYPE "partially-inline-libcalls"
  26. DEBUG_COUNTER(PILCounter, "partially-inline-libcalls-transform",
  27. "Controls transformations in partially-inline-libcalls");
  28. static bool optimizeSQRT(CallInst *Call, Function *CalledFunc,
  29. BasicBlock &CurrBB, Function::iterator &BB,
  30. const TargetTransformInfo *TTI, DomTreeUpdater *DTU) {
  31. // There is no need to change the IR, since backend will emit sqrt
  32. // instruction if the call has already been marked read-only.
  33. if (Call->onlyReadsMemory())
  34. return false;
  35. if (!DebugCounter::shouldExecute(PILCounter))
  36. return false;
  37. // Do the following transformation:
  38. //
  39. // (before)
  40. // dst = sqrt(src)
  41. //
  42. // (after)
  43. // v0 = sqrt_noreadmem(src) # native sqrt instruction.
  44. // [if (v0 is a NaN) || if (src < 0)]
  45. // v1 = sqrt(src) # library call.
  46. // dst = phi(v0, v1)
  47. //
  48. Type *Ty = Call->getType();
  49. IRBuilder<> Builder(Call->getNextNode());
  50. // Split CurrBB right after the call, create a 'then' block (that branches
  51. // back to split-off tail of CurrBB) into which we'll insert a libcall.
  52. Instruction *LibCallTerm = SplitBlockAndInsertIfThen(
  53. Builder.getTrue(), Call->getNextNode(), /*Unreachable=*/false,
  54. /*BranchWeights*/ nullptr, DTU);
  55. auto *CurrBBTerm = cast<BranchInst>(CurrBB.getTerminator());
  56. // We want an 'else' block though, not a 'then' block.
  57. cast<BranchInst>(CurrBBTerm)->swapSuccessors();
  58. // Create phi that will merge results of either sqrt and replace all uses.
  59. BasicBlock *JoinBB = LibCallTerm->getSuccessor(0);
  60. JoinBB->setName(CurrBB.getName() + ".split");
  61. Builder.SetInsertPoint(JoinBB, JoinBB->begin());
  62. PHINode *Phi = Builder.CreatePHI(Ty, 2);
  63. Call->replaceAllUsesWith(Phi);
  64. // Finally, insert the libcall into 'else' block.
  65. BasicBlock *LibCallBB = LibCallTerm->getParent();
  66. LibCallBB->setName("call.sqrt");
  67. Builder.SetInsertPoint(LibCallTerm);
  68. Instruction *LibCall = Call->clone();
  69. Builder.Insert(LibCall);
  70. // Add attribute "readnone" so that backend can use a native sqrt instruction
  71. // for this call.
  72. Call->removeFnAttr(Attribute::WriteOnly);
  73. Call->addFnAttr(Attribute::ReadNone);
  74. // Insert a FP compare instruction and use it as the CurrBB branch condition.
  75. Builder.SetInsertPoint(CurrBBTerm);
  76. Value *FCmp = TTI->isFCmpOrdCheaperThanFCmpZero(Ty)
  77. ? Builder.CreateFCmpORD(Call, Call)
  78. : Builder.CreateFCmpOGE(Call->getOperand(0),
  79. ConstantFP::get(Ty, 0.0));
  80. CurrBBTerm->setCondition(FCmp);
  81. // Add phi operands.
  82. Phi->addIncoming(Call, &CurrBB);
  83. Phi->addIncoming(LibCall, LibCallBB);
  84. BB = JoinBB->getIterator();
  85. return true;
  86. }
  87. static bool runPartiallyInlineLibCalls(Function &F, TargetLibraryInfo *TLI,
  88. const TargetTransformInfo *TTI,
  89. DominatorTree *DT) {
  90. Optional<DomTreeUpdater> DTU;
  91. if (DT)
  92. DTU.emplace(DT, DomTreeUpdater::UpdateStrategy::Lazy);
  93. bool Changed = false;
  94. Function::iterator CurrBB;
  95. for (Function::iterator BB = F.begin(), BE = F.end(); BB != BE;) {
  96. CurrBB = BB++;
  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. if (!Call || !(CalledFunc = Call->getCalledFunction()))
  102. continue;
  103. if (Call->isNoBuiltin() || Call->isStrictFP())
  104. continue;
  105. // Skip if function either has local linkage or is not a known library
  106. // function.
  107. LibFunc LF;
  108. if (CalledFunc->hasLocalLinkage() ||
  109. !TLI->getLibFunc(*CalledFunc, LF) || !TLI->has(LF))
  110. continue;
  111. switch (LF) {
  112. case LibFunc_sqrtf:
  113. case LibFunc_sqrt:
  114. if (TTI->haveFastSqrt(Call->getType()) &&
  115. optimizeSQRT(Call, CalledFunc, *CurrBB, BB, TTI,
  116. DTU.hasValue() ? DTU.getPointer() : nullptr))
  117. break;
  118. continue;
  119. default:
  120. continue;
  121. }
  122. Changed = true;
  123. break;
  124. }
  125. }
  126. return Changed;
  127. }
  128. PreservedAnalyses
  129. PartiallyInlineLibCallsPass::run(Function &F, FunctionAnalysisManager &AM) {
  130. auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
  131. auto &TTI = AM.getResult<TargetIRAnalysis>(F);
  132. auto *DT = AM.getCachedResult<DominatorTreeAnalysis>(F);
  133. if (!runPartiallyInlineLibCalls(F, &TLI, &TTI, DT))
  134. return PreservedAnalyses::all();
  135. PreservedAnalyses PA;
  136. PA.preserve<DominatorTreeAnalysis>();
  137. return PA;
  138. }
  139. namespace {
  140. class PartiallyInlineLibCallsLegacyPass : public FunctionPass {
  141. public:
  142. static char ID;
  143. PartiallyInlineLibCallsLegacyPass() : FunctionPass(ID) {
  144. initializePartiallyInlineLibCallsLegacyPassPass(
  145. *PassRegistry::getPassRegistry());
  146. }
  147. void getAnalysisUsage(AnalysisUsage &AU) const override {
  148. AU.addRequired<TargetLibraryInfoWrapperPass>();
  149. AU.addRequired<TargetTransformInfoWrapperPass>();
  150. AU.addPreserved<DominatorTreeWrapperPass>();
  151. FunctionPass::getAnalysisUsage(AU);
  152. }
  153. bool runOnFunction(Function &F) override {
  154. if (skipFunction(F))
  155. return false;
  156. TargetLibraryInfo *TLI =
  157. &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
  158. const TargetTransformInfo *TTI =
  159. &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
  160. DominatorTree *DT = nullptr;
  161. if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
  162. DT = &DTWP->getDomTree();
  163. return runPartiallyInlineLibCalls(F, TLI, TTI, DT);
  164. }
  165. };
  166. }
  167. char PartiallyInlineLibCallsLegacyPass::ID = 0;
  168. INITIALIZE_PASS_BEGIN(PartiallyInlineLibCallsLegacyPass,
  169. "partially-inline-libcalls",
  170. "Partially inline calls to library functions", false,
  171. false)
  172. INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
  173. INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
  174. INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
  175. INITIALIZE_PASS_END(PartiallyInlineLibCallsLegacyPass,
  176. "partially-inline-libcalls",
  177. "Partially inline calls to library functions", false, false)
  178. FunctionPass *llvm::createPartiallyInlineLibCallsPass() {
  179. return new PartiallyInlineLibCallsLegacyPass();
  180. }