//===-- LibCallsShrinkWrap.cpp ----------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This pass shrink-wraps a call to function if the result is not used. // The call can set errno but is otherwise side effect free. For example: // sqrt(val); // is transformed to // if (val < 0) // sqrt(val); // Even if the result of library call is not being used, the compiler cannot // safely delete the call because the function can set errno on error // conditions. // Note in many functions, the error condition solely depends on the incoming // parameter. In this optimization, we can generate the condition can lead to // the errno to shrink-wrap the call. Since the chances of hitting the error // condition is low, the runtime call is effectively eliminated. // // These partially dead calls are usually results of C++ abstraction penalty // exposed by inlining. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/LibCallsShrinkWrap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/DomTreeUpdater.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstVisitor.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/MDBuilder.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include <cmath> usingnamespacellvm; #define DEBUG_TYPE … STATISTIC(NumWrappedOneCond, "Number of One-Condition Wrappers Inserted"); STATISTIC(NumWrappedTwoCond, "Number of Two-Condition Wrappers Inserted"); namespace { class LibCallsShrinkWrap : public InstVisitor<LibCallsShrinkWrap> { … }; } // end anonymous namespace // Perform the transformation to calls with errno set by domain error. bool LibCallsShrinkWrap::performCallDomainErrorOnly(CallInst *CI, const LibFunc &Func) { … } // Perform the transformation to calls with errno set by range error. bool LibCallsShrinkWrap::performCallRangeErrorOnly(CallInst *CI, const LibFunc &Func) { … } // Perform the transformation to calls with errno set by combination of errors. bool LibCallsShrinkWrap::performCallErrors(CallInst *CI, const LibFunc &Func) { … } // Checks if CI is a candidate for shrinkwrapping and put it into work list if // true. void LibCallsShrinkWrap::checkCandidate(CallInst &CI) { … } // Generate the upper bound condition for RangeError. Value *LibCallsShrinkWrap::generateOneRangeCond(CallInst *CI, const LibFunc &Func) { … } // Generate the lower and upper bound condition for RangeError. Value *LibCallsShrinkWrap::generateTwoRangeCond(CallInst *CI, const LibFunc &Func) { … } // For pow(x,y), We only handle the following cases: // (1) x is a constant && (x >= 1) && (x < MaxUInt8) // Cond is: (y > 127) // (2) x is a value coming from an integer type. // (2.1) if x's bit_size == 8 // Cond: (x <= 0 || y > 128) // (2.2) if x's bit_size is 16 // Cond: (x <= 0 || y > 64) // (2.3) if x's bit_size is 32 // Cond: (x <= 0 || y > 32) // Support for powl(x,y) and powf(x,y) are TBD. // // Note that condition can be more conservative than the actual condition // (i.e. we might invoke the calls that will not set the errno.). // Value *LibCallsShrinkWrap::generateCondForPow(CallInst *CI, const LibFunc &Func) { … } // Wrap conditions that can potentially generate errno to the library call. void LibCallsShrinkWrap::shrinkWrapCI(CallInst *CI, Value *Cond) { … } // Perform the transformation to a single candidate. bool LibCallsShrinkWrap::perform(CallInst *CI) { … } static bool runImpl(Function &F, const TargetLibraryInfo &TLI, DominatorTree *DT) { … } PreservedAnalyses LibCallsShrinkWrapPass::run(Function &F, FunctionAnalysisManager &FAM) { … }