1 //===-- PPCGenScalarMASSEntries.cpp ---------------------------------------===// 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 transformation converts standard math functions into their 10 // corresponding MASS (scalar) entries for PowerPC targets. 11 // Following are examples of such conversion: 12 // tanh ---> __xl_tanh_finite 13 // Such lowering is legal under the fast-math option. 14 // 15 //===----------------------------------------------------------------------===// 16 17 #include "PPC.h" 18 #include "PPCSubtarget.h" 19 #include "llvm/Analysis/TargetTransformInfo.h" 20 #include "llvm/CodeGen/TargetPassConfig.h" 21 #include "llvm/IR/Instructions.h" 22 #include "llvm/IR/Module.h" 23 24 #define DEBUG_TYPE "ppc-gen-scalar-mass" 25 26 using namespace llvm; 27 28 namespace { 29 30 class PPCGenScalarMASSEntries : public ModulePass { 31 public: 32 static char ID; 33 34 PPCGenScalarMASSEntries() : ModulePass(ID) { 35 ScalarMASSFuncs = { 36 #define TLI_DEFINE_SCALAR_MASS_FUNCS 37 #include "llvm/Analysis/ScalarFuncs.def" 38 }; 39 } 40 41 bool runOnModule(Module &M) override; 42 43 StringRef getPassName() const override { 44 return "PPC Generate Scalar MASS Entries"; 45 } 46 47 void getAnalysisUsage(AnalysisUsage &AU) const override { 48 AU.addRequired<TargetTransformInfoWrapperPass>(); 49 } 50 51 private: 52 std::map<StringRef, StringRef> ScalarMASSFuncs; 53 bool isCandidateSafeToLower(const CallInst &CI) const; 54 bool isFiniteCallSafe(const CallInst &CI) const; 55 bool createScalarMASSCall(StringRef MASSEntry, CallInst &CI, 56 Function &Func) const; 57 }; 58 59 } // namespace 60 61 // Returns true if 'afn' flag exists on the call instruction with the math 62 // function 63 bool PPCGenScalarMASSEntries::isCandidateSafeToLower(const CallInst &CI) const { 64 // skip functions with no scalar or vector FP type (like cosisin) 65 if (!isa<FPMathOperator>(CI)) 66 return false; 67 68 return CI.hasApproxFunc(); 69 } 70 71 // Returns true if 'nnan', 'ninf' and 'nsz' flags exist on the call instruction 72 // with the math function 73 bool PPCGenScalarMASSEntries::isFiniteCallSafe(const CallInst &CI) const { 74 // skip functions with no scalar or vector FP type (like cosisin) 75 if (!isa<FPMathOperator>(CI)) 76 return false; 77 78 // FIXME: no-errno and trapping-math need to be set for MASS converstion 79 // but they don't have IR representation. 80 return CI.hasNoNaNs() && CI.hasNoInfs() && CI.hasNoSignedZeros(); 81 } 82 83 /// Lowers scalar math functions to scalar MASS functions. 84 /// e.g.: tanh --> __xl_tanh_finite or __xl_tanh 85 /// Both function prototype and its callsite is updated during lowering. 86 bool PPCGenScalarMASSEntries::createScalarMASSCall(StringRef MASSEntry, 87 CallInst &CI, 88 Function &Func) const { 89 if (CI.use_empty()) 90 return false; 91 92 Module *M = Func.getParent(); 93 assert(M && "Expecting a valid Module"); 94 95 std::string MASSEntryStr = MASSEntry.str(); 96 if (isFiniteCallSafe(CI)) 97 MASSEntryStr += "_finite"; 98 99 FunctionCallee FCache = M->getOrInsertFunction( 100 MASSEntryStr, Func.getFunctionType(), Func.getAttributes()); 101 102 CI.setCalledFunction(FCache); 103 104 return true; 105 } 106 107 bool PPCGenScalarMASSEntries::runOnModule(Module &M) { 108 bool Changed = false; 109 110 auto *TPC = getAnalysisIfAvailable<TargetPassConfig>(); 111 if (!TPC || skipModule(M)) 112 return false; 113 114 for (Function &Func : M) { 115 if (!Func.isDeclaration()) 116 continue; 117 118 auto Iter = ScalarMASSFuncs.find(Func.getName()); 119 if (Iter == ScalarMASSFuncs.end()) 120 continue; 121 122 // The call to createScalarMASSCall() invalidates the iterator over users 123 // upon replacing the users. Precomputing the current list of users allows 124 // us to replace all the call sites. 125 SmallVector<User *, 4> TheUsers(Func.users()); 126 127 for (auto *User : TheUsers) 128 if (auto *CI = dyn_cast_or_null<CallInst>(User)) { 129 if (isCandidateSafeToLower(*CI)) 130 Changed |= createScalarMASSCall(Iter->second, *CI, Func); 131 } 132 } 133 134 return Changed; 135 } 136 137 char PPCGenScalarMASSEntries::ID = 0; 138 139 char &llvm::PPCGenScalarMASSEntriesID = PPCGenScalarMASSEntries::ID; 140 141 INITIALIZE_PASS(PPCGenScalarMASSEntries, DEBUG_TYPE, 142 "Generate Scalar MASS entries", false, false) 143 144 ModulePass *llvm::createPPCGenScalarMASSEntriesPass() { 145 return new PPCGenScalarMASSEntries(); 146 } 147