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