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