| 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>(Val: 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>(Val: 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 | Name: MASSEntryStr, T: Func.getFunctionType(), AttributeList: 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(x: 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>(Val: User)) { |
| 129 | if (isCandidateSafeToLower(CI: *CI)) |
| 130 | Changed |= createScalarMASSCall(MASSEntry: Iter->second, CI&: *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 | |