xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/Utils/LibCallsShrinkWrap.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- LibCallsShrinkWrap.cpp ----------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This pass shrink-wraps a call to function if the result is not used.
100b57cec5SDimitry Andric // The call can set errno but is otherwise side effect free. For example:
110b57cec5SDimitry Andric //    sqrt(val);
120b57cec5SDimitry Andric //  is transformed to
130b57cec5SDimitry Andric //    if (val < 0)
140b57cec5SDimitry Andric //      sqrt(val);
150b57cec5SDimitry Andric //  Even if the result of library call is not being used, the compiler cannot
160b57cec5SDimitry Andric //  safely delete the call because the function can set errno on error
170b57cec5SDimitry Andric //  conditions.
180b57cec5SDimitry Andric //  Note in many functions, the error condition solely depends on the incoming
190b57cec5SDimitry Andric //  parameter. In this optimization, we can generate the condition can lead to
200b57cec5SDimitry Andric //  the errno to shrink-wrap the call. Since the chances of hitting the error
210b57cec5SDimitry Andric //  condition is low, the runtime call is effectively eliminated.
220b57cec5SDimitry Andric //
230b57cec5SDimitry Andric //  These partially dead calls are usually results of C++ abstraction penalty
240b57cec5SDimitry Andric //  exposed by inlining.
250b57cec5SDimitry Andric //
260b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric #include "llvm/Transforms/Utils/LibCallsShrinkWrap.h"
290b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
300b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
3106c3fb27SDimitry Andric #include "llvm/Analysis/DomTreeUpdater.h"
320b57cec5SDimitry Andric #include "llvm/Analysis/GlobalsModRef.h"
330b57cec5SDimitry Andric #include "llvm/Analysis/TargetLibraryInfo.h"
340b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
350b57cec5SDimitry Andric #include "llvm/IR/Dominators.h"
360b57cec5SDimitry Andric #include "llvm/IR/Function.h"
370b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h"
380b57cec5SDimitry Andric #include "llvm/IR/InstVisitor.h"
390b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
400b57cec5SDimitry Andric #include "llvm/IR/MDBuilder.h"
410b57cec5SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h"
42bdd1243dSDimitry Andric 
43bdd1243dSDimitry Andric #include <cmath>
44bdd1243dSDimitry Andric 
450b57cec5SDimitry Andric using namespace llvm;
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric #define DEBUG_TYPE "libcalls-shrinkwrap"
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric STATISTIC(NumWrappedOneCond, "Number of One-Condition Wrappers Inserted");
500b57cec5SDimitry Andric STATISTIC(NumWrappedTwoCond, "Number of Two-Condition Wrappers Inserted");
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric namespace {
530b57cec5SDimitry Andric class LibCallsShrinkWrap : public InstVisitor<LibCallsShrinkWrap> {
540b57cec5SDimitry Andric public:
5506c3fb27SDimitry Andric   LibCallsShrinkWrap(const TargetLibraryInfo &TLI, DomTreeUpdater &DTU)
5606c3fb27SDimitry Andric       : TLI(TLI), DTU(DTU){};
570b57cec5SDimitry Andric   void visitCallInst(CallInst &CI) { checkCandidate(CI); }
580b57cec5SDimitry Andric   bool perform() {
590b57cec5SDimitry Andric     bool Changed = false;
600b57cec5SDimitry Andric     for (auto &CI : WorkList) {
610b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "CDCE calls: " << CI->getCalledFunction()->getName()
620b57cec5SDimitry Andric                         << "\n");
630b57cec5SDimitry Andric       if (perform(CI)) {
640b57cec5SDimitry Andric         Changed = true;
650b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "Transformed\n");
660b57cec5SDimitry Andric       }
670b57cec5SDimitry Andric     }
680b57cec5SDimitry Andric     return Changed;
690b57cec5SDimitry Andric   }
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric private:
720b57cec5SDimitry Andric   bool perform(CallInst *CI);
730b57cec5SDimitry Andric   void checkCandidate(CallInst &CI);
740b57cec5SDimitry Andric   void shrinkWrapCI(CallInst *CI, Value *Cond);
750b57cec5SDimitry Andric   bool performCallDomainErrorOnly(CallInst *CI, const LibFunc &Func);
760b57cec5SDimitry Andric   bool performCallErrors(CallInst *CI, const LibFunc &Func);
770b57cec5SDimitry Andric   bool performCallRangeErrorOnly(CallInst *CI, const LibFunc &Func);
780b57cec5SDimitry Andric   Value *generateOneRangeCond(CallInst *CI, const LibFunc &Func);
790b57cec5SDimitry Andric   Value *generateTwoRangeCond(CallInst *CI, const LibFunc &Func);
800b57cec5SDimitry Andric   Value *generateCondForPow(CallInst *CI, const LibFunc &Func);
810b57cec5SDimitry Andric 
8206c3fb27SDimitry Andric   // Create an OR of two conditions with given Arg and Arg2.
8306c3fb27SDimitry Andric   Value *createOrCond(CallInst *CI, Value *Arg, CmpInst::Predicate Cmp,
8406c3fb27SDimitry Andric                       float Val, Value *Arg2, CmpInst::Predicate Cmp2,
8506c3fb27SDimitry Andric                       float Val2) {
8606c3fb27SDimitry Andric     IRBuilder<> BBBuilder(CI);
8706c3fb27SDimitry Andric     auto Cond2 = createCond(BBBuilder, Arg2, Cmp2, Val2);
8806c3fb27SDimitry Andric     auto Cond1 = createCond(BBBuilder, Arg, Cmp, Val);
8906c3fb27SDimitry Andric     return BBBuilder.CreateOr(Cond1, Cond2);
9006c3fb27SDimitry Andric   }
9106c3fb27SDimitry Andric 
920b57cec5SDimitry Andric   // Create an OR of two conditions.
930b57cec5SDimitry Andric   Value *createOrCond(CallInst *CI, CmpInst::Predicate Cmp, float Val,
940b57cec5SDimitry Andric                       CmpInst::Predicate Cmp2, float Val2) {
950b57cec5SDimitry Andric     Value *Arg = CI->getArgOperand(0);
9606c3fb27SDimitry Andric     return createOrCond(CI, Arg, Cmp, Val, Arg, Cmp2, Val2);
970b57cec5SDimitry Andric   }
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric   // Create a single condition using IRBuilder.
1000b57cec5SDimitry Andric   Value *createCond(IRBuilder<> &BBBuilder, Value *Arg, CmpInst::Predicate Cmp,
1010b57cec5SDimitry Andric                     float Val) {
1020b57cec5SDimitry Andric     Constant *V = ConstantFP::get(BBBuilder.getContext(), APFloat(Val));
1030b57cec5SDimitry Andric     if (!Arg->getType()->isFloatTy())
1045f757f3fSDimitry Andric       V = ConstantFoldCastInstruction(Instruction::FPExt, V, Arg->getType());
10506c3fb27SDimitry Andric     if (BBBuilder.GetInsertBlock()->getParent()->hasFnAttribute(Attribute::StrictFP))
10606c3fb27SDimitry Andric       BBBuilder.setIsFPConstrained(true);
1070b57cec5SDimitry Andric     return BBBuilder.CreateFCmp(Cmp, Arg, V);
1080b57cec5SDimitry Andric   }
1090b57cec5SDimitry Andric 
11006c3fb27SDimitry Andric   // Create a single condition with given Arg.
11106c3fb27SDimitry Andric   Value *createCond(CallInst *CI, Value *Arg, CmpInst::Predicate Cmp,
11206c3fb27SDimitry Andric                     float Val) {
11306c3fb27SDimitry Andric     IRBuilder<> BBBuilder(CI);
11406c3fb27SDimitry Andric     return createCond(BBBuilder, Arg, Cmp, Val);
11506c3fb27SDimitry Andric   }
11606c3fb27SDimitry Andric 
1170b57cec5SDimitry Andric   // Create a single condition.
1180b57cec5SDimitry Andric   Value *createCond(CallInst *CI, CmpInst::Predicate Cmp, float Val) {
1190b57cec5SDimitry Andric     Value *Arg = CI->getArgOperand(0);
12006c3fb27SDimitry Andric     return createCond(CI, Arg, Cmp, Val);
1210b57cec5SDimitry Andric   }
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   const TargetLibraryInfo &TLI;
12406c3fb27SDimitry Andric   DomTreeUpdater &DTU;
1250b57cec5SDimitry Andric   SmallVector<CallInst *, 16> WorkList;
1260b57cec5SDimitry Andric };
1270b57cec5SDimitry Andric } // end anonymous namespace
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric // Perform the transformation to calls with errno set by domain error.
1300b57cec5SDimitry Andric bool LibCallsShrinkWrap::performCallDomainErrorOnly(CallInst *CI,
1310b57cec5SDimitry Andric                                                     const LibFunc &Func) {
1320b57cec5SDimitry Andric   Value *Cond = nullptr;
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric   switch (Func) {
1350b57cec5SDimitry Andric   case LibFunc_acos:  // DomainError: (x < -1 || x > 1)
1360b57cec5SDimitry Andric   case LibFunc_acosf: // Same as acos
1370b57cec5SDimitry Andric   case LibFunc_acosl: // Same as acos
1380b57cec5SDimitry Andric   case LibFunc_asin:  // DomainError: (x < -1 || x > 1)
1390b57cec5SDimitry Andric   case LibFunc_asinf: // Same as asin
1400b57cec5SDimitry Andric   case LibFunc_asinl: // Same as asin
1410b57cec5SDimitry Andric   {
1420b57cec5SDimitry Andric     ++NumWrappedTwoCond;
1430b57cec5SDimitry Andric     Cond = createOrCond(CI, CmpInst::FCMP_OLT, -1.0f, CmpInst::FCMP_OGT, 1.0f);
1440b57cec5SDimitry Andric     break;
1450b57cec5SDimitry Andric   }
1460b57cec5SDimitry Andric   case LibFunc_cos:  // DomainError: (x == +inf || x == -inf)
1470b57cec5SDimitry Andric   case LibFunc_cosf: // Same as cos
1480b57cec5SDimitry Andric   case LibFunc_cosl: // Same as cos
1490b57cec5SDimitry Andric   case LibFunc_sin:  // DomainError: (x == +inf || x == -inf)
1500b57cec5SDimitry Andric   case LibFunc_sinf: // Same as sin
1510b57cec5SDimitry Andric   case LibFunc_sinl: // Same as sin
1520b57cec5SDimitry Andric   {
1530b57cec5SDimitry Andric     ++NumWrappedTwoCond;
1540b57cec5SDimitry Andric     Cond = createOrCond(CI, CmpInst::FCMP_OEQ, INFINITY, CmpInst::FCMP_OEQ,
1550b57cec5SDimitry Andric                         -INFINITY);
1560b57cec5SDimitry Andric     break;
1570b57cec5SDimitry Andric   }
1580b57cec5SDimitry Andric   case LibFunc_acosh:  // DomainError: (x < 1)
1590b57cec5SDimitry Andric   case LibFunc_acoshf: // Same as acosh
1600b57cec5SDimitry Andric   case LibFunc_acoshl: // Same as acosh
1610b57cec5SDimitry Andric   {
1620b57cec5SDimitry Andric     ++NumWrappedOneCond;
1630b57cec5SDimitry Andric     Cond = createCond(CI, CmpInst::FCMP_OLT, 1.0f);
1640b57cec5SDimitry Andric     break;
1650b57cec5SDimitry Andric   }
1660b57cec5SDimitry Andric   case LibFunc_sqrt:  // DomainError: (x < 0)
1670b57cec5SDimitry Andric   case LibFunc_sqrtf: // Same as sqrt
1680b57cec5SDimitry Andric   case LibFunc_sqrtl: // Same as sqrt
1690b57cec5SDimitry Andric   {
1700b57cec5SDimitry Andric     ++NumWrappedOneCond;
1710b57cec5SDimitry Andric     Cond = createCond(CI, CmpInst::FCMP_OLT, 0.0f);
1720b57cec5SDimitry Andric     break;
1730b57cec5SDimitry Andric   }
1740b57cec5SDimitry Andric   default:
1750b57cec5SDimitry Andric     return false;
1760b57cec5SDimitry Andric   }
1770b57cec5SDimitry Andric   shrinkWrapCI(CI, Cond);
1780b57cec5SDimitry Andric   return true;
1790b57cec5SDimitry Andric }
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric // Perform the transformation to calls with errno set by range error.
1820b57cec5SDimitry Andric bool LibCallsShrinkWrap::performCallRangeErrorOnly(CallInst *CI,
1830b57cec5SDimitry Andric                                                    const LibFunc &Func) {
1840b57cec5SDimitry Andric   Value *Cond = nullptr;
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric   switch (Func) {
1870b57cec5SDimitry Andric   case LibFunc_cosh:
1880b57cec5SDimitry Andric   case LibFunc_coshf:
1890b57cec5SDimitry Andric   case LibFunc_coshl:
1900b57cec5SDimitry Andric   case LibFunc_exp:
1910b57cec5SDimitry Andric   case LibFunc_expf:
1920b57cec5SDimitry Andric   case LibFunc_expl:
1930b57cec5SDimitry Andric   case LibFunc_exp10:
1940b57cec5SDimitry Andric   case LibFunc_exp10f:
1950b57cec5SDimitry Andric   case LibFunc_exp10l:
1960b57cec5SDimitry Andric   case LibFunc_exp2:
1970b57cec5SDimitry Andric   case LibFunc_exp2f:
1980b57cec5SDimitry Andric   case LibFunc_exp2l:
1990b57cec5SDimitry Andric   case LibFunc_sinh:
2000b57cec5SDimitry Andric   case LibFunc_sinhf:
2010b57cec5SDimitry Andric   case LibFunc_sinhl: {
2020b57cec5SDimitry Andric     Cond = generateTwoRangeCond(CI, Func);
2030b57cec5SDimitry Andric     break;
2040b57cec5SDimitry Andric   }
2050b57cec5SDimitry Andric   case LibFunc_expm1:  // RangeError: (709, inf)
2060b57cec5SDimitry Andric   case LibFunc_expm1f: // RangeError: (88, inf)
2070b57cec5SDimitry Andric   case LibFunc_expm1l: // RangeError: (11356, inf)
2080b57cec5SDimitry Andric   {
2090b57cec5SDimitry Andric     Cond = generateOneRangeCond(CI, Func);
2100b57cec5SDimitry Andric     break;
2110b57cec5SDimitry Andric   }
2120b57cec5SDimitry Andric   default:
2130b57cec5SDimitry Andric     return false;
2140b57cec5SDimitry Andric   }
2150b57cec5SDimitry Andric   shrinkWrapCI(CI, Cond);
2160b57cec5SDimitry Andric   return true;
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric // Perform the transformation to calls with errno set by combination of errors.
2200b57cec5SDimitry Andric bool LibCallsShrinkWrap::performCallErrors(CallInst *CI,
2210b57cec5SDimitry Andric                                            const LibFunc &Func) {
2220b57cec5SDimitry Andric   Value *Cond = nullptr;
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric   switch (Func) {
2250b57cec5SDimitry Andric   case LibFunc_atanh:  // DomainError: (x < -1 || x > 1)
2260b57cec5SDimitry Andric                         // PoleError:   (x == -1 || x == 1)
2270b57cec5SDimitry Andric                         // Overall Cond: (x <= -1 || x >= 1)
2280b57cec5SDimitry Andric   case LibFunc_atanhf: // Same as atanh
2290b57cec5SDimitry Andric   case LibFunc_atanhl: // Same as atanh
2300b57cec5SDimitry Andric   {
2310b57cec5SDimitry Andric     ++NumWrappedTwoCond;
2320b57cec5SDimitry Andric     Cond = createOrCond(CI, CmpInst::FCMP_OLE, -1.0f, CmpInst::FCMP_OGE, 1.0f);
2330b57cec5SDimitry Andric     break;
2340b57cec5SDimitry Andric   }
2350b57cec5SDimitry Andric   case LibFunc_log:    // DomainError: (x < 0)
2360b57cec5SDimitry Andric                         // PoleError:   (x == 0)
2370b57cec5SDimitry Andric                         // Overall Cond: (x <= 0)
2380b57cec5SDimitry Andric   case LibFunc_logf:   // Same as log
2390b57cec5SDimitry Andric   case LibFunc_logl:   // Same as log
2400b57cec5SDimitry Andric   case LibFunc_log10:  // Same as log
2410b57cec5SDimitry Andric   case LibFunc_log10f: // Same as log
2420b57cec5SDimitry Andric   case LibFunc_log10l: // Same as log
2430b57cec5SDimitry Andric   case LibFunc_log2:   // Same as log
2440b57cec5SDimitry Andric   case LibFunc_log2f:  // Same as log
2450b57cec5SDimitry Andric   case LibFunc_log2l:  // Same as log
2460b57cec5SDimitry Andric   case LibFunc_logb:   // Same as log
2470b57cec5SDimitry Andric   case LibFunc_logbf:  // Same as log
2480b57cec5SDimitry Andric   case LibFunc_logbl:  // Same as log
2490b57cec5SDimitry Andric   {
2500b57cec5SDimitry Andric     ++NumWrappedOneCond;
2510b57cec5SDimitry Andric     Cond = createCond(CI, CmpInst::FCMP_OLE, 0.0f);
2520b57cec5SDimitry Andric     break;
2530b57cec5SDimitry Andric   }
2540b57cec5SDimitry Andric   case LibFunc_log1p:  // DomainError: (x < -1)
2550b57cec5SDimitry Andric                         // PoleError:   (x == -1)
2560b57cec5SDimitry Andric                         // Overall Cond: (x <= -1)
2570b57cec5SDimitry Andric   case LibFunc_log1pf: // Same as log1p
2580b57cec5SDimitry Andric   case LibFunc_log1pl: // Same as log1p
2590b57cec5SDimitry Andric   {
2600b57cec5SDimitry Andric     ++NumWrappedOneCond;
2610b57cec5SDimitry Andric     Cond = createCond(CI, CmpInst::FCMP_OLE, -1.0f);
2620b57cec5SDimitry Andric     break;
2630b57cec5SDimitry Andric   }
2640b57cec5SDimitry Andric   case LibFunc_pow: // DomainError: x < 0 and y is noninteger
2650b57cec5SDimitry Andric                      // PoleError:   x == 0 and y < 0
2660b57cec5SDimitry Andric                      // RangeError:  overflow or underflow
2670b57cec5SDimitry Andric   case LibFunc_powf:
2680b57cec5SDimitry Andric   case LibFunc_powl: {
2690b57cec5SDimitry Andric     Cond = generateCondForPow(CI, Func);
2700b57cec5SDimitry Andric     if (Cond == nullptr)
2710b57cec5SDimitry Andric       return false;
2720b57cec5SDimitry Andric     break;
2730b57cec5SDimitry Andric   }
2740b57cec5SDimitry Andric   default:
2750b57cec5SDimitry Andric     return false;
2760b57cec5SDimitry Andric   }
2770b57cec5SDimitry Andric   assert(Cond && "performCallErrors should not see an empty condition");
2780b57cec5SDimitry Andric   shrinkWrapCI(CI, Cond);
2790b57cec5SDimitry Andric   return true;
2800b57cec5SDimitry Andric }
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric // Checks if CI is a candidate for shrinkwrapping and put it into work list if
2830b57cec5SDimitry Andric // true.
2840b57cec5SDimitry Andric void LibCallsShrinkWrap::checkCandidate(CallInst &CI) {
2850b57cec5SDimitry Andric   if (CI.isNoBuiltin())
2860b57cec5SDimitry Andric     return;
2870b57cec5SDimitry Andric   // A possible improvement is to handle the calls with the return value being
2880b57cec5SDimitry Andric   // used. If there is API for fast libcall implementation without setting
2890b57cec5SDimitry Andric   // errno, we can use the same framework to direct/wrap the call to the fast
2900b57cec5SDimitry Andric   // API in the error free path, and leave the original call in the slow path.
2910b57cec5SDimitry Andric   if (!CI.use_empty())
2920b57cec5SDimitry Andric     return;
2930b57cec5SDimitry Andric 
2940b57cec5SDimitry Andric   LibFunc Func;
2950b57cec5SDimitry Andric   Function *Callee = CI.getCalledFunction();
2960b57cec5SDimitry Andric   if (!Callee)
2970b57cec5SDimitry Andric     return;
2980b57cec5SDimitry Andric   if (!TLI.getLibFunc(*Callee, Func) || !TLI.has(Func))
2990b57cec5SDimitry Andric     return;
3000b57cec5SDimitry Andric 
301349cc55cSDimitry Andric   if (CI.arg_empty())
3020b57cec5SDimitry Andric     return;
3030b57cec5SDimitry Andric   // TODO: Handle long double in other formats.
3040b57cec5SDimitry Andric   Type *ArgType = CI.getArgOperand(0)->getType();
3050b57cec5SDimitry Andric   if (!(ArgType->isFloatTy() || ArgType->isDoubleTy() ||
3060b57cec5SDimitry Andric         ArgType->isX86_FP80Ty()))
3070b57cec5SDimitry Andric     return;
3080b57cec5SDimitry Andric 
3090b57cec5SDimitry Andric   WorkList.push_back(&CI);
3100b57cec5SDimitry Andric }
3110b57cec5SDimitry Andric 
3120b57cec5SDimitry Andric // Generate the upper bound condition for RangeError.
3130b57cec5SDimitry Andric Value *LibCallsShrinkWrap::generateOneRangeCond(CallInst *CI,
3140b57cec5SDimitry Andric                                                 const LibFunc &Func) {
3150b57cec5SDimitry Andric   float UpperBound;
3160b57cec5SDimitry Andric   switch (Func) {
3170b57cec5SDimitry Andric   case LibFunc_expm1: // RangeError: (709, inf)
3180b57cec5SDimitry Andric     UpperBound = 709.0f;
3190b57cec5SDimitry Andric     break;
3200b57cec5SDimitry Andric   case LibFunc_expm1f: // RangeError: (88, inf)
3210b57cec5SDimitry Andric     UpperBound = 88.0f;
3220b57cec5SDimitry Andric     break;
3230b57cec5SDimitry Andric   case LibFunc_expm1l: // RangeError: (11356, inf)
3240b57cec5SDimitry Andric     UpperBound = 11356.0f;
3250b57cec5SDimitry Andric     break;
3260b57cec5SDimitry Andric   default:
3270b57cec5SDimitry Andric     llvm_unreachable("Unhandled library call!");
3280b57cec5SDimitry Andric   }
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric   ++NumWrappedOneCond;
3310b57cec5SDimitry Andric   return createCond(CI, CmpInst::FCMP_OGT, UpperBound);
3320b57cec5SDimitry Andric }
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric // Generate the lower and upper bound condition for RangeError.
3350b57cec5SDimitry Andric Value *LibCallsShrinkWrap::generateTwoRangeCond(CallInst *CI,
3360b57cec5SDimitry Andric                                                 const LibFunc &Func) {
3370b57cec5SDimitry Andric   float UpperBound, LowerBound;
3380b57cec5SDimitry Andric   switch (Func) {
3390b57cec5SDimitry Andric   case LibFunc_cosh: // RangeError: (x < -710 || x > 710)
3400b57cec5SDimitry Andric   case LibFunc_sinh: // Same as cosh
3410b57cec5SDimitry Andric     LowerBound = -710.0f;
3420b57cec5SDimitry Andric     UpperBound = 710.0f;
3430b57cec5SDimitry Andric     break;
3440b57cec5SDimitry Andric   case LibFunc_coshf: // RangeError: (x < -89 || x > 89)
3450b57cec5SDimitry Andric   case LibFunc_sinhf: // Same as coshf
3460b57cec5SDimitry Andric     LowerBound = -89.0f;
3470b57cec5SDimitry Andric     UpperBound = 89.0f;
3480b57cec5SDimitry Andric     break;
3490b57cec5SDimitry Andric   case LibFunc_coshl: // RangeError: (x < -11357 || x > 11357)
3500b57cec5SDimitry Andric   case LibFunc_sinhl: // Same as coshl
3510b57cec5SDimitry Andric     LowerBound = -11357.0f;
3520b57cec5SDimitry Andric     UpperBound = 11357.0f;
3530b57cec5SDimitry Andric     break;
3540b57cec5SDimitry Andric   case LibFunc_exp: // RangeError: (x < -745 || x > 709)
3550b57cec5SDimitry Andric     LowerBound = -745.0f;
3560b57cec5SDimitry Andric     UpperBound = 709.0f;
3570b57cec5SDimitry Andric     break;
3580b57cec5SDimitry Andric   case LibFunc_expf: // RangeError: (x < -103 || x > 88)
3590b57cec5SDimitry Andric     LowerBound = -103.0f;
3600b57cec5SDimitry Andric     UpperBound = 88.0f;
3610b57cec5SDimitry Andric     break;
3620b57cec5SDimitry Andric   case LibFunc_expl: // RangeError: (x < -11399 || x > 11356)
3630b57cec5SDimitry Andric     LowerBound = -11399.0f;
3640b57cec5SDimitry Andric     UpperBound = 11356.0f;
3650b57cec5SDimitry Andric     break;
3660b57cec5SDimitry Andric   case LibFunc_exp10: // RangeError: (x < -323 || x > 308)
3670b57cec5SDimitry Andric     LowerBound = -323.0f;
3680b57cec5SDimitry Andric     UpperBound = 308.0f;
3690b57cec5SDimitry Andric     break;
3700b57cec5SDimitry Andric   case LibFunc_exp10f: // RangeError: (x < -45 || x > 38)
3710b57cec5SDimitry Andric     LowerBound = -45.0f;
3720b57cec5SDimitry Andric     UpperBound = 38.0f;
3730b57cec5SDimitry Andric     break;
3740b57cec5SDimitry Andric   case LibFunc_exp10l: // RangeError: (x < -4950 || x > 4932)
3750b57cec5SDimitry Andric     LowerBound = -4950.0f;
3760b57cec5SDimitry Andric     UpperBound = 4932.0f;
3770b57cec5SDimitry Andric     break;
3780b57cec5SDimitry Andric   case LibFunc_exp2: // RangeError: (x < -1074 || x > 1023)
3790b57cec5SDimitry Andric     LowerBound = -1074.0f;
3800b57cec5SDimitry Andric     UpperBound = 1023.0f;
3810b57cec5SDimitry Andric     break;
3820b57cec5SDimitry Andric   case LibFunc_exp2f: // RangeError: (x < -149 || x > 127)
3830b57cec5SDimitry Andric     LowerBound = -149.0f;
3840b57cec5SDimitry Andric     UpperBound = 127.0f;
3850b57cec5SDimitry Andric     break;
3860b57cec5SDimitry Andric   case LibFunc_exp2l: // RangeError: (x < -16445 || x > 11383)
3870b57cec5SDimitry Andric     LowerBound = -16445.0f;
3880b57cec5SDimitry Andric     UpperBound = 11383.0f;
3890b57cec5SDimitry Andric     break;
3900b57cec5SDimitry Andric   default:
3910b57cec5SDimitry Andric     llvm_unreachable("Unhandled library call!");
3920b57cec5SDimitry Andric   }
3930b57cec5SDimitry Andric 
3940b57cec5SDimitry Andric   ++NumWrappedTwoCond;
3950b57cec5SDimitry Andric   return createOrCond(CI, CmpInst::FCMP_OGT, UpperBound, CmpInst::FCMP_OLT,
3960b57cec5SDimitry Andric                       LowerBound);
3970b57cec5SDimitry Andric }
3980b57cec5SDimitry Andric 
3990b57cec5SDimitry Andric // For pow(x,y), We only handle the following cases:
4000b57cec5SDimitry Andric // (1) x is a constant && (x >= 1) && (x < MaxUInt8)
4010b57cec5SDimitry Andric //     Cond is: (y > 127)
4020b57cec5SDimitry Andric // (2) x is a value coming from an integer type.
4030b57cec5SDimitry Andric //   (2.1) if x's bit_size == 8
4040b57cec5SDimitry Andric //         Cond: (x <= 0 || y > 128)
4050b57cec5SDimitry Andric //   (2.2) if x's bit_size is 16
4060b57cec5SDimitry Andric //         Cond: (x <= 0 || y > 64)
4070b57cec5SDimitry Andric //   (2.3) if x's bit_size is 32
4080b57cec5SDimitry Andric //         Cond: (x <= 0 || y > 32)
4090b57cec5SDimitry Andric // Support for powl(x,y) and powf(x,y) are TBD.
4100b57cec5SDimitry Andric //
4110b57cec5SDimitry Andric // Note that condition can be more conservative than the actual condition
4120b57cec5SDimitry Andric // (i.e. we might invoke the calls that will not set the errno.).
4130b57cec5SDimitry Andric //
4140b57cec5SDimitry Andric Value *LibCallsShrinkWrap::generateCondForPow(CallInst *CI,
4150b57cec5SDimitry Andric                                               const LibFunc &Func) {
4160b57cec5SDimitry Andric   // FIXME: LibFunc_powf and powl TBD.
4170b57cec5SDimitry Andric   if (Func != LibFunc_pow) {
4180b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Not handled powf() and powl()\n");
4190b57cec5SDimitry Andric     return nullptr;
4200b57cec5SDimitry Andric   }
4210b57cec5SDimitry Andric 
4220b57cec5SDimitry Andric   Value *Base = CI->getArgOperand(0);
4230b57cec5SDimitry Andric   Value *Exp = CI->getArgOperand(1);
4240b57cec5SDimitry Andric 
4250b57cec5SDimitry Andric   // Constant Base case.
4260b57cec5SDimitry Andric   if (ConstantFP *CF = dyn_cast<ConstantFP>(Base)) {
4270b57cec5SDimitry Andric     double D = CF->getValueAPF().convertToDouble();
4280b57cec5SDimitry Andric     if (D < 1.0f || D > APInt::getMaxValue(8).getZExtValue()) {
4290b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "Not handled pow(): constant base out of range\n");
4300b57cec5SDimitry Andric       return nullptr;
4310b57cec5SDimitry Andric     }
4320b57cec5SDimitry Andric 
4330b57cec5SDimitry Andric     ++NumWrappedOneCond;
43406c3fb27SDimitry Andric     return createCond(CI, Exp, CmpInst::FCMP_OGT, 127.0f);
4350b57cec5SDimitry Andric   }
4360b57cec5SDimitry Andric 
4370b57cec5SDimitry Andric   // If the Base value coming from an integer type.
4380b57cec5SDimitry Andric   Instruction *I = dyn_cast<Instruction>(Base);
4390b57cec5SDimitry Andric   if (!I) {
4400b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Not handled pow(): FP type base\n");
4410b57cec5SDimitry Andric     return nullptr;
4420b57cec5SDimitry Andric   }
4430b57cec5SDimitry Andric   unsigned Opcode = I->getOpcode();
4440b57cec5SDimitry Andric   if (Opcode == Instruction::UIToFP || Opcode == Instruction::SIToFP) {
4450b57cec5SDimitry Andric     unsigned BW = I->getOperand(0)->getType()->getPrimitiveSizeInBits();
4460b57cec5SDimitry Andric     float UpperV = 0.0f;
4470b57cec5SDimitry Andric     if (BW == 8)
4480b57cec5SDimitry Andric       UpperV = 128.0f;
4490b57cec5SDimitry Andric     else if (BW == 16)
4500b57cec5SDimitry Andric       UpperV = 64.0f;
4510b57cec5SDimitry Andric     else if (BW == 32)
4520b57cec5SDimitry Andric       UpperV = 32.0f;
4530b57cec5SDimitry Andric     else {
4540b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "Not handled pow(): type too wide\n");
4550b57cec5SDimitry Andric       return nullptr;
4560b57cec5SDimitry Andric     }
4570b57cec5SDimitry Andric 
4580b57cec5SDimitry Andric     ++NumWrappedTwoCond;
45906c3fb27SDimitry Andric     return createOrCond(CI, Base, CmpInst::FCMP_OLE, 0.0f, Exp,
46006c3fb27SDimitry Andric                         CmpInst::FCMP_OGT, UpperV);
4610b57cec5SDimitry Andric   }
4620b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Not handled pow(): base not from integer convert\n");
4630b57cec5SDimitry Andric   return nullptr;
4640b57cec5SDimitry Andric }
4650b57cec5SDimitry Andric 
4660b57cec5SDimitry Andric // Wrap conditions that can potentially generate errno to the library call.
4670b57cec5SDimitry Andric void LibCallsShrinkWrap::shrinkWrapCI(CallInst *CI, Value *Cond) {
4680b57cec5SDimitry Andric   assert(Cond != nullptr && "ShrinkWrapCI is not expecting an empty call inst");
4690b57cec5SDimitry Andric   MDNode *BranchWeights =
470*0fca6ea1SDimitry Andric       MDBuilder(CI->getContext()).createUnlikelyBranchWeights();
4710b57cec5SDimitry Andric 
4720b57cec5SDimitry Andric   Instruction *NewInst =
47306c3fb27SDimitry Andric       SplitBlockAndInsertIfThen(Cond, CI, false, BranchWeights, &DTU);
4740b57cec5SDimitry Andric   BasicBlock *CallBB = NewInst->getParent();
4750b57cec5SDimitry Andric   CallBB->setName("cdce.call");
4760b57cec5SDimitry Andric   BasicBlock *SuccBB = CallBB->getSingleSuccessor();
4770b57cec5SDimitry Andric   assert(SuccBB && "The split block should have a single successor");
4780b57cec5SDimitry Andric   SuccBB->setName("cdce.end");
4790b57cec5SDimitry Andric   CI->removeFromParent();
480bdd1243dSDimitry Andric   CI->insertInto(CallBB, CallBB->getFirstInsertionPt());
4810b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "== Basic Block After ==");
4820b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << *CallBB->getSinglePredecessor() << *CallBB
4830b57cec5SDimitry Andric                     << *CallBB->getSingleSuccessor() << "\n");
4840b57cec5SDimitry Andric }
4850b57cec5SDimitry Andric 
4860b57cec5SDimitry Andric // Perform the transformation to a single candidate.
4870b57cec5SDimitry Andric bool LibCallsShrinkWrap::perform(CallInst *CI) {
4880b57cec5SDimitry Andric   LibFunc Func;
4890b57cec5SDimitry Andric   Function *Callee = CI->getCalledFunction();
4900b57cec5SDimitry Andric   assert(Callee && "perform() should apply to a non-empty callee");
4910b57cec5SDimitry Andric   TLI.getLibFunc(*Callee, Func);
4920b57cec5SDimitry Andric   assert(Func && "perform() is not expecting an empty function");
4930b57cec5SDimitry Andric 
4940b57cec5SDimitry Andric   if (performCallDomainErrorOnly(CI, Func) || performCallRangeErrorOnly(CI, Func))
4950b57cec5SDimitry Andric     return true;
4960b57cec5SDimitry Andric   return performCallErrors(CI, Func);
4970b57cec5SDimitry Andric }
4980b57cec5SDimitry Andric 
4990b57cec5SDimitry Andric static bool runImpl(Function &F, const TargetLibraryInfo &TLI,
5000b57cec5SDimitry Andric                     DominatorTree *DT) {
5010b57cec5SDimitry Andric   if (F.hasFnAttribute(Attribute::OptimizeForSize))
5020b57cec5SDimitry Andric     return false;
50306c3fb27SDimitry Andric   DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
50406c3fb27SDimitry Andric   LibCallsShrinkWrap CCDCE(TLI, DTU);
5050b57cec5SDimitry Andric   CCDCE.visit(F);
5060b57cec5SDimitry Andric   bool Changed = CCDCE.perform();
5070b57cec5SDimitry Andric 
5080b57cec5SDimitry Andric   // Verify the dominator after we've updated it locally.
50906c3fb27SDimitry Andric   assert(!DT ||
51006c3fb27SDimitry Andric          DTU.getDomTree().verify(DominatorTree::VerificationLevel::Fast));
5110b57cec5SDimitry Andric   return Changed;
5120b57cec5SDimitry Andric }
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric PreservedAnalyses LibCallsShrinkWrapPass::run(Function &F,
5150b57cec5SDimitry Andric                                               FunctionAnalysisManager &FAM) {
5160b57cec5SDimitry Andric   auto &TLI = FAM.getResult<TargetLibraryAnalysis>(F);
5170b57cec5SDimitry Andric   auto *DT = FAM.getCachedResult<DominatorTreeAnalysis>(F);
5180b57cec5SDimitry Andric   if (!runImpl(F, TLI, DT))
5190b57cec5SDimitry Andric     return PreservedAnalyses::all();
5200b57cec5SDimitry Andric   auto PA = PreservedAnalyses();
5210b57cec5SDimitry Andric   PA.preserve<DominatorTreeAnalysis>();
5220b57cec5SDimitry Andric   return PA;
5230b57cec5SDimitry Andric }
524